OmniAICreator/Qiita-1.07M huggingface dataset:
ProtocとWireで生成されるJavaファイルとバイトコードのサイズを比較してみた

GradleでProtocol Bufferを使う時には[GoogleのProtobuf Plugin for Gradle](https://github.com/google/protobuf-gradle-plugin)か[WireのGradle Plugin](https://github.com/square/wire/blob/master/wire-library/docs/wire_compiler.md)が主流だと思いますが、それぞれのコンパイラ(protoc/wire)で生成されるJavaファイル(およびKotlinファイル)のサイズと、さらにそれをJVMバイトコードにコンパイルした時のファイルサイズを比較してみました。

きっかけはSquare社の[Introducing Wire Protocol Buffersという記事](https://developer.squareup.com/blog/introducing-wire-protocol-buffers/)で、Protocol Bufferの実装を**protocからwireに変えたらメソッドが10,000くらい減った**と書いてあり、ファイルサイズでいうとどのくらい減るのかが気になったためです。

> For the Square Register app, generated Protocol Buffer code was taking up a large chunk of our method space. By switching to Wire, we removed almost 10,000 methods from our application and gained a lot of breathing room to add new features

## コンパイル対象のprotoファイル
コンパイル対象とするproroファイルは以下です。

```Persion.proto
syntax="proto3";

option java_package = "com.example.protobufsample";

// This is Person
message Person {
  string first_name = 1;
  string last_name = 2;
  repeated string family_names = 3;
}
```

## protoc/wireのコンパイルで生成されたJavaファイルの比較



|  コンパイラ  |  生成ファイル  | ファイルサイズ |
| ---- | ---- | ----|
|  protoc  |  Person.java  |20K|
|  Wire  |  Person.java  |6.4K|
|  Wire  |  Person.kt  |5.1K|

protocがGoogleのProtocol Bufferの実装で、WireはそのままWireですが、見ての通り、**wireの方が3~4倍ファイルサイズが小さい**ですね。
ファイルサイズのみならず、[可読性](https://square.github.io/wire/#why-wire)の面でも、Wireの方が良い印象。

## JVMバイトコードのファイルサイズの比較

実際にJVMのメモリに乗る時のサイズでも一応見比べてみるために、今度はさっきのjava/kotlinファイルを、classファイルに変換してみます。

|  元のコンパイラ  |  java/kotlinファイル  | classファイル | ファイルサイズ(合計)
| ---- | ---- | ----| ----|
|  protoc  |  Person.java  |Person\$1.class, Person\$Person\$Builder.class, Person\$Person.class, Person\$PersonOrBuilder.class, Person.class| 17K |
|  Wire  |  Person.java  |Person\$Builder.class, Person\$ProtoAdapter_Person.class, Person.class|9.1K|
|  Wire  |  Person.kt  |Person\$Companion\$ADAPTER\$1.class, Person\$Companion.class, Person.class|13K|

先のjava/kotlinの時にはWireかつKotlinの組み合わせ一番小さかったですが、さらにJVMバイトコードになると、まぁ予想通り、WireかつJavaファイルの組み合わせが一番小さかったです。

なお補足ですが、JVMバイトコードへの変換はそれぞれ以下のようにやりました。
バージョンの箇所は適宜ご自分の環境に合わせてください。

```terminal
// protocで生成されたjavaファイルをclassファイルに変換
javac -cp path/to/protobuf-java-3.0.0.jar Person.java
```
```terminal
// Wireで生成されたjavaファイルをclassファイルに変換
javac -cp path/to/wire-compiler-3.6.1-jar-with-dependencies.jar Person.java
```
```terminal
// Wireで生成されたKotlinファイルをclassファイルに変換
kotlinc -jvm-target 1.8 -cp path/to/wire-compiler-3.6.1-jar-with-dependencies.jar Person.kt
```


##まとめ
protocやWire自体のサイズ、あるいは依存ライブラリも含めたサイズがどっちが大きいかまでは調べてないですが、少なくとも生成されるJVMバイトコードのサイズで比較する限りは、Gradleでprotoファイルをコンパイルする場合、**WireでJavaファイルにコンパイルすることで場合によってはprotocより50%減**できるかもしれないですね。もし可読性も重視するのでしたら、WireとKotlinの組み合わせが良きかなと思います、それでも70%ほど減らせる可能性があるので。

参考：
- https://developer.squareup.com/blog/introducing-wire-protocol-buffers/
- https://square.github.io/wire/wire_vs_protoc/
- https://search.maven.org/search?q=g:com.squareup.wire%20AND%20a:wire-compiler
- https://search.maven.org/artifact/com.google.protobuf/protobuf-java/3.15.0/bundle
Rustにおける変数の不変性と可変性

# Rustにおける変数の不変性

* Rustでは、変数は不変を推奨しています。
* 変数が不変とは、値が一旦名前と結びつけられたら、その値を変えることができないことを指します。

例

```Rust
fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

```

実行結果

```
❯ cargo run                
   Compiling variables v0.1.0 (/Users/yoshitaka.koitabashi/Desktop/variables)
error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: make this binding mutable: `mut x`
3 |     println!("The value of x is: {}", x);
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0384`.
error: could not compile `variables`

To learn more, run the command again with --verbose.
```

* 実行結果から分かるように、コンパイルエラーで落ちています。
* エラーの原因は、不変変数xに2回代入(変数に別の値を代入)できない為です。

=> Rustでは、値が不変だと宣言したら、変わらないことをコンパイラが担保します。

# Rustにおける変数の可変性

* Rustにおいて、変数を不変としてしか扱えない訳ではない。(標準として、不変なだけ)
* 変数名の前に**mut**を付けることで、**可変にできます**。

例

```Rust
fn main() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}
```

実行結果

```
❯ cargo run
   Compiling variables v0.1.0 (/Users/yoshitaka.koitabashi/Desktop/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.94s
     Running `target/debug/variables`
The value of x is: 5
The value of x is: 6
```

# Rustにおける定数

変数の値を変更できないようにする概念として**定数**があります。
ただ、変数と定数での違いがありそれが下記です。

* **mut**は使えない。(常に不変である為)
* **let**の代わりに、**const**で宣言し、**値の型は必ず注釈しないといけない**。
* どんなスコープでも定義できる。(グローバルスコープも含めて)
* 定数式にしか設定できない(関数呼び出し結果や、実行時に評価される値にはセットできない)
* プログラムが走る期間、定義されたスコープ内でずっと有効

例

```Rust
const MAX_POINTS: u32 = 100_000;
```

# 参考文献
* [THE BOOK 3章](https://doc.rust-lang.org/book/)
CarrierwaveとFogを使ってS3にアップロードしているファイルをダウンロードする署名付きURLの有効期限を指定する方法

ファイルのダウンロードを1週間ほど許可したい要件があったのですが、 [有効期限がデフォルトで600秒に設定されて](https://github.com/carrierwaveuploader/carrierwave/blob/2a0fefcd7762f91292fbc84911fc91f142699766/lib/carrierwave/uploader/configuration.rb#L193)おり、変更方法がなかなかわからなかったのでメモしておきます。

以下のモデルがある場合、

```ruby
class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader
end
```

有効期限を1週間後にする場合は以下になります。

```ruby
User.first.avatar.file.url(expire_at: Time.now + 604800)
```

該当のコードは[こちら](https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/storage/fog.rb#L204)。
【Laravel】.envファイルの情報を編集して、DBを作成する。

```php

DB_CONNECTION=mysql
DB_HOST=<サーバー名>
DB_PORT=3306
DB_DATABASE=clothes_app
DB_USERNAME=<ユーザーネーム>
DB_PASSWORD=<パスワード>
```
これで、phpmyadminなどでDBにアクセスすることができる。
Dockerfileの`COPY`に注意せよ！

畑田です。  
最近チーム内での開発でDockerfileを書くことがしばしばあるのですが、いくつ書きになる点があったので整理しました。  
その中でも`ADD`と`COPY`の違いとともに**`COPY`における注意点**をまとめておきます。

# Dockerfileの`ADD`と`COPY`について
`ADD`と`COPY`は機能が似ていますが、`COPY`が単にlocalのファイルをcontainerにコピーするだけなのに対して、`ADD`はtarファイルの展開やremote URLからのデータの取得をサポートしています。  
したがって、localファイルのコピーを意図しているときにはより限定的な意味の`COPY`を用いることがdockerによって推奨されています。  
さらに、`ADD`によってremote URLを用いてリソースを取得することは非推奨とされており、`curl`や`wget`を`RUN`コマンドによって実行することが推奨されます。  
このため、ADDコマンドはtar展開などを含んだcontainerへのリソース追加に適用することが推奨されていると考えられます。  

# Dockerfileの`COPY`における注意点
上の項目でも推奨している`COPY`について、directoryをコピーするときに注意する必要があります。  
まず、以下のようにファイルをコピーするときにはなんら問題は生じません。  

```Dockerfile
COPY ./package*.json ./
```
しかし、次のようにdirectory自体をコピーしようとするときに問題は生じます。

```Dockerfile
COPY ./src/ ./
```
このように書いてしまうと、host machineの`./src/`の中身がcontainer machineの`./`のなかに展開されてコピーされてしまいます。(イメージはJavaScriptの`[...data]`です。違うか。)  
つまり、container machineの`./`が空であれば、container machineの`./`はhost machineの`./src/`と全く同じものになるし、もともと中身が入っていればmergeされてしまうということです。  
展開せずにcontainer machineの`./`の下に`./src`としてコピーしたい場合は以下のように記述してください。

```Dockerfile
COPY ./src/ ./src/
```
この仕様に若干の違和感があるのは、Linux系共通コマンドである以下のものと仕様が異なるからだと思います。

```sh
$ cp -r DIRECTORY_NAME DESTINATION
```
オブジェクト/コンパニオンオブジェクトを拡張する

# 概要
コンパニオンオブジェクトも同じくインスタンスであるため同じくimplicit classでメソッドを生やすことが出来るのでその方法を記す。

# 適用先
適用先としては以下の物が挙げられる。

- テストでしか使用したくない・使用させたくないメソッドを定義したい
- 外部ライブラリのオブジェクトにメソッドを追加したい

# 方法
objectの型は***type***で取ることが出来るので、それに対してimplicit classを定義しているだけである。***t*** の部分は通常不要だが書かなければいけないので適当に書いている。また ***t*** をコンパニオンオブジェクトとして利用することも出来る。

```scala
object Scalab {

  def main(args: Array[String]): Unit = {

    SampleObject.newMethod
    // SampleObject!

    SampleCaseClass.newMethod
    // SampleCaseClass!

    println(SampleCaseClass.getNew)
    // SampleCaseClass(1)
  }

  object SampleObject

  implicit class SampleObjectOps(t: SampleObject.type) {

    def newMethod = println("SampleObject!")

  }

  case class SampleCaseClass(i: Int)

  implicit class SampleCaseClassOps(t: SampleCaseClass.type) {

    def newMethod = println("SampleCaseClass!")
    
    def getNew = t(1)
  }

}
```
解決！Your Ruby version is x.x.x, but your Gemfile specified x.x.x

#Herokuにデプロイしようとすると...
ruby のバージョンが 2.6.3 になっているけど、2.6.6 を使用しろと言われた。
この時点で参考にした[サイト][link-1]はこちら。
[link-1]:
https://qiita.com/___xxx_/items/12c8ab953bc6aaeb8c24#1ruby%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92266%E3%81%8B272%E3%81%8B300%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B

まずはrbenv でバージョンを変えてみて確認する。

```terminal:ターミナル
% rbenv global 2.６.6
% rbenv versions
  system
  2.5.1
  2.6.3
* 2.6.6 (set by /Users/randytozuka/.rbenv/version)

```
フムフム 2.6.6 になったね。
じゃ、念の為…

```
% ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin20]
```
ありゃ？ 2.6.３ のまま？！ とりあえずbundle install してみっか・・・

```
% bundle install      
Your Ruby version is 2.6.3, but your Gemfile specified 2.6.6
```

やっぱり指導される…
プロジェクト直下に .ruby-version というものが生成されていてこれがある状態だと、rbenv で選択しているversion よりこちらが優先されるのでまずこのファイルを削除し、
その後 rbenv のバージョンを変え、
さらに Gemfiles の ruby '2.6.3' の記述も変更してから再度 bundle install！
…結果変わらず…

色々もがいた末に、

```
$ rbenv init
# Load rbenv automatically by appending
# the following to ~/.bash_profile:

eval "$(rbenv init -)"
```
で、

```
% source ~/.bash_profile
% rbenv versions
  system
  2.5.1
  2.6.3
* 2.6.6 (set by /Users/randytozuka/.rbenv/version)

% ruby -v
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin20]
```
お！ なんとかうまく行った！！
２日彷徨いました・・・
【SAP Data Warehouse Cloud】オンプレ OracleDBへの接続手順 ~その１~

年初からSAP Data Warehouse Cloud（以下DWC）に触れる機会がありました。

そもそもデータウェアハウスの知見があまり無い。というかSAP製品触るの初めてに等しい。
そんな感じのエンジニアが、とりあえず得意なOracle DBと繋げてみました。


# 目的
DWCからオンプレのOracle DB(12c)へ接続して、テーブルを参照する。
（PDBでもOK）

※サーバのOSはWindows Server 2016です。

# 作業工程

ざっとこんな感じです。
検証したのが2021年1月頃。現在バージョンと変わっている部分もあるかと思うのでご勘弁を。

まぁまぁ長いので今回はStep.1~3から始めていきます。

| Step.| 内容 |
|:-:|:-|
| 1 | DP Agentの入手  |
| 2 |  DP Agentのインストール |
| 3 |  IP許可リストの登録 |
| 4 |  DP Agentの設定 |
| 5 |  サードパーティのドライバアップロード |
| 6 |  DP Agentの疎通確認 |
| 7 |  データベースへの接続 |


# Step.1 DP Agentの入手
[SAP Support Portal](https://support.sap.com/en/index.html)からDP Agentの最新版をダウンロードします。  
ダウンロードファイル：SAP Software Download Center > Support Packages and Patches > By Category > SAP IN-MEMORY (SAP HANA) > HANA PLATFORM EDITION > SAP HANA SDI > SAP HANA SDI 2.0 > COMPRISED SOFTWARE COMPONENT VERSIONS > HANA DP AGENT 2.0 > 最新Patch`  

もしダウンロードする権限が無ければ[SAP Development Tools](https://tools.hana.ondemand.com/#cloudintegration)からダウンロードします。
こちらのほうが簡単。（WindowsのDP Agentをダウンロードします）
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/fd09b9b9-5ec7-7d5f-4917-ed3ba2d6f8a0.png)

# Step.2  DP Agentのインストール
ダウンロードしたファイルをDP Agentをインストールするマシンへ展開し、「hdpsetup.exe」を管理者権限で実行します。 
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/9f4891d1-b725-57ff-a527-d0a4171b19f9.png)


インストール画面。エージェントのインストールフォルダを変更する必要が無ければ、そのまま「Next」をクリック。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/d2551b3a-2493-fcee-fbef-e6d9ded10149.png)  

インストール情報を入力する。入力後に「Next」をクリック。
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/835e25d5-6b85-bada-3d2b-e20acb13e01e.png)　　


| 設定項目 | 設定値 |
|:-|:-|
|Installation path   | デフォルトのままでよい。  |
| Agent Unique Name  | ユニークな名前をつける。ここでつけた名前はサービス名の接尾辞として使われる。  |
|Domain\Username for Agent service   |DP Agentを動かすユーザーを入力。（できればAdministratorではなく専用ユーザーを作成して利用する）   |
|Pasword for Agent service user   |DP Agentを動かすユーザーのパスワードを入力。   |
|Agent Listener Port   | デフォルトのまま。  |
|Agent Administration Port   | デフォルトのまま。  |
|Custom JRE directory   | 空白でよい。　　
　　

設定した情報に誤りが無ければ「Install」をクリック。
![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/17328123-a46d-ac7e-59d8-7f821c53cad8.png)

インストールが行われます。
![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/34e8ac94-62e3-d2df-7f5d-37bc5d9e2b51.png)

インストール完了。「Finish」をクリック。
![キャプチャ6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/d7b08c27-273a-5dc3-a530-7038d4e503ef.png)






# Step.3  IP許可リストの登録

DWCの管理画面から「IP許可リスト」を開き、DP AgentをインストールしたサーバのグローバルIPを入力します。
これでDWCとオンプレのサーバが通信できます。

「グローバルIPが分からん！」という方は[ここ](https://www.cman.jp/network/support/go_access.cgi)で確認を。


![キャプチャ7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064296/69eadb99-6b53-0657-ff82-7008c42f9fcc.png)


# 次回
Step.4 DP Agentの疎通確認
Step.5 サードパーティのドライバアップロード

https://qiita.com/sebastian85/items/914e7d03aaa863521334
Django + Ajaxでいいねボタンを実装

DjangoとAjaxを使っていいねボタンを実装します。
いいねボタンは以下のようにします。
・記事一つ一つにつける
・いいねボタンは何回も押せる
・いいねボタンは「いいね (数字)」のようにしてボタンが押されるたびにかっこの中の数字が増えるようにする。

```urls.py
from django.urls import path
from . import views

app_name = 'article'
urlpatterns = [
    path('<int:article_id>/like/', views.like, name='like'),
]
```

```views.py
from django.http import Http404
# データをJSON型に変換する
from django.shortcuts import get_object_or_404
from django.http import JsonResponse

from .models import Article

def like(request, book_id):
    try:
        article = Article.objects.get(id=article_id)

    # 記事が存在しない時はエラーメッセージを表示する
    except Article.DoesNotExist:
        raise Http404

    # この関数が呼び出された時にlikeに１を足して保存する
    article.like += 1
    article.save()

    article = get_object_or_404(Article, id=article_id)

    return JsonResponse({"article_like": article.like, "article_id": article.id})
```

```index.html
<!--JQuery-->
<script src="https://code.jquery.com/jquery-3.5.0.js"
        integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>

<!--いいねボタン-->
<a href="javascript:void(0)" id="article_{{ article.id }}" class="like"
name="{{ article.id }}" type="button">いいね ({{ article.like }})</a>

<script type="text/javascript">
//cookie
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');

    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
        crossDomain: false, // obviates need for sameOrigin test
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });

    //いいねボタンが押されたら非同期通信を行う
    $('.like').on('click', function () {
        var article_id = $(this).attr('name')
        $.ajax({
            type: 'POST',
            method: 'POST',
            url: article_id + '/like/',
            data: {
                'id': article_id
            },
            dataType: 'json'
        }).done(function (data) {
//views.pyからarticle_id, article_likeをjson型のデータで受け取る
//'#article_' + String(data['article_id'])で記事それぞれのidを指定する
            $('#article_' + String(data['article_id'])).text('いいね' + '(' + String(data['article_like']) + ')');
        })
    });

</script>
```

これでいいねボタンがクリックされてもリロードなしでボタンの中身を更新できます！
間違い等あればご指摘していただけると嬉しいです！
最後まで読んでいただきありがとうございました！
jQueryを使わずにページ内スムーススクロールの実装

#はじめに
ページ内でのスクロールをスムーススクロールで実装したい。
その際に、jQueryを使って実装するのも方法ですが、使わなくてもそんなに複雑な記述なしで簡単に実装することが可能です。
以下より、その方法について解説していきたいと思います。

##最初にコードの確認
```html:index.html
<nav id="pageAnker">
  <a href="#anker1"></a>
  <a href="#anker2"></a>
  <a href="#anker3"></a>
  <a href="#anker4"></a>
  <a href="#anker5"></a>
</nav>
```


```js:index.js
const pageAnkers = document.querySelectorAll("#pageAnker a");
pageAnkers.forEach(pageAnker => {
  pageAnker.addEventListener("click", e => {
    e.preventDefault();
    const ankerId = e.target.hash;
    const ankerTarget = document.querySelector(ankerId);
    ankerTarget.scrollIntoView({ behavior: "smooth" });
  });
});
```
スムーススクロールの記述は、これだけです。
次項より、各記述部分を解説していきます。

##最初にページ内のアンカーを取得

```js:index.js
const pageAnkers = document.querySelectorAll("#pageAnker a");
```

* ここでは仮に、`<nav>`タグ内のアンカーを`document.querySelectorAll("#pageAnker a")`ですべて取得します。<br>取得したアンカーはすべて、定義した定数`pageAnkers`に格納されます。

##取得したアンカーにそれぞれクリックイベントを追加する
```js:index.js
pageAnkers.forEach(pageAnker => {
  pageAnker.addEventListener("click", e => {

　　〜〜〜〜〜中略〜〜〜〜〜

  });
});
```
* 取得したアンカー`pageAnkers`にそれぞれアクセスして処理するためには、`forEach`を使います。<br>個別にアクセスする際に、使う引数は`pageAnker`になります。

* `pageAnker`に対して`addEventListener`で、イベントの種類に`"click"`を指定し、引数にイベントハンドラの`e`を与えます。これにより、クリックしたアンカーに対して`{}`内の記述を実行することができます。

##スムーススクロールのイベントの記述
```js:index.js
〜〜〜〜〜中略〜〜〜〜〜
pageAnkers.forEach(pageAnker => {
  pageAnker.addEventListener("click", e => {
    e.preventDefault();
    const ankerId = e.target.hash;
    const ankerTarget = document.querySelector(ankerId);
    ankerTarget.scrollIntoView({ behavior: "smooth" });
  });
});
```
* 最初の処理に、`e.preventDefault()`を指定してアンカーをクリックした際のページ遷移を無効にします。

* `e.target.hash`でイベントハンドラ(クリックイベントが発生したアンカー)のhref属性の値を取得し、定数`ankerId`に格納します。

* `document.querySelector`で、`ankerId`と一致するid属性を持つセレクターを取得し、定数`ankerTarget`に格納します。

* 最後に`ankerTarget.scrollIntoView({ behavior: "smooth" })`[^1]で、取得したセレクター`ankerTarget`までスクロールを実行します。
[^1]: `scrollIntoView`メソッドは、オプションで`behavior: "smooth"`を指定することでスクロールのアニメーションを指定しています。

#まとめ
スムーススクロールの記述は、そんなに難しくなく仕組みさえ分かってしまえば非常に簡単なものです。
ただ、今回の記述はIE11などのブラウザでは非対応のメソッドを使用しているため注意が必要です。
IE11への対応版は、今後の更新で取り上げる予定なので今しばらくお待ちください。
Nginx リバースプロキシ基本設定

#まず始めに
　前回まとめた[ロードバランサ設定](https://qiita.com/noblin_1031/items/751cbe6d62125f851ee8)の記事もぜひ見てください。
　今回はリバースプロキシの基本設定についてまとめました。

#プロキシとは？
　プロキシ(Proxy)とは、日本語で”代理”を意味し
　サーバから外部インターネットへの接続を中継する**プロキシサーバ(フォワードプロキシ)**と呼ばれます。また、外部インターネットからサーバへの接続を中継する仕組みを**リバースプロキシ**と呼びます。
　リバースプロキシの役割としては負荷分散・キャッシュによる負荷軽減・SSL高速化やセキュリティ向上があげられます。
　今回はNginxにリバースプロキシを設定します。

#Nginxのリバースプロキシ設定
 

```nginx.conf
server{
    server_name    example.com;

    proxy_set_header    Host    $host;
    proxy_set_header    X-Real-IP    $remote_addr;
    proxy_set_header    X-Forwarded-Host       $host;
    proxy_set_header    X-Forwarded-Server    $host;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    location /example/ {
        proxy_pass    http://localhost:8080/app/;
    }

    location /example2/ {
        proxy_pass    http://example2.com/example/;
    }
}
```

　**proxy_set_header**… 転送先にアクセス元のIPやホスト情報を再定義・追加が可能です。
　　　　　　　　　　クッキーの書き換えも可能で、書き方は proxy_cookie_path /abc/ /edf/; のようになる。
　**proxy_hide_header**…ヘッダー情報を消します。
　　　　　　　　　　セキュリティ上クライアントに漏らしたくない情報を消します。
　**proxy_ignore_headers**…指定した値は無視する。Expiresだと無視するのでキャッシュされない。

```
proxy_connect_timeout　　10;
proxy_send_timeout　　10;
proxy_read_timeout　　60;
```
　**proxy_connect_timeout**…nginxから後続へのコネクションを張るタイムアウト時間。
　　　　　　　　　　　　デフォルトは１s。最大75s。10sの設定で十分だと思います。
　**proxy_send_timeout**…nginxから後続に対してデータ送信する際のタイムアウト値。
　　　　　　　　　　　送信で時間がかかることは無いので、10sの設定で十分だと思います。
　**proxy_read_timeout**…渡されたデータを後続が処理をし、レスポンスを返すタイムアウト値。
　　　　　　　　　　　後続のサーバでもタイムアウト値より長めに設定します。

```
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 　10;
proxy_next_upstream_tries 　2;
```

　**proxy_next_upstream**…どのリクエストをリトライするかを設定できます。
　　``error``:接続の確立時、リクエストを渡す時、応答ヘッダを読込時にエラーが起きた場合。
　　``timeout``:接続の確立時、リクエストを渡す時、応答ヘッダを読込時にタイムアウトが起きた場合。
　　``invalid_header``:サーバが空あるいは無効な応答を返した場合。
　　``http_XXX``:サーバがコードXXXの応答を返した場合。
　　　　　　　XXXには500,502,503,504,403,404,429が設定可能。
　　``non_idempotent``:1.9.13Ver以降、POST・LOCK・PATCHのリクエストは
　　　　　　　　　　　2重処理防止のためリトライされません。
　　　　　　　　　　　この設定を有効にすると上記のリクエストでもリトライされます。
　　``off ``:リクエストを次のサーバに渡すのを無効化する。
　**proxy_next_upstream_timeout**…リトライの間隔を制限します。0 の値はこの制限なし。
　**proxy_next_upstream_tries**…リトライ回数を制限します。0 の値はこの制限なし。



#最後に
　今回はリバースプロキシの基本設定をまとめました。
　[負荷分散](https://qiita.com/noblin_1031/items/751cbe6d62125f851ee8)の設定と組み合わせることで、かなり詳細な場合の設定も可能です。
　少しでも参考にしていただければと思います。
　
　最後まで読んでいただきありがとうございました。
【AWS】IAMの概要を5分で理解する

|　　　　　　　　  　　　　　　　　   　　　　　　　　　　　　　　　　　　　　　　　　　|
|:-:|
|![IAM (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1197988/5d94cd0c-4891-f37f-545b-0c6e5adea7fd.png)
|


# はじめに
自身の知識の整理も兼ねて、IAMの要点を記事にまとめてみました。概要の解説に留め、詳しい解説はしていません。初学者向けにざっくりとした説明をする際に利用するイメージで執筆してます。

# 想定している読者
- AWS（IAM）初学者
- IAMを利用するにあたり重要なポイントをざっくり理解したい方

# IAMとは
AWS Identity And Access Management(IAM)はAWSを安全に操作するためのアクセス制御の仕組みです。

# 主要なトピック
### IAMポリシー
どのリソースに対してアクセスを許可/拒否するかを定義することができるもの。

設定項目
- Effect：許可するのか拒否するのか ex.) Allow/Deny
- Action：対象のAWSサービス ex.) s3:Listbucket
- Resource：対象のAWSリソース ARNの形式で記述 
- Condition：制御を有効とする条件 MFA設定有無、送信元IPの範囲など

以下のように、JSON形式で設定される。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::test-bucket",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "xxx.xxx.xxx.xxx/16"
                }
            }
        }
    ]
}
```

#### ポリシー3種類

- AWS管理ポリシー
AWS 管理ポリシーでは、ポリシーを自身で記述する場合よりも簡単に、適切なアクセス許可がユーザー、グループ、ロールに割り当てることが可能。

- カスタマー管理ポリシー
利用者自身でアクセス許可を定義することができます。こちらも、ユーザー、グループ、ロールに割り当てることが可能。通常、インラインポリシーではなく、管理ポリシーを使用することが推奨されている。

- インラインポリシー
インラインポリシーは、IAM アイデンティティ (ユーザー、グループ、またはロール) に埋め込まれたポリシー。インラインポリシーと、そのポリシーが適用されるアイデンティティが一対一となるため、他のアイデンティティに割り当てることはできない。逆に、ポリシー内のアクセス権限が意図したアイデンティティ以外のアイデンティティに間違って割り当てられないようにする必要がある場合などにはインラインポリシーが有効。

参考：
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#choosing-managed-or-inline

### IAMユーザー
- 個人に対するアクセス権限を定義するためのもの。
- 通常、IAMユーザーを利用して、AWSマネジメントコンソール画面にログインする。
- IAMポリシーを付与した範囲でAWSサービスを利用できる。

### IAMグループ
- 権限をまとめて設定された単位のこと。
- IAMグループにIAMユーザーを追加して、複数ユーザーの権限をまとめて管理する。
- 管理者、開発者など、それぞれの利用者グループ毎に必要な権限を付与することで、効率的に権限管理が行える。

### IAMロール
- AWSリソースに対するアクセス権限
- EC2インスタンスに付与したり、LambdaやCloudFormationを実行する際の権限を付与したりする。

### ルートユーザー
- AWSアカウント作成時に作られる。
- 全てのAWSサービスとリソースを操作できる
- 日常的にはルートユーザーは利用せず、IAMユーザーを利用する
- IAMユーザーの課金情報に対するアクセス許可/拒否など、ルートユーザーのみにしか実施できない操作もある。

# IAMを通じたAWSサービスの操作方法について
### AWSマネジメントコンソールを利用する
IAMユーザーを利用して、WEBブラウザにログインした上でAWSサービスを操作する方法。

### AWS CLIを利用する
AWS CLI（Command Line Interface）は、AWSサービスを管理するためのコマンド群を利用する方法。WindowsやLinuxから各種コマンドを利用できる。
サービス操作のための権限を得る方法は以下２種類。

- IAMユーザーごとに作成できるアクセスキーとシークレットアクセスキーをLinuxやWindowsの環境変数として設定する
- IAMロールによる認証を利用する

前者のようなアクセスキーとシークレットアクセスキーを利用した認証を利用する場合、キー流出のリスクが懸念されるため、現在ではIAMロールによる認証が推奨されている。

### AWS SDKでAPIを利用する
AWS SDKは、Javaなどの主要なプログラミング言語向けにAWSから提供されているAPI群を利用する方法。AWS CLIと同様、アクセスキー、シークレットアクセスキーによる認証、もしくは、IAMロールによる認証が必要。


# ベストプラクティスについて
AWS リソースのセキュリティを確保するために、ベストプラクティスに準じた設計を行うことが推奨されている。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html#create-iam-users
Visual Studioで絶対に使いたいショートカット30選

#はじめに
Visual Studioで開発をするようになって便利だな、よく使うなと思ったショートカットをまとめてみました。備忘録として作成した記事です。

#ショートカット一覧
|  コマンド  |  できること  |
| :----: | :----: |
|  Ctrl + L  |  行削除  |
|  Ctrl + K, Ctrl + C  |  選択行のコメントアウト  |
|  Ctrl + K, Ctrl + U  |  選択行のアンコメント  |
|  Alt + Enter  |  Propertiesを表示  |
|  F7  |  コードの表示  |
|  Alt + ←  |  前に戻る  |
|  Ctrl + Shift + F  |  ファイル検索  |
|  F12  |  定義に移動  |
|  Shift + F12  |  呼び出し元を検索  |
|  Ctrl +Space  |  コード補完  |
|  F9  |  BreakpointのON/OFFを切り替える  |
|  Ctrl + Shift + F9  |  すべてのBreakpointを削除  |
|  Ctrl + Alt + B  |  Breakpointウインドウの表示  |
|  Ctrl + K, Ctrl + K  |  BookmarkのON/OFFを切り替える  |
|  Ctrl + K, Ctrl + P  |  前のBookmarkへ移動  |
|  Ctrl + K, Ctrl + N  |  次のBookmarkへ移動  |
|  Ctrl + K, Ctrl + L  |  すべてのBookmarkを削除  |
|  Ctrl + K, Ctrl + W  |  Bookmarkウインドウの表示  |
|  Ctrl+End  |  カーソルをドキュメントの最後に移動させる  |
|  Ctrl+Home  |  カーソルをドキュメントの最初に移動させる  |
|  Ctrl+Shift+↓  |  ページ内で使われている選択中の単語に飛ぶ  |
|  Ctrl+Alt+PageDown  |  右側のタブに移動  |
|  Ctrl+Alt+PageUp  |  左側のタブに移動  |
|  Ctrl+F4  |  現在開いているタブを閉じる  |
|  F5  |  デバッグ実行  |
|  Shift + F5  |  デバッグ停止  |
|  F10  |  ステップオーバー  |
|  F11  |  ステップイン  |
|  Shift + F11  |  ステップアウト  |

#参考にした、参考になるサイト
- [Visual Studio のショートカットに関するヒント]
(https://docs.microsoft.com/ja-jp/visualstudio/ide/productivity-shortcuts?view=vs-2019)
- [初心者必見！？ すごく使えるVisual Studioショートカットまとめ]
(https://amg-solution.jp/blog/21410)
- [Visual Studioのショートカットキーで効率化！カスタマイズの方法とは？]
(https://www.fenet.jp/dotnet/column/tool/5444/)
Windowsでログイン時に自動で時刻同期コマンドを実行する

# Windows PCで電源入れるといつも時刻がずれている問題

Windowsを立ち上げた際，自動で時刻同期をさせる方法を紹介します．

自分のWindowsマシンは電源をいれると時刻がずれていることがよくありました．ネットで調べるとタイムサーバーを設定する（[Windows10 - NTPサーバーの変更 - インターネット時刻](https://pc-karuma.net/windows-10-datetime-ntp-update/)）という解決策がよく紹介されていますが，自分の場合それでも問題は解決されませんでしたので，**ログイン時に自動で時刻同期コマンドを実行**させることで解決しました．本記事でその方法を説明していきます．


# ログイン時に時刻同期コマンドを自動実行

### 時刻同期コマンド
こちらを参考にしました．
[How do I force sync the time on Windows Workstation or Server?]
(https://serverfault.com/questions/294787/how-do-i-force-sync-the-time-on-windows-workstation-or-server)

コマンドプロンプトを管理者権限で立ち上げます．コマンドプロンプトを管理者権限で立ち上げるには，タスクバーの検索ボックスに「コマンドプロンプト」と打ち，出てきたアイコンを右クリックして「管理者として実行」を押します．
現れたコマンドプロンプトへ以下のコマンドをうち，実行することで時刻同期ができます．

```bat
C:\WINDOWS\system32> net stop w32time
C:\WINDOWS\system32> net start w32time
C:\WINDOWS\system32> w32tm /resync
C:\WINDOWS\system32> w32tm /query /status
```
これらのコマンドをバッチファイル`.bat`に書き，このバッチファイルを自動実行させることになります．ファイルエクスプローラーを開き，任意の場所（例えばドキュメントファルダの中）で右クリック>新規作成>テキストドキュメントを押して新規作成されたファイルを拡張子ごと変更し以下のような`time_sync.bat`というファイルを作ります．

```time_sync.bat
net stop w32time
net start w32time
w32tm /resync
w32tm /query /status
```
ちなみに，`.bat`ファイルはWindowsでの実行ファイルの一つで，Linuxでいうshellスクリプトに相当します．

### ログイン時に管理者権限でコマンドを実行
特定のファイルをログイン時に**管理者権限で**自動実行させる方法については以下のサイトが写真とともに丁寧に説明されていてとても分かりやすいので，そちらを参照してください．
[Windows10 - 管理者権限が必要なアプリを自動起動（スタートアップ）](https://pc-karuma.net/windows-10-task-schedule-without-uac-prompt/)

設定までの流れは

1. タスクスケジューラーを起動
2. タスクの設定
3. 「最上位の特権で実行する」にチェックを入れる
4. 新しい操作を指定する際，先ほど作成した`time_sync.bat`ファイルのフルパスをダブルクオーテーション`"`で挟んで入力

といった感じになります．

以上が終われば，今後ログイン時に時刻同期コマンドが自動で実行されるようになります．ログインするとコマンドプロンプトが表示されるようになりますが，1,2秒ですぐ消えるのでご安心ください．
【PHP】特殊文字をエスケープするhtmlspecialchars

htmlspecialchars() は、HTMLタグなどに使われる特殊文字をエスケープし、XSSや悪意のあるスクリプトによる攻撃を防ぐためのPHPの関数です。

##XSS（クロスサイトスクリプティング）とは
クロスサイトスクリプティングとは、Webサイトの中にHTMLやJavaScriptを埋め込むことでサイト管理者が意図しない動作を引き起こす攻撃手法のことです。

この攻撃を受けると、Cookieを盗み取られたりセッションハイジャックを行われたり、Webサイトを改ざんされてしまう可能性があります。

##XSSの攻撃例
実際にXSSの攻撃例を考えてみましょう。

例えばユーザが入力した任意のユーザーネームを、プロフィールに表示するWebページがあるとします。

ユーザーネーム設定フォーム

```
<form action="/setting" method="post">
  <input type="text" name="username">
  <input type="submit" value="登録する">
</form>
```
 プロフィール

```
<h2><?php echo $username; ?>さんのプロフィールです</h2>
```


このプロフィールページでは、ユーザーが入力したテキストがそのまま出力されます。
開発者は、ここにユーザーネームを表す文字列を入力してもらうものとしてフォームを設置しています。

しかしここには、悪意をもったユーザーが開発者の意図に反した文字列を入力することができてしまいます。



```
<script>location.reload();</script>
```

例えばこのようなjavascriptのコードが入力されると、延々とページの再読み込みが続きます。

同様の方法で、アラートを表示したり違うページに飛ばしたり、訪問者のcookieを取得することもできます。

##PHPで行うXSS対策
ここで登場するのがPHPの関数のひとつ、htmlspecialcharsです。

HTMLでは、< や > 等の特殊文字はHTMLのタグを示す記号として働いています。そこでHTMLタグやスクリプトが実行されないよう、htmlspecialchars関数を使ってこれらの特殊文字をHTMLエンティティに変換するエスケープを行います。

・アンド （&）→ 『&amp;amp;』
・小なり （<）→ 『&amp;lt;』
・大なり （>）→ 『&amp;gt;』
・シングルクォーテーション （'）→ 『&amp;#039;』または『&amp;apos;』但しENT_QUOTESが指定されている場合
・ダブルクォーテーション （"）→ 『&amp;quot;』但しENT_NOQUOTESが指定されていない場合

```
htmlspecialchars(エスケープする文字列, エスケープの方法, 文字コード);
```
・第二引数はエスケープの方法を指定
デフォルトは「 ENT_COMPAT | ENT_HTML401 」です。基本的に「 ENT_QUOTES 」を指定します。

・第三引数はエンコードする文字コードを指定
省略した場合には、PHP のバージョンによってデフォルト値が変わります。
PHP 5.6.0 以降であれば default_charset が使用され、default_charsetのデフォルトは UTF-8 です。

使用例（先ほどのプロフィールにエスケープ処理を行う）

```
<h2><?php echo htmlspecialchars($username, ENT_QUOTES); ?>さんのプロフィールです</h2>
wordpressからhugoへの移行（超絶シンプル-簡単編-）

# きっかけ
CMSの維持管理が大変。Tumblrなんかで独自ドメイン運用も考えたけど、今更htmlでサイト作りたくなかったのパスした。
最終的にgitlab-pagesでhugoを運用することにした。コストは全然掛からない。が！wordpressから記事を移行しなくてはいけない。

##方法
wordpressの移行ツールや、xmlのエクスポートは直接触らない。画像などのデータのみエクスポート機能を使った。
おもむろに動いているwordpressのRSSにすべての記事、本文全文を配信するように設定した後、以下のrubyスクリプトを実行する。

```ruby
#!/bin/ruby

require 'xmlsimple'
require 'open-uri'
require 'reverse_markdown'
require 'date'
require "fileutils"

domain = "XXXX.YYYYY.ZZZ"
rss = "https://" + domain + "/feed"

hash = XmlSimple.xml_in(open(rss))
arr = hash["channel"][0]["item"]

arr.each do |item|

  title = item["title"][0].empty? ? "無題" : item["title"][0]
  date = Time.parse(item["pubDate"][0]).iso8601()
  contents = ReverseMarkdown.convert item["encoded"][0]
  discription = ReverseMarkdown.convert item["description"][0]
  discription = discription.split("...")[0] + "..."

  dir =  item["link"][0].split("/")[3] +"/"+ item["link"][0].split("/")[4]
  name = "/index.md"
  FileUtils.mkdir_p(dir)
  mdfile = "---\n"
  mdfile = mdfile + 'title: "' + title + '"'
  mdfile = mdfile + "\ndate: " + date + "\n"
  mdfile = mdfile + 'description: "' + discription  + '"'
  mdfile = mdfile + "\ndraft: false"
  mdfile = mdfile + "\n---"
  mdfile = mdfile + "\n\n"
  mdfile = mdfile + contents.to_s

  File.open(dir + name, mode = "w"){|f|
    f.write(mdfile)
  }
end

```
これでカレントディレクトリにURL階層を守ったマークダウンが生成されるはず。
車輪の再発明をするなとか怒られそうだけど、生成中に移行したメッセージ等の追記なんかもできる。

シンプルな機能は大げさな機能は必要なくて、自分が使える言語で書かれたスクリプトが必要なのだ。

必要な人はタグやカテゴリーの記載もできると思います。

また、僕はwordpressでやり取りしたコメントの記載も本文記事に書いてしまって移行しました。

##最後に
ブログのURLを維持することは実はめっちゃ簡単なのにそれだけのために金を巻き上げる有料サービスは一体何なの？
インターネットは無料で、自由だ！スキルが有るなら。

大げさなこと言ったけど、gitlab最高。有能すぎる。

移行した最後の[記事](https://blog.cfw4.tokyo/wordpress/1086/),シン・エヴァンゲリオン見てきました。
【初心者向け】たった三行でiOSのinput要素にCSS効かせる方法【iPhone】

【備忘録】

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777576/cc00561e-0b22-fd42-d1b0-29a7748ca1ff.png">
Win環境だけで制作してる場合、iPhoneで確認した時このような見た目になることありますよね…

Safariでinput要素にCSSが当たらない場合、

```
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
```
この3行を追加する:writing_hand:
-webkit-のベンダープレフィックスを追加することで、Safariでも効くようになります。

―――――――――――
私も普段Win環境で制作してるので忘れがち。
抜けたまま実機確認して／(^o^)＼となるので、inputには一緒に入れるようにしましょう！
BuefyのDialogProgrammaticを使ったダイアログには文字列しか受け付けないので注意

# BuefyのDialogProgrammaticを使ったダイアログには文字列しか受け付けないので注意

```javascript
import { DialogProgrammatic as Dialog } from 'buefy';

Dialog.alert(1); // 何も表示されない
Dialog.alert("1"); // 1と表示される
Dialog.alert((1).toString()); // 1と表示される
```
React学習のアウトプット（２日目：ライフサイクルフック）

React学習2日目

今回もアウトプットしていきます。

今回の内容は``useEfect``と呼ばれる、ライフサイクルについて書いていきます。

Vueで言うと、``mounted``、``updated``、``destryed``に当たるものです。

これら３つをまとめたものが**useEfect**です。

百聞は一見に如かずということでとりあえず例を見ていきましょう。

#レンダーごとに呼び出し#

まず、１つ目はレンダー毎に呼び出す方法です。

レンダー毎とは、``mounted``、``updated``、``destoryed``のライフサイクルフックです。

```hook.jsx
useEffect(() => {
    console.log('render')

    return () => {
      console.log('destoryed')
    }
  })
```

この``return``で返しているところは**クリーンアップ関数**とも呼ばれています。

これで要素が破棄されたときに関数を呼び出すことができます。

Vueだと``created``や``mounted``をわざわざ記述しなきゃいけないことをたった１つの関数でまとめて行えるとは非常に便利ですね。

#マウント時のみ#

次はマウントされたときだけ呼び出す方法です。

```hook.jsx
useEffect(() => {
    console.log('mounted')
  }, [])
```

このように``useEfect``の第二引数に``[]``（空の配列）を渡すことによってマウント時のみ実行されます。

これは、``useEfect``が第二引数の値が同じの場合、``useEfect``が実行されないことを意味しています。

逆を言えば、第二引数の値が変わっていれば呼び出されます。

#マウント、アンマウント時#

上記と同じように、マウント、アンマウント時のみ呼び出すことも可能です。

```hook.jsx
useEffect(() => {
    console.log('mounted')
    return () => {
      console.log('destoryed')
    }
  }, [])
```

#特定のレンダー時#

最後に特定のレンダー時に呼び出す方法です。

```hook.jsx
useEffect(() => {
    console.log('認証されています！')
  }, [auth])
```

ひとつ前は第二引数に空の配列を渡していましたが、今回は```logged`を渡すことで``logged``の値が変化したときに発動されます。

これも凄く便利ですね。

ユーザーがログインしているかしていないかでページの表示を変えることも可能です。

このようにしてライフサイクルをコントロールすることができます。

まだ、そこまでVueとの違いを実感できていないのでもっと学んでいこうかなと思います。

皆さんも頑張りましょう！

以上、「React学習のアウトプット（２日目：ライフサイクルフック）」でした！

Thank you for reading
C#で全メール受信 (全メール取得)


# まえおき


オープンソースのライブラリ「OpenPop.net」を使用して全メールを取得してみます。

コードサンプルでは下記の項目を取得しています。
- 全メールのUIDリスト
- UID
- 差出人メールアドレス
- 件名
- 本文


差出人メールアドレスと本文取得の箇所でnullのチェックをいれているのは、
NullReferenceExceptionが発生する可能性があるためです。
メール情報を一通り(4項目)取得したらちゃんと取得に成功しているかチェックをいれる処理を必ずしてください。
(fromAddressやbodyが空文字のケースがありますので・・・)


#### 新着メールを検出するには
全メールのUIDをデータベースに保存して再度メール取得した際に
データベースと比較をしてデータベースに該当UIDが存在しなければ新着として検出することができます。
(フラグや未開封などを使った方法もあるみたいです)

# コードサンプル

メールホストとメールユーザー、メールパスワードには対象メールサーバー情報を記述してください。
もちろんNuGetで「OpenPop.net」のインストールも忘れずに・・・

```cs:
            using (Pop3Client client = new Pop3Client())
            {
                client.Connect("メールホスト(変更してください)", 995, true);
                client.Authenticate("メールユーザー(変更してください)", "メールパスワード(変更してください)");

                // 全メールのUIDL取得
                List<string> uidList = client.GetMessageUids();

                // 全メール古い順で繰り返し処理
                for (int i = 1; i <= client.GetMessageCount(); i++)
                {
                    try
                    {
                        string uid = "";
                        string fromAddress = "";
                        string subject = "";
                        string body = "";

                        // メール情報取得
                        Message message = client.GetMessage(i);
                    
                        if (message.Headers.From.MailAddress != null)
                        {
                            // 差出人メールアドレス取得
                            fromAddress = message.Headers.From.MailAddress.Address;
                        }

                        // 件名取得
                        subject = message.Headers.Subject;

                        // UID取得
                        uid = client.GetMessageUid(i);

                        // 本文取得
                        var plainText = message.FindFirstPlainTextVersion();

                        if (plainText != null)
                        {
                            body = plainText.GetBodyAsText();
                        }

                        // 取得情報出力
                        Console.WriteLine("UID={0} ,FROM={1} ,SUBJECT={2}", uid, fromAddress, subject);
                        //Console.WriteLine("BODY={0}", body);

                    }
                    catch (Exception e) {
                        Console.WriteLine(e.Message);
                    }
                }
            }
```

# おまけ (OpenPopのDebug出力を無くす)

OpenPop.Common.Logging.DefaultLogger.SetLogを使用してロガークラスを上書きします。

まずは下記の様に独自ロガークラスを作成します。
デバッグ出力はコメントアウトして出力させないようにします。

```cs:Logger.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenPop.Common.Logging;


namespace MyProject.Common
{
    public class Logger : ILog
    {
        public void LogError(string message)
        {
            Console.WriteLine("ERROR=" + message);
        }

        public void LogDebug(string message)
        {
           // Console.WriteLine("DEBUG=" + message);
        }
    }
}

```

メール受信を行うクラスの関数内で下記のメソッドを実行

```cs:Test.cs

 OpenPop.Common.Logging.DefaultLogger.SetLog(new Logger());

```
プログラミング未経験だったぼくのエンジニア転職日記【ポートフォリオ作成編】

#はじめに
昨年9月からプログラミングスクールに通って、プログラミングを勉強し始めてから早半年、この度、自社開発企業複数社様から内定をいただくことができました。そこで、スクールのカリキュラム終了後から転職活動までの経験をこれから複数回に分けて投稿していこうと思います。こんな人もいるんだなあという感じで見てください。第一回は自分がどのようにポートフォリオサイトを作ったかについて書いていきます！

#ポートフォリオ概要
###どんなサイトを作ったか
実際、ぼくがどんなポートフォリオサイトを作ったかですが、自分の趣味であるサイクリングに関して、その体験を投稿し、共有できるサイトを作成しました。このサイトの制作意図や実装機能については、以下の記事にまとめているので、もしよかったら見てみてください。

https://qiita.com/kyoyasai/items/09288d26b22459eba0a1


実際のアプリの画面を少しお見せすると、以下のように、トップページに、投稿内容が一覧表示されるようになっています。
![投稿一覧](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829213/c891d1e2-10ee-422b-75b2-42d0cbeb4347.gif)

#ポートフォリオの作り方
###このサイトの着想に至るまで
多くのスクール受講生の方が、どんなサイトを作るかについて、一度は悩んだことがあるのではないでしょうか。ぼくもその一人で、このアプリにたどり着くまでに紆余曲折ありました（最初は本のレビューサイトとかを作ろうとしてた時期もありました）。
そんな中、行き着いた答えが
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__作りたいもの：作れるもの = 50%：50%__
ぐらいの意識で作るのがベストということです。
これについて解説します。
まず、作りたいものを重視し過ぎて、色々難しい機能から作ろうとすると、最初のハードルが高くなり過ぎてしまい、何から始めてよいか分からず、全然制作が進まない恐れがあります。
一方、作れるものだけに偏り過ぎても、制作物の特徴やこだわりポイントを語ることができなかったり、自分自身作っていく上で面白味を感じられなくなる恐れがあります。
ぼく自身、この2つの要素はそれぞれメリット・デメリットがあり、両方重要だと思っているので、半々ぐらいのいい感じのバランスがベストだと思っています。

###「作れるもの」としておすすめ機能
じゃあ作りたいものは個々人で色々あるとして、作れるものってなんやねん！となると思います。これは、ぼくの中で1つおすすめ機能があります。それは、ぼくの制作物でいうところの投稿機能(下図参照)にあたる、「何かフォームで情報を送信してそれをビューに表示させる」機能です。他の方のポートフォリオを見ていて気づいたんですが、ぼくのようなSNS系サイトや料理サイト、業務効率化サイトなど、何か情報をフォームで送信してそれがトップページに表示されることで意味を持つサイトってすごく多いと思います。これは、実際の身の回りのアプリにも言えるのかなと思います。ぼくのようにスクールに通ってる人だとフリマアプリの作成でform_withとかの使い方は知ってるはずなので、これを利用した機能を主要機能に含めるのが、個人的にはおすすめです！
![投稿機能](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829213/3be814b3-5bd2-2a02-1af8-e69c5cd6bac0.gif)


###実際どんな流れで作ったか？
以上の内容を踏まえて、実際ぼくがどのような手順でポートフォリオサイトを作成したかについて、以下で述べようと思います。
ザックリいうと以下の通りです。
1. 一旦、フリマアプリ(スクールでの制作物)のビューをパクる
2. テキストで習った機能をまず作る（上で言うフォームを用いた機能もここに該当します）
3. ビューを直す or 自分で調べつつテキストで習った以外の機能を作る

すごくザックリとまとめたんですが、ここでは特に1について詳しく述べていこうと思います。
まず、作りたいもの・作れるものの両方を意識して、アプリの構想を固めたはいいものの、どこから手をつけてよいかという点は結構悩みました。というのも、スクールの課題ではフロント側をほとんど一切いじってなかったからです。そこで、色々考えた結果、新規登録・ログイン画面はサイトによってそんなに変わらないので、一旦フリマアプリのものを全部パクろうと考えました。もちろん、最終的には修正するつもりでしたが、何もないところで1から始めるよりも、一旦ビューを丸パクりして少しずつ修正していく中で、フロント側の言語に慣れようと考えました。その中でも、ヘッダーとフッターだけはフリマアプリをまるパクりという訳にはいかないので、ヘッダーとフッターを作りつつフロントの言語にも慣れていきました。今は、新規登録画面も修正済ですが、イメージ的には、下図の感じです。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829213/b3d2c7e0-218e-503d-0eab-6db993924778.png)

こういった感じで、少しずつ自分のできることを増やしながらやっていく内に、ポートフォリオサイトを完成させることができました。

#終わりに
最後に、これは完全に持論なんですが、ポートフォリオ作成は楽しんでやるのが一番だと個人的には思っています。自分の知識や考えを好き勝手表現できる機会はそうそう無いと思います。上で述べた作りたいもの、作れるもの半々という考えも、楽しく制作をするための工夫だと思ってます。個人的には、この記事が楽しくポートフォリオサイトを作る助けになればいいなと思います。
Laravel8 No tests executed!解決方法

今回は、Laravel入門書の最後の項目である「ユニットテスト」で発生したエラーについてです！
（　参考書：Laravel入門(Laravel6), PC：Mac, Laravelバージョン：Laravel8　）


早速ですが、Laravel入門p.340,345,347のところで、PHPUnitを実行する為に、

```
$ vendor/bin/phpunit
```
参考書の通りこちらのコマンドをターミナルで実行したところ、下記のエラーが発生しました。

```
No tests executed!
```

##No tests executed!
このエラーが出たら先ず、PHPUnitを実行するテストクラスの配置を確認します。

Laravelでのテストは、`Feature`と`Unit`ディレクトリに分かれていて、
`Feature`は`Controllerのテスト`で`Unit`は`それ以外のテスト`という位置づけです。

デフォルトでは、`tests/Feature`と`tests/Unit`ディレクトリにテストクラスを配置する必要があります。

この時点で上記のディレクトリにテストクラスがないと今回のようなエラーが発生しますが、
僕の場合ディレクトリの配置は特に問題ありませんでした！

##解決方法
今回の場合は、PHPUnit実行コマンドを下記のように変更したことで、正常にテストが実行され、テスト判定も問題なくOKが出ました！

```
$ vendor/bin/phpunit
↓ //変更
$ vendor/bin/phpunit tests/Unit/ExampleTest.php
```
スマホを操作してESP32のLチカを行う

スマホからESP32を操作したいと思ったところ、Blynkというアプリを使うとESP32を操作できるという記事を見つけました。

![blynk app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/4b7ff019-0b4b-46c7-4119-9ada6b20a30d.png)


## 前提

- arduino ide が使える
- blynkがダウンロードできる

## 使ったデバイス

- iPhone 8
- ESP32 WROOM 32
- LED ライト1つ
- 300オーム抵抗1つ

配線は以下のようにします。IO21にLEDをつけて、330オームの抵抗で続けます。

![Screen Shot 2021-03-18 at 20.33.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/adcb5a90-20dc-d2ce-ebeb-1a0b2e434453.png)


## Blynkの設定

まず New projectで新しいプロジェクトを作成します。

![IMG_3726.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/c8bd4b60-38a9-36a2-03cd-9e2d57d4144f.png)

esp32 demoという名前にしてデバイスはESP32 Dev Boardを選びます。Connection TypeはBLEです。

![IMG_3727.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/703b9c64-485a-995c-a168-d5a4c90a3441.png)

プロジェクトが作成されるとメールが送信されるはずです。このメールに書かれている認証トークンをソースコードで使います。

ボタンを以下のように右のサイドバーから追加します。

![IMG_B9E718D26C7F-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/653c1d9b-dbd2-08b3-e0bd-6defeb735e4c.jpeg)

ボタンを押して、設定を選びます。ピンをとりあえずDigitalのGP21に設定します。他は何もいじりません。

![IMG_3735.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/120ff462-eec8-9fd5-b5af-1392a7f93294.png)

続いてBLEボタンを右のサイドバーから選びます。

![IMG_D920D35F6D5B-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/933b9e17-0e8d-3fb3-43f0-0314313f316b.jpeg)



## ソースコード

ソースコードの `your auth`にはメールで届いたトークンを記述してください。

```
//Blynk で リモートLチカ

#define BLYNK_PRINT Serial
#define BLYNK_USE_DIRECT_CONNECT
#include <BlynkSimpleEsp32_BLE.h>
#include <BLEDevice.h>
#include <BLEServer.h>
char auth[] = "your auth";

void setup(){
  pinMode(21, OUTPUT);
  Serial.begin(9600);
  Serial.println("Waiting for connections...");
  Blynk.setDeviceName("L-chika");
  Blynk.begin(auth);
}

void loop(){
  Blynk.run();
}
```

アップロードがすんだら、ESP32のBLE信号の発信が始まります。

## 走らせる

これでBlynkの右上のボタンを押すと、自動的にBLEの接続をしてくれます。

![IMG_EDD178759A34-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/42ea1d39-b6b5-9a4b-e226-08b509bdee41.jpeg)

これでボタンを実際に押してみると、以下のように対応したLEDが光ります！

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/103cc435-005f-8df0-1e71-ef34efe228d0.gif)
pi picoでmicropython その12

#概要

picoでmicropythonやってみた。
pioアセンブラで、アセンブル、やってみた。


#サンプルコード

```

def tic():
   set(pins, 1)
   set(x, 31)
   label("loop0")
   nop()
   jmp(x_dec, "loop0")
   set(pins, 0)
   set(x, 31)
   label("loop1")
   nop()
   jmp(x_dec, "loop1")


```

#asmに書き直す

```

.program tic
    set pins 1
    set x 31
loop0:
    nop
    jmp x-- loop0
    set pins 0
    set x 31
loop1:
    nop
    jmp x-- loop1


```

#アセンブル結果


```
e001
e03f
a042
0042
e000
e03f
a042
0046

```

以上。
C# の Trim メソッドで取り除かれる「空白」文字は具体的に何なのか

## `string.Trim`メソッドとは

C# `string.Trim`メソッドは文字列の前後の「空白」を削除するメソッドです。

[.NET の文字列からの文字のトリミングと削除](https://docs.microsoft.com/en-us/dotnet/standard/base-types/trimming)

> 単語の両端に空白（空白とも呼ばれます）が含まれる単語になってしまう可能性があります。

[String.Trim Method](https://docs.microsoft.com/en-us/dotnet/api/system.string.trim?view=net-5.0)

> 文字列の最初と最後から、文字の配列で指定された空白または文字を削除します。

ただ、一口に「空白」といっても半角スペース・全角スペース・タブ、改行コード...などさまざま空白が存在します。

<!--truncate-->

## 取り除かれる「空白」は具体的にどの文字を指しているのか？

`string.Trim`メソッドで取り除かれる「空白」は`Char.IsWhiteSpace`にマッチする文字を指します。

> 空白文字は Unicode 標準で定義されています。この Trim メソッドは true、Char.IsWhiteSpace メソッドに渡されたときの戻り値を生成する先頭と末尾の文字をすべて削除します。

[Char.IsWhiteSpace](https://docs.microsoft.com/en-us/dotnet/api/system.char.iswhitespace?view=net-5.0) がマッチする文字は下記の通りです。

> - Members of the UnicodeCategory.SpaceSeparator category, which includes the characters SPACE (U+0020), NO-BREAK SPACE (U+00A0), OGHAM SPACE MARK (U+1680), EN QUAD (U+2000), EM QUAD (U+2001), EN SPACE (U+2002), EM SPACE (U+2003), THREE-PER-EM SPACE (U+2004), FOUR-PER-EM SPACE (U+2005), SIX-PER-EM SPACE (U+2006), FIGURE SPACE (U+2007), PUNCTUATION SPACE (U+2008), THIN SPACE (U+2009), HAIR SPACE (U+200A), NARROW NO-BREAK SPACE (U+202F), MEDIUM MATHEMATICAL SPACE (U+205F), and IDEOGRAPHIC SPACE (U+3000).
> - Members of the UnicodeCategory.LineSeparator category, which consists solely of the LINE SEPARATOR character (U+2028).
> - Members of the UnicodeCategory.ParagraphSeparator category, which consists solely of the PARAGRAPH SEPARATOR character (U+2029).
> - The characters CHARACTER TABULATION (U+0009), LINE FEED (U+000A), LINE TABULATION (U+000B), FORM FEED (U+000C), CARRIAGE RETURN (U+000D), and NEXT LINE (U+0085).

## なぜ調査したのか

ここからは補足で、なぜ上記の調査をしたか記述いたします。

### 見た目上問題ないのに電話番号がエラー

外部から連携される電話番号が問題ないように見えるのに正規表現にマッチせずバリデーションエラーになっていました。

電話番号の文字列の先頭でカーソルキーが滑るので、先頭にゼロ幅スペース（Zero Width Space `U+200B`）があると考えました。

> [ゼロ幅スペース | Unicode キャラクター図鑑](https://unicode-table.com/jp/200B/)

ただ、`string.Trim`してもエラーが出続けました。

そこで、具体的に「空白」判定される文字（`char`）は何なのか調べることにしました。

### 電話番号のエラーの原因はなんだったのか

電話番号の文字列の Unicode を確認しました。

すると先頭に双方向テキストの「左から右への埋め込み」（Left-To-Right Embedding `U+202A`）というものが付いていました。

> [左から右への埋め込み | Unicode キャラクター図鑑](https://unicode-table.com/jp/202A/)

`string.Trim`には`Char`型の配列を引数に取るオーバーロードもあります。

`U+202A`も取り除くようにして最終的に解決しました。

```csharp
phoneNumber = phoneNumber.Trim().Trim(new[] { 'U+202A' })
```

※`Char`型の配列を引数に取るオーバーロードメソッドは「空白」のトリム処理は行われないので`Trim`を２度呼び出しています。
VScodeに求められたのでAWS SAM CLIの導入

# はじめに

VScodeを起動したところ、AWS拡張機能にAWS SAM CLIを導入を求められた(というかcliないぞとエラーが出た)ので、対応のためインストールしたので備忘録。
環境はwsl2(ubuntu 18.0.4)です。

# AWS SAM とは

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/what-is-sam.html


>- AWS サーバーレスアプリケーションモデル (AWS SAM)は、オープンソースのフレームワークで、 サーバレス・アプリケーション AWS上で。

>サーバーレスアプリケーションは、Lambda 関数、イベントソース、およびその他のリソースを組み合わせたもので、協調して動作することによってタスクを実行します。サーバーレス アプリケーションは
>AWS SAM コマンドラインインターフェイス (AWS SAM CLI)。このツールを使用して、AWS SAM テンプレートによって定義されたサーバーレスアプリケーションを構築します。CLI には、AWS SAM テンプレートファイルが仕様に従って記述されていることを確認したり、Lambda 関数をローカルで呼び出したり、デバッグ Lambda 関数をステップスルーしたり、サーバーレスアプリケーションをパッケージ化して AWS クラウドにデプロイしたりするためのコマンドが用意されています。詳細な AWS SAM CLI コマンドリファレンスを含む AWS SAM CLI の使用方法については、AWS SAM CLI コマンドリファレンス を参照してください。

Lamdaを呼び出してくれたりするそうです。VScode上のAWS拡張機能アップデートでの裏で用いるようにされたのかなと思います。

# インストールコマンド

基本以下リンク先のコマンドをすぐ実行できるようにまとめたのみです。
インストーラーをwgetしてきて解凍してインストールして最後にバージョン確認します。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install-linux.html

```bash
mkdir aws-sam
&& cd ./aws-sam
&& wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
&& unzip aws-sam-cli-linux-x86_64.zip -d sam-installation  
&& sudo ./sam-installation/install
&& sam --version
```

# ぼやき
VScodeの拡張機能のアップデートで別途アプリケーションインストールが必要になるのは全然良いのですが、VScodeがインストールまでナビしてほしいものです。
Raspberry Pi Pico Audio PackでX68000のMDXファイルを再生する

秋月電子で買えるようになった[Pico Audio Pack](https://shop.pimoroni.com/products/pico-audio-pack)で遊んでみます。
(今回はNuttXでなく、Pico SDK上で動かします)

https://akizukidenshi.com/catalog/g/gM-16237/

# 概要

[Pico Playground](https://github.com/raspberrypi/pico-playground)内のデモでI2Sを用いたオーディオ出力の方法が分かってきたので、X68000用音楽データのMDXファイルをPico上で再生してみました。
MDXについては以下のWikipediaの記述をご覧ください。

https://ja.wikipedia.org/wiki/MDX_(%E9%9F%B3%E6%A5%BD%E3%83%87%E3%83%BC%E3%82%BF)

FM音源+ADPCMのフォーマットであるMDXファイルは、mdx2wavというコンバータでストレートPCMに変換できます。

https://github.com/mitsuman/mdx2wav

元のコードではLinux用アプリケーションとして標準出力にPCMデータを出力するようになっていますが、これをライブラリとして組み込んで、出力されたPCMデータをそのままI2Sに流し込みます。

# ソースコード

ソースコードは[githubに置いてあります](https://github.com/yunkya2/pico-mdx)。mdx2wavをsubmoduleにしているので、git cloneの際には`--recursive`を付けてください。
makeすると build/pico-mdx/pico-mdx.uf2 が出来るので、これをインストールして起動するとMDXファイルの再生が始まります。

https://github.com/yunkya2/pico-mdx

再生するファイルはバイナリ内に埋め込みになっています。~~pico-mdx/CMakeLists.txt に以下の記述があるので、ファイルを変更する場合はここに再生したいファイルをフルパスで指定してください。
MDXファイルに対応するPDXファイルがある場合には、`PDX_FILE_NAME`の行のコメントアウトを外してここにファイル名をフルパスで指定してください。~~
**【追記】** 最新のソースコードでは複数ファイルの再生に対応したので、MDXファイルの指定方法が変更されています。[Raspberry Pi PicoのBOOTSELボタンを使ってMDX playerを制御する](https://qiita.com/yunkya2/items/e415eed7b3bf4b637201) を参照してください。

```pico-mdx/CMakeLists.txt
target_compile_definitions(pico-mdx PRIVATE
                    :
       #
       MDX_FILE_NAME="${CMAKE_CURRENT_LIST_DIR}/test.mdx"
#      PDX_FILE_NAME=""
)
```

内部で利用しているmdx2wavは、オリジナルのソースコードから以下の変更を加えています。

- 固定データにconstを付加
  - ライブラリ中にある書き換え不要なデータにconstを付けました。Picoの場合こうしたデータはフラッシュ上に置かれるので、少ないRAMを節約するためには重要です。
- FM音源エミュレートライブラリfmgenを削除 
  - 元のコードではFM音源のエミュレート用ライブラリとしてfmgenとmameの両方が載っていて切り替え可能になっていますが、デフォルトではmameを使うようになっている上fmgenが大きな配列を固定で持っていたので、メモリ節約のために削除しました。
- 非アラインメントデータアクセスの修正
  - 再生するMDXファイルをRAMにコピーする処理でワードデータをunalignedアクセスする可能性のある箇所があり、ファイルによってクラッシュする問題があったので修正しました。PCではunalignedアクセスは遅いだけで動作はしますが、Cortex-M0+ではHard Faultになるためこの修正が必要です。
- **【追記】渡されたデータの直接再生**
  - 元のコードでは、最初に渡されたMDX, PDXデータを一旦自分で確保したメモリにコピーしてから使うようになっていましたが、渡されたデータを直接参照して再生するように変更しました。特にサイズの大きなPDX(サンプリング音)をフラッシュに置いたままにできるようになったことで、RAM消費を大幅に削減できるようになりました。

# 制約

現状では以下の制約があります。

- ~~再生できるMDXファイルはバイナリに埋め込まれた1つのみです~~
- ファイル再生時のサンプリングレートは22.05kHzになります
  - 44.1kHzだと処理が間に合わず音が途切れ途切れになってしまいます。特にPico向けの最適化などをやっていないこともあり、リアルタイムでのFM音源のエミュレーションはさすがにちょっと厳しいようです。 
- ~~PDX(サンプリング音)の再生は未サポートです~~
  - ~~これは非常に残念なのですが、端的に言うと「RAMが足りない!」。mdx2wavは再生ファイルを一旦メモリに読み込んでから処理するようになっていますが、264kBしかないPicoのSRAMはサンプリング音を扱うには小さすぎました。フラッシュには余裕があるのでフラッシュメモリ上のデータを直接処理できれば再生できるかも知れませんが、上記の通りFM音源のみでも44.1kHzだと間に合わないので、PCM合成も行うと22.05kHzでも厳しいかも知れません。~~
- **【追記】PDXファイルの再生に対応しました!**
  - mdx2wavを修正してデータを一旦RAMにコピーせず直接再生するようにしてみたところ、MDX,PDXともに問題なく再生できるようになりました。性能的に間に合うかも気になっていたのですが、22.05kHzであればPCM再生も問題ないようです。 

# 実行

再生時の動画をtwitterに上げました。

https://twitter.com/yunkya2/status/1372206003098329095
駆け出しエンジニア用！結構業務で出てくる単語①(トランザクションとマスタって？？)

## 対象
- エンジニアになりたい
- 駆け出しエンジニア

## 概要
現場に入って実際に働くとわからない単語がたくさん出てきます。
そのメモ。
逆に言うと入社する前に知っていたら強い。
そんな内容です


## トランザクションとは？
トランザクションとは簡単に言うと複数のデータを一つにまとめたことです。
特徴から言うと成功と失敗の二つのパターンしかありません。

例えば

```
田中さんの口座に3万円あることを確認
田中さんの口座から3万円減らす
阿部さんの口座に3万円を送金
```

こういった処理があったとします、この一連の処理をトランザクション処理みたいな感じでいいます。
こういった処理の場合最初の処理だけ成功して最後の処理が失敗した！
なんてことが起きたらまずいですよね。

なのでどれかが失敗すると必ず全ての処理が失敗になると言うわけです。


##　トランザクションデータとマスタデータ
これまた紛らわしいのですが、最近要件定義書をみていて、
トランザクションとマスタといった分類を見つけました。

マスタデータ... 企業のデータベースなどで業務を遂行するのに必要なデータ
例... SNSで言えばユーザーデータ、投稿データ

トランザクションデータ... 企業の情報システムなどが扱うデータの1つで、業務に伴って発生した、出来事の詳細の記録
例... ECサイトの商品の購入履歴データ、ユーザーのログイン履歴のデータ

略されて、マスタ、トランザクションと言われることが多いみたいです。
トランザクションといった言葉で結構ごっちゃになったのでメモを残しておきます。

これから就職したいエンジニアなどはしっかり覚えておきましょう。

## おまけ

バッチ処理...日本語で"一団"といった意味、一定量または一定期間の情報を集めて処理をする
例...工場の在庫処理、いちいち在庫を一つずつカウントしていくのは大変なので、まとめて処理することも多いそうです。リアルタイムにデータの反映が必要な場合は向いていない

リアルタイム処理... バッチ処理とは反対にその名の通り、リアルタイムでその場で処理を行うことです。大規模なデータには向かない特徴があります。


cron処理...UNIXのOSLinuxなどに入っているプログラムの一つ。事前に"いつになったら、このプログラムを走らせてね"みたいな感じで指示を出しておくと自動でその時間にプログラムを動かすことができる。