OmniAICreator/Qiita-1.07M huggingface dataset:
AWSのSESを使ってCakePHP4からメールを送信するための設定方法

## 本文について
自分でやっているサイトにSESを導入して新規登録ユーザーにメールが届くシステムの導入をするため、行ったAWSのSESの設定方法を記載しておきます。（備忘録程度に）

CakePHP4での設定になりますが、ruby on rails側でもrailsガイドの<a href="https://railsguides.jp/action_mailer_basics.html#action-mailer%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B">ここら辺</a>を参考に設定をすればおそらくメールの設定ができるはずなので、ポートフォリオ作成の参考になるかと思います。

また、<a href="https://qiita.com/Nash-BETA/items/8ca99e35c6fadbc53049">さくらインターネットのサーバーでAWSのSESの設定方法</a>でAWSとドメインの設定方法を記載しておりますので、もし、AWSとドメインの設定が終わっていない場合は、、<a href="https://qiita.com/Nash-BETA/items/8ca99e35c6fadbc53049">前回の記事</a>を参照ください。

## AWSの設定

「Create My SMTP Credentials」をクリックして、メール送信するアカウントの作成
![スクリーンショット 2021-05-18 1.16.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454305/e2a25422-24d2-6760-ccbe-cdce171233bb.png)

IAM User Name:の中にわかりやすいユーザー名を記載し、右下の「作成」をクリック

![スクリーンショット 2021-05-18 1.17.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454305/2a03aede-4a56-99cf-f695-101fe03eef01.png)

作成が完了すると下記の画面になるので「認証情報のダウンロード」をクリック
![スクリーンショット 2021-05-18 1.19.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454305/f677eb31-8fcf-d325-e1a3-248ba0102133.png)

「SMTP ユーザー名」と「SMTP パスワード」が表示されるのでこれをメモすれば、AWSの設定は完了

## CakePHPでの設定

app.php(app_local.phpがあればapp_local.phpに記入)の`EmailTransport`と`Email`の設定を行う

`EmailTransport`には、登録したサーバー（AWSのSES）の設定を記入
`Email`には送信する内容のデフォルトの設定（送信するメールアドレスとか）

```Config/app.php

   'EmailTransport' => [
        'default' => [
            'className' => 'Smtp',
            'host' => 'email-smtp.ap-northeast-1.amazonaws.com',
            'port' => 587,  //25にする場合は別途設定が必要っぽい
            'timeout' => 10,
            'username' => 'awsで表示されたusername',
            'password' => 'awsで表示されたpassword',
            'client' => null,
            'tls' => true,
            'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
        ],

    ],

    'Email' => [
        'default' => [
            //EmailTransportのdefaultの読み込み
            'transport' => 'default',
            //ここに送信で使用するメールアドレスを記載する
            'from' => 'test@exsample.com',
            'charset' => 'utf-8',
            'headerCharset' => 'utf-8',
        ],
    ],
```

## メール送信テスト

テスト用にCommandに簡単なメール送信の記述

```Command/MailCommand.php
<?php
namespace App\Command;

use Cake\Console\Arguments;
use Cake\Console\Command;
use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOptionParser;
//メーラーを使うために記述をたす
use Cake\Mailer\Mailer;

class MailCommand extends Command{

    public function initialize(): void{
        parent::initialize();
    }

    public function execute(Arguments $args, ConsoleIo $io){
        //Emailの設定を読み込ます
        $mailer = new Mailer('default');
        $mailer
            ->setTo('exsample@gmail.com') //送信先
            ->setSubject('About')         //タイトル
            ->deliver('メッセージテスト');     //本文かつ送信
    }
}
```

上記の設定後、下記のコマンドをターミナルで打てば`setTo`で記載されているメールアドレスにメールが飛ぶようになります。

```terminal
$ bin/cake mail
```
Google アナリティクス設定

これは下記の設定をしただけという内容で、情報量ほぼゼロなのですが、個人のメモです。m(__)m

https://qiita.com/Qiita/items/c7f704e3786df3aa7a11

# 設定方法

上記の通りに設定するだけ。

- Google アナリティクスのアカウントを用意
- プロパティの設定でhttp://qiita.com を設定。ユニバーサル アナリティクス プロパティの作成を有効にする。
- Google アカウントに割り当てている トラッキングIDをqiita に設定する

です。

少しはまったポイントをメモ。

1. Google アナリティクスのアカウントの作成は「設定から」

上記の解説で、いきなり「2. 新しいアカウントを作る」の方法がわからなくて、少しさまよいました。左側のバーの歯車記号の「設定」からたどり着けました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294040/c4e6ca5f-d84b-502d-a3c4-69bea414f498.png)


2. Qiita のアカウントがGoogle アカウントと連携していなければダメ。

よく考えれば当然ですが、Qiita側からGoogle アカウントに連携しなければダメでした。トラッキングIDを設定しているのに、アナリティクスのアクセスがゼロのままで？？？と思って試行錯誤しました。Qiita側でGoogleアカウントを連携したら、「リアルタイム」--> [トラフィック」で無事にアクセスが見えました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294040/38067757-490e-04e8-3de5-50990bc91fca.png)


# まとめ

とりあえずGoogleアナリティクスが使えるようになったらしい。スマホでも見えるらしい。
何に使えるかわからないが、、、とりあえずTODOは

- スマホでアナリティクスを見る

かな。^^;)

(2021/05/18, 2:03)
駆け出しpythonエンジニアのまとめ デザインパターンまとめ6(adapter)

# 趣旨
駆け出しエンジニアの備忘録の垂れ流し。
　※ 出典漏れがあればご指摘ください

> 出典: 
https://yamakatsusan.web.fc2.com/
https://dackdive.hateblo.jp/
https://www.oreilly.co.jp/books/9784873117393/

# adapterパターン概要
オブジェクトの構成に関するデザインパターンの１つ。
既存クラスのインターフェイスにラッパーを実装し、別のクラスと互換性をもたせる。
主な実装方法として、継承を利用する方法と移譲を利用する方法がある。
>Adapter パターンの目的は，“既存の”オブジェクトのインタフェースを変換することである。

## クラス図とシーケンス図
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3130333539352f37653635343537612d626236622d376366662d353236352d3965626663346434653230652e6a706567.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382557/44b619cf-d923-120d-9fa2-f7ff693f34b4.jpeg)


[wikipedia][wikipedia]より引用

## 実装方針
### 継承を利用する場合
- 利用したいクラス(Adaptee)を継承したAdapterクラスを作る。
- Adapterクラスにはclient向けのIFを実装し、メソッド内で、スーパクラスのIFを利用する処理を書く。

```python:実装例1

class Adaptee:
   def specific_operation(some_args):
      hogehoge()

class Adapter(Adaptee):
   
   @classmethod
   def create(cls: Adapter):
        return cls()

   def wrapper_operation(self):
       some_args = make_args()
       self.specfic_operation(some_args)

# client側
def main():
    adpt = Adapter.cerate()
    adpt.wrapper_operation()
```
### 移譲を利用する場合

```python:実装例2

class Adaptee:
   def specific_operation(some_args):
      hogehoge()

class Adapter:
   def __init__(self, adaptee_cls: Adaptee):
      self._adaptee = adaptee_csl

　　@classmethod
   def create(cls):
      return cls(Adaptee())

   def wrapper_operation(self):
       some_args = make_args()
       self._adaptee.specfic_operation(some_args)

# client側
def main():
    adpt = Adapter.cerate()
    adpt.wrapper_operation()

```
## 使い所
- 使い所
 - 既存のクラスのインタフェースが、必要なインタフェースと一致していないケース
 

[wikipedia]:https://ja.wikipedia.org/wiki/Adapter_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
[UniRx] ストリームのMerge

ObservableのMergeオペレータがかなり便利だと思ったので突発的に記事を書いてみました。

## とりあえずサンプルコード
YesかNoのどちらかを選択するダイアログをイメージしてください。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UniRx;
using System;
using UniRx.Operators;

/// <summary>
/// ストリームのマージサンプル
/// </summary>
public class MergeStreamSample : MonoBehaviour
{
    /// <summary>
    /// Yesボタン
    /// </summary>
    [SerializeField]
    private Button YesButton = null;

    /// <summary>
    /// Noボタン
    /// </summary>
    [SerializeField]
    private Button NoButton = null;

    /// <summary>
    /// Yesボタンが押された
    /// </summary>
    private IObservable<Unit> OnSelectedYes { get { return YesButton.OnClickAsObservable(); } }

    /// <summary>
    /// Noボタンが押された
    /// </summary>
    private IObservable<Unit> OnSelectedNo { get { return NoButton.OnClickAsObservable(); } }

    /// <summary>
    /// 何かが選択された
    /// </summary>
    private IObservable<bool> OnSelectedAny
    {
        get
        {
            return OnSelectedYes
                .Select((_) => true)
                .Merge(
                    OnSelectedNo
                        .Select((_) => false)
                );
        }
    }

    void Awake()
    {
        // 特に加工されていないストリームのSubscribe
        OnSelectedYes.Subscribe((_) => Debug.Log("YES")).AddTo(gameObject);
        OnSelectedNo.Subscribe((_) => Debug.Log("NO")).AddTo(gameObject);

        // MergeされたストリームのSubscribe
        OnSelectedAny
            .Where((b) => b)
            .Subscribe((_) => Debug.Log("Merge YES"))
            .AddTo(gameObject);

        OnSelectedAny
            .Where((b) => !b)
            .Subscribe((_) => Debug.Log("Merge NO"))
            .AddTo(gameObject);

        OnSelectedAny
            .Subscribe((b) => Debug.Log("b:" + b))
            .AddTo(gameObject);
    }
}
```

## OnSelectedAnyプロパティが行っている事
1. OnSelectedYesの型をUnitからboolに変換してtrueを流す
1. OnSelectedNoの型をUnitからboolに変換してfalseを流す
1. 上記で作ったストリームを合成し、Yesボタンが押されたらtrueが、Noボタンが押されたらfalseが流れてくるストリームの完成

## 所感
「どちらが選択されても共通の処理を行う」という場合に便利だと思います。
``` Subject<bool> ```を定義してボタンイベントで発火させるという手段でも同じ結果が得られると思いますが、こちらの方がシンプルなコードになる気がします。
【Ruby on Rails】bootstrap導入時のExecJS::ProgramError

## エラー概要
bootstrap4のgemをインストールし、rails sでサーバーを立ち上げてページを表示しようとしたところ、ExecJS::ProgramError , TypeError: cannot read property 'version' of undefined　と表示されてしまいました。(2021/5/15)

以前の開発では問題なく導入できていましたが、今回突然できなくなったため、その原因を探してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918398/fb438ee0-6789-0d53-15a9-fd6a75c4d0e9.png)

## 動作環境
- rails 5.2.6
- ruby 2.6.3
- linux

## エラーの原因
2021/5/14にリリースされたexecjs2.8.1が依存関係にあるautoprefixer-railsに対応していないことが可能性として高いです。

<details>
<summary>さらに詳しく</summary>
<div>

#### 新規アプリ作成
新規アプリを作成すると、同時に80個程度最低限必要なgemがインストールされます。その一つにexecjsというgemがあり、最新版のものがインストールされます。

```terminal:ターミナル
[~/] rails new sample_app
:
Fetching execjs 2.8.1
Installing execjs 2.8.1
:
```
- execjs 2.8.1 (最新 2021/5/14リリース)
    - ver.2.8.0 (2021/5/10 リリース)

#### bootstrapの導入
gemfileに追記をし、インストールを行います。bootstrapはいくつかのgemと依存関係があり、そのうちの一つにautoprefixer-railsというgemと依存関係があります。bootstrapのインストール時に一緒にインストールされます。

```ruby:Gemfile
:
gem 'bootstrap', '~> 4.5'
gem 'jquery-rails'
```

```terminal:ターミナル
[~/sample_app] bundle install
:
Fetching autoprefixer-rails 10.2.4.0
Installing autoprefixer-rails 10.2.4.0
:
Fetching bootstrap 4.6.0
Installing bootstrap 4.6.0
:
```

#### autoprefixer-rails
bootstrapのインストール時に最新のバージョンがインストールされますが、このautoprefixer-railsはexecjsと依存関係を持っています。実際にgemの依存関係を確認すると、最新の状態であってもexecjs 2.8以上に対応していないことが分かります。ここがエラーの原因である可能性が高いです。

- autoprefixer-rails 10.2.5 (最新 2021/5/11 リリース)
    - 依存性：　execjs < 2.8 (バージョンが2.8未満で最新のもの) 
 
- autoprefixer-rails10.2.4 (2021/2/11 リリース) 
    - 依存性：　execjs > 0 (バージョンが0以上で最新のもの)  

いずれのautoprefixer-railsのバージョンであっても、エラーは発生してしまいますが、現状としてすでにexecjs 2.8.1がインストールされてしまっているため、ver. 10.2.5をインストールすることができず、ver. 10.2.4をインストールしている形になります。
</div>
</details>

## エラーの解消方法

```terminal:ターミナル
[~/sample_app] bundle update autoprefixer-rails
:
Fetching execjs 2.7.0 (was 2.8.1)
Installing execjs 2.7.0 (was 2.8.1)
Fetching autoprefixer-rails 10.2.5.0 (was 10.2.4.0)
Installing autoprefixer-rails 10.2.5.0 (was 10.2.4.0)
:
```

autoprefixer-rails 10.2.5に更新することで、新たにexecjs 2.7がインストールされ、無事エラーを解消することができました。


## 参考資料
- execjs
    - [rubygems](https://rubygems.org/gems/execjs)
    - [github](https://github.com/rails/execjs) 
- autoprefixer-rails
    - [rubygems](https://rubygems.org/gems/autoprefixer-rails)
    - [github](https://github.com/ai/autoprefixer-rails) 
- bootstrap
    - [rubygems](https://rubygems.org/gems/bootstrap/versions/4.6.0)
    - [github](https://github.com/twbs/bootstrap-rubygem/tree/4.6-stable)
【Vuetify】ハンバーガーアイコンが表示されなかった時のチョンボ事件

##概要
ポートフォリオを作成していて、レスポンシブ対応やらデザイン調整やらがお手頃に導入できると聞いてVuetifyを導入した。

・・・が、ヘッダー部分をスマホサイズで表示させた時に現れるいわゆるハンバーガーアイコンが表示されなくなった。

↓これ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112640/b1cf8ffb-ced6-722f-9b3a-583db56937a9.png" width="30">
その事象に出会した際の確認ポイントを挙げる。

##1. mdiのダウンロードは済んでいるか
Vuetifyのダウンロードだけでは![アイコンフォント](https://vuetifyjs.com/ja/features/icon-fonts/)を利用できない。
Material Disign Icons（通称mdi）をインストールする必要がある。

```bash:terminal
npm install @mdi/font
```

また、Vuetify関連のファイルにいくつかアイコンフォントを利用できるよう施す。

```js:Vuetify.js
import '@mdi/font/css/materialdesignicons.css'

// 既存のコンストラクタに下記のように追加
export default new Vuetify({
    icons: {
      iconfont: 'mdi', // 追加
    },
  })
```

##2.コンポーネントの一番大枠部分が\<v-app>で括られているか
私はこれだった。
Vuetifyを使用する場合、各コンポーネントは\<template>の次に\<v-app>で定義しておくほうがよい。

(参考：[Vuetify公式 "Application"](https://vuetifyjs.com/ja/components/application/#section-30c730d530a930eb30c8306e30a230d730ea30b130fc30b730e730f330de30fc30af30a230c330d7))

まだまだ勉強不足で、なぜ\<v-app>がないとレンダリングされないのかは理解できていない。

```vuejs:一番大枠のコンポーネント.vue
<template>
   <v-app>
     <!-- Any Code -->
   </v-app>
</template>
```
Githubのプルリク時にeslintをチェック(reviewdog)




[reviewdog/action-eslint: Run eslint with reviewdog](https://github.com/reviewdog/action-eslint)


![Kobito.8REo05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/b17e742a-cff7-ab27-e742-edde8f33f9b9.png "Kobito.8REo05.png")




## 導入

`.github/workflows/reviewdog.yml` を追加し、以下をコピペする

```:.github/workflows/reviewdog.yml
name: reviewdog
on: [pull_request]
jobs:
  eslint:
    name: runner / eslint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: reviewdog/action-eslint@v1
        with:
          reporter: github-pr-review # Change reporter.
          eslint_flags: 'src/**/*.{ts,tsx,js,jsx}'
```


## 手順

1. eslintに引っかかりそうなコードをコミットする。例）console.log()など
2. プルリクを作る
3. Actionsが動くのを確認する



しばらく待つとプルリクのコメント欄に自動で指摘が入る。
![Kobito.8REo05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/b17e742a-cff7-ab27-e742-edde8f33f9b9.png "Kobito.8REo05.png")





### eslintに引っかかった場合に、エラーとして通知したい

上記のままであれば、指摘は入るが`All checks have passed`となっていてレビュアーは失敗に気づかないこともあるかもしれない。
eslintチェックに引っかかった場合にはエラーとしたい

`fail_on_error: 'true'`を追加します。


```:.github/workflows/reviewdog.yml
name: reviewdog
on: [pull_request]
jobs:
  eslint:
    name: runner / eslint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: reviewdog/action-eslint@v1
        with:
          reporter: github-pr-review # Change reporter.
          eslint_flags: 'src/**/*.{ts,tsx,js,jsx}'
          fail_on_error: 'true'　←　追加
```


これで、次のコミット時でActionが走り、`All checks have failed`になりました。


![スクリーンショット 2021-05-18 1.19.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/fc587f42-0f21-3b48-eb16-777d89e47a94.png "スクリーンショット 2021-05-18 1.19.51.png")
SQL呼び出しに伴う脆弱性

## 対策

### プレースホルダによるSQL文組み立てする
```
SELECT * FROM user where id = ?
```

値は、バインド(bind)する

### PDOの安全な利用法
PDO(PHP Data Objects)のオプション指定

- 例外処理を使用する
    - PDO::ATTR_ERRMODE = PDO::ERRMODE_EXCEPTION
- 複文の実行禁止
    - PDO::MYSQL_ATTR_MULTI_STATEMENTS = false
    - 複数のSQLを;で区切って実行することを禁止する
- 静的プレースホルダの指定
    - PDO::ATTR_EMULATE_PREPARES = false
    - 動的プレースホルダ：アプリケーション側のライブラリでパラメータをバインドしてからデータベースエンジンに送る（処理系にバグがなければSQLインジェクションは発生しない）
   

### 保険的対策

- 詳細なエラーメッセージの抑止
phpの場合、displau_errors = Off
- 入力値の妥当性検証
- データベースの権限設定
    - 表示のみの場合は、書き込み権限をつけない
    - ファイル読み込み権限
【自業自得】愚かな文系猪が起業したらプログラミング何もわからなくて泣いちゃった【単価2円】

■拝啓
Qiitaのつよつよエンジニアの皆様

国立大学法学部で凶悪犯罪者の判例を日々読んでは、ぼっち!!っであったがゆえに実家と大学を往復し、せっかく悪くない企業に入ったのに、何を思ったか起業への道を踏み出し、現在は日々圧倒的成長に明け暮れています。

名をうりぼーと申します。文系は潰しがきくから....という高校教師の甘い言葉に誘われて、おろかにも文系の道を歩んでしまい、Productを作れぬ悔しさ、臆病な自尊心、尊大な羞恥心からか、目が覚めると、体が「猪」になっていたのです。

今回は「己の恥部を晒したい」という下卑た欲望の下で、うだつの上がらない駄文をカタカタと書いております。下記をご覧ください。

■できること/やったこと
・WordPressでの法人向けWebサイト制作受託
　(継続的に問い合わせがくる仕掛けをしたり、やや高度なSEO対策を施しており、クライアントの企業様からもおおむね好評です。)
・適切にディレクションして小さなシステムぐらいなら作れる
・エックスサーバーの機能の大半がわかって弄れる(笑)
・問題が発生しても、解決できるまでググって記事を読んで、なんとかできる
・少し収益が出ていたアフィサイトをベンチャー企業に売却したことがある
・FTPソフトが使える(失笑)

■ITを触り始めたきっかけ
・Stalkerというロシアのゲームにドはまりするが、日本語化が不十分で、これを解決するためのパッチを探したり、改善したりする中で、なんとなく興味を持つ。
・それ以降は、特にプログラミングを勉強することはなく、Webに興味を持って、サイトを作ったり、自分用の便利なツールを作ったりする。

■できないこと
・全くコードが書けない、コードを学ぼうとしても、途中でやめてしまう。全体を理解するより先に自分にとって必要な知識だけ知りたくなって萎えてしまう。無駄なことが本当に死ぬほど嫌いなので、古くなりそうな知識や支配力の弱い言語を学びたくないが、じゃあ何から勉強したらいいか分からず、手が止まる。

■現状
MacbookProを買うか迷い中・・・

■まとめ
今の私では単価は2円がいいところでしょう。
TwitterのTLのつよつよエンジニアが憎い....憎いよおおおお
みんな知らない英語で話し合っててズルい！！！

Macを買ったら不思議な力が働いて
朝起きたらエンジニアになれたりしませんか😭

実際のところ、いったい皆さんは何を基準に学習する言語を決めておられるのでしょうか。いま主力で開発しているプロダクトは技術的には新しいものは使っておらず(これは継続的安定的に顧客に供給するためです)、かといって、ずっとそのままだと技術的競争力が失われる確信があります。個人的には一生0⇒1をやりたい(つまりサービスを作っては売却して作っては売却して...といった感じです)ので、即サービスや即プロダクトを作って即テストできるような言語があったら勉強してみたいです。プログラミング界隈もポジショントークが増えすぎて何が何やら.....。●●はモダンだとか●●はオワコンだとか.....。もうわかりません！うわあああ！
Duplicate keys detected: '0'. This may cause an update error.

## フォーム要素を表示すると

下記のように、v-forで複数要素を表示しようとした。

``` .vue
<el-form>
  <!-- 要素 ① -->
  <div v-for="(item, index) in data1" :key="index">
      <el-form-item>
        <!-- 略 -->
      </el-form-item>
    </ui-allowed-domain>
  </div>
  <!-- 要素 ② -->
  <div v-for="(item, index) in data2" :key="index">
      <el-form-item>
        <!-- 略 -->
      </el-form-item>
    </ui-allowed-domain>
  </div>
</el-form>
```

要素②を追加したところ・・
![d4d83dd6a608afe75186e8bcbdb7e95c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681029/2250b703-820e-6a6b-e2a2-5aeef7b223e6.png)

このようなエラーが発生。

## 親要素を変えるか、keyにプレフィックスを与える

原因を調べてみると、どうやら同一の親要素の直下にある要素同士がkeyにindexを使った場合、「キーが重複している」とエラーを出すようになっているらしい。

解決方法は、div要素などで囲ってあげることで親要素を変える。
または下記のようにプレフィックスをindexにつけることで、indexをユニークにする。

```
要素①
:key="`form-1-${index}`"

要素②
:key="`form-2-${index}`"
```
GDevelop v5.0.0-beta110 がリリースされました。

問題の発見された beta109 を飛ばして GDevelop v5.0.0-beta110 がリリースされました。
今回も色々追加されたので、個人的に気になった更新内容をピックアップしてご紹介します！

##✨ 新機能
###・ビットマップテキストオブジェクトの追加
新しく「ビットマップテキスト（Bitmap Text）」オブジェクトが、実験的なオブジェクトとして追加されました。

このオブジェクトを使用することで [BMFont](https://www.angelcode.com/products/bmfont/) や [bmGlyph](https://www.bmglyph.com/) などのソフトウェアで生成された、ビットマップフォントを表示できるようになります。
![2021-05-17 213815.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224830/2f5024d0-ae97-8dd2-f522-e26d064c3e89.png)
ビットマップフォントは、デザインされた文字を予め画像として保存したものを利用するので、これまでは表現できなかった文字の装飾などが可能になります。

また、従来のテキストオブジェクトより描画にかかる負荷が軽く、頻繁に更新されるテキスト（例えばスコアなど）での利用に向いています。

対して画像なので、拡大すると画質は下がってしまう点と、用意していない文字は表示できない点に注意が必要です。

##・オブジェクトの中心が利用しやすくなりました
オブジェクトの中心を取得したり、中心を利用して位置を指定するための、アクション、条件、および式が追加されました。

今までもスプライトオブジェクトは Point("Center") で Center 位置は取得できましたが、それ以外のオブジェクトの中心位置も簡単に取得できるようなりました。

また、中心位置を基準にした位置指定も可能になりました。

##💝 改善点
###・衝突マスクエディタとポイントエディタを刷新
編集画面が大きく表示されるようになり、かなり使いやすくなりました！
![2021-05-17 220410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224830/f676cbda-cdee-b6cc-3855-9c60c9d51d30.png)
プレビューと設定欄の分割はドラッグすることができます。

ポイントにカーソルを合わせると、ツールチップにポイント名が表示されます。

ポイントや衝突マスクの頂点を画像より外側にドラッグしても、カーソルに追従し続けるようになりました。（衝突マスクは画像より外側には設定できません）

衝突マスクの設定欄を折りたためるようになりました。
スプライトの衝突マスクがたくさんある場合に便利です。

エディターの市松模様の背景も、選択したテーマに合わせて異なる色を使用するようになりました。

###・ビヘイビアの設定が折りたためるようになりました
もぉビヘイビアをたくさん追加しても、ゴチャゴチャしません。
![2021-05-17 222133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224830/756942fa-2a71-6ae7-fd76-f18a38bcd8ee.png)
###・オブジェクトの衝突マスクとポイントを表示するアクションを追加
デバッガーツールに「衝突ヒットボックスとポイントを描画する（Draw collisions hitboxes and points）」というアクションが追加されました。
![2021-05-17 223610.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224830/0e90d115-3969-a754-849b-e87589436c8f.png)
ハイ便利～👍

###・P2P でクライアント ID を任意の値に設定できるようになりました
へ、へぇ……😅（P2P 使ったことないけどきっと便利っぽいｗ）
###・Firebase の Firestore にネットワークと永続性の構成を追加しました
ほほう……😅（オフラインでも DB のキャッシュへアクセスが可能になるとかなんとか……なんか便利そうｗ）

###・XFromAngleAndDistance() と YFromAngleAndDistance() を追加
角度と距離を指定すると、X 軸または Y 軸の座標を返してくれる、便利な式が追加されました！

単独で「XFromAngleAndDistance(45, 100)」と使ったり、「Object.XFromAngleAndDistance(45, 100)」としてオブジェクトの中心からの座標を取得することができます。

###・エディターの UI を改善
ダイアログの外側をクリックすると問答無用でキャンセル扱いになってしまう動作が改善されました。（設定で変更できます）

他にも、色々と分かりやすくしたようです（雑）

##🐛 バグの修正
###・スプライトの更新が 1 フレーム遅れる問題を修正
イベントでスプライトを生成した瞬間や、シーンが変更されたときなどの「ちらつき」が修正されます。
また、イベントでオブジェクトを生成した瞬間に、適切なサイズ、位置、角度になっていない問題も修正されました。

###・Web ページに埋め込まれたゲームでキーボードが使用されたときのページスクロールを修正
これは嬉しい！
追加の Javascript でインターセプトする必要はなくなりました！

##🤓 まとめ
描画負荷の低いビットマップテキストの追加は嬉しいですね。
ただ、ビットマップフォント自体が古典的な手法なので、生成できるソフトもあまり新しいものは無いのが辛いところ😓
もし良いソフトが見つかったら紹介しますね。

他には、衝突マスクエディタとポイントエディタの刷新が、個人的にはかなり嬉しいです👍
正直、以前のは使いにくかった！
気になっていた点はほぼクリアーされているので、衝突マスクが多いスプライトの設定もストレス無くおこなえそうです😊

以上！
ここで紹介した点以外にも、色々と改善されているので、詳しくは GitHub の [GDevelop Releases](https://github.com/4ian/GDevelop/releases) ページをチェック！
データベース検索data取得

このようなテーブルがあるとします。

|id|name|email|create_at|update_at|password|
|-|-|-|-|-|-|
|10|kasandra|hiphop@glove.com|2021-05-17 23:00|2021-05-18 23:18|hjkl|
|11|Andrew|terrace@earth.com|2021-05-17 23:11|2021-05-18 23:20|uioo|
|12|James|beach@boat.com|2021-23:17|2021 05-18-23:23|wery|



①find:idを検索キーとしてデータを取得するメソッド(複数取得可能)
-
**id以外のキーでは検索できないので注意**。具体的な使い方は上記ユーザーテーブルのidが11の人のオブジェクトを取得したい時です。

```rb:
@user = User.find(11)Copy
```
これで@userインスタンスにidが11の人のデータが取得されました。引数に(10, 11)としてあげれば配列として、両方のオブジェクトを取得できます。

②find_by:任意の条件（すきなカラム）で値を1件だけ取得するメソッド
-

```rb
@user = User.find_by(email: "example-9@rails...")Copy
```

id、10のレコードが取得できますね。なお、このメソッドは上からみていって最初にマッチした条件（１件）を取得します。

③where:条件を絞り込むメソッド（複数取得する）
-

whereメソッドは該当するデータを複数取得します。

```rb
@users = User.where(created_at:  "2021-05-17..")Copy
```

@usersでは上記の３つのデータがみられるようになりました。

ここで、「みられるようになった」という表現をしたのですが、それには理由があり、whereメソッドは値と取得している訳ではなく（オブジェクトとして変数に格納されているわけではなく）ただ、指定した条件で、範囲を絞っただけなので、whereに対して特定のカラムのデータなどを取得することはできません。

なおwhereは検索キーはid以外になっています。

④order

カラムの順番を変更するメソッド
これは簡単ですね。例えば、上の三つの順序を逆にしたものを表示したいとすると

@users =　User.order("id DESC")Copy
idを降順に並び替えると行った感じのことができてます。

⑤distinct:重複しているデータを一つにまとめるメソッド
-
簡単に言うと同じカラム内に全く同じデータが存在していた場合に、重複しているデータをまとめてくれるメソッド。例えば上のデータの例だと、created_atが全部同じ値。

```rb:
@user = User.select("created_at").distinctCopy
```

selectは、単にどのカラムか指定してるだけです。このように使うと、@userには2018-12-4 08がのみのデータが格納されます。

⑥limit:取得するデータの数を制限するメソッド
-

```rb:
@user = User.limit(2)Copy
```

単純に上から2件データを持ってきてるだけ

⑦group:カラムの値をグループ化するメソッド
-

⑧で具体例をあげます。

⑧average、sum、minimum、maximum:演算メソッド（平均、加、最小、最大）
-

groupと⑧のメソッドはまとめて説明した方が早いのでまとめます。上記のテーブルだけだと説明しにくいので、新しいテーブルで考えます。

例えば、ある2人の生徒のテストの点数が保存されているテーブルがあるとします。

|name|subject|score|
|-|-|-|
|hoge|math|40|
|hoge|english|50|
|foobar|math|90|
|foobar|english|10|

このような場合、hogeとfoobarの二人の2科目の合計を知りたい時、これらのメソッドを組み合わせてこのようにデータを取得することができます。

```rb
@users = User.group(:name).sum(:score)Copy
```

nameでグループ化して、scoreを足しています。
なので、@userには{“hoge” => 90, “foobar” => 100}
このようなハッシュで値を取得できています。

⑨having:データベースから取得したデータを元に絞り込む
-

再び先ほどの教科のテーブルを例で使うと、

```rb
@user = User.group(:name).having(['SUM(score) >= ?',  50"])Copy
```

これは先ほどのハッシュの値を元に、さらに検索条件を絞っています。足した値が50以上のデータなので{hoge、50}が取得されます。

参考:マクロロ（macroro）さん
>https://macroro.com/rails-date-get/
【Swift】Jsonどうやって取り込むん？

<h1>デコーダブル作ったけどあとわからん。。</h1>
な人たち向けに、その後どうするのかを書いておきます。(備忘録)

<h3>政府が出してるコロナjsonを崩したものを使って説明します。</h3>

https://opendata.corona.go.jp/api/OccurrenceStatusOverseas?dataName=%E6%97%A5%E6%9C%AC

```swift:***.swift
//これは説明せんでええ,,,？
struct CovidJson: Decodable {
     let errorInfo : Errorinfo
     let itemList : [Itemlist]
}

struct Errorinfo:Decodable {
     let errorFlag : String
     let errorCode:String?
     let errorMessage:String?
}

struct Itemlist:Decodable {
     let date: String
     let dataName: String
     let infectedNum: String
     let deceasedNum: String
}
```

```swift:***.swift
// 入れ物
var covid = [CovidJson]()
//Jsonを持ってくるサイト
var jsonUrlString = "https://opendata.corona.go.jp/api/OccurrenceStatusOverseas?dataName=%E6%97%A5%E6%9C%AC"
//URLに変換
guard let url = URL(string: jsonUrlString) else {return}

//セッション開始
URLSession.shared.dataTask(with: url) { (data, response, error) in
     //データなかったときはreturn
     guard let data = data else {return}
     do{
          //デコードしますよ。(struct,from data)
          covid = try JSONDecoder().decode(CovidJson.self, from: data)
     } catch let jsonError{
          print("error", jsonError)
     }

}.resume()

// 上記は非同期処理なので無理やり同期させてね↓参考
// https://sussan-po.com/2020/03/01/swift-async-as-sync/

// covidにデータが入ってる
print(covid.itemlist[0].dataName)
```


こんだけでとれるの？って思うかもしれないけど、これだけで取れます。
ちょっと編集したけどこれだけで求めてるものは取れる。

## 最後に
iOSアプリ開発をしています。
主にSwiftですが、最近は熱が入ってきてFlutterも🦾
色々やってます。もし良かったら見てってください。

https://sogablog.net/
Apple M1環境のrosettaなしでpandas,numpy,Scikit-learn, matplotlibの使用。


最近Apple M1環境でデーター分析を習おうと思ってpython3.9をインストールして以下のライブラリを設置しましたがうまくいきませんでした。

* pandas
* numpy
* Scikit-learn
* matplotlib

グーグル神様に聞いてもらいましたが何個の方法が相次いだのでここに整理しておきます。

#### 1. Rosetta環境でpythonを実行する方法

Apple M1のarm64の確認方法は以下のようです。

```
>uname -m
arm64
```

これを`arch`コマンドを用いてx86で変更します。

```
>arch -x86_64 zsh
>uname -m
x86_64
```

こうすれば以前のApple intelヴァージョンのように`pip install`を使えます。

でもここには何個の短所があるので…

* Rosettaの性能的な限界
* 実行するたびにarchで変更する不便さ

なのでライブラリーごと各個撃破を決定ました。

#### 2. ライブラリーごとの各個撃破

まず`brew install`でインストールできるのは以下のようです。

* numpy
* scipy

pandasとscikit-learnはBigSurのblasライブラリーが合わないから発生する問題です。

これはbrewでopenblasをインストールしこれを用いながらpandasとscikit-learnを設置します。

```
>brew install openblas

>OPENBLAS="$(brew --prefix openblas)" pip3 install pandas
>OPENBLAS="$(brew --prefix openblas)" pip3 install sklearn
```

ちょっと時間がかかるけど結局インストールができます。

matplotlibもpipではインストールができないんです。これはBigSurでlibjpegライブラリーがないからです。これは以下のコマンドラインで解決。

```
>brew install libjpeg

>pip3 install matplotlib
```



これでpandasからmatplotlibまでrosetta依存なしでインストール完了です。
OpenProcessingでml5.js の学習モデルをロードする時の注意

下記の動画では、p5.js の ml5ライブラリ の feature extractor を使って、学習したモデルデータをセーブ、ロードする方法を紹介しています。

<iframe width="560" height="315" src="https://www.youtube.com/embed/eU7gIy3xV30?start=517" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

OpenProcessing で同じコードを実行すると、以下のエラーが出ます。
`byte length of Float32Array should be a multiple of 4`

ロードするファイルのパスに./をつけると解決しました。
`classifier.load('./model.json', customModelReady);`
ベクトルを十字方向に固定する

マウスによるドラッグ等で決まった方向に移動させたいとき、移動方向を上下左右前後にのみにさせるためのスクリプトです。

~~（内積の絶対値のもっとも大きい方向＝その方向にもっとも向いている）~~
（内積のもっとも大きい方向＝その方向にもっとも向いている）

ことを利用し、斜め入力を無視します

・別なスクリプトと混在してて絶対値を求めるようになってました。
絶対値は必要ありません（修正済み）

```C#
    public static Vector3 DirectionToFix(Vector3 Direction, bool is2D = true)
    {
        Vector3 v = Direction;
        if (is2D)
        {
            v = Vector3.ProjectOnPlane(v, Vector3.back);
        }
        float dotUp =　Vector3.Dot(v, Vector3.up);
        float dotRight = Vector3.Dot(v, Vector3.right);
        float dotDown = Vector3.Dot(v, Vector3.down);
        float dotLeft = Vector3.Dot(v, Vector3.left);
        float dotForword = Vector3.Dot(v, Vector3.forward);
        float dotBack =　Vector3.Dot(v, Vector3.back);

        float maxDot = dotUp;
        Vector3 result = Vector3.up;

        if (dotRight > maxDot)
        {
            maxDot = dotRight;
            result = Vector3.right;
        }
        if (dotDown > maxDot)
        {
            maxDot = dotDown;
            result = Vector3.down;
        }
        if (dotLeft > maxDot)
        {
            maxDot = dotLeft;
            result = Vector3.left;
        }
        if (dotForword > maxDot)
        {
            maxDot = dotForword;
            result = Vector3.forward;
        }
        if (dotBack > maxDot)
        {
            result = Vector3.back;
        }
        return result;
    }

```
RubyonJets×DynamoDBでstaging環境なのにテーブル名にstagというprefixが付かない

## 現象

`JETS_ENV=staging`の環境でmigrateを実行したところテーブル名が`<project_name>-stag-<table_name>`になるはずが、
prefixを付けずにテーブルを作成しようとしていた。
既にあるテーブルだったので作成できなかった。

```bash
$ jets dynamodb:migrate dynamodb/migrate/20210307142215-create_users_migration.rb
=>
Running database migrations
Calling create_table with params:
{:table_name=>"users", # ここがproject-stag-usersになっていない
 :key_schema=>
  [{:attribute_name=>"id", :key_type=>"HASH"},
   {:attribute_name=>"created_at", :key_type=>"RANGE"}],
 :attribute_definitions=>
  [{:attribute_name=>"id", :attribute_type=>"S"},
   {:attribute_name=>"created_at", :attribute_type=>"S"}],
 :billing_mode=>"PROVISIONED",
 :provisioned_throughput=>{:read_capacity_units=>5, :write_capacity_units=>5}}
Unable to create table: Table already exists: users
```

## 環境
dynamiteはRubyonJetsでDynamoDBを操作するためのgemです。

- Ruby: 2.7.2
- RubyonJets: 3.0.3
- dynomite: 1.2.6

## 対応

`config/dynamodb.yml`にstagingを追加してあげる

```yaml
development:
  table_namespace: <%= Jets.config.table_namespace %>
  endpoint: http://localhost:8000

test:
  endpoint: http://localhost:8000
  table_namespace: <%= Jets.config.table_namespace %>

# ここに追加
staging:
  table_namespace: <%= Jets.config.table_namespace %>

production:
  table_namespace: <%= Jets.config.table_namespace %>
```

## 実行結果

prefixが付いて`<project_name>-stag-<table_name>`のようなテーブル名を作成することができました。

```bash
$ jets dynamodb:migrate dynamodb/migrate/20210307142215-create_users_migration.rb
=>
Running database migrations
Calling create_table with params:
{:table_name=>"project-stag-users",
 :key_schema=>
  [{:attribute_name=>"id", :key_type=>"HASH"},
   {:attribute_name=>"created_at", :key_type=>"RANGE"}],
 :attribute_definitions=>
  [{:attribute_name=>"id", :attribute_type=>"S"},
   {:attribute_name=>"created_at", :attribute_type=>"S"}],
 :billing_mode=>"PROVISIONED",
 :provisioned_throughput=>{:read_capacity_units=>5, :write_capacity_units=>5}}
DynamoDB Table: users Status: CREATING
```
BLEUスコアのスコア算出方法



BLEUスコアのスコアの算出方法はズバリ以下のとおりです
$BLEU=BP \cdot exp(\Sigma_{n=1}^{N}w_nlogp_n)$
でスコアを算出します。

簡単に説明するとモデルの出力の1-gram, 2-gram, 3-gram, 4-gramが正解質問(Reference)がどの程度含まれているかを表す指標です

用語の説明をしていきます
## p_nとは
$p_n$ はprecisionスコアと呼ばれるもので以下の式で計算される
$p_n= \frac{\Sigma_{C\in \{Candidates\}} \Sigma_{n-gram \in C} Count_{clip}(n-gram)}{\Sigma_{C'\in \{Candidates\}} \Sigma_{n-gram' \in C'} Count(n-gram')}$
で定義される

ここで、$Count_{clip}(n-gram)=min(Count(n-gram), MaxRefCount(n-gram))$
と定義される

$Count(1-gram)$は、Candidateに含まれるn-gramの数を表す
$MaxRefCount(n-gram)$は、candidateに含まれるn-gramがReference文中に観測される回数を表す

例えばCandidateに「the cat sat at chair」、Referenceに「the cat sat on the table」だったら1-gramのときは $Count(1-gram)=5, MaxRefCount(1-gram)=3$となるので $Count_{clip}(n-gram)=3$となる。したがって、このような状況の場合precisionは　$p_n=\frac{3}{5}=0.6$となる。

簡単に言えば、precisionは、candidateに含まれるn-gramがreferenceに含まれる割合を表す
precisionが高い場合は、n-gram単位でreferenceと単語の一致度が高いということを意味する
一方precisionが低い場合は、n-gram単位でreferenceと単語の一致度が低いということを意味し、関係のない単語が出力されている可能性が高い。
## BPとは
BPとは下記の式で定義されます
$
\text{BP}
\begin{cases}
  1 & c > r \\\
  e^{1-r/c} & c \leqq  r
\end{cases}
$
$c:candidate$の長さ
$r:reference$の長さ

例えば、candidateが極端に短い場合$e^{1-r/c}$が0に近くなる。そのときBLEUスコアは低い値を出す。
逆に、candidateが十分に長い場合,c>rのときBPは1であり、その時のBLEUスコアは$BLEU=exp(\Sigma_{n=1}^{N}w_nlogp_n)$で計算することができる

このBPを導入する理由は、Candidateに「the cat」、Referenceに「the cat sat on the table」
などのCandidateの文の長さが短い場合でも、candidateに含まれるn-gramがreferenceに含まれる割合が高くなってしまいます。今回の場合、$precision=1.0$になってしまう。このような場合に罰則としてBPを導入する

# 参考文献
[Mathwork BLEUスコア算出方法](https://jp.mathworks.com/help/textanalytics/ref/bleuevaluationscore.html)
【Node.js】dotenvで環境変数設定


<br>
Node.jsの環境変数について、同じような記事はたくさんあるけど、いつも忘れるので自分用メモを兼ねて。
<br>

##dotenvをインストール

```
npm install --save dotenv
```
<br>
##コード

たとえば、あるURLを環境変数にする場合

以下のように、.envファイルを作成する。
（ファイル名が、.envで、同じフォルダに保存する）

```
URL=https://www.abcdefg.com
```

<br>
すると、以下のように、process.envで呼び出せる。

```js:hogehoge.js
require("dotenv").config();

const URL = process.env.URL

```

<br><br>
Vue.js 備忘録1 

・親要素から子要素への受け渡し（props）

```app.vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <!-- 下のように親要素から子要素に渡したい値を変数名のように記述する　-->
    <Modal header="Sign up for the Giveaway" />
  </div>
</template>

<script>
import Modal from "./components/Modal.vue";
export default {
  components: {
     Modal
  }
}
</script>
```

```Modal.vue
<template>
  <div class="backdrop">
    <div class="modal">
      <h1>{{ header }}</h1>
      <p>modal content</p>
    </div>
  </div>
</template>

<script>
export default {
  // 親から受け取りたい要素をpropの中に配列として書く
  props: ["header"],
  // ただし、ほとんどの場合は型を指定したいことがあるため、オブジェクトとして渡すこともできる
  props: {
    header: String
  }
};
</script>
```

・props2
 →必ずしも、親から子へと渡す要素がStringとは限らない
→そうした場合、子へ渡す値を”バインド”する

```app.vue
<template>
  <div>
    <h1>{{ title }}</h1>
<!-- 下のようにバインドしたい値を:で指定する　-->
    <Modal :header="header" :text="text" />
  </div>
</template>

<script>
import Modal from "./components/Modal.vue";

export default {
  name: "App",
  components: {
    Modal,
  },
  data() {
    return {
      title: "My First Vue App :)",
      header: "Sign up for the Giveaway",
      text: "Hello Modal World!!",
    };
  }
}
```

```Modal.vue
<template>
  <div class="backdrop">
    <div class="modal">
      <h1>{{ header }}</h1>
      <p>{{ text }}</p>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    header: String,
    text: String,
  },
};
</script>
```

・子から親のイベントを発火させる方法（emit）
→モーダル画面などを閉じる時、子から親へのメソッドの移動が必要になる
→そういった場合に、emitを使用して子から親のイベントを発火させる

```app.vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <div v-if="showModal">
<!-- 子のコンポーネントのemitで指定した変数を@hoge（今回はclose）と設定し、ファンクションを記述する
      <Modal :header="header" :text="text" theme="sale" @close="closeModal" />
    </div>
    <button @click="toggleModal">open modal</button>
  </div>
</template>

<script>
import Modal from "./components/Modal.vue";

export default {
  name: "App",
  components: {
    Modal,
  },
  data() {
    return {
      title: "My First Vue App :)",
      header: "Sign up for the Giveaway",
      text: "Hello Modal World!!",
      showModal: false,
    };
  },
  methods: {
    handleClick() {
      console.log(this.$refs.name);
      this.$refs.name.classList.add("active");
      this.$refs.name.focus();
    },
    toggleModal() {
      this.showModal = !this.showModal;
    },
    closeModal() {
      this.showModal = !this.showModal;
    },
  },
};
</script>
```

```Modal.vue
<template>
<!-- 通常と同様に、@clickでファンクションの設定を行う -->
  <div class="backdrop" @click="closeModal">
    <div class="modal" :class="{ sale: theme === 'sale' }">
      <h1>{{ header }}</h1>
      <p>{{ text }}</p>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    header: String,
    text: String,
    theme: String,
  },
  methods: {
    closeModal() {
// 子から親のイベントを使用するためemitを使用する
// emitで指定する変数を宣言する
      this.$emit("close");
    },
  },
};
```
pyenvエラー（Run `pyenv init` to see the necessary changes to make to your configuration）

pyenvのバージョンを上げたら、何故かpython, condaコマンドを上手く認識しなくなり、下記のWarningが表示されるようになる。

```
Run `pyenv init` to see the necessary changes to make to your configuration
```

対策は下記URLの通り。

https://blog.serverworks.co.jp/2021/05/12/233520
Mac環境でVivadoを動かしたい話②

<a href="https://qiita.com/kamura375/items/21993909e33895d4c428">前回</a>、Ubuntuのイメージにx11-appsパッケージをインストールして、xeyesコマンドが通るところまでを確認した。今回は、これらの作業をDockerfile化することでもう少しDockerの理解を深めたい。

# コンテナのライフサイクル
前回試したのはpull, run, (stop), pruneであった。停止状態のコンテナに対して、```docker image commit```することで、イメージかすることが可能だが、このフローは非推奨らしい。Dockerfileを作成し、これをbuildしてイメージ化するのが推奨手順とのこと。
![container_lifecycle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/996063/bd8199b2-6bd1-ebd9-cdeb-94415da7b3a1.png)




# Dockerfileの作成
以下のようなdockerfileを作成した。

```dockerfile
From ubuntu
RUN apt-get update
RUN apt-get install -y x11-apps
#VOLUME ~/.Xauthority:/root/.Xauthority
ENV DISPLAY "<IPADDR>:0"
CMD ["xeyes"]
```

dockerfileと同じディレクトリで

```zsh
% docker image build ./ -t ubuntu-x11
% docker container run -v ~/.Xauthority:/root/.Xauthority  ubuntu-x11
```

とすることで、前回と同様のことを実現できた。
コマンドの意味は、

- ここにあるdockerfileでubuntu-x11と言うイメージを作ってね
- ubuntu-x11と言うイメージからコンテナを立ち上げてね

Dockerfileでホストの.Xauthorityファイルをマウントしているつもりができておらず、xeyesを立ち上げた時に"No protocol specified"で怒られて、それの解決に時間がかかった。
結論から言うと、Dockerfile上でホストのパスを参照することはできない。このDockerfileを別の環境で利用した際に、同じパスにそのファイルがある保証がないから。言われてみればその通りだ。

と言うわけでDockerfile上でのマウントは行わず、コンテナ実行時に従来通りマウントするようにした。

最低限のdockerの操作について概観できたので、いよいよvivadoの立ち上げに移行する。
JIS配列の折り畳み式Bluetoothキーボードを買ってみた

# きっかけ

ふと、折り畳みキーボードを持ち歩いたらスマホで簡単にメモがとれて、便利じゃないかと思いました。同じように思う人もいるかもしれないので、どんな選択をしたのかまとめておきます。

# 要件

- androidでJIS配列で入力できること（これが主たる目的）
- どうせならiPadでもJIS配列で入力したい
- かな入力は不要
- 持ち運びに便利なように軽いこと
- 打ちやすい

# 問題

- まず折り畳みキーボードでJIS配列になっているものは、かなり限られます
- 仮にJIS配列であってもiPadでJIS配列でできるものは、さらに限られます
- iPadサポートと謳ったものでも本当にJIS配列入力できるかも怪しいです。
    - 「英語配列」で入力できますというだけかもしれない
    - 製品発売当初はJIS配列で入力できていたとしても、最新のiPadOSで同じように使えるのかもよく分からない
   
# Elecom TK-FLP01BK

https://www.elecom.co.jp/products/TK-FLP01BK.html

キーピッチ 17mmのキーボードです。
軽くて小さいのと、elecomはiPad用のJIS配列のキーボードをいくつか出していたりするので、iPadでもスイッチを切り替えればJIS配列で入力できるかもしれません。
一方でデメリットとしては、小さすぎることです。実物を店頭で触ってみた感じだとブラインドタッチは結構厳しいような気がします。仮にできても打ち間違いがかなり多そうです。

この製品の兄弟機として、TK-FLP01PBKという極小タッチパッドの搭載されたモデルもあるようです。

https://www.elecom.co.jp/products/TK-FLP01PBK.html

# Ewin折り畳み日本語キーボード

https://www.amazon.co.jp/dp/B08MFHPPNJ/

最初に買おうと思った製品です。
YouTubeで英語配列版のレビュー動画を見て結構打ちやそうだと思いました。またフェイクレザー素材の外装が見た目的にも安定性にも良さそうに思えました。amazonのQ&Aを見る限り、iPadでもJIS配列でいけるかもしれません。（真偽不明）
しかしJIS配列版には右Shiftがないという致命的な欠点があることが分かりました。このJIS配列版、英語版の印字をJISに変えただけのハードウェアになっていて、キー数が増えた分は何かを落とさなければいけないわけで、結果的に複数存在するキーの片方を落すということになったようです。何とか右shiftなしでも使えないかと想像をめぐらしてみましたが、どう考えても使い辛いので断念しました。

Ewinにはこれとは別にタッチパッド付きのJIS配列折り畳みキーボードもありました。やはりこちらも右シフトなどは省かれているようでした。

# ミヨシ TOR-BT03

https://www.mco.co.jp/products_pc/tor-bt03/

最後まで迷ったキーボードです。
ファンクションキーなどの特殊キーはFn+別のキーという組み合わせが多用されているものの、英数字は普通だし、記号類もそれほど変な配列にはなっていません。そして軽い。iPadに関しては、JIS配列で入力できるかどうか不明でした。amazonのコメントを見ても、JISになるという意見とならないという意見がありました。キーピッチも18mmで実機を触った感じでは、ブラインドタッチができそうでした。ただ打ち易いという印象ではありませんでした。
デメリットとしては、軽さの裏返しで、作りがチープな感じです。しばらく使ったら壊れてしまう心配があります。

# Mobo Keyboard

https://mobo-jp.com/products/mobo-keyboard/

最終的にこれを買いました。
このキーボードの最大のメリットはキーピッチ19mmのフルキーボードと同じサイズのキーです。上にあげた商品とくらべると打ちやすさは断然上です。筐体は金属でできていて頑丈そうな感じです。一部の記号類がキーが小さめになっていますが、配置などは普通のJISキーボードです。これならノートPCと同程度には入力できると思います。

一方でデメリットもそれなりにあります。

- iPadでは英語配列
    - 商品説明にも書いてありますが、残念ながら英語配列でした。
        - 本当に残念。ファームウェアアップで対応してほしい
- 重い
    - 他の商品が150g〜200gに対して、本商品は250gくらいあります。
    - さらにケース兼タブレットスタンドが、結構重くて、本体とあわせて400gを超えます
        - 入れ物は100均で手頃なものを買うことにしました
- 価格が高い
    - 他の商品が3000円台〜4000円台くらいなのに対して、こちらは6000〜7000円台
- マルチペアリングの接続台数が少な目
    - 本商品はBluetooth x 2台 ＋ USB接続 1台です。
    - 他の商品はBluetooth x 3台や4台だったりするので、少し手狭な感じがします。

とまぁ色々あげましたが、250g程度でノートPCに匹敵する打ちやすさは他には代え難く、主目的がandroidということもありこの商品を買うことにしました。

もしこの記事を見て折り畳みキーボードを買おうと思った人がいたら、なるべく電気屋で実際に試してみることをおすすめします。触った時の感覚は、文字や動画ではなかなか分からないものです。

# 追記：iClever IC-BK06Mate

https://www.amazon.co.jp/dp/B083M3HL84/


あとから気付いた商品。
amazonでもiClever公式ページでも商品画像は英語配列ですが、amazonのレビュー画像を見ると、のきなみJIS配列になっている。しかもEwinと違って右シフトもある。
amazonのレビューを見るとiPadで使っている人が多いようなので、iPadでJIS配列がつかえるのかも知れない。ただ商品画像とレビュー画像が違う配列になっている理由がまったく分からない。期間限定でJISだったとか？
さすがにMOBOほど打ちやすくはなさそうだけど、iPadでJIS配列が使えてキーピッチ19mmならかなり希少だと思われる。値段も3000円程度と安い。



https://www.iclever.co.jp/products/IC-BK06Mate
コンフリクト解消方法[Git]

開発をしているとコンフリクトが起こることがよくあります。
今回はそのコンフリクトを解消した方法について書いていきます。

■流れ
・git feach,pull 違い
・コンフリクト解消

#git feach,pull 違い

![Got-1 3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/a7885de8-7f31-69de-363d-ad6da62012ab.jpeg)

```git
git feach origin master
```
①リモートリポジトリの最新が更新されます。

```git
git merge origin/master
```
②最新情報をmasterブランチに結合させます。

```git
git pull origin master
```
③は①＋②を同時に行ってくれます。

#コンフリクト解消
例を用いて解説して行こうと思います。
今回は、1branchと2branchで同じファイルを変更した際にコンフリクトが発生したと仮定します。
![Got-6 2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/c80f22bf-0972-6398-5a55-ffff7c02f3cd.jpeg)

1branch（C）をpushでき、masterブランチ（D）にマージすることができます。
コンフリクト発生なし。

2branch（C）をpushできるが、masterブランチにマージすることができません。
コンフリクト発生あり。

※コンフリクト・・・競合

###2branch（C）はどうすればいいのか？

```git
git pull origin master(D)
```
ローカルmasterブランチを最新にする。ここではDが一番最新。

```git
git checkout 2branch（C）
```
2branch（C）に移動します。

```git
git merge master(D)
```
2branch（C）にmaster(D)（最新情報）を結合します。
（1branch（C）で変更した内容が2branch（C）に反映されるイメージ）

競合の警告が表示されるので必要箇所を修正してください。
修正が終わったブランチを2branch（E）とします。

２branch（E）をpushでき、masterブランチ（F）にマージすることができます。

そうすることよってコンフリクトが解消できます。
[AtCoder] ABC 189 C - Mandarin Orange

https://atcoder.jp/contests/abc189/tasks/abc189_c

解説と解法が同じでガッツポーズ。
$l$を固定して$r$を移動させながら最大値を探します。
$l$から$r$の間の最小値$A_{i}$を求めながら、それまでのみかんの最大値と比較して更新していきます。
計算量は$O(N^2)$ですが、$1 \le N \le 10^4$なのでいけると判断しました。
言語はC++(GCC 9.2.1)でAtCoderのコードテストで確認しています。

```c++
#include <bits/stdc++.h>
using namespace std;

int main() {
  int N;
  long long maxA, result = 0;
  cin >> N;
  
  vector<int> A(N);
  
  for (int i = 0; i < N; i++) {
    cin >> A[i];
  }
  
  for (int i = 0; i < N; i++) {
    maxA = A[i];
    for (int j = i; j < N; j++) {
      if (A[j] < maxA) {
        maxA = A[j];
      }
      result = max(result, (j - i + 1) * maxA);
    }
  }
  
  cout << result << endl;
}
```
Homestead環境で複数プロジェクトの管理

#Homesteadで複数プロジェクト管理

Homesteadで複数プロジェクトを管理する際は、`folders`、`sites`をそれぞれプロジェクト毎にHomestead.ymlに記述しておく。foldersをプロジェクト毎に定義しておかないと、オートローダの設定などがうまく走ってくれなかったので、まとめて一つのディレクトリで管理しない方がよい。

```yaml
---
ip: "192.168.10.10"
memory: 2048
cpus: 2
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: C:\Users\user\Project1
      to: /home/vagrant/code/Project1
      type: "nfs"
    - map: C:\Users\user\Project2
      to: /home/vagrant/code/Project2
      type: "nfs"

sites:
    - map: homestead.project1
      to: /home/vagrant/code/Project1/public
    - map: homestead.project2
      to: /home/vagrant/code/Project2/public

databases:
    - homestead

features:
    - mariadb: false
    - ohmyzsh: false
    - webdriver: false
```

それと、Windowsの場合、foldersの定義で`type: 'nfs'`を設定していても、ホストとフォルダ同期できなかったので、プラグインをインストールする必要がある。

```terminal
$ vagrant plugin install vagrant-winnfsd
$ vagrant reload
```

これで、複数のプロジェクトをHomestead環境で管理することが出来た。
and演算子とor演算子について

# and演算子とor演算子について

##and演算子

論理演算子は複数の条件式を組み合わせた式を評価してtrueまたはfalseを返します。

```
if(A && B){} //論理積、AとBが共にtureならtrue
```

「A&&B」だった場合、Aの条件式がtrueかつBの条件式がtureだった場合は式全体の評価がtrueとなる。
そうでなかった場合はfalseとなります。

```
if(A & B){}
```

ちなみに、「A & B」の場合はAがtrueの場合でも、Bを評価します。

##or演算子

or演算子はAもしくはBがtrueの場合、条件式全体でtrueを返します。

```
if(A || B){}
```

「A||B」の場合、Aがtrueだった場合、Bは評価せず条件式はtrueで評価します。
Aがfalseだった場合はBを評価します。

```
if(A | B){}
```

「A｜B」の場合、Aがtrueだった場合でもBを評価します。

##まとめ
・and演算子はAかつBがtrueだった場合、trueを返す
・or演算子はAもしくはBがtrueの場合、trueを返す。
Gitのrepositoryをcloneするときに、ディレクトリを作らない方法

まずは、User/practice/git を作ってそこにクローンさせる。

git clone 'https://github.com/dossy/git-practice'



git-practiceにはindex.htmlとindex.jsがあるとする

```js
git-practice
 |- index.html
 |
 |- index.js
```

cloneを行うと、User/practice/git/git-practiceが出来上がる。
htmlはUser/practice/git/git-practice/index.htmlのpathになる。


しかし、ピリオドをつけると
User/practice/git/のところにhtmlとjsが置かれる。
htmlはUser/practice/git/index.htmlのpathになる。

```js
git clone 'https://github.com/dossy/git-practice .'
// シングルクォーテーションは不要
```

git直下にindex.jsを置くことができる

```js
git
 |- index.html
 |
 |- index.js

```


参考記事：

https://orfool.com/programing/git-clone-without-dir/
Shopify ユーザレビューアプリ Stamped.io のウィジェット日本語ラベルを変更する

## Shopify レビューアプリ

Shopify デフォルトの Product Reviews から一歩踏み込んで本格的な商品レビューアプリを入れるとなると、YOTPO、Stamped.io、Judge.me Product Reviews あたりが定番です。

[PRMAL](https://www.prmal.com/ja) では Stamped.io を利用しています。機能に対して、お値段も月額 $23/month と現実的なことと、シンプルなデザインということもあり、採用しました。

https://apps.shopify.com/product-reviews-addon

しかし、機能は申し分ないですが、日本語の翻訳がデフォルトではやや不完全です。まず、サイト上の Widget のラベル名を変更することができません。デフォルトのままだと、「**あなたの全体的な経験はいかがでしたか？**」という、やや英語直訳感のあるラベルになります。

日本のユーザからすると、不安感もあるので、Stamped.io のサポートに直接ヒアリングした所、対応方法を教えて頂けたので、備忘録。


## 結論: JSで書き換えるしかない

theme.liquid の body タグに以下のコードを書き込むのが唯一の解決手段とのことです。

```html
<script>
  function addEventListenerStamped(el, eventName, handler) {
    if (el.addEventListener) { el.addEventListener(eventName, handler); }
    else { el.attachEvent('on' + eventName, function () { handler.call(el); }); }
  }

  addEventListenerStamped(document, 'stamped:reviews:loaded', function(e) {
    $(".stamped-form-contact-name .stamped-form-input").attr('placeholder', 'ニックネーム（一般公開）');
    $(".stamped-form-contact-name .stamped-form-label").text('ニックネーム');
    $(".stamped-form-contact-email .stamped-form-input").attr('placeholder', 'sample@gmail.com（非公開／ご連絡用）');
    $(".stamped-form-review-title .stamped-form-input").attr('placeholder', 'タイトルを入力する');
    $(".stamped-form-review-body .stamped-form-label").text('商品のご感想');
    $(".stamped-form-review-body .stamped-form-input").attr('placeholder', '商品の感想を入力する');
    $("#stamped-button-submit").attr('value', 'レビューを投稿する');
  })
</script>
```

`stamped:reviews:loaded` のイベントが発火されたタイミングで、即座に上書きします。こちらで綺麗に書き換えが完了しました。

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142932/b8f1a9fa-be1b-dbd7-ddc5-3546f5aa0124.png)
> https://www.prmal.com/ja/collections/ring/products/pile-ring


細かいJSイベントの発火タイミングは公式ドキュメントに掲載されています。

https://help.stamped.io/article/149-javascript-events-references



## おわり

Stamped.io にラベルに対するi18n設定機能が実装されることを、祈ります。
macにComposer入れようと思ったら、つまづいた話

Laravelで開発するため、Composerインストールして、
```usr/local/bin```
に移動しようと思ったら、

```No such file or directory```
そんなフォルダないよ、と言われる

Macのリリース時期にもよるが、binフォルダは存在しないこともあるそう。

対応方法↓
https://atuweb.net/202005e_error-no-such-dir-usr-local-bin/

管理者権限とか面倒かったけど無事Laravelもインストールできました。
EC2で自身が所属しているVPCのIDを調べるワンライナー


タイトルの通り、EC2上で自身が所属しているVPC IDを取得するワンライナーです。


```sh
aws ec2 describe-instances --query "Reservations[].Instances[?InstanceId == \`$(curl -s 169.254.169.254/2021-01-03/meta-data/instance-id)\`].VpcId" --output text
```

変数に入れて使いたい場合。

```sh
$ vpcid=$(aws ec2 describe-instances --query "Reservations[].Instances[?InstanceId == \`$(curl -s 169.254.169.254/2021-01-03/meta-data/instance-id)\`].VpcId" --output text)

$ echo $vpcid
vpc-xxxxx
```
Windows > npm & yarn を使えるようになるまで


wrote: 2021/5/17


# nodist


## nodistのインストール

[Releases · nullivex/nodist · GitHub](https://github.com/nullivex/nodist/releases)

最新を入れとく


確認
cmd から以下を打つ

```
nodist --v
```



## Nodeのインストール


[リリース一覧 \| Node\.js](https://nodejs.org/ja/download/releases/) からお好きなバージョンをチョイスする


以下のコマンドでインストール可能か調べる


```
nodist dist
```

```
割愛
  15.11.0
  15.12.0
  15.13.0
  15.14.0
  16.0.0
  16.1.0
```


執筆現在（2021/5/17）最新の 16.1.0 をチョイスする
cmd から以下を打つ

```
nodist + 16.1.0
nodist 16.1.0

# 確認
node -v
```


## npm

[リリース一覧 \| Node\.js](https://nodejs.org/ja/download/releases/)から、インストールしたnodeのバージョンと対応するnpmにバージョンアップする

執筆現在（2021/5/17）16.1.0 には 7.11.2 のようです
 
![スクリーンショット 2021-05-17 21.39.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/74d76d91-a610-d8d5-32ac-3d90f4faabfa.png "スクリーンショット 2021-05-17 21.39.48.png")


```
nodist npm 7.11.2

# 確認
npm -v
```



## yarn

```
npm i -g yarn

# 確認
yarn -v
```


## npx

```
npm i npx -g


# 確認
npx -v
```


## vscode


yarnができない

![スクリーンショット 2021-05-17 22.05.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/ec14334f-bf52-65a5-0762-57553dbe7c41.png "スクリーンショット 2021-05-17 22.05.57.png")



powershellを管理者として実行

![スクリーンショット 2021-05-17 22.03.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/a7d007cc-851f-78a4-cba6-6a7d32f11f1b.png "スクリーンショット 2021-05-17 22.03.13.png")



powershellにて以下を実行

```
Set-ExecutionPolicy RemoteSigned
```

質問には「A」全て実行で回答


![スクリーンショット 2021-05-17 22.04.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/d90d1058-04fc-65f2-5608-7a7ca37c61f2.png "スクリーンショット 2021-05-17 22.04.24.png")


無事にyarnが実行できるようになりました。



### yarnしたらRetryingとなる場合

```
info There appears to be trouble with your network connection. Retrying...
info There appears to be trouble with your network connection. Retrying...
```

以下のようにtimeoutを指定してyarn

```
yarn install --network-timeout 1000000
```
Flutterのmulti_image_pickerでパスを保存する方法

#取得した画像をパスで保存したい(FireStorageを使いたくない)
multi_image_pickerを使って端末から画像を取得するとパッケージ固有のAssetで取得できる。
そのAssetのパスを見つけて保存する方法。
iOSだとアップデートしたときにファイルが消えて無くなる(パスが変わる)ので、アプリ専用ディレクトリ相対パスを保存する必要がある。

##パッケージ
使ったパッケージはこれです。
設定は省いてます。

https://pub.dev/packages/multi_image_picker/example

https://pub.dev/packages/path_provider

### 1.画像データの取得(Asset)
ドキュメントの通りにAssetを取得する

```dart:getimage.dart
try {
      resultList = await MultiImagePicker.pickImages(
        maxImages: 300,
        enableCamera: true,
        selectedAssets: images,
        cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
        materialOptions: MaterialOptions(
          actionBarColor: "#abcdef",
          actionBarTitle: "Example App",
          allViewTitle: "All Photos",
          useDetailsView: false,
          selectCircleStrokeColor: "#000000",
        ),
      );
    } on Exception catch (e) {
      error = e.toString();
    }
```
###2.Assetを処理してパスを取得する

```dart:getimage.dart
for (var image in resultList) {
　　//Assetの元画像のByteDataを取得する
  　final byteData = await image.getByteData();
    //multi_image_pickerが取得した画像の一時ディレクトリのパスを取得(path_providerを使用)
    final tempFile =
    File('${(await getTemporaryDirectory()).path}/${image.name}');
    //ByteDataを使って一時パスのデータをファイルに変換
    final file = await tempFile.writeAsBytes(
     byteData.buffer.asUint8List(
        byteData.offsetInBytes,
        byteData.lengthInBytes,
        ),
     );
     /*
     一時ディレクトリのパスだとデータがアプリをアップデートしたときに消えて無くなるのでiOSでアプリ専用ディレクトリにコピー
     そのときにディレクトリの絶対パスを保存するとこれまた消えて無くなるので相対パスを保存する必要がある
     */
     //任意のパス設定(最終的に保存するパス)
     String relativePath = '/' +
         DateTime.now().millisecondsSinceEpoch.toString() +
         Path.extension(file.path);
     //アプリ専用ディレクトリのパス
     final String appdirpath = (await getApplicationDocumentsDirectory()).path;
     //アプリ専用ディレクトリに保存する時のパス
     String newPath = '$appdirpath' + relativePath;
     //一時ディレクトリからアプリ専用ディレクトリにfileをコピー
     File res = await file.copy(newPath);
     //
     pictureURL.add(relativePath);
     picturewiget.add(Image.file(res));
}
//firestoreに保存する処理
uploadfirestore(relativePath);
```

### 3.保存したパスで画像の絶対パスを取得する

```dart:getimage.dart
//この関数に保存したパスを渡せば画像の保存先絶対パスが取得できる
Future<String> getDocumentsPathByRelativePath(String relativePath) async {
  final String appdirpath = (await getApplicationDocumentsDirectory()).path;
  return relativePath != null && relativePath.isNotEmpty
      ? appdirpath + relativePath
      : null;
}
//FileImage(File(pictureURL)),で画像を表示
```

##書いている途中で気付いたこと
multi_image_pickerが使えなくなっていてmulti_image_picker2変更になっていた。
（恐らく同じやり方でいけると思います✨）

https://pub.dev/packages/multi_image_picker2