OmniAICreator/Qiita-1.07M huggingface dataset:
Elixir × Nerves で MH-Z19 を動かす


# はじめに

Elixir で CO2センサー MHZ19 の読み取り方を書いたものが見つからなかったため，この記事を書くことにした．

# 使用するもの

* Raspberry pi 3b (など)
* mh-z19 CO2センサー (https://akizukidenshi.com/catalog/g/gM-16142/)

# 前提

* Nervesが入っている
* mh-z19 が配線されている

# 本編

## ライブラリのインストール

* mh-z19 は UART通信を用いるので，`Circuits.UART`([ドキュメント](https://hexdocs.pm/circuits_uart/readme.html)) を使う．

まずは `mix.exs` に追加したあと，`mix deps.get` する．

```exs
defp deps do
    [
      # ....
      {:circuits_uart, "~> 1.3"}
    ]
  end
```

## コード 

[mh-z19 データシート](https://www.winsen-sensor.com/d/files/PDF/Infrared Gas Sensor/NDIR CO2 SENSOR/MH-Z19 CO2 Ver1.0.pdf) に従って，後々使いやすいように(?) `GenServer`の形で実装する．


### `init`

* UART の GenServer (このGenServerとは別) を起動して，pid を状態としてを持っておく．
* UART GenServer の "ttyAMA0" インタフェースを開く．このとき，データシートに従って `baud_rate` 等のパラメタを設定しておく．

### `handle_call`

GenServer へ `:read` の呼び出しが来たときに，センサーの読み取り値を返す．

* センサーの値を読み取るコマンド `@sensor_read_command`を `write` してあげる．
* `read_uart` を呼び出して，帰ってきた値を読む．
    * `read_uart` では，結果を含む返信を読むまでループして，結果を返すか，結果が得られなければ `{:error, reason}` を返す．(`reason` は `Circuits.UART` のエラーを含む)

### `measure`

値を読むためのメソッド．使うときはこれを呼べば良い．

```elixir
defmodule WarblerUi.Sensors.Mhz19 do
  use GenServer, restart: :permanent

  alias Circuits.UART

  @baud_rate 9600
  @sensor_read_command <<0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79>>

  def init(_opts) do
    {:ok, uart_pid} = UART.start_link()

    :ok =
      UART.open(uart_pid, "ttyAMA0",
        speed: @baud_rate,
        data_bits: 8,
        stop_bits: 1,
        parity: :none,
        active: false
      )

    {:ok, uart_pid}
  end

  def handle_call(:read, _from, uart_pid) do
    :ok = UART.write(uart_pid, @sensor_read_command)
    read_uart(uart_pid)
  end

  defp read_uart(uart_pid) do
    case UART.read(uart_pid) do
      {:ok, <<255, 134, higher_bits, lower_bits, _, _, _, _>>} ->
        decoded_data = higher_bits * 256 + lower_bits
        {:reply, {:ok, decoded_data}, uart_pid}

      {:error, reason} ->
        {:reply, {:error, reason}, uart_pid}

      _ ->
        read_uart(uart_pid)
    end
  end

  def measure(pid) do
    GenServer.call(pid, :read)
  end
end
```

## 使い方

Nerves のコンソールを `ssh nerves.local` して開き，こんな感じで実行すれば，CO2 濃度がわかる．

```exs
alias WarblerUi.Sensors.Mhz19
{:ok, mhz19_pid} = GenServer.start_link(Mhz19, {})
{:ok, co2} = Mhz19.measure(mhz19_pid)
```

# あとがき

現在は Phoenix フレームワークを使って，センサーの値を liveview で表示したりしようとしています．
気が向いたらそれについても書くかもしれません．

また，Elixir, Nerves を始めて間もなく，初めての記事なので，間違い等あるかもしれないです．
見つけた場合は指摘していただければ幸いです．
Lightsailの初期ユーザ名をデフォルトから変える


## 経緯

### ユーザ名をデフォルトから変えたい

Lightsailの（Linuxの）ユーザ名は起動時には`admin`（Debian）や`ubuntu`（Ubuntu）といったデフォルト名が設定されている。

Linuxでは一般的に`root`でのログインが非推奨だと言われているが、そうであれば、`root`ほどではないにしろ、デフォルトとして多くのサーバで使われ、さらにパスワード無しで`sudo`ができるデフォルトユーザも避けられるなら避けたほうがいい気がする。

### ユーザ名変えるとWebクライアントが使えない

変えることはできるが、そうすると[Lightsailコンソール上のブラウザベースのsshクライアント](https://lightsail.aws.amazon.com/ls/docs/ja_jp/articles/lightsail-how-to-connect-to-your-instance-virtual-private-server)が使えなくなる。
というのもこのクライアント、以下のような仕様になっている。

- デフォルトのユーザー名、デフォルトのポート、デフォルトのキーによりアクセスする
- ターミナル側の設定は変えられない
  - ポートやユーザー名をサーバー側で変更すると接続できない

そのためこれを維持するのにデフォルトのユーザー名を変更できなくなったり、ポートも変えられなくなったり（22ポートをWebコンソール限定にして他のポートを追加で開けるならできる）と融通が聞かなかった。

Webクライアントを常用するつもりはもちろんなかったが、かと言って素人が手探りで設定している以上、いざというときの緊急アクセス手段として[^clutch]ブラウザからのアクセス手段があるにこしたことはない。ということで、これまでWebコンソールを維持するためデフォルトユーザ名をそのまま使っていた。

### AWS CloudShellつかうなら変えても問題なさそう

しかし最近になって[AWS CloudShell](https://aws.amazon.com/jp/about-aws/whats-new/2020/12/introducing-aws-cloudshell/)という別のWebコンソールがあることを知った。

ここからアクセスするならLightsailコンソールのターミナル使えなくても問題ない、ということで、改めてユーザ名（と公開鍵）を変えて作ることにした。

## スクリプト

これをLightsailの新規インスタンスの初期設定時に起動スクリプトとして設定すれば、一度もデフォルトのユーザ名でログインすることなく、はじめから別のユーザ名でログインできる。

すでに動かしているサーバ、ユーザ名で実行するのは非推奨だが、一応処理自体は起動スクリプトではなく運用中に動かしても機能するはず。

```
# デフォルトのユーザ名 Ubuntuならubuntu debian なら admin 
OLD_USER=admin 

# 新しくしたいユーザ名
NEW_USER=fluo10

# ユーザ名の変更、ホームディレクトリの移動
usermod -l $NEW_USER -md /home/$NEW_USER -c $NEW_USER  $OLD_USER

# グループ名の変更
groupmod -n $NEW_USER $OLD_USER

# パスワードの設定（詳細は後述）
echo $NEW_USER:$NEW_USER | chpasswd
passwd -e  $NEW_USER

# 公開鍵の追加（詳細は後述）
# 新規ユーザ名がgithubのアカウントと違うなら適宜書き換える必要あり
curl https://github.com/$NEW_USER.keys > /home/$NEW_USER/.ssh/authorized_keys
```

### 補足1: パスワードの設定

Lightsailのデフォルトユーザはパスワード無しで`sudo`できる。そのためユーザー名の変更を試すまで気づかなかったのだが、このデフォルトユーザは以下のように**名指し**で**パスワードなしで`sudo`ができる**ように設定されている

```/etc/sudoers.d/90-cloud-init-users
# User rules for admin
admin ALL=(ALL) NOPASSWD:ALL
```

そして、この初期パスワード、**確認する手段がない**ので、ユーザー名を変えたが最後`sudo`ができなくなり最悪詰む。

そこでパスワードを暫定的にユーザー名にし、次回ログイン時に再設定を強制するようにしている。

参考: [初回ログインにパスワードを設定する - 作業ノート](https://te2u.hatenablog.jp/entry/20090121/p1)

### 補足2: 公開鍵の追加

Lightsail の鍵はデフォルトだとリージョンごとに秘密鍵と公開鍵のペアが作られ、秘密鍵をダウンロードして使うという形になっている。

~~そもそも秘密鍵を共有するのはありなのだろうか…名前的にはだめっぽいが実際の運用上はよくやってる感じなのだろうか？~~
AWSがアリだというならアリなのだろうが、個人的には抵抗があるので、LightSailの鍵は使わず自分の既存の公開鍵をgithubから引っ張ってきて上書きした。

参考: [複数人のSSHの鍵をGitHubに登録している鍵を使ってシュッと鯖にいれる - 冬のソフトウェア海岸](https://tkmr.hatenablog.com/entry/2017/10/25/201426)

[^clutch]: 設定ミスで外部からのアクセスが締め出されたり、クライアントの機器でトラブルが起き自己所有でない機器からアクセスする必要ができたり
JavascriptでWebAPIを叩いてみる

# はじめに
バックエンドの練習でJavascriptでWebAPIをたたいてみました。初学者の自分にとってとても苦しい分野ですが、備忘録としてアウトプットします。

## プロジェクトを用意

```php:ターミナル
projects $ mkdir js-WebAPI
projects $ cd js-WebAPI
js-WebAPI $ touch index.html
js-WebAPI $ touch index.js
```
HTMLの雛形を作成します。

```php:index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <p>コンソールで確認</p>
  <script src="./index.js"></script>
</html>
```

## JSONPlaceholderにアクセス
JSONPlaceholderは便利なオンライン上のREST APIサービスです。URLにアクセスするだけで、手軽にテストデータをJSONで受け取ることができます。
↓
[https://jsonplaceholder.typicode.com/users](https://jsonplaceholder.typicode.com/users)このURLは後ほど使用します。

## index.jsを編集

```php:index.js
function callApi() {
  const res = fetch("https://jsonplaceholder.typicode.com/users");
  console.log(res)
};

callApi();
```
まず`callApi`という関数を用意してjson形式で返ってくるデータの格納先として`変数res`を用意します。resには`fetch関数`を代入しfetch関数の引数に`https://jsonplaceholder.typicode.com/users`を渡してあげます。fetchメソッドとは非同期通信でリクエストを発行、そのレスポンスを取得できるメソッドのことです。これで一旦ブラウザを確認してみます。

![スクリーンショット 2021-05-15 16.22.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772095/d357fe3b-945e-f798-07ec-8757be61d839.png)
画像のようにfetch関数を実行すると**Promiss**というオブジェクトが返ってきました。Promissとは**非同期処理**の操作が完了したときに結果を返すものです。 非同期処理とは、ある処理が実行されてから終わるまで待たずに、次に控えている別の処理を行うことです。

## 非同期関数
index.jsを以下のように編集してみましょう。

```php:index.js
async function callApi() {
  const res = await fetch("https://jsonplaceholder.typicode.com/users");
  console.log(res)
};

callApi();
```
functionの前に`async(エイシンク)`をつけました。asyncをつけると`非同期関数`という関数になり、同時に`await`という式を使えるようになります。なので、fetchの前にawaitをつけてみます。ここで、コンソールを確認してみます。

![スクリーンショット 2021-05-15 16.39.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772095/a086c66f-f6f8-bbfe-6734-7a1f9fc27b99.png)
先程はPromissというオブジェクトでかえって来てたものが**Responseオブジェクト**で返ってきてることが確認できます。しかし、これでは中身がまだ見れないのでResponseオブジェクトが持っている`jsonメソッド`を使用して中身を確認していきます。

```php:index.js
async function callApi() {
  const res = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await res.json();
  console.log(users)
};

callApi();
```
新しく変数usersを用意してjsonメソッドの結果を格納します。jsonメソッドの前にもawaitをつけましょう。コンソールを確認してみます。
![スクリーンショット 2021-05-15 16.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772095/a13303b2-b2e3-9cbd-a353-b61256771371.png)
するとJSONPlaceholderのユーザー一覧情報を取得することができました！

# 最後に
用語がたくさん登場し、初学者にとっては難しいですが、今回はasyncとawaitを使えばwebAPIを叩くことができるということがわかったので詳しいことはこれから勉強していきたいと思います。asyncとawaitを使った記述方法の他に`then`を使って書くやり方もあるそうですが、今の主流は前者のようです。エラー処理の書き方も前者のほうがわかりやすいそうなので、モダンな方を学んでいきましょう。
Laravelでダミーデータを作成する方法



## factoryでダミーデータを定義する
database/factories/【モデル名】Factory.php
下記のようにdefinition()内にダミーデータの定義を記述する

```
public function definition()
    {
        return [
            # fakerを使用することでランダムなダミーデータを作成できる
            'title' => $this->faker->realText(rand(15,40)),
            'hoge_flg' => $this->faker->boolean(10),
            'created_at' => now(),
            'updated_at' => now(),
        ];
    }
```

## seederでfactoryの定義を作成する
database/seeders/【モデル名】Seeder.php
下記を追記して対応モデルをインポートする

```
use App\Model\【モデル名】;
```

下記のようにrun()内にfactoryのダミーデータ定義を実行するメソッドを記述する

```
public function run()
    {
        # countは作成するデータ数
        【モデル名】::factory()->count(10)->create();
    }
```

下記のようにrun()内にseederファイルを呼び出し、実行するメソッドを記述する
seeders/DatabaseSeeder.php

```
public function run()
    {
        $this->call(【モデル名】Seeder::class);
    }
```

## seederを実行する
下記のコマンドを実行する

```
php artisan db:seed
```

実際にDBを確認してみて反映されていれば成功です！
JetbrainsのSpacesでGit用SSHキーの登録

# 手順
- 下記コマンドを実行し、sshキーを生成

```shell:cmd
ssh-keygen -t ed25519
# Generating public/private ed25519 key pair.
# Enter file in which to save the key (/Users/xxxxxxxxxxxxx/.ssh/id_ed25519): /Users/xxxxxxxxxxx/.ssh/spaces
# Enter passphrase (empty for no passphrase):(パスワード入力)
# Enter same passphrase again:(同じパスワードを再入力)
# Your identification has been saved in /Users/xxxxxxxxxxxx/.ssh/spaces.
# Your public key has been saved in /Users/xxxxx/.ssh/spaces.pub.
# The key fingerprint is:
# SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# The key's randomart image is:
# 
```
-  ~/.ssh/configを下記の様に編集し、ホストをjetbrainsに設定する

```plaintext:config
Host git.jetbrains.space
  IdentityFile ~/.ssh/spaces
```
- 後はクローンして動作確認
Docker-compose上のLaravelでRedisキャッシュ

#Redisのセットアップ

- ``composer require predis/predis``する
- ``docker-compose.yaml``にRedisを足す。yamlファイルはインテンドの高さを間違えると動かないので注意。

```yaml
redis:
    image: redis
    ports:
      - 6379:6379
```
- ``config/database.php``のRedisクライアントをpredisに変更

```php:config/database.php
//前略
    'redis' => [
        'client' => env('REDIS_CLIENT', 'predis'),
//後略
```

- ``.env``でキャッシュドライバとホストを変更

```.env
CACHE_DRIVER=redis
REDIS_HOST=redis
```

以上でとりあえずRedisが動きます。

#Cacheをコントローラで使う

とりえあず``Product::all()``の結果をキャッシュする場合を考える。
この場合、

- すでにキャッシュがあればそこからデータを取り出す
- ない場合は``Product::all()``のクエリを走らせ、結果をキャッシュする

という処理を行うこととなる。

```php
public function frontend(){
         if($products = \Cache::get('products_frontend')){
             return $products;
         }

         $products = Product::all();
        \Cache::set('products_frontend',$products,30*60);
         return $products;
   }
```
``Cache::get($cache_name)``でキャッシュを呼び出せる。明快だ。``Cache::set()``は第一引数がキャッシュ名、第二引数がキャッシュするデータ、第三引数がキャッシュする時間（秒単位）だ。
なおファサードからは、先頭にバックスラッシュを付けることでクラスを呼び出せる。

また上記の処理は、``\Cache::remember``を使うと一行で書くことが出来る。

```php
$products = \Cache::remember('products_frontend',30*60,fn()=>Product::all());
return $products;
```

#イベントを使ってキャッシュを消したい！

``$products``をキャッシュしたが、商品をupdateしたりcreateしたりdeleteしたりしても、getする際にはキャッシュから引っ張ってくるので情報が変わらないという問題がある。
つまり、update、create、deleteを行う場合はキャッシュを消す必要があるわけだ。

```php
    public function deleteCache(){
        \Cache::forget('products_frontend');
    }
```
とやるのも全然ありだが、ここはイベントを使って消す方法を見ていく。

まずは``php artisan make:event ProductUpdatedEvent``と``php artisan make:listener ProductUpdatedListener``を作成する。
また、EventServiceProviderに両者を登録する。

```php:App/Providers/EventServiceProvider.php
protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        ProductUpdatedEvent::class=>[
            ProductUpdatedListener::class
        ]
    ];
```
これで、``ProductUpdatedEvent``のリスナとして``ProductUpdatedListener``が登録される。

さて、``ProductUpdatedEvent``のコードだが、今回はただ発火するだけのイベントなので、コードの大半は削っていい。

```php:App/events/ProductUpdatedEvent.php
class ProductUpdatedEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
}
```
そしてリスナ内に、必要な処理を書き込む。

```php:App/Listeners/ProductUpdatedListener.php
class ProductUpdatedListener
{
    public function handle( ProductUpdatedEvent $event)
    {
        \Cache::forget('products_frontend');
        \Cache::forget('products_backend');
    }
}
```

これで、ProductUpdatedEventがアプリのどこかで発火し次第、リスナ内のキャッシュ消去処理が実行されることになる。
最後にコントローラ内の必要箇所で、以下のコードでイベントを発火させる。

```php
event(new ProductUpdatedEvent);
```
【JavaScript】メールアドレスの正規表現(RFC準拠)を解読する

##はじめに

メールアドレスの正規表現(RFC準拠)を解読しました。
```^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$```


上記のメールアドレスの正規表現は[Vue.js公式ドキュメント](https://jp.vuejs.org/v2/cookbook/form-validation.html)でも使用されており、信頼性は高いと思われます。

正規表現とは...？という方は[こちらの記事](https://qiita.com/str32/items/a692073af32757618042)や当記事の最下部にある参考サイトをご覧になってからお読みください。

この記事では上記正規表現について、

* @マーク以前
* @マーク以後

に分けて解読します。

##@マーク以前

```javascript
^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))
```

一番先頭の^()は開始マークなので無視して、
分解すると...
```①　([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*```
または
```②　".+"```

①と②それぞれ見ていきます。

####①
```javascript
([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*
```

**<>()[]\.,;:空白文字@"以外の文字**が1文字以上
+
**.マーク**と**<>()[]\.,;:空白文字@"以外の文字**の繰り返しが一回以上

上記を満たした要素が0個以上

ex) hoge.hoge

>**Point**
>[^ABC]でABC以外にマッチという意味

####②
```javascript
".+"
```

**""で囲った文字**が1文字以上

ex)"hoge"

##@以後

```javascript
((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$
```

一番最後の()$は終了マークなので無視して、
分解すると...
```①　(\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])```
または
```②(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,})```

①と②それぞれ見ていきます。

####①
```javascript
(\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])
```

**[]内が**

**0~9の数字**が1文字以上3文字以下
+
(**.マーク**と**0~9の数字**が1文字以上3文字以下)×3回

ex) [0.0.0.0]

####②
```javascript
(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,})
```

**アルファベット小文字/大文字/数字**が1文字以上と**.マーク**
+
**アルファベット小文字/大文字**が2文字以上

ex) gmail.com

##有効なメールアドレス例
wikiより引用
>Abc@example.com (dot-atom)
>Abc.123@example.com (dot-atom)
>user+mailbox/department=shipping@example.com (dot-atom)
>!#$%&'*+-/=?^_`.{|}~@example.com (dot-atom)
>"Abc@def"@example.com (quoted-string)
>"Fred\ Bloggs"@example.com（quoted-pairを含んだquoted-string）
>"Joe.\\Blow"@example.com（quoted-pairを含んだquoted-string）

##参考

https://jp.vuejs.org/v2/cookbook/form-validation.html

https://qiita.com/str32/items/a692073af32757618042

https://murashun.jp/article/programming/regular-expression.html

https://qiita.com/kne-cr/items/eba5d331c7ae781bd1c6

https://www.javadrive.jp/regex-basic/sample/index13.html

https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9

https://www-creators.com/tool/regex-checker
AdMobでアプリが見つからずリンクできない場合の対応方法

# はじめに
**Google AdMob を利用する際**、まず始めに自分のアプリを **AdMob にリンクする必要**があります。

[AdMob のヘルプページ](https://support.google.com/admob/answer/10037806?hl=ja)によると、アプリがリンク可能になるまでには、アプリをアプリストア( iOS アプリの場合は App Store )で**公開後1週間程度かかる**ことがあるそうです。

# 問題
しかし、アプリ**公開後3週間経過**後も私のアプリが **AdMob 内で見つからず、リンクすることができない**という問題が発生しました。

![スクリーンショット 2021-05-15 12.05.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322870/62148475-0347-16ad-38e5-3e9de7cb25e1.png)

この問題は昔から何度も発生しており、多くの人の報告をインターネット上で見つけることができます。

* [AdMobのAppStoreへのリンクができない](https://thwork.net/2020/11/25/admob%E3%81%AEappstore%E3%81%B8%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84/)
* [Stack Overflow: App is not visible in appstore on Admob search](https://stackoverflow.com/questions/64858928/app-is-not-visible-in-appstore-on-admob-search)
  * 「２ヶ月以上待ってもリンクできない」というコメントもあります。

# 解決方法

**AdMob 開発者向けの Google フォーラムで問い合わせる。**

* **Google Mobile Ads SDK Developers**: https://groups.google.com/g/google-admob-ads-sdk

上記のフォーラム上で、**問題が発生していることを報告**(例: `I cannot find my app on AdMob for linking`)し助けを求めると、 Google の AdMob の担当者が**すぐに問題を解決**してくれます。
私の場合は、上記フォーラムで問題を報告した後、**わずか30分後**には AdMob 内でアプリが表示されるようになり、リンクすることができました。

# 記録

* 2021年4月
  * iOS アプリをリリースし、 App Store にアプリが登録されてから、3週間経過後もアプリが AdMob 内で表示されなかった。
    * 👉 上述した方法を使い問題を解決しました。

* 2022年2月
  * iOS アプリを新規にリリースし、 App Store にアプリが登録されてから、24時間を経たずしてそのアプリが AdMob 内で表示されました。
    * 👉 上述した方法を使う必要はなかった。


* 2022年5月
  * iOS アプリを新規にリリースし、 App Store にアプリが登録されてから、36時間ほど経過したタイミングで、そのアプリが AdMob 内で表示されました。
    * 👉 上述した方法を使う必要はなかった。

# 参考元
この解決方法は、以下のツイートで知りました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">AdmobのiOSストアリンクでアプリが1ヶ月表示されず、下のリンクでAdmobのフォーラムに投稿したら、速攻で対応してくれました😳<br>2週間くらい経ったらやるべきですね。<br>やっとリンクできました◎<a href="https://t.co/fjnLAlSZSK">https://t.co/fjnLAlSZSK</a></p>&mdash; まさし☕️Flutterアプリ開発 (@masashi_navi) <a href="https://twitter.com/masashi_navi/status/1392413764041936899?ref_src=twsrc%5Etfw">May 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
アプリのデータが初期化されない時に確認したこと

Unityでアプリを作成し実機で何度か動作確認した際、以前のデータが残ったままになってしまっていたため対処法を記載

####1.すでにアプリが実機内に存在している場合

アプリをアンインストール後に再度ビルドを行う

####2.アプリが実機内に存在していないにもかかわらず、アプリインストール後に起動するとデータが残っている場合

[Androidの自動バックアップ]
(https://developer.android.com/guide/topics/data/autobackup?hl=ja)が有効になっている場合、作成されたバックアップファイルのデータが復元されてしまうため自動バックアップを無効にする

```
<manifest ...>
  <application android:fullBackupContent="false">
    ...
  </application>
</manifest>
```

アプリアンインストール後に再インストールすると初期化された
Salesfoece Live: Japan(2021年6月1日～6月4日)の注目セッションをまとめてみた！

皆さんこんにちは。
2021年6月1日から6月4日まで開催されるイベント「Salesforce Live:Japan」は皆さんご存じでしょうか？
Salesforce Live:Japanとは、株式会社セールスフォース・ドットコムが主催する無料オンラインイベントです。
（詳細は[公式ホームページ](https://www.salesforce.com/jp/events/salesforce-live/)）

イベントでは140を超えるセッションが用意されていて、基調講演や豪華ゲストによる特別講演、各種セッションを通じて、先進事例、ソートリーダーシップ、最新のイノベーションなどが紹介されているようです。

今回はその140を超えるセッションの中から面白そうなものを紹介します！

##その①　豪華ゲストが出るセッション

※[ビジネスの成功をどこからでもSuccess from Anywhere]
2021/6/1（火）09:00-09:55 
https://live.salesforcejapan.com/public/session/view/622?d=70130000000sUVb
Salesforce Live:Japan１日目の最初のセッションなので一番気合の入っている（？）
感じがしますし、なおかつゲストも豪華です（ナビゲーターは柴咲コウ）
「誰もがどこからでも直接信頼できる関係を築き、成功を実現することができる方法」を探るとのことですが、
セールスフォース・ドットコム社長が何をお話されるか気になりますね。

※一人ひとりの創造力が、心を動かすビジネスをつくる！
2021/6/2（水）09:00-09:45
https://live.salesforcejapan.com/public/session/view/659?d=70130000000sUVb
各方面でいろいろ話題になっている株式会社TOKIO の国分 太一副社長が登壇。
株式会社TOKIO はSalesforceを使っているのでしょうか？気になりますね。

※より良い地球環境のために、国と企業ができること
2021/6/3（木）13:30-14:15
https://live.salesforcejapan.com/public/session/view/704?d=70130000000sUVb
小泉進次郎衆議院議員とセールスフォース・ドットコム社長がお話するようです。
セールスフォース・ドットコムは環境問題など社会貢献活動に積極的に取り組まれていますね。


##その②　Salesforceの社内定着化に興味がある方向けセッション

※最短で成果を上げるデータマネジメント手法 Salesforce を究極の顧客マスタに
2021/6/1（火）10:00-10:25
https://live.salesforcejapan.com/public/session/view/638?d=70130000000sUVb
Salesforceを導入したまではいいが、そこからどう使いこなしていくかが肝心かと思います。ここでは具体的な事例を交えながら DX推進を成功に導くデータマネジメント手法が紹介されるようです

※Salesforce × DX 成功のために抑えるべきポイントとソリューションとは？
2021/6/1（火）11:30-11:50
https://live.salesforcejapan.com/public/session/view/648?d=70130000000sUVb
Salesforceあるあるとして「導入前までは頑張ってたけど導入しても結局エクセルを使ってしまう」ということがあるかと思います。
ここでは
「 Salesforce を導入したけど、エクセルから移行できずに中々定着しない…」
「 Salesforce へのデータ入力が負荷になっている…」
という問題解決されるセッションです。


※現場がデータをどんどん入力！システム管理者の上手な社内巻き込み術
2021/6/4（金）12:30-12:55 
https://live.salesforcejapan.com/public/session/view/746?d=70130000000sUVb

「せっかく導入した Salesforce。それなのに未だに商談や活動にあまりデータを入れてもらえていない。」という悩みがある方は見るべきセッション。
「上手に現場を巻き込む 3つの方法論」とは何か気になりますね。

##その③　Salesforce資格取得のためのセッション
※認定アドミニストレーター試験合格のポイント
2021/6/4（金）10:00-10:25 
https://live.salesforcejapan.com/public/session/view/753?d=7013y000002QnULAA0
認定アドミニストレーター試験の合格を目指す方向けの情報があるそうです。

※認定テクニカルアーキテクトへの道
2021/6/4（金）10:30-10:55 
https://live.salesforcejapan.com/public/session/view/754?d=7013y000002QnULAA0
現在 30以上ある Salesforce 認定資格の最高峰に位置する認定テクニカルアーキテクト（CTA: Certified Technical Architect）について、CTA を目指すために必要とされる試験やその勉強方法が紹介されるセッションです


##Trailblazer Guidesの案内もご参考に！

まだまだ魅力的なセッションはたくさんありますよ！

Salesforce Live:JapanTrailblazerではTrailblazer GuidesというTrailblazerコミュニティで活躍する先輩Trailblazerたちが様々なセッションを紹介しています。
https://www.salesforce.com/jp/events/salesforce-live/trailmaps/
「他にもどんなセッションがあるんだろう」と思う人はぜひご参考にしてみてはいかがでしょうか。
【SwiftUI】Picker使ってみた

今回作成するアプリに複数の選択肢から１つだけ値を選択する機能が必要なので
Pickerという部品を使って実装してみました。

SwiftUI初学者の方々に参考になれば嬉しいです。

実装後の動作は以下になります。

<img width="400" alt="mojikyo45_640-2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1223933/c161dcfa-3f2f-5262-9cb2-dd460eb9cda7.gif">


ソースコードは以下です。

```swift:
import SwiftUI

struct ContentView: View {
    @State var selection: String = "和食"
    var array: [String] = ["和食", "洋食", "中華"]
    
    var body: some View {
        VStack {
            Picker(selection: $selection,label: Text(selection).frame(width: 100))  {
                ForEach(array, id: \.self) { word in
                    Text(word).tag(word)
                }
            }
            .pickerStyle(MenuPickerStyle())
            .padding()
            .cornerRadius(5)
            Text("選択値：\(selection)")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```


pickerStyleを変更すれば、よくあるスクロール形式？のリスト表示も出来ます。

ここをこうした方が可読性が上がるとか、もっとスマートになるとかあればコメントお願いします。
※見直したらGIFの動きがめちゃくちゃ遅いですね。変換時の設定ミスっぽいです。気をつけます
Python ファイルの指定の文字を含む行番号を取得

txtファイルを読み込んで「梅雨」という単語を含む行番号と数値を含む行番号を取得する

```python
from tkinter import filedialog
import re

dir = "D:\Python\Hello" #ダイアログの初期フォルダ
typ = [("", '*.txt')]
file_path = filedialog.askopenfilename(
    title="文字抽出ファイル名を指定", filetypes=typ, initialdir=dir) 

f = open(file_path, 'r', encoding='UTF-8')
lines = f.readlines()
lines_strip = [line.rstrip() for line in lines] #改行文字を除く
line_num = [i for i,moji in enumerate(lines_strip) if '梅雨' in moji] #「梅雨」を含む行番号を取得
print(line_num) 

for i,moji in enumerate(lines_strip):
    result = re.sub(r"\D", "", lines_strip[i]) #数値を含む行番号を出力
    print(result)
f.close()

```
【MySQL】MacでMySQLを使う

# MySQLをインストール


```
brew install mysql
```

# ログイン/ログアウト

```
//ログイン
mysql -u [ログインするユーザー名] -p
```

```
//ex)rootでログインする場合
mysql -u root (-p)

※パスワードを設定していない場合は-pは不要 
```

```
//ログアウト
mysql> exit
mysql> quit
mysql> \q
```
# データベースの新規作成

```
mysql> create database [データベース名] 
```
# データベースの削除

```
mysql> drop database [データベース名] 
```

# データベースの選択

```
//データベース一覧表示
mysql> show databases; 
```

```
//利用するデータベースの選択
mysql> use [データベース名]
```

# テーブルの新規作成

```
CREATE TABLE [テーブル名] (
    id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    →, //必要なカラムを追加していく
    →, //必要なカラムを追加していく
    →  //必要なカラムを追加していく(最後は「,(カンマ)」は不要)
);

//ex)
CREATE TABLE members (
   id int AUTO_INCREMENT NOT NULL PRIMARY KEY,
   name VARCHAR(225),
   email VARCHAR(225),
   password  VARCHAR(100),
   picture  VARCHAR(225),
   created_at datetime 
);

```
# テーブルの削除

```
mysql> DROP TABLE [テーブル名];
```
# テーブル一覧表示

```
mysql> show tables (status);
```
#テーブルにカラム追加

```
ALTER TABLE [テーブル名] ADD [新規カラム名] [型情報] [オプション];
```



関連記事
【MySQL】mysqlのrootユーザーがsudo無しでログインできるようにする
https://qiita.com/aoaoao/items/9fc78ff92948ed885d1a
【C#】デフォルト引数を追加したらアプリケーションが動かなくなった

## はじめに
メソッドの呼び出し側を修正することなく、機能を追加できるデフォルト引数（オプション引数）は便利ですが、使いどきを誤るとアプリケーションに予期しない影響を及ぼすことがあります。

この記事では私が実務でデフォルト引数を追加した際にアプリケーションが動かなくなった体験を元に、デフォルト引数の追加時の注意点と解決方法をまとめます。

## この記事の対象者

- C#を使って開発をしている人

## アプリケーションが動かなくなった状況
下の図のように1つのソリューションに共通メソッドを定義するプロジェクトと、それを利用する複数のプロジェクトがある状況で、共通メソッドの動作を変更する修正案件がありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68663/3bf10074-6012-e642-f0ff-0d29af9ec4ee.png)

共通メソッドは以下のような税込み価格を返すメソッドだったとしましょう。

```cs:CommonLib.cs
public static class CommonLib
{
    public static decimal CalcTaxIncludedPrice(decimal price)
    {
        return price * 1.08M;
    }
}
```

プロジェクトAからの呼び出しのときだけ、税率を変更したかったため、下記のようにデフォルト引数を追加して税率を変更できるようにしました。

```cs:CommonLib.cs
public static class CommonLib
{
    public static decimal CalcTaxIncludedPrice(decimal price, decimal rate = 1.08M)
    {
        return price * rate;
    }
}
```

動作検証も完了し、担当者に修正したコードを渡して、ホッと一息ついていると、担当者が動作検証したところ、プロジェクトBの機能でエラーが起きるとの報告が来ました。

私の環境では正しく動作していたため、何が起きたのか確認すると、担当者は**プロジェクトAと共通メソッドプロジェクトのみをリコンパイル**して動作検証したとのことでした。

## 何が起きたのか
デフォルト引数を追加した場合、**呼び出し側に定数が埋め込まれる**形で解釈されます。

```cs
// デフォルト引数を書いていないこのコードは
var taxIncludedPrice = CommonLib.CalcTaxIncludedPrice(100);

// コンパイル時にこのようなコードに解釈される
var taxIncludedPrice = CommonLib.CalcTaxIncludedPrice(100, 1.08M);
```

そのため、リコンパイルしていないプロジェクトBでは、定数が埋め込まれておらず、引数が1つの`CalcTaxIncludedPrice`メソッドを呼んでしまうため、実行すると以下のようなエラーが起きてしまいます。

```
ハンドルされていない例外: System.MissingMethodException: メソッドが見つかりません:
'System.Decimal CommonLib.CalcTaxIncludedPrice(System.Decimal)
```

私が動作検証した際はソリューションごとリコンパイルしており、プロジェクトBもリコンパイルされていたため、エラーに気づくことができませんでした。

このようにメソッドにデフォルト引数を追加する場合は、そのメソッドの呼び出し側がリコンパイルされるかどうか注意する必要があります。

## どのように解決するのか
必ずリコンパイルされるのであれば問題ないのですが、今回のように呼び出し側の一部はリコンパイルしないという場合は**メソッドをオーバーロード**して機能を追加します。
元のメソッドはオーバーロードしたメソッドを呼び出すようにして処理を一箇所にまとめましょう。

```cs:CommonLib.cs
public static class CommonLib
{
    // オーバーロードして利率を渡せるバージョンのメソッドを作る
    public static decimal CalcTaxIncludedPrice(decimal price, decimal rate)
    {
        return price * rate;
    }

    // 元のメソッドはオーバーロードしたメソッドを呼び出すようにする
    public static decimal CalcTaxIncludedPrice(decimal price)
    {
        return CalcTaxIncludedPrice(price, 1.08M);
    }
}
```

こうすれば、引数が2つのメソッドと引数が1つのメソッドが存在するため、修正していないプロジェクトをリコンパイルしなくても、エラーは起きなくなります。

## まとめ
この記事では私の実務での体験をもとにデフォルト引数の追加時の注意点と解決方法をまとめました。
呼び出し側を修正せずに機能を追加できるため、デフォルト引数はとても便利ですが、修正していないコードもリコンパイルが必要になるということは理解しておかないと、上で述べたようにアプリケーションに予期しない影響が出てくることがあるため、注意しましょう。

それではまた。

TomoProg

## 参考
[オプション引数・名前付き引数 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C](https://ufcpp.net/study/csharp/sp4_optional.html)
[【C#】デフォルト引数のバージョニング問題 - 滅入るんるん](https://blog.meilcli.net/2018/10/20/200903)
.NETランタイムやライブラリに依存しない自己完結型アプリの発行方法

# はじめに
この記事では、.NET ランタイムがインストールされていないコンピューター上で実行することができる自己完結型の実行可能ファイル(.exe)の生成手順を記載しています。

# 環境
- Windows 10 home
- visual studio Community 2019
- C# （.NET Core）


# 手順

## プロジェクト作成
以下のようなコンソールアプリ（.NET Core）を作成して、発行しようと思います。
![1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/ef98af04-42b3-b145-4260-3235914ec597.jpeg)



## コード

"Hello World!"をコンソール上に出力して、文字列の入力待ちをするようなアプリを作成します。

```cs
using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Console.ReadLine();
        }
    }
}
```

## 発行

ソリューションエクスプローラーにあるプロジェクトファイル（ConsoleApp1）を右クリックして、**「発行」** を選択をすると以下のような画面が表示されます。

![2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/f49e633e-a54d-a595-dc8c-59b764ede9ab.jpeg)

フォルダーを選択し、「プロファイルの作成」をクリックします。

![3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/e777e9b4-6ddf-add3-1774-a5d1114ed92c.jpeg)

上図の発行ボタンの下にある **「編集」** をクリックします。

![4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/69c2376d-7ae1-e62b-8107-dd7dcd190df8.jpeg)

- 配置モードを **「自己完結」**
- ターゲットランタイムを **「win-x64」**
- ファイル公開オプションを開いて、**単一ファイルの作成にチェック**

上記の設定をして、保存します。
作成したプロジェクトのフォルダの **[ bin ] > [ Release ] > [ netcoreapp3.1 ] > [publish] > 「ConsoleApp1.exe」** が生成されています。
この実行可能ファイルは自己完結型になりますので、どこに移動させても実行することができます。

## 自己完結型アプリの実行
![5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/6b3757f2-a60b-5746-2ef4-49ca432d61c8.jpeg)

実際に、ConsoleApp1.exeをデスクトップ上に移動させて実行してみると、コンソール上に"Hello World!"と出力して、入力待ちになっているかと思います。

以上になります。ありがとうございました。
AWS Summit Online 2021のセッション情報を可視化してみた。

AWS Summit Online 2021が開催中です。
https://summits-japan.virtual.awsevents.com/

すごくたくさんのセッションがあるのですが、ふと、どんな分野が流行りなのかなぁと思ったのでセッションの情報を分析してみました。

# 使用したツール

僕にはなんにもスキルがありませんので、便利なサイトを利用させていただきました。

AIテキストマイニング by ユーザーローカル
https://textmining.userlocal.jp/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/3f8ac17f-8a0b-09a6-63fd-6467bf307d93.png)


# データ取得方法

セッションの一覧ページは、こんな感じで、タイトルと説明文で構成されています。
説明文が途中で切れてますが、このまま使用しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/3dd64925-1261-bb4a-3aa2-3e5b79d9998d.png)

Chrome DevToolsの`Console`タブで以下のコマンド実行で取得できました。

```javascript:タイトルの取得
item__name = ''
document.querySelectorAll('.event-list-item__name').forEach(value => item__name = item__name + value.innerText + '\n')
item__name
copy(item__name) // クリップボードにコピー
```

```javascript:説明文の取得
item__description = ''
document.querySelectorAll('.event-list-item__description').forEach(value => item__description = item__description + value.innerText + '\n')
item__description
copy(item__description) // クリップボードにコピー
```

# 結果

セッションがAWSセッションとパートナーセッションに分かれているのでそれぞれでやってみました。

## AWSセッション編

ワードクラウド

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/9929bf89-c5dc-640e-d576-dc28a1e12111.png)

AWSは当然ですが、`機械学習`や`ワークロード`などが目を引く感じでしょうか

頻出単語（名詞）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/7eb6808d-f558-a35d-c261-01826efb3a0f.png)

先程のワードクラウドとはちょっと結果が異なる感じでしょうか。`詳細`や`情報`は説明文の末尾に必ず`詳細情報`とあるので、それが出てるだけと思います。

# パートナーセッション編

ワードクラウド

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/35f2a731-2bf9-61db-e95e-bc1e68808137.png)

パートナーセッションだけに、`パートナー`の文字がでかい！！。AWSセッションとの違いでは`dx`、`サーバレス`の大きさが目を引きますね。

頻出単語（名詞）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/e4027fee-98d8-faba-7964-8d0c87e81eff.png)

セキュリティがパートナーセッションの方だけランクインですね。


以上です。
例題演習matplotlibのまとめ

Pythonのmatplotlibライブラリで，グラフ作成を学ぶ．
サンプルコードは細部までグラフの設定ができるものを用意した．
そのサンプルコードをもとに，例題と演習でmatplotlibの使い方を習得する．

## 例題演習matplotlib(1) 最初の一歩
https://qiita.com/s4s/items/33323d95b93c8ceec52d

## 例題演習matplotlib(2)：単純な折れ線グラフ
https://qiita.com/s4s/items/11db1cdb4c604e1dd42a

## 例題演習matplotlib(3)：Axes（軸）の設定
https://qiita.com/s4s/items/99c8c6aad1339dfbc544

## 例題演習matplotlib(4)：Legend（凡例）の設定
https://qiita.com/s4s/items/2b5ef8a1dc96db790070

## 例題演習matplotlib(5)：対数グラフ
https://qiita.com/s4s/items/8c5cb68cb0f03411f9da
Chromeでブラウザ拡大とiframeのバグっぽい挙動

Chromeで開発者ツールを開いているとき、なぜかレイアウトが崩れるバグに悩まされていたが、その原因がブラウザの拡大率とiframeの関係だったのでメモに残す。


まず、以下の条件のとき、ブラウザの拡大率は無視される

- Chromeで開発者ツールを開いている
- device toolbar を開いている
- Device typeを `mobile` にしている

しかし、iframeの中に限っては上記の条件でも拡大率が影響する
見た方が早いと思うので、次の画像を見て欲しい

|拡大率100%|拡大率200%|
|---|---|
|通常の拡大率の表示|上記条件を満たしたときの拡大率200%の表示|
|![スクリーンショット 2021-05-15 15.41.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68087/2e3e7d77-3bf1-696e-f6dd-c2201c109e2f.png)|![スクリーンショット 2021-05-15 15.41.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68087/9dee2c26-bd2f-2fb1-d789-ffd0dac8d526.png)|

右の200%にした場合の画像を見ると、タイトルの `<iframe>:インラインフレーム要素` などは拡大しておらずそのままで `HTML Demo: <iframe>` とあるiframeの中だけ200%に拡大している。

以下のような表示であればPCとMobileで表示に差異はでないため問題ないのだが

- PC版表示： 全て200%表示
- Mobile版表示: 全て100%表示

実際には以下のようになる

- PC版表示： 全て200%表示
- Mobile版表示: 基本100%表示だが、iframe内のみ200%表示

そのため、PC版とMobile版で表示が異なってしまい、iframe内だけバグっているように見える。
これが原因で3時間ほど溶かしたので気をつけていきたい...

気づけなかった原因としては
プロジェクトA（localhost:3000）を立ち上げて拡大してみていたあと、
プロジェクトB（localhost:3000）を立ち上げて普通にみて、
プロジェクトAで拡大していたのを忘れていたためである。
つらい。
Laravel+PostgreSQLでtimestampのあるテーブルデータがCarbonのtrailing dataエラーが出てしまう解決の備忘録

表題の通りのエラーを解決した忘備録。

```
CREATE TABLE 社員s (
    id SERIAL PRIMARY KEY,
    user_id integer NOT NULL,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
以下略・・・
```

みたいなテーブルにおいて、
モデルでは、更新日時カラムをlaravelのデフォルトから変更して

```
class Staffs extends Model
{
    const UPDATED_AT = 'updated_time';
    const CREATED_AT = 'updated_time';

```

みたいにカラムを指定している。。。


これを表示したり保存したりしようとすると。。。

```
"message": "Trailing data",
    "exception": "InvalidArgumentException",
    "file": "/var/www/app/api/vendor/nesbot/carbon/src/Carbon/Carbon.php",
    "line": 910,
```

こんなエラーがでる:weary:

```
const UPDATED_AT = null;
const CREATED_AT = null;
```

にすればエラーは出ないが、保存時にタイムスタンプが自動更新されない。
SQLを書けばいいんだけど、案件的な事情でLaravelの自動保存を使いたい。

## ネットで示されている解決法

```
protected $dateFormat = 'Y-m-d H:i:s.u'; 
```

とか、

```
public function getDateFormat()
{
     return 'Y-m-d H:i:s.u';
}
```

みたいにデータ型を指定しても、うまくいかない・・・
`Y-m-d H:i:sP`とか`Y-m-d H:i:s0`とかもダメ。
`Y-m-d H:i:s`でもうまくいかない。なんでや:cry:

## 解決策

世界には必ず同じエラーで困っている人がいる！！

### Carbon trailing data for dates with timezone #16839

Traitを作るしか無いようだ

https://github.com/laravel/framework/issues/16839

このように、データ型を見てCarbonへ渡すデータを調整するtraitを作成して、useすれば解決した。

## 原因（よくわからん）

古いlaravel or Posgres or Carbonの仕様なんだろうか・・・？
特に理由がない限りは最新版のパッケージを使いたい:cry:

**よくわからんが動いているのでヨシ！！！**状態なので

根本的な原因について分かる人はコメントください・・・

## 似たエラーやこの辺の仕様、解決URL

https://www.suzu6.net/posts/164-laravel-createat-updateat/
https://yoo-s.com/topic/detail/788
https://laracasts.com/discuss/channels/laravel/carbon-trailing-data-error?page=0
https://toriyaru.com/2020/01/09/laravel6のtimestamp型のデータでtrailing-dataエラーが発生/
Macからvirtualbox上端末にリモート接続する方法

こんにちはspchanです。本日はMacからvirtualbox上端末にリモート接続する方法について説明します。

まずvirtualboxのポートフォワーディング設定をします。
次にvirtualboxの接続したいマシンにopenssh-serverをインストールしてsshd待機状態にします。
次にローカルホスト、ここではMacの~/.ssh/configに

```vim:~/.ssh/config
Host matcha(任意の名前)
Hostname 　hogehoge(ホスト名やipアドレス）
User hoge(リモート側のログインする名前）
Port 2022(ローカル側のホスト番号）
IdentityFile ~/.ssh/id_rsa
```
と書き込んで、

```bash
$ssh matcha
```
と先ほど書き込んだ任意のHostの名前を書くと、リモート側のログインパスワードを聞かれ、正しいパスワードを入力すると、無事接続が完了します。
接続を切りたいときは、

```bash
matcha@hogehoge$ exit
```
とすれば切ることができます。

以上で説明を終わります。
Macはssh環境が既にターミナルにインストールされているため、簡単にリモート接続ができますね♪
VBAの基本操作（補足１）

前回までは分類や課題に対して関数やコードの内容を説明してきましたが、説明に含めなかった関数やコードがありましたので、今回の記事で補足したいと思います。


```:インデックスの最大値
    '配列の宣言
    Dim arr1(3) As Integer
    Dim arr2(5) As Integer
    Dim arr3(11) As Integer
    
    'UBound関数の戻り値の表示
    Dim str As String
    str = UBound(arr1) & vbCrLf & UBound(arr2) & vbCrLf & UBound(arr3)
    MsgBox str, vbInformation
```

UBound関数は配列の中にインデックスの最大値を出すことができます。

```:多次元配列の場合のインデックスの数
    '配列の宣言
    Dim arr(3, 5, 11) As Integer
    
    'UBound関数の戻り値の表示
    Dim str As String
    str = UBound(arr, 1) & vbCrLf & UBound(arr, 2) & vbCrLf & UBound(arr, 3)
    MsgBox str, vbInformation
```

配列の中に配列を複数置いた場合においても上記のコードで、それぞれ配列のインデックスの最大値を取り出すことができます。

```:インデックスの最小値
    '配列の宣言
    Dim arr1(1 To 3) As Integer
    Dim arr2(3 To 5) As Integer
    Dim arr3(5 To 11) As Integer
    
    'LBound関数の戻り値の表示
    Dim str As String
    str = LBound(arr1) & vbCrLf & LBound(arr2) & vbCrLf & LBound(arr3)
    MsgBox str, vbInformation
```

上記のようにLBoundはインデックスの最小値を取り出すことができます。これもUBoundと同様に多次元配列においても使用することができます。

```:ファイルの有無を確認する
 Dim FSO As Object
 Dim Tgt As String
  
 'FileSystemObjectオブジェクトを生成
 Set FSO = CreateObject("Scripting.FileSystemObject")
 '存在を調べたいファイル名をフルパスで指定し変数に代入
 Tgt = "D:\デスクトップ\Sample\Sample1.xlsx"
 
 If FSO.FileExists(Tgt) Then
     'ファイルが存在する場合の処理
     MsgBox Tgt & "が見つかりましたので、ファイルを開きます"
     Workbooks.Open Tgt
   Else
     'ファイルが存在しない場合の処理
     MsgBox "ファイルが存在しません", vbCritical
  End If
```

FileExists関数はファイルのパスを指定して見つかった場合にTrueを返す関数になります。上記のようにFSOと組み合わせることで検索して見つかった場合に開くといったこともできます。

```:改行
   'vbCrLfで改行
    a = "aaa" & vbCrLf & "bbb"
    
    'セルに入力
    ActiveSheet.Cells(1, 1) = a

```

上記のコードでaaaとbbbが2行になって表示されたかと思います。他にも下記のようなコードで改行が行えます。vbCrLfを使えばエクセルのセル内、メッセージボックス、メモ帳など多くの場面で使用できます。（vbLfなど他にも使用できる関数は有りますがvbCrLfで基本代用ができます。媒体によって改行したくない場合にはvbLfやCrLfなど他の関数を使ってみてください）

```:スペースの削除
    Dim str As String
    str = " Hello VBA! "
    
    MsgBox str & "(LTrim前)" & vbCrLf & _
            LTrim(str) & "(LTrim後)" & vbCrLf & _
            RTrim(str) & "(RTrim後)"
```
Trim関数は文字列に空白が存在する場合にそれを取り除くことができます。RTrimで文字列の最初のスペース、LTrimで文字列の最後のスペースを取り除くことができます。

```:イミディエイトウインドウ
'00000を表示する
Debug.Print "00000" + intnum

Debug.Print Right("00000" & intnum, 5)

Debug.Print "00000" & intnum
```
Debug.Printはイミディエイトウィンドウに表示する際に使用する関数です。イミディエイトウィンドウとはアプリをデバックした際に確認できるウィンドウだと思ってい下さい。

[イミディエイトウィンドウとは？](https://exceldake.com/s1-2-1/)

いかがでしたか？こんな感じで今後も説明していない関数を補足として記事にしていこうと思います。
[Docker/Windows]Next.jsを10.2にしたら自動更新されなくなった

##状況
WindowsのDocker(WSL2)で動かしているNext.jsを10.2にアップグレードしたら自動更新(Auto Refresh)されなくなりました。

問題が起きているのはWindows上のDockerのみで、Macでは問題なしです。


Next.jsを9系に戻せば直るのですが、10.2では壊れていたIE11サポートが修正されているので、できれば10.2を使いたいという特殊な事情がありました。
イキって最新の10.2を使いたい方向けです。

## 環境
Windows10 Pro 64bit
Docker 3.3.3 (WSL2, image node:alpine)
Next 10.2


## とりあえずの解決方法
下記の様にデフォルトの webpack5 ではなく、webpack4 を使う指定をします。
Next.jsプロジェクトのルートにnext.config.js が無ければ新規で作成します。

```javascript:next.config.js
module.exports = {
  future: { webpack5: false }
}
```

## 参考
[Next.js 10.0.6以降のwebpack5設定方法](https://zenn.dev/kodai/articles/67ae0b8cf018ed)
[GitIssues](https://github.com/vercel/next.js/issues) (それっぽいの無い）
Heroku × Railsアプリの時間表記を日本時間に合わせる

# まずはHerokuのタイムゾーン設定を変更

プロジェクトファイルのディレクトリで、以下コマンドを叩きます

```
heroku config:add TZ=Asia/Tokyo
```

以下のような記述が出たらok

```
% heroku config:add TZ=Asia/Tokyo
Setting TZ and restarting ⬢ puffshare... done, v64
TZ: Asia/Tokyo
```
LANGも変更

```
heroku config:add LANG=ja_JP.UTF-8
```

heroku側にSSH

```
heroku run bash
```


コンソールで確認してみてその日の日付になってたら完了です！

```
% heroku console
Running console on ⬢ puffshare... up, run.6216 (Free)
Loading production environment (Rails 6.1.3.1)
irb(main):001:0> Time.now
=> 2021-05-15 14:43:04.20104537 +0900
irb(main):001:0> Date
Sat May 15 14:44:24 JST 2021
```

うん、JSTになりました！

# Rails側の設定をしていく

### config/application.rbに追記する


```config/application.rb
~(省略)~
module App
  class Application < Rails::Application
   ~(省略)~
    # Don't generate system test files.
    config.generators.system_tests = nil

    #以下を追記
    config.time_zone = "Tokyo"
    config.active_record.default_timezone = :local
  end
end
```

### created_atの後にstrftimeを設定していく

()で指定するのはよしなに。

```nantoka.erb
<%= letter.created_at.strftime("%m月%d日%Y年 %H:%M")  %>
```

こちらの出力だと04月


strftimeに指定できる書式は以下のような感じらしい

|書式	| 返り値	| 説明|
|:-:|:-:|:-:|
|%Y|	2019|	西暦を4桁の数で取得する※西暦1年は「0001」|
| %m|	01|	月を必ず2桁の数字で取得する（01-12）|
|%-m	|1|	月を1桁か2桁の数字で取得する（1-12）|
|%d	|01|	日付を必ず2桁で取得する（01, 02 ... ）|
|%-d	|1|	日付を1桁か2桁で取得する（1, 2 ... 10, 11 ...）|
|%H	|12|	24時間制の時刻を必ず2桁で取得する（00-23）|
|%-H	|12|	24時間制の時刻を1桁か2桁で取得する（0-23）|
|%I	|12|	12時間制の時刻を1桁か2桁で取得する（1-12）|
|%M	|00|	分を取得する（00-59）|
|%S|	00|	秒を取得する（00-60）※60はうるう秒|
|%A || 曜日名|
|%a || 曜日名（短縮形）|



# 参考

Thank you:))

http://azuuun-memorandum.hatenablog.com/entry/2017/03/25/132607

https://qiita.com/tetsuya/items/e0fd25fc3da2615d1cb2

https://pikawaka.com/rails/strftime
ターミナルからディレクトリを指定してPhpStormで開く方法

PhpStorm上でディレクトリを指定して開く作業が手間だったので、ターミナルから開けるようにしました。

# 前提
- Mac バージョン11.3.1
- シェル：zsh

# 手順
## 1. pecoをインストールしておきます。
https://github.com/peco/peco

#### 参考

https://qiita.com/vintersnow/items/08852df841e8d5faa7c2

## 2. .zshrcファイルを編集します。
``` shell:.zshrc
op() {
  target=`find ~/GitRepository -type d -maxdepth 1 | sed 1d |cut -d / -f 5 | peco`
  if [ "$target" != "" ]; then
    open -a PhpStorm ~/GitRepository/"$target"
  else
    echo 'Cancel open PhpStorm' >&2
  fi
}

```

筆者は/GitRepository以下にgithubで管理しているディレクトリを集めているので、ディレクトリ構成は次のようになっています。

`/Users/masumoto/GitRepository/PhpStormで開くディレクトリ`


GitRepositoryの部分をご自身のディレクトリ名に変更してください。

また、ディレクトリ構成の階層の深さによって`cut -d / -f 5`の数値を変更してください。
（上記の階層だと5番目が**PhpStormで開くディレクトリ**の階層となる）


# 3 zshを更新します。
```
$ source .zshrc
```

# 4 ターミナルで$ opとコマンドを入力します。
うまく設定ができていれば、/GitRepository以下のディレクトリ一覧が表示されます。
![スクリーンショット-2021-05-15-14.14.33-1024x148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616723/1c73b62e-6139-7454-0b6c-99eccdd213e8.png)

絞り込みもできます。
![スクリーンショット-2021-05-15-14.14.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616723/386d791e-29b4-ddb6-5eac-791712dd4509.png)

あとは上下キーで選択してEnterを押せばPhpStormで対象のフォルダを開くことができます。

# 補足
```
open -a PhpStorm ~/GitRepository/"$target"
```
の部分を

```
open -a SourceTree ~/GitRepository/"$target"
```
などに変更することでSourceTreeやVSCodeなどの他のアプリでも開くことが可能です。

#### 参考
https://qiita.com/yousan/items/06e395debc2b4bff2b27
nodenvでインストール済みのバージョンリストを表示させる

## nodenvでインストール済みのバージョンリストを表示させる

検索してもなかなか出てこなかったので自分用にメモ
↓でいけました。現在利用しているバージョンについても教えてくれます。

```
nodenv versions    
  system
  14.4.0
* 15.10.0 (set by /Users/barabara/.anyenv/envs/nodenv/version)

```

helpコマンドを使えば各コマンドについての説明がちゃんとありました。

```
nodenv help
Usage: nodenv <command> [<args>]

Some useful nodenv commands are:
   commands    List all available nodenv commands
   local       Set or show the local application-specific Node version
   global      Set or show the global Node version
   shell       Set or show the shell-specific Node version
   install     Install a Node version using node-build
   uninstall   Uninstall a specific Node version
   rehash      Rehash nodenv shims (run this after installing executables)
   version     Show the current Node version and its origin
   versions    List installed Node versions
   which       Display the full path to an executable
   whence      List all Node versions that contain the given executable

See `nodenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/nodenv/nodenv#readme
```

## まとめ

わからないことがあったらまずhelpコマンドとか公式ドキュメントを確認するようにしよう。
Qt C++ 3Dグラフ表示 QtDataVisualization

#実行サンプル
x, y, z の3次元座標のテキストファイルを読み込み
3Dグラフ　散布図(scatter)として表示する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423803/7720e46f-b546-cd97-e12f-fdf762d588ad.png)

※マウス操作でズームのみ可能。
※視点移動(=グラフ回転）はスライダーでする。（マウス操作はできない。）
※今時点のソースコードでは、スライダーを動かすと先にズームしていたのものが
　初期の位置に戻ってしまう。
　これから調べて、方法がわかれば修正するが
　それまでは、まず回転をスライダーでする→ズームするの順番で見たい位置を見る操作になる。

#実行環境
windows10
Qt5.9
VisualStudio2019

#実行手順
通常通り　QtCreatorでコード作成して、実行する。


#ソースコード
https://github.com/sakurataiko1/Qt_Cplus_DataVisualization/tree/main/QtDataVisual_my_3Dcsvfile_rotate

#コード作成手順ポイント
■　Qt project 作成は通常通り (Qt Widget)

■　.proファイルに下記記述が必要

```
QT       += core gui datavisualization qml quick
```

■ MainWindow.cpp / h ファイルどちらも下記記述を記述する。
※記述する位置は　
・\#includeの後　
・MainWindow::MainWindow(QWidget *parent)の手前

```
using namespace QtDataVisualization;
```

■　Mainwindow.h ファイルに下記記述が必要

```
#include <QtDataVisualization/q3dscatter.h>
```

■　Mainwindow.cpp ファイルに下記記述が必要

```
#include <QtDataVisualization/QScatter3DSeries>
```

■ MainWindow.cpp  散布図グラフ表示のため下記記述が必要だった。

```
    //初期設定 
    QScatter3DSeries *series = new QScatter3DSeries;
    series->setItemLabelFormat(QStringLiteral("@xLabel, @yLabel, @zLabel"));
    series->setMesh(QAbstract3DSeries::MeshCube);
    series->setItemSize(0.15f);
    m_graph->addSeries(series);
```

```
    // Add data from the QVector to datamodel 行、データを生成する
    QScatterDataArray *dataArray = new QScatterDataArray;
    dataArray->resize(itemList.count());
    QScatterDataItem *ptrToDataArray = &dataArray->first();
    for (int i = 0; i < itemList.count(); i++) {
        ptrToDataArray->setPosition(itemList.at(i));
        ptrToDataArray++;
    }

    m_graph->seriesList().at(0)->dataProxy()->resetArray(dataArray);
```

#参考資料
参考：
■　3D　立方体の自動回転表示　（マウス操作：ズームあり、視点移動なし）
https://github.com/fengfanchen/Qt/tree/master/3D%20move%20rotation

■　3D　objファイルから散布図でデータ表示（マウス操作：ズームあり、視点移動なし）
https://blog.csdn.net/qq78442761/article/details/103678544
https://github.com/fengfanchen/Qt/tree/master/3DScatter%20Demo

■　参考：Qt付属のExampleコード
　・サンプル　customplot　（マウス操作：ズームあり、視点移動なし？）
　・サンプル　bars (視点移動=グラフ回転）
　　↑スライダーで視点移動（マウス操作ではない。）

#今後の参考予定
・マウス操作での視点移動のサンプルは、見つかっていない。
　これから調べる。

・Qt公式　サンプル surface （グラフ表示を参考にする）

・1つのグラフ領域(Axis)に2つ以上のグラフを描く 
　→https://forum.qt.io/topic/92510/overlapped-surface3d-and-scatter3d/8
  →Qt公式サンプルcustomitems　
  　https://doc.qt.io/archives/qt-5.9/qtdatavisualization-customitems-example.html
  →Qt公式サンプルrotation も参考になるかもしれない。　

・散布図表示　各座標点で色変更
https://stackoverflow.com/questions/44329125/q3dscatter-how-to-add-a-point-with-a-different-color-to-a-point-cloud
pixi.jsでApplicationのサイズをスマホの画面に合わせる

今やパソコンでWebサイトを閲覧する人などこの世にいない。
いない、というのは嘘だが、サイトを作るときはこのくらいの気持ちでいたほうが良い気がする。
どんなサイズの端末でサイトを訪れられてもイイカンジのデザインで表示されていてほしいものだ。

特にそれがゲームであればなおさらである。
わざわざブラウザでゲームを作るなという正論は聞こえないふりをして、ゲーム画面をスマホのサイズに合わせる方法を紹介する。

```js:script.js
//Aliases
let Application = PIXI.Application;
    
//アプリケーション宣言
const width = 500;
const height = 600;
const widRatio = 0.9;
const heiRatio = 0.95;
let app= new Application({
    width:width, 
    height:height,
    backgroundColor:0xAAAAAA,
});

//貼り付け
document.getElementById("game").appendChild(app.renderer.view);

function screenResize() {
    let wid = widRatio*window.innerWidth;//ゲームを表示できる最大横幅
    let hei = heiRatio*window.innerHeight;//ゲームを表示できる最大縦幅
    let x = width;
    let y = height;
    app.stage.scale.x = app.stage.scale.y = 1;//スクリーン幅が十分の時は画面倍率を1にする
    resizeRatio = Math.min(wid/width, hei/height);//横幅と縦幅の、ゲーム画面に対する比のうち小さい方に合わせる
    if(wid < width || hei < height) {//スクリーン幅が足りないとき
        //リサイズ倍率を調整
        x = width*resizeRatio; 
        y = height*resizeRatio; 
        app.stage.scale.x = resizeRatio;
        app.stage.scale.y = resizeRatio;
    }
    app.renderer.resize(x, y);//レンダラーをリサイズ
}
window.addEventListener("load", screenResize);//ロード時に画面サイズを変える
window.addEventListener('resize',screenResize,false);//ウィンドウの大きさが変わったらその都度画面サイズを変える
```

これでどんな端末でもイイカンジに画面表示ができる。やったね！！！
素敵なデータ構造：Union-Find木 by Python

#データ構造の説明
Union-Find木とは、
・根付き木の構造を用いて
・グループ分けを効率的に管理するデータ構造
なようです。
<br>

```Python:UnionFind.py
class UnionFind():
    par = []
    siz = []
    
    def __init__(self, x):
        self.par = [-1 for n in range(x)]
        self.siz = [1 for n in range(x)]
    
    def root(self, x):
        if self.par[x] == -1:
            return x
        else:
            self.par[x] = self.root(self.par[x])
            return self.par[x]
    
    def issame(self, x, y):
        if self.root(x) == self.root(y):
            return True
        else:
            return False
    
    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return False
        if self.siz[x] < self.siz[y]:
            x, y = y, x
        self.par[y] = x
        self.siz[x] += self.siz[y]
        return True
    
    def size(self, x):
        return self.siz[self.root(x)]
        
uf = UnionFind(7)
uf.unite(2, 3)
uf.issame(2, 3)

# 出力 True
```

#アルゴリズムへの適用
###連結成分個数カウント
```Python:CountConnectedComponent.py
# アルゴリズム定義
# Union-Find木を用いた連結成分個数カウント
def CountConnectedComponent(uf, N):
    res = 0
    for i in range(N):
        if uf.root(i) == i:
            res += 1

    print(res)

# 入力受取
# 頂点数、辺数
N, M = map(int, input().split())

# Union-Find木の生成
# Nで初期化
uf = UnionFind(N)

# グラフの生成
# 各辺の情報をUnion-Find木に追加
for i in range(M):
    a, b = map(int, input().split())
    uf.unite(a, b)

# アルゴリズム実行
# Union-Find木を用いた連結成分個数カウント
CountConnectedComponent(uf, N)

# 入力
# 13 14
# 0 1
# 0 2
# 0 3
# 1 4
# 2 4
# 3 5
# 2 6
# 6 7
# 5 8
# 7 8
# 10 11
# 11 12
# 4 5
# 1 6

# 出力
# 3
```


###クラスカル法
```Python:Kruskal.py
# アルゴリズム定義
# クラスカル法
def Kruskal(N, M):
    res = 0    
    uf = UnionFind(N)
    for i in range(M):
        w = edges[i][0]
        u = edges[i][1][0]
        v = edges[i][1][1]

        if uf.issame(u, v):
            continue

        res += w
        uf.unite(u, v)

    print(res)

# 入力受取
# 頂点数、辺数
N, M = map(int, input().split())

# グラフの生成
# 辺(u,v)と重みwの集合
edges = ["" for i in range(M)]
for i in range(M):
    u, v, w = map(int, input().split())
    edges[i] = [w, [u, v]]

# グラフの並び替え
# 重みの小さい順に並び替え
edges.sort()

# アルゴリズム実行
# クラスカル法
Kruskal(N, M)

# 入力
# 4 6
# 0 1 10
# 1 2 20
# 2 3 30
# 3 0 40
# 1 3 15
# 0 2 45

# 出力
# 45
```
Google データポータルで 2 つの値の比率を表示する

Google データポータルでファネル分析やコンバージョンレート等の可視化を行う際に、2 つの値の比率を計算して表示したいケースがあります。その際の操作がなかなか見つけられなかったので備忘録として記事にしておきます。

![Google データポータルで複数の値の比率を表示する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/8a6bfe9d-11cf-9e1d-5458-720669d6f59d.png)
やりたいこと

## 1. 比率を計算したい要素を複数選択
Command + Click または Shift + Click で要素を複数選択します。

![比率を計算したい要素を複数選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/475d7360-855e-7844-7a9f-c55745e3e8f4.png)

## 2. 右クリック〜データを統合

![右クリック〜データを統合](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/7b46bd9a-ab5e-4b3c-2b37-cdf663d3279a.png)


## 3. 比率が計算された要素が表示される

![比率が計算された要素が表示される](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/57e9af7e-462f-5c95-2153-c69d0418a987.png)

## 4. 数式の確認、修正
分子・分母が逆だったり、数式を確認・修正したい場合には以下の画像の `fx` から確認・修正できます。1 の操作で分子にしたい要素を先に選択すると分子と分母が逆に計算されないようです。

![数式の確認、修正1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/0e2a2913-054e-56ac-5b9a-d00be8ddce28.png)

![数式の確認、修正2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/bee5f4f6-8606-02e7-a937-90d1f1f27bbe.png)

以上。