OmniAICreator/Qiita-1.07M huggingface dataset:
has_secure_password でつくられたpassword_digestをBcryptで検証する

# 概要
Railsで[has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password) パスワードの変更時に、「現在のパスワードを入力する」っていうやつをどうやってやろうかなーと思って、考えたことをメモする

具体的には、現在のパスワードがとpassword_digestを称号して、一致するなら 真となる値（trueなど）を返す方法です。

# Deviseの人
[devise](https://github.com/heartcombo/devise)ならば `valid_password?`を使ってください。

https://github.com/heartcombo/devise/blob/81bf3ad8c1e3812448ba4588598493c8e80ecf10/lib/devise/models/database_authenticatable.rb#L71-L73

# has_secure_passwordな人のやり方

```db/migrate/20210129094437_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.text :password
    end
  end
end
```

```app/models/user.rb
class User > ApplicationRecord
  has_secure_password
end
```
## authenticateメソッドを使う

```irb
irb(main):001:0> user = User.new
   (0.4ms)  SELECT sqlite_version(*)
irb(main):002:0> user.password = 'hoge'
irb(main):003:0> user.password_digest
=> "$2a$12$kzeCnmviABPsc3hLDrLqWuXVFqp3Jweotl6jmWAOTv4YDhThEY/BW"
irb(main):004:0> user.authenticate_password('fuga')
=> false
irb(main):005:0> user.authenticate_password('hoge')
=> #<User id: nil, password_digest: [FILTERED]> # 一致した場合は自身を返す。 真となる。

```

## BCrypt::Password#is_password?メソッドを使う

BCryptを直接叩いてもできます。参考にしたのhas_secure_passwordが定義されているモジュール内の下記のコードです。

https://github.com/rails/rails/blob/404ad9e8acf8ab45ae2314050131a00e57e63b40/activemodel/lib/active_model/secure_password.rb#L96-L98


```irb
irb(main):001:0> user = User.new
   (0.4ms)  SELECT sqlite_version(*)
irb(main):002:0> user.password = 'hoge'
irb(main):003:0> user.password_digest
=> "$2a$12$kzeCnmviABPsc3hLDrLqWuXVFqp3Jweotl6jmWAOTv4YDhThEY/BW" # この文字列を検証する
irb(main):009:0> password_digest = user.password_digest
irb(main):010:0> password_digest
=> "$2a$12$kzeCnmviABPsc3hLDrLqWuXVFqp3Jweotl6jmWAOTv4YDhThEY/BW"
irb(main):011:0> BCrypt::Password.new(password_digest).is_password?('fuga')
=> false # 一致しない
irb(main):012:0> BCrypt::Password.new(password_digest).is_password?('hoge')
=> true # 一致するので true

```

`BCrypt::Password.new(password_digest).is_password?('hoge')` が肝です。 password_digestの暗号化された文字列が 検証したい文字列（'hoge'）から暗号化する文字列と一致するかを検証しています。

# おまけ
[Rails 6以降のhas_secure_password](https://github.com/rails/rails/blob/66cabeda2c46c582d19738e1318be8d59584cc5b/activemodel/lib/active_model/secure_password.rb#L61)は `password` というattributeもしくは `password_digest` というカラム以外も使えます。 （ rails 5.2だと使えない [5.2のhas_secure_password](https://github.com/rails/rails/blob/375a4143cf5caeb6159b338be824903edfd62836/activemodel/lib/active_model/secure_password.rb#L55) ）

https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password

たとえば、 `recovery_password` という文字列を使う場合は、以下の通りです。

これは、便利だ。 

```app/models/user.rb
class User > ApplicationRecord
  has_secure_password :recovery_password, validations: false
end
```

# 所感

実は、パスワード管理 deviseしか使っていなかった。相談を機に調べたらとても勉強になった。
has_secure_passwordの中身を知ったらパスワードだけなら has_secure_passwordでいいかなーと思った。
devise・・・はまりどころが多いからできれば使いたくないーと思っていたので。
Gatsbyでブログサイト生成

###CLIのインストール

~~~
$npm install -g gatsby-cli
~~~

適当なフォルダでサンプル作成

~~~
gatsby new hello-world https://github.com/gatsbyjs/gatsby-starter-hello-world
cd hello-world
gatsby develop
~~~

Reactのプロジェクトができた。
gatsby developで開発サーバー立ち上げ。
右側がテンプレートのリポジトリ



###ブログのリポジトリにしてみる。

~~~
$ gatsby new my-blog https://github.com/gatsbyjs/gatsby-starter-blog
~~~

それっぽいサイトが表示された。

content/blog下に記事が入っている。

content/blog/my-second-post/index.md

~~~
---
title: My Second Post!
date: "2015-05-06T23:46:37.121Z"
---

Wow! I love blogging so much already.
~~~

###記事追加
試しに、my-second-postをコピーして記事追加したら画面に反映された。
Qiitaのようにマークダウンで書けばOK。

###ビルド
~~~
$ gatsby build
~~~

普通のReactプロジェクトのようにpublic配下にリソースが出力されている。
記事はマークダウンからhtmlになっている。
これを静的WEBサイトとして配信すれば良いのだろう。
Gatsbyとかのコンテンツ配信サービスを使えば
githubにソースpushすれば配信してくれる。
いろいろインストールしたりコマンド打ったりする障壁はあるが、
非エンジニアでも運用できそう。
【初心者でもわかる】inputのボタンに改行は入らいないから代案を考える

#inputのボタンには改行を入れることができないのでほかの方法を考えます。

inputのボタンの文章が長いので改行しよう↓

## ×「普通に改行を入れる」

```index.html
<input type="button" value="この後で
改行させるよ" />
```

**失敗**

![miss01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/9d75d935-99eb-e381-f84b-39e04f73eeae.png)


## ×「brタグを入れる」

```index.html
<input type="button" value="この後で<br>改行させるよ" />
```

**失敗**
![miss02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/f1259c23-c8db-1e72-64be-e54c9021573b.png)


## ×「brタグを実体参照で書く」

```index.html
<input type="button" value="この後で&lt;br&gt;改行させるよ" />
```

**失敗**

![miss03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/3a7c4b74-69bb-4cb7-6e9f-9a2a8c29fe13.png)


## ◎「inputタグを使わずにbutton要素を使う」

```index.html
<button>この後で<br>改行させるよ</button>
```

**成功！**

![ok01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/38906b8f-7a8a-055e-a34c-85a65038e892.png)

## まとめ

この結果からわかるように、**inputタグのままボタンのテキストを改行させることはできません。**

しかし、改行ではなく文字送りさせることで2列にすることは可能です。

```index.html
<input type="button" value="この後で改行させるよ" />
```

```style.css
input {
  width: 100px; /* 文字送りされるように幅を決める */
  white-space: normal; /* 文字がはみ出た時のルールを文字送りに指定 */
}
```

**結果**

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/71734814-0161-053e-efee-68336ae6efbd.png)


#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
【Rails】urlヘルパーでhostの指定

urlのヘルパー（[こちら](https://railsguides.jp/routing.html#%E3%83%91%E3%82%B9%E3%81%A8url%E7%94%A8%E3%83%98%E3%83%AB%E3%83%91%E3%83%BC)）を使うとURLを生成してくれますが、このときホストを指定したいなんてときにどうするかのメモです。

## 使い方
普通にurlを生成すると以下のようになったとします

```ruby
hoge_url
# => http://host/hoge
```

引数で`host`を指定するだけです

```ruby
hoge_url(host: 'fuga')
# => http://fuga/hoge
```

## 余談
Railsのコンソールでurlがどのように生成されるか確認する場合は、単にhoge_urlと入力してもうまくいきません

```
$ rails c
pry(main)> hoge_url
NameError: undefined local variable or method `hoge_url' for main:Object
```

`app`を前につければOKです

```
$ rails c
pry(main)> app.hoge_url
=> "http://www.example.com/hoge"
```
【Javascript】配列の中にあるオブジェクトを取得したい

###以下の配列から2番目のオブジェクトにあるyのバリューを取り出したい場合
```javascript:sample.js
  const points = [
    {x: 10, y:20},
    {x: 30, y:40},
    {x: 50, y:60},
  ];

```

###取得方法
配列の番号を指定してその番号（オブジェクト）の値を指定してあげるとバリューを取得可能
  `console.log(points[1]["y"])`もしくは`console.log(points[1].y)`

```javascript:sample.js
  const points = [
    {x: 10, y:20},
    {x: 30, y:40},
    {x: 50, y:60},
  ];

```
「Google Maps の検索結果から Yahoo! カーナビで経路案内できる iOS ショートカット」を復活させた

#概要
この記事は、@otchyさん作の[Google Maps の検索結果から Yahoo! カーナビで経路案内できる iOS ショートカット](https://qiita.com/otchy/items/79184c6124c683509aeb)を改良したといった内容です。

# Y!カーナビで経路案内 v4 (2021/02/03更新)
[ここを参照](#改良版url)


# @otchyさんのショートカットが便利すぎて泣ける
タイトル通りです。
日常的に使用させていただいています。

### 2021/01現在、動かなくなった
本ショートカットを起動しても、Yahooカーナビアプリに目的地が転送されなくなりました。

### 原因分析
元記事の[HTML の取得](https://qiita.com/otchy/items/79184c6124c683509aeb#html-%E3%81%AE%E5%8F%96%E5%BE%97)に記載されている「```URLの内容の取得```」で、Googleからのレスポンスにエラーが出ていることを確認しました。**JavaScript**が有効になっていない環境で、上記URLでのレスポンスが返ってこなくなったみたい。
......緯度経度情報が取得できないため詰んでる。

|デバッグ処理|結果|
|:--|:--|
|![debug.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/8c203cf8-f63e-eadb-3027-2c0557429bb3.png)|![IMG_2666.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/64bbe54d-5678-9a3a-9701-7543d3e796a1.png)
|

#改良方針 (v4: 2021/02/03更新)
Google APIに頼らずに、緯度経度情報を取得できればいいのでは？
→Google Mapsアプリから受け取るURLだけで緯度経度情報を取得できないか？

※ショートカット標準機能を駆使し、緯度経度を取得する方法を考えたが、2021/02時点で動かなくなったためNG。忘備録として過去の検討経緯は残しておきます。
<details>
<summary>v3の方針（動作せず）</summary>
<div>

**改良方針**
Google APIに頼らずに、緯度経度情報を取得できればいいのでは？

**改良結果**
実はショートカットの**標準機能**に、「場所」から「緯度・経度・地名・etc...」を取得する機能が備わっています。Google Maps Appから送信される「場所」情報も、この標準機能が使用できるみたいです。この機能をフルに活用することで、無事Yahoo!カーナビへの経路案内ショートカットが復活しました。うれしい。

![improved.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/2216d583-d3ed-3b94-bd0b-e027a98aa2f1.png)

v3までの忘備録終わり

</div>
</details>

## Google Maps URLのパース
Yahoo!カーナビを実行するのに必要な情報は、目的地の緯度・経度情報です。URLのパースの最終目的は、緯度・経度情報の取得となります。

### 0.フォーマットの確認
Google Mapsから受け取る短縮URLを復元すると、
1. **緯度・経度情報のみ**帰ってくるパターン
2. **住所・地名のみ**帰ってくるパターン
の2つの形式になります。
1.のパターンならURLに記載された緯度・経度情報をそのまま使用できますが、2.のパターンの場合、住所から緯度・経度を取得しなければなりません。
![format.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/3606d168-ad54-28ca-1b94-183849985221.png)

### 1.URLから情報の抽出
上記2つのパターンに合わせ、URLを解析し、「緯度・経度情報」または「住所」を取得します。ショートカット機能を駆使し、頑張って分解します。
![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/bd9718d4-05b6-25ed-5a3b-d40124e6bc3e.png)


### 2.住所情報から緯度・経度情報の取得
住所情報から緯度・経度を取得するには、ショートカットに内蔵されているマップ機能の「**入力から住所を取得**」を使用します。この機能は、住所情報を「場所」オブジェクトに変換します。取得した場所は、「**場所の詳細を取得**」機能を使うと緯度・経度情報に変換できます。

これらの機能を駆使することで、住所情報から緯度・経度情報を取得します。ここまで来たら、あとはいつも通り、Yahoo!カーナビのURL Schemeを実行すれば終わりです。
![map_object.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/3f0931d9-f1e8-e08a-9c5d-133084223248.png)

## ショートカット全体像
v3では6アクションだったのが、v4で32アクションに増えてしまった...
![all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81808/b560788e-1bd5-5012-8cfe-a1473c09a838.png)


#改良版URL
v4: [https://www.icloud.com/shortcuts/47403d0acdfb4c34bd599e2397e03acf](https://www.icloud.com/shortcuts/47403d0acdfb4c34bd599e2397e03acf)
~~v3.1: [https://www.icloud.com/shortcuts/fe7eca336ee64cfebf48031cac82e31c](https://www.icloud.com/shortcuts/fe7eca336ee64cfebf48031cac82e31c)~~
~~v3: [https://www.icloud.com/shortcuts/1017154b3deb45d0834fd4acbbeb46dd](https://www.icloud.com/shortcuts/1017154b3deb45d0834fd4acbbeb46dd)~~

v4: 緯度・経度取得方法をURL解析に変更しました
v3.1: 本ショートカットがGoogle Mapsに表示されないという致命的なミスを修正しました
v3: リリースしました
【Rails】bundle installでエラー(Could not verify the SSL certificate for https://rubygems.org/)が出る時の対処法

##はじめに
git pullしたrailsのフォルダでbundle installをしたらエラー(Could not verify the SSL certificate for https://rubygems.org/) が発生したので、下記に解決法をまとめます。
なぜ解決できたのか？はよく理解できていませんが、それは今後の課題とします。
初学者が書いていますので、ご指摘等ありましたら、コメントいただけますと幸いです。

##上手く行かなかった解決法
###①OpenSSLの有効期限を更新する。
最初に、下記記事を参考にしました。

[rails の bundle install が 「Could not verify the SSL certificate for https://rubygems.org/.」で失敗するとき](https://qiita.com/ego/items/38f8de30996ba12108b4)

下記コマンドを実行するとちゃんと結果が返ってきました。

```
% openssl version
LibreSSL 2.8.3
```
LibreSSLというのは、OpenSSLの派生改良版のようですね。
そのためOpenSSLはきちんと入っていることになります。
参考： [OpenSSLとLibreSSLを比較](https://www.ossnews.jp/compare/OpenSSL/LibreSSL)


証明書の有効期限を下記コマンドで確認するも、こちらは問題無いようでした。

```
% openssl s_client -connect example.com:443 < /dev/null 2> /dev/null | openssl x509 -text | grep Not
            Not Before: Nov 24 00:00:00 2020 GMT
            Not After : Dec 25 23:59:59 2021 GMT
```


###②Gemfileのhttps://を書き換える。
次に、下記記事を参考にしました。
[bundle コマンドで SSL エラーが出て進めない](https://moriya.xrea.jp/tdiary/20170122.html)

とりあえずGemfileにある`https://rubygems.org`を`http://rubygems.org`に書き換えましたが、変わらずエラー(Could not verify the SSL certificate for〜)が出ました。

##解決法

まず、下記コマンドでrubyが使用している証明書の場所を確認します。

```
% ruby -ropenssl -e 'p OpenSSL::X509::DEFAULT_CERT_FILE'
/Users/user_name/.rbenv/versions/2.6.6/openssl/ssl/cert.pem
```
次に下記コマンドを実行します。

```
% sudo curl "https://curl.haxx.se/ca/cacert.pem" -o /Users/user_name/.rbenv/versions/2.6.6/openssl/cert.pem
```
これでbundle installが無事成功しました！

参考: [Rails開発環境の構築（複数バージョン共存可能）（Homebrew編）](https://qiita.com/emadurandal/items/e43c4896be1df60caef0#ssl%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88)
RDS for MySQL の Audit Log を取得する

# はじめに

RDS for MySQL の Audit ログを取得する方法を紹介します。RDS でどんなユーザーがいつログインして、どのようなクエリーを発行したのか、といったことを CloudWatch Logs に出力が出来ます。監査目的に非常に重要な重要なので、必要なセキュリティ要件が有る場合はぜひ取得するのが良いです。

備忘録的に手順を紹介します。



# Option group 作成

まず、Option group で、Audit Log 取得用の Plugin を有効にします。

Create group

![1611996208250.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/6d3cbefa-e8a9-45b9-35d2-58a6602b2f07.png)



Create

![1611996400488.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3d63e234-6f1a-9d3b-6ceb-3d2eae139786.png)



Add option

![1611996456153.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/0a1a2f5a-e702-bc45-9b7d-3c230b411b3d.png)



Option name で、`MARIADB_AUDIT_PLUGIN` を選択して、どのような Audit Log を有効にするか指定します。

SERVER_AUDIT_EVENTS

```
CONNECT,QUERY,TABLE,QUERY_DDL,QUERY_DML,QUERY_DCL
```

![1611996579982.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/cfab7d7f-f602-2c19-39cd-27d3566143ff.png)



# RDS 作成

Create database

![1611996791708.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ae343e72-a654-f38d-4f8c-bfa5b3334019.png)



作成した Option group を指定

![1611996924397.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/38d72aba-537a-f45b-aa80-fb225ce79d9f.png)



Log exports も有効化

![1611996942136.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/4155cfda-80fd-5d29-6aaf-0371ab5ab021.png)



Create を押すと、作成される

![1611997433685.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/df9fd41e-9338-1eba-5e00-532990ccc30f.png)



# Cloud Watch Logs

Log groups が自動的に作成される

![1611997274955.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/11567241-b6ed-3514-cb93-1e39bd8cad03.png)



# 確認

接続

```
[opc@onprem-server01 ~]$ mysql -u admin -h audit-test01.comulzzpkhpz.ap-northeast-1.rds.amazonaws.com -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.7.31-log Source distribution

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```



コマンドを実行すると、Log group が新たに生成される

![1611998267730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/825e44ed-b89e-407b-f5e3-1d2b48a9398d.png)



こんな感じに適当に database や table を作成

```
create database sugitest;

use sugitest;

CREATE TABLE sample(
 id INT(11) NOT NULL AUTO_INCREMENT,
 value INT(5) NOT NULL DEFAULT 0,
 PRIMARY KEY (id)
);

INSERT INTO sample(value) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
```



実行したクエリーが、CloudWatch Logs 上でも確認できます。

![1612005720127.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/34754d2b-b9ff-b025-4dea-319cb13de20e.png)



# 参考URL

https://aws.amazon.com/jp/premiumsupport/knowledge-center/advanced-audit-rds-mysql-cloudwatch/
UITableViwCell内のボタンからindexPathの取得方法

tableViewCell.xib でcellをカスタムした際にbutton のindexの取得が必要になり調べました。
私的備忘録として。

tableViewCellにてindexPathを定義

```TableViewCell.swift
import UIKit

class TableViewCell: UITableViewCell {
    
    @IBOutlet weak var button: UIButton!
      var indexPath = IndexPath()

    @IBAction func button(_ sender: Any){
      print(indexPath.row)
}
```

cellForRowAt内でindexをcellわたす

```ViewController.swift

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self

        tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "tableViewCell")
}

extension ViewController: UITableViewDelegate, UITableViewDataSource{
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! TableViewCell
        cell.indexPath = indexPath

        return cell
```
go-playground / validatorライブラリアップデート作業メモv8 -> v10

# 前書き

今後同じ作業をする方と自分の振り返りのため、メモを残します。

|goバージョン   |go-playground / validatorバージョン|
|:-----------|---------------:|
|v1.15.3     |v10.4.1         |

## TagName

v8のvalidatorはデフォルトの`TagName`を指定してありません。
毎回validator初期化する際に`TagName`を渡してます、v8の場合は以下の書き方になってます。

#### v8
```go:main.go
var validate *validator.Validate
config := &validator.Config{TagName: "validate"}
validate = validator.New(config)
```

v9以降の`TagName`のデフォルト値が `validate`に指定されてます、ライブラリのソースコードを見てみよう。

```go:validator_instance.go

	v := &Validate{
		tagName:     defaultTagName,
		aliases:     make(map[string]string, len(bakedInAliases)),
		validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)),
		tagCache:    tc,
		structCache: sc,
	}
```

```go:validator_instance.go
const (
	defaultTagName        = "validate"
```
よって、v9以降特に指定がなければ、以下の書き方になります。

#### v9以降
```go:main.go
validate = validator.New()
```

## validator.RegisterValidation

カスタムバリデーションを作る際にvalidator.RegisterValidation()が使われます。
v8の場合以下の書方になっていました、戻り値の真偽で判断しています。

#### v8

```go:main.go
...
v.RegisterValidation("bookabledate", bookableDate)
...

func bookableDate(
  v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
  field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
  if date, ok := field.Interface().(time.Time); ok {
      today := time.Now()
      if date.Unix()>today.Unix(){
          return true
      }
  }
  return false
}
```
v9以降では、使い方は変わってないですが、検証用の関数を受けるパラメーターが簡略化されました。
 `field`パラメーターなどは `validator.FieldLevel`に集約されました。

#### v9以降
```go:main.go
...
v.RegisterValidation("bookabledate", bookableDate)
...
func bookableDate(fl validator.FieldLevel) bool {
    if  date,ok:=fl.Field().Interface().(time.Time);ok{
        today:=time.Now()
        fmt.Println("date:",date)
        if date.Unix()>today.Unix(){
            fmt.Println("date unix ：",date.Unix())
            return true
        }
    }
    return false
}
```

## validator.ValidationErrors


- v8の `validator.ValidationErrors`のタイプは `map[string]*FieldError`
  -  `FieldError`は構造体
- v9以降の `validator.ValidationErrors`のタイプは `ValidationErrors []FieldError`
  - `FieldError`はインターフェース
 

v8では以下のような書き方で`FieldError`を生成していましたが、v9以降では使えません。

#### v8

```go:main.go
validator.ValidationErrors{err: &karma.InvalidParamError{
	"xx.yy": &validator.FieldError{Field: "yy", Tag: "gt"},Err: errors.New(fmt.Sprintf(fieldErrMsg, "xx.yy", "yy", "gt")),
}
```

v9以降で同じエラーを生成したい場合、`fieldError`の Error()関数の書き方を真似するといいです。

```go:errors.go
const fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"

func (fe *fieldError) Error() string {
	return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag)
}
```

#### v9以降

```go:mian.go
const fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"
validator.ValidationErrors{err: errors.New(fmt.Sprintf(fieldErrMsg, "xx.yy", "yy", "gt"))}
```
scratch変数クエスト★1 カウントアップとカウントダウン

# 完成イメージ
![ダウンロード (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/d97d5ea0-997d-d06c-3289-116181a5631b.gif)

# このクエストについて
- 変数をカウントアップしよう

# 仕様の説明
- スプライトはひとつ
- 変数「カウントアップ」を用意する
- 実行時に、変数「カウントアップ」の値を0にする
- スプライトが1回押されたら、変数「カウントアップ」が1上がる

# チャレンジクエスト
- 新しくスプライトを用意する
- 新しく変数「カウントダウン」を用意する
- 実行時に、変数「カウントダウン」の値を10にする
- 新しいスプライトが1回押されたら、変数「カウントダウン」が1下がる

![カウントダウン.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/3698aa50-48e2-41e4-93e2-6ccb504d205f.gif)
M1チップでの仮想Linux環境を諦めたが、返品を思い止まった話

#M1チップ搭載 Macbook Air購入
2021年1月にApple独自開発M1チップ搭載のMacbookを購入した。  

* 13インチMacbook Air-ゴールド
* CPU8コアGPU8コア
* 512GBのSSDストレージ  

購入理由はシンプルに性能が良さそう。
色はいい感じ。
<img width="250" alt="312595D3-B571-430F-8A32-3E5E27FC245D_1_105_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057425/6c90cbb7-6b1b-33bc-fe46-80231638d5d2.jpeg"><img width="250" alt="38048AF8-382E-4112-B972-3AA783CF6651_1_105_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057425/cf319ced-864a-d9bc-6df6-cb3bd29c4796.jpeg">


#Lunux仮想マシン導入方法を探した話
以前から少しdockerコンテナをいじっていたため、まず今回も新しく購入したMacにVertualBoxを使ってLinux仮想マシンを構築しようとした。
しかし、よく考えるとVertualBoxってx86CPU用ソフトウェア。
M1チップ対応してるのかなとOracle Communitiesを見てみると、こんな[Discussions](https://community.oracle.com/tech/apps-infra/discussion/4477612/will-the-latest-version-of-vm-virtual-box-will-run-in-new-silicon-mac-with-m1-chip)を発見。
残念。対応してないようだ。そらそうだ。

Apple Silicon搭載のMacでIntelバイナリを動作させるトランスレータ「Rosetta 2」は存在するが、[カーネル拡張とx86_64プラットフォームを仮想化するVMアプリをサポートしない](https://applech2.com/archives/20200624-about-apple-rosetta-2.html)ため、現状ではVMは難しい。

一方で、Parallelsが「Parallels Desktop for Mac」としてTechnical Preview版を公開していた。
Intel版OSは動作しないが、Arm版OSを動かすことができるらしい。
Windowsは動きそうだが、Linuxについての詳しい言及は見つけられなかった。

#仮想化関連での公式リリースが少ない
うーん、中々有益な情報が得られない。
QiitaでARM版Ubuntuの仮想化をやってる人はちらほら見かけたが、ARMアーキテクチャのデストリは少ない上に、x86向けパッケージが使えないので、一般的なLinuxのイメージでの利用は難しそうである。

というわけで、現段階では、仮想化関連で公式リリースされているものや簡単に仮想マシンでLinuxを起動する方法は見つからなかった。
AppleもintelチップからM1チップに移行する期間を2年としているので、この程度待てば問題なく全ての仮想関連ソフトが使えるようになるのだろうか。
それにしても今すぐ開発環境が欲しい人間はM1チップ搭載Macbookを買うべきではなかった。これが結論。

#Docker for MAC
一旦仮想Linux環境は諦めるにしても、そもそもDockerはM1チップ搭載Macbookの上で動くのか。
2021年1月現在DockerがApple Silicon M1チップに対応した「Docker Desktop Technical Preview」を一般にも公開している。
今後については不明点が多いが、Preview版が出ているので公式リリースも間近なのだろうか。

#M1チップ搭載Macを返品するか悩んだ

今すぐ環境が欲しいところではあるので、返品・intelコアMacbookを再購入を悩んだ。
(既にintelコアMacbookは公式で買えないので、ネットか家電量販店でゲットすることになる。)
しかし、以下の理由で思い止まった。

* Apple製品の良さはリセールバリューが非常に高いところ
* 今後intelチップ製品に対してAppleのサポート期間が終了する
* シンプルにM1チップの性能が高い
* AWSなどのクラウドサービスを用いれば、Dockerが使える
* AppleもM1チップ搭載製品を浸透させるために迅速に対応を進めてくれそうという期待

正直一回セットアップしたPCをクリーンにして返品してもう一回買ってセットアップという作業が面倒だったというのも理由の1つだった。
何はともあれ、M1チップ搭載Macbookでの仮想Linux環境構築は今後も調べていきたいところである。情報があれば是非ください。
「分散調節済みソフトマックス関数」なんていかがでしょうか

# 1. 前提
softmax関数とは、$n$(任意の自然数)次元ベクトルを受け取って、$n$次元ベクトルを出力する関数であって、出力には次の特徴がみられる。

- 各成分は0以上1以下
- 総和は1

$${\rm softmax}\left(\begin{array}{c}
v_{0}\\\\
\vdots\\\\
v_{n-1}
\end{array}\right) = 
\left(\sum_{i=0}^{n-1}\exp{v_i}\right)^{-1}
\left(\begin{array}{c}
\exp{v_{0}}\\\\
\vdots\\\\
\exp{v_{n-1}}
\end{array}\right)$$

# 2.問題点
softmax関数は、その特徴から、分類問題を解くネットワークにおける出力層の活性化関数としてしばしば利用される。
例えば「猫とライオン」を見分ける問題であれば、2次元ベクトルを計算してsoftmax関数に入力することで
「各成分が0以上1以下で、しかも成分の総和が1」である2次元ベクトルを得ることができる。
その各成分を「猫である確率」「ライオンである確率」と半ば無理やり解釈することができる。

しかしだ。softmax関数の出力を「各選択肢が正解である確率」とみる手法では、「自信の強さ」が変数のスケールによって変化してしまう。
例えば
$$
{\rm softmax}\left(\begin{array}{c}
1\\\\-2
\end{array}\right)=
\left(\begin{array}{c}
0.953\\\\
0.047
\end{array}\right)$$
であるが、
$$
{\rm softmax}\left(\begin{array}{c}
0.1\\\\-0.2
\end{array}\right)=
\left(\begin{array}{c}
0.574\\\\
0.426
\end{array}\right)$$
である。
成分比が同じでも、その絶対的な大きさが小さければ小さいほど、「自信がなくなる」(出力の各成分が一様に近づく)し、
大きければ大きいほど、「自信がでる」(出力の各成分が一様でなくなる)

もちろん、この特性は「正解を予測するだけでなく、自身まで表現できて素晴らしいじゃないか」という場合もあるだろう。その場合は「分散調節済みソフトマックス関数」など不要だろう。

しかし、「遺伝的アルゴリズムにおける交叉の過程で、各遺伝子が親として選ばれる確率を
${\rm softmax}(各遺伝子のスコア)$
として求めたい」といった場合、確率の偏りの大きさがある程度決まっていた方が便利だろう。

# 改善
出力の各成分の分散を予め決めて置き、その分散が得られるように変数のスケールを調整する

```python:定義
def softmax(v):
    分子 = np.exp(v)
    分母 = sum(分子)
    return 分子/分母

def 分散調節済みソフトマックス(入力, 分散, see_a=False):
    入力 = np.array(入力)
    a = 1 # 各成分のスケールを調整する係数を2分法で求める
    da = 1
    while not (np.var(softmax(a*入力)) > 分散[0] and np.var(softmax(a*入力)) < 分散[1]):
        while np.var(softmax(a*入力)) < 分散[0]:
            a += da
        da /= 2
        while np.var(softmax(a*入力)) > 分散[1]:
            a -= da
        da /= 2
    if see_a: print("a:", a)
    return softmax(a*入力)
 
```

```python:利用例
>>> np.var(softmax([1,2]))
0.053388066758518156
>>> np.var(softmax([10,20]))
0.24995460419226406
>>> 分散調節済みソフトマックス([1,2], [0.01, 0.02], see_a=True) # 分散を0.01~0.02の範囲に収めたい
a: 0.5
array([0.37754067, 0.62245933])
>>> np.var(分散調節済みソフトマックス([1,2], [0.01, 0.02]))
0.014996287798405504 # 範囲内！
```
MySQLの条件分岐の仕方

最近、レガシーコードの改修でどうしても条件分岐を伴った生SQLを書かないと行けない機会があったので、その時のメモです。

# IF
SQLの場合はIF文とIF関数があります。

## IF関数
```sql
IF(10 > 5, "TRUE", "FASE") -- TRUEが返る
```
という書き方をします。
第一引数には、条件を第二引数には条件がtrueの時の値を、第三引数には条件がfalseの時の値を入れます。

実際にUPDATE文とかと絡めると

```SQL
UPDATE test SET testcolumn = IF(testcolumn > 0, 1,-1);
```
こんな書き方ができます。

## IF文
こちらはアプリケーションのコードのような書き方です。

```sql
-- 適当な値 n,m
IF n > m  THEN 1 
ELSE IF n = m THEN 0
ELSE -1
END IF
```

わかりやすい。　
更新処理などと絡めると

```sql
UPDATE test SET column1 = IF column1 > column2 THEN 1 
ELSE IF column1 = column2 THEN 0
ELSE -1
END IF
```

こんな感じになります。

# CASE文
CASE文はswitch文に相当する構文です。

```sql
-- 適当な値 n,m
CASE
    WHEN n > m THEN 1
    WHEN n = m THEN 0
    ELSE -1
END
```

適当なクエリと絡めると

```sql
SELECT column1, column2,
CASE
    WHEN column1 > column2 THEN 1
    WHEN column1 = column2 THEN 0
    ELSE -1
END AS value
FROM test;
```


# 最後に
分岐処理をSQLに寄せすぎると危ないですが、演算結果が負の値の時に... 　みたいな処理をアプリケーション側で仕込むのは面倒だったりするので、その時に使ってみてもいいかもしれないですね。
SQLで連想配列が使えないかを調査→JSONならできる（PostgreSQL）

#概要
ストアドファンクションの中で、テーブルのデータを取得して連想配列のように使いたい場面があったので調査。
データを1つのJSONにすれば、key指定でvalueが取れるようなので、JSON型を利用することにした。
※何となくもっと良い方法がありそうな気もするけど

##前提条件
* postgres9.5.x

#お試し用テーブルを準備

以下のようにwith句で一時テーブルをつくって試すことにする。

```sql
with tmp as ( 
	select * from (values 
		('a', 1), 
		('b', 2), 
		('c', 3), 
		('d', 4), 
		('e', 5)
	) as a(item1, item2)
) 
select * from tmp order by item1
;

-- 結果
 item1 | item2 
-------+-------
 a     |     1
 b     |     2
 c     |     3
 d     |     4
 e     |     5
(5 行)
```

#データをまるごとJSON形式にする

jsonb_object_aggで集約すると1つのJSONにできることがわかった。
JSONBの方が便利なのでJSONB型を使っている。

※集約については↓参照
https://www.postgresql.jp/document/9.5/html/functions-aggregate.html

```sql
-- with句は省略（上をみてください）
select
	jsonb_object_agg(item1, item2)
from tmp
;

-- 結果
             jsonb_object_agg             
------------------------------------------
 {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
(1 行)
```

#JSONのデータにkeyを指定してvalueを取得する

JSONB型に専用の機能があることがわかった。
「->」は、値をそのまま取得で、「->>」は、値をtextで取得。
psqlで実行した結果では同じ表示になる模様。

※JSON関数については↓参照
https://www.postgresql.jp/document/9.5/html/functions-json.html

```sql
-- with句は省略（上をみてください）
select
	jsonb_object_agg(item1, item2)->'c',
	jsonb_object_agg(item1, item2)->>'c'
from tmp
;

-- 結果
 ?column? | ?column? 
----------+----------
 3        | 3
(1 行)
```

#JSONのデータを更新する

「||」を使うとデータを更新できる。
既にあるkeyだと更新になるし、ない場合は追加される。
なお、jsonb_build_objectはJSONBを作る関数。

```sql
-- with句は省略（上をみてください）
select
	jsonb_object_agg(item1, item2) || jsonb_build_object('d', 40),
	jsonb_object_agg(item1, item2) || jsonb_build_object('f', 6)
from tmp
;

-- 結果
                 ?column?                  |                     ?column?                     
-------------------------------------------+--------------------------------------------------
 {"a": 1, "b": 2, "c": 3, "d": 40, "e": 5} | {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6}
(1 行)
```

#JSONをフォーマットする

jsonb_prettyというフォーマットする関数もある。

```sql
-- with句は省略（上をみてください）
select
	jsonb_pretty(jsonb_object_agg(item1, item2))
from tmp
;

-- 結果
 jsonb_pretty 
--------------
 {           +
     "a": 1, +
     "b": 2, +
     "c": 3, +
     "d": 4, +
     "e": 5  +
 }
(1 行)
```

以上。
RecyclerViewにサムネイルを表示する

RecyclerViewにネットから取得した画像を表示する方法を纏めます。

画像のキャッシュにglideを使うことで簡単に表示することができました（下記参照）。
https://developer.android.com/topic/performance/graphics/cache-bitmap?hl=ja

### サンプルコード
依存ライブラリにglideを追加します。

```gradle:build.gradle
dependencies {
    implementation "com.github.bumptech.glide:glide:4.11.0"
}
```

使い方は簡単でItem内に配置したImageViewに対して、
`Glide.with(context).load("https://xxxx").into(holder.imageView)`
と記載するだけです。

```kotlin:ListAdapter.kt
class ListAdapter (private val context: Context) : RecyclerView.Adapter<ListAdapter.ListAdapterHolder>() {
    private val inflater = LayoutInflater.from(context)

    class ListAdapterHolder(view: View) : RecyclerView.ViewHolder(view) {
        var textView: TextView = view.findViewById(R.id.text)
        var imageView: ImageView = view.findViewById(R.id.image)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListAdapterHolder {
        val view = inflater.inflate(R.layout.list_item, parent, false)
        return ListAdapterHolder(view)
    }

    override fun getItemCount(): Int {
        return 100
    }

    override fun onBindViewHolder(holder: ListAdapterHolder, position: Int) {
        holder.textView.text = "image ${position + 1}"
        Glide.with(context).load("https://xxxx").into(holder.imageView)
    }
}
```

```xml:list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listItem"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:focusable="true"
    android:clickable="true">

    <ImageView
        android:id="@+id/image"
        android:layout_gravity="center"
        android:layout_width="50dp"
        android:layout_height="wrap_content" />

    ...
</LinearLayout>
```

### 補足
単純に画像を取得するだけでなく、処理（ハッシュチェックなど）が必要な場合は、ModelLoaderを作成することで処理が行えます。
ModelLoaderについては、下記参照。
https://bumptech.github.io/glide/tut/custom-modelloader.html

Kotlinで実装する場合は、下記も参照。
https://bumptech.github.io/glide/doc/download-setup.html#kotlin
[React] ReactとNode.jsを使って何か作ってみる 20210130

#[React] ReactとNode.jsを使って何か作る 20210130

これまで、チュートリアルなどで勉強してきましたので、何か自分らしいものを作っていこうかなと思っています。

##とはいえ

とはいえ、一から作るとなるとどうしたらいいのか分からないので、likrさんの二つのチュートリアルを元にして作り始めてみました。

##本日までの成果

iwashi-stationという名前の自分用ホームページを作っています。

（チュートリアルを元にしていますので、今のところ意味もなく「人気のラーメン店」 「loading」と表示されています。

バックエンド側のデータベースをうまく作成できると良いのですが・・・。）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897250/9da3a664-9736-cc37-cfd9-0f4feab9c375.png" width="30%">
cordovaとvueでアプリを作る（導入）

私はアプリのネイティブ開発が長く、クロスプラットフォームに関しては最近Flutterを勉強しています。ですがWebの知識だけで簡単にアプリを制作したいという社内需要もあり今回はそのための環境作成を備忘録として残しておきます。
個人的には今cordovaを新しく勉強するくらいならちょっと学習は必要ですけどFlutter/React Nativeのほうがよっぽど開発が楽です。特にホットロード。。

前提: macOS Catalina / node.js / Xcodeはインストール済み
（node.jsはこの方の記事がとても参考になります。）
https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09

Cordovaはクロスプラットフォームアプリの開発環境です。
Vue.jsは学習コストが低いWebフレームワークです。
「Webの知識はあるけど、アプリはちょっと、、」という方におすすめします。

(1) Vue CLIとcordovaをインストール

```
$ npm install @vue/cli -g
$ npm install cordova -g
```

(2) プロジェクトフォルダを作成(今回はhelloという名前)

```
$ cordova create hello
$ cd hello
```

この段階でcordovaアプリができました。

(3) エミュレーターで確認
(デバッグはbrowser環境で行うのが楽なので一緒に追加)

```
$ cordova platform add browser ios
$ cordova emulate ios
```

Xcodeがインストールされていればエミュレータが起動しcordovaアイコンの画面が表示されます。

(4) Vue.jsを入れる
(色々な設定ができますが、とりあえず簡単に確認でき後々楽な組み合わせにしました)

```
$ vue create .

? Generate project in current directory > Y
? Please pick preset
 > Manually select features
? Check the features needed for your project
 > Babel
 > Router
 > Vuex
 > Linter / Formatter
? Use history mode for router > n
? Pick a linter / fomatter config > ESLint with error prevention only
? Pick additional lint features > Lint on save
? Where do you prefer placing config for ... > In dediated config files
? Save this as a preset for future projects > N
```

(5) 設定ファイルを作成
プロジェクトフォルダの直下にvue.config.jsを作成する

```vue.config.js

module.exports = {
 publicPath : './',
 outputDir : 'www',
}
```

(6) cordova/vueのアプリを起動
 
```
$ npm run build
$ cordova emulate ios
```

正しく手順を踏めていればエミュレータが起動しVueの初期画面が表示されます。


あとはWebアプリを構築するのと同じような感覚でアプリを制作できます。
Vue router/Vuexが標準で設定されているので画面の切り替えや情報の伝達が比較的簡単にできます。ただ私個人の肌感覚として細かいことろの調整や機能修正で苦労するイメージが強く、単純なアプリの製作に使うにとどめておくのが良いと思っています。
とりあえず簡単にできる環境構築の備忘録でした。
[Rails]画面表示される時間の正体

#時間の正体
![スクリーンショット 2021-01-30 19.37.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/faaf9441-ac6e-f76b-5cb2-8910a1b0705d.png)

画面左上の時間は、レンダリングに掛かった時間を意味しています。
表示したい場合、`rack-mini-profiler`というgemをインストールする必要があります。非表示にしたければ、`Gemfile`にてインストールの箇所をコメントアウトすれば大丈夫です。

#rack-mini-profilerインストール

```
gem 'rack-mini-profiler'
```
※Railsのバージョンによっては、デフォルトでGemfileにrack-mini-profilerが導入されています。

導入すると`Gemfile`に開発環境グループで追加されます。

```:Gemfile
group :development do
  // 省略
  gem 'rack-mini-profiler', '~> 2.0'
  // 省略
end
```

もし環境によって適用を変更したい場合は、こちらの記事を参考になります。
[Railsのパフォーマンス調査でrack-mini-profilerを使ってみました](https://techblog.gmo-ap.jp/2020/06/08/rack-mini-profiler/)
manimの作法 その34

#概要

manimの作法、調べてみた。
練習問題やってみた。

#練習問題

ルービックキューブを回せ。

#サンプルコード

```
class test(Rubik_Scene):
	CONFIG = {
		'order': 3,
	}
	def construct(self):
		self.wait()
		self.rotate_rubik_anim(1, 3, 1)
		self.rotate_rubik_anim(1, 1, -1)
		self.rotate_rubik_anim(0, 2, 1)
		self.rotate_rubik_anim(1, 3, 2)
		self.rotate_rubik_anim(2, 1, -2)
		self.rotate_rubik_anim([1, 2], 3, -2)
		self.rotate_rubik_anim(1, 1, -1)
		self.rotate_rubik_anim([2, 3], 2, 1)
		self.rotate_rubik_anim(1, 3, -1)
		self.wait()
		self.rotate_rubik_anim(1, 3, 1)
		self.rotate_rubik_anim([2, 3], 2, -1)
		self.rotate_rubik_anim(1, 1, 1)
		self.rotate_rubik_anim([1, 2], 3, 2)
		self.rotate_rubik_anim(2, 1, 2)
		self.rotate_rubik_anim(1, 3, -2)
		self.rotate_rubik_anim(0, 2, -1)
		self.rotate_rubik_anim(1, 1, 1)
		self.rotate_rubik_anim(1, 3, -1)
		self.wait()


```

#生成した動画

https://www.youtube.com/watch?v=qbEdVep8cyU

以上。
WSL(Windows Subsystem for Linux)で画像を用意したい

###はじめに
開発中にデフォルト表示用の画像が必要になったので画像を準備する方法のメモ。


##Windows上にダウンロードしてからWSL(Windows Subsystem for Linux)へ画像を転送する

Windows上の`C:\`には、Linux側では`/mnt/c`でアクセスできます。

Windows上のデスクトップに**sample.jpg**という画像を用意してLinux上の現在のディレクトリに保存する場合

```:ターミナル
// cp [オプション] コピー元 コピー先

$ cp /mnt/c/Users/ユーザー名/Desktop/sample.jpg .
```

## curlコマンドでWeb上から直接ダウンロードする

Web上の**foo.jpg**という画像をLinux上の現在のディレクトリに**sample.jpg**という名前で保存する

```:ターミナル
// curl 画像のURL　-o 保存したい名前

$ curl https://example.com/foo.jpg -o sample.jpg
```

※名前を指定したい場合-oは小文字であることに注意

##参考
[Windows Subsystem for Linux(WSL)でWindowsのファイルにアクセス](https://www.lisz-works.com/entry/wsl-windows-data-access)
[curlで保存先を指定してファイルをゲットだぜ!](https://whitypig.hatenadiary.org/entry/20130722/1374504857)
[curl コマンド 使い方メモ](https://qiita.com/yasuhiroki/items/a569d3371a66e365316f#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E5%87%BA%E5%8A%9B--o--o)
manimの作法 その33

#概要

manimの作法、調べてみた。
練習問題やってみた。

#練習問題

コッホ曲線を描け。

#サンプルコード


```
class test(LSystem):
	CONFIG = {
		'rules': {
			'F': 'F+F--F+F'
		},
		'iteration': 3,
		'start_loc': (FRAME_X_RADIUS - 0.3) * LEFT + DOWN,
		'step_time': 0.1,
		'length': 0.5
	}
	def construct(self):
		self.generate()
		self.draw()
		self.wait()


```

#生成した動画

https://www.youtube.com/watch?v=Co5IV9EYpWA

以上。
CentOS8 PostfixとDovecotでメール送受信(その2)


# その2 STARTTLSで暗号化 #
[前回の続きです。](https://qiita.com/someone-said-so/items/b14c66cf03c3a71d2d59)

次にSTARTTLSで暗号化をするところまでを設定します。

## Postfix ##

+ 1.SSL証明書

main.cfにSSLの記載があります。証明書は既に取得できていると仮定して以下のように編集します。
（例.certbotでSSL証明書を取得）

```main.cf
...
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/cert.pem
...
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
...
smtp_tls_CAfile = /etc/letsencrypt/live/mail.example.com/chain.pem
...
# (追加)
# STARTLS
smtpd_tls_received_header = yes
smtp_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_timeout = 3600s

# security
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
smtpd_sender_restrictions = reject_unknown_sender_domain
smtpd_helo_restrictions = reject_unknown_hostname
...
```

ここでは順にサーバー証明書/秘密鍵/中間CAを設定しています。
次にSTARTTLSと接続の制限に関する設定を記述します。

+ 2.CRAM-MD5認証

次に認証方式を変更します。plainよりcram-md5を優先します。
（あるいはplainを削除してもOK）

```/etc/sasl2/smtpd.conf 
pwcheck_method: auxprop
mech_list: cram-md5 login plain
```

## Dovecot ##

+ 1.SSL証明書

Postfixの時と同様に証明書を指定します。

```/etc/dovecot/conf.d/10-ssl.conf
...
# (前回はnoにしましたが今回はSTARTTLS用に設定し直す)
...
ssl = yes
...
ssl_cert = </etc/letsencrypt/live/mail.example.com/cert.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_ca = </etc/letsencrypt/live/mail.example.com/chain.pem
```

+ 2.CRAM-MD5認証

Postfixの時と同様に認証方式を変更します。

```/etc/dovecot/conf.d/10-auth.conf
...
# (前回はnoにしましたが今回はSTARTTLS用に設定し直す)
...
# (plainを許可しない場合はyesにする)
disable_plaintext_auth = yes
...
#（あるいはplainを削除してもOK）
auth_mechanisms = cram-md5 login plain
...
```

+ 3.ユーザーパスワードの再設定

passwd-fileにCRAM-MD5を追加します。

```
$ doveadm pw -s CRAM-MD5
(この後パスワードを入力)
```

パスワードをコピーしてファイルに追加します。

```/etc/dovecot/users. 
no-reply@example.com:{PLAIN}password:1001:1001::/home/no-reply:/sbin/nologin
no-reply@example.com:{CRAM-MD5}abcdefgh...:1001:1001::/home/no-reply:/sbin/nologin
```

あとはpostfixとdovecotを再起動して終了です。一度平文で動作することを確認できていればそんなに苦戦はしないはずです。
前回ではメーラーによっては平文の警告が出ていたこと思いますが、今回の作業でそれが消えているはずです。あと、ちょっと。。。
VirtualBox 起動できない時の対処法　MacOS

##はじめに
Linuxインストールをするために仮想環境のVirtualBoxを起動しようしましたが、うまくできなかったので、その時に試した事と解決方法をまとめてみました。
参考になれば、幸いです。


###1.起動を押すと以下のエラーのポップアップが表示される。

```
Implementation of the USB 2.0 controller not found!

Because the USB 2.0 controller state is part of the saved VM state, the VM cannot be started. To fix this problem, either install the 'Oracle VM VirtualBox Extension Pack' or disable USB 2.0 support in the VM settings.

Note! This error could also mean that an incompatible version of the 'Oracle VM VirtualBox Extension Pack' is installed (VERR_NOT_FOUND).

終了コード : NS_ERROR_FAILURE (0x80004005)
コンポーネント: ConsoleWrap
インターフェース: IConsole {872da645-4a9b-1727-bee2-5585105b9eed}
```
エラーメッセージをそのまま検索し、以下の記事を参考にさせていただきました。
https://askubuntu.com/questions/453393/virtualbox-fails-with-implementation-of-the-usb-2-0-controller-not-found-after

###2.USBをオフにする
####2.1VirtualBoxのマシンを右クリックする
####2.2設定を押し、ポートのUSBを無効にする

上記の方法を試し、起動ボタンを再度押すと、起動しました。

##今回のエラーで学んだこと
・エラー分をそのままコピーするだけでもエラーに関連している記事にたどり着くことはできるため、エラー文をしっかり読むことは大切だと感じました。
・今回参考にさせていただいた記事は海外のものでしたが、海外だからといって苦手意識を持たず、しっかりエラー内容と記事とを照らし合わしたり、日本語翻訳などの機能を使えば、有益な情報を見つけることができることがわかりました。
また、写真などを使用している場合が多いため、比較的わかりやすかった。
　　
以上、VirtualBox 起動できない時の対処法でした。
日本語版GPT2を動かそうと思ったら”ValueError: Can't load save_path when it is None.”が出た話


ＧＰＴ２の日本語版が出ていたと聞いたのでありがたく使わせてもらいました。使おうとした際エラーで詰まった点を記載しておきます。
https://github.com/tanreinama/gpt2-japanese/blob/master/README.md　
# 環境
python 3.7.9
tensorflow-gpu 2.4.0
仮想環境：pipenv
Windows10
GPU : GeForce RTX3070

# 結論
modelで指定しているpathがずれている。
gpt2-japanese\gpt2-generate.py内の113行目、

```python:gpt2-generate.py
ckpt = tf.train.latest_checkpoint(args.model) 
```
を

```python:gpt2-generate.py
ckpt = tf.train.latest_checkpoint(".\gpt2ja-medium.tar\gpt2ja-medium") 
```
に書き換える。

この際のディレクトリ構造は以下の通り

```

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2021/01/30     10:32                .github
d-----        2021/01/30     17:34                gpt2ja-medium.tar
d-----        2021/01/30     10:32                report
-a----        2021/01/30     10:32         189183 emoji.json
-a----        2021/01/30     10:32           6317 encode_bpe.py
-a----        2021/01/30     18:27           3893 gpt2-generate.py
-a----        2021/01/30     10:32           4375 gpt2-score.py
-a----        2021/01/30     10:32           2075 gpt2-transform.py
-a----        2021/01/30     10:32         128339 ja-bpe.txt
-a----        2021/01/30     10:32           1067 LICENSE
-a----        2021/01/30     10:32           7285 model.py
-a----        2021/01/30     10:32           9129 README.md
-a----        2021/01/30     10:32             29 requirements.txt
-a----        2021/01/30     10:32           8830 run_finetune.py
-a----        2021/01/30     10:32           4781 sampling.py
-a----        2021/01/30     10:32            553 special_thanks.txt
```

gpt2ja-medium.tar\gpt2ja-medium　内にモデルがある様子。

# 詰まった点について
windows10であったため、tar コマンドが使えず、wgetした後の「tar xvfj gpt2ja-medium.tar.bz2」でbz2を展開できなかった。
従って解凍ソフト、LhaForgeを使用した。
https://www.lzh-zip.com/freesoft/free108zukai.html　

これでひとまずbz2形式をwindowsで展開することに成功。

## ディレクトリ配置云々
そもそもこのエラー、解凍したあとに適当にここだろと思う場所に配置したのが原因っぽい。

参考になったサイト
「Trained tensorflow model moved to another directory cannot be loaded」:
https://www.reddit.com/r/tensorflow/comments/bg2rte/trained_tensorflow_model_moved_to_another/　

「ArgumentParserの使い方を簡単にまとめた」：
https://qiita.com/kzkadc/items/e4fc7bc9c003de1eb6d0　

### これで最後に試してみる。
twitter でバズってたツイートの続きを生成してみよう。

```
...\gpt2-japanese> python gpt2-generate.py --context="""
>> 男に誘われた時の判別表つくっといたよ
>>
>> 宅飲みヤリモク
>> 飲み屋ヤリモク
>> 焼肉ヤリモク
>> カラオケヤリモク
>> ドライブヤリモク
>> ゲーセン(UFOキャッチャー、プリクラなど)ヤリモク
>> 
>> 競技プログラミング圧倒的に信用できる
>> """
```
出力

```
========

AIが発達しすぎた時代の世界
1080以上プログラミングできる人すげー!
「今は、この人が最適ですね」って
いつも思ってたら「今は、この人がすきだ」の間違いだと思うよ、

IoT(インタラクティブ・モノの自動制御)が発達した

クラウドサインを超えた時代の世界
クラウドサインの進化する意味がわかるよ


========

ゲームプログラミング、インキャリ(遊び方がわからないけどなんか遊んでみる、みたいな)
ゲームクリエイター

遊び方は?
なんだろう、「FEATURE」みたいな??ゲームシステムなんだろうな(笑)

これを利用してなにか動きをつけることがあるでしょうか?


========


========
人が何人いるかわからない

ゲーム内デートが定番
キャリアを選択
ゲームに潜り込む
その他のスポッチャやゲーム機を借りる




競技プログラミングが当たり前の人にスポーツは有害

スポーツが嫌いな人は競技プログラミングをやりたがる
競技プログラミングが嫌いな人は競技プログラミングにハマる

競技プログラミングにハマれば、競技プログラミングを選ぶ

競技プログラミングが流行らないのも、競技プログラミングそのものを否定している
```

ちゃんと動いてますね。以上です。もっといろいろ遊んでみたいと思います。
同じような状態の方の参考になれば幸いです。
オープンソースのシェーダーコンパイラ

オープンソースのシェーダーコンパイラについて調べてみました。


## DirectXShaderCompiler
マイクロソフトのDirectX用シェーダーコンパイラ。2017年にオープンソースで公開された。LLVM/Clangを利用。

* 入力 HLSL
* 出力 DXIL
* https://github.com/microsoft/DirectXShaderCompiler

## shaderc
GoogleのVulkan用シェーダーコンパイラ

* 入力 GLSL, HLSL
* 出力 SPIR-V
* https://github.com/google/shaderc

## Mesa3D

Mesa3D/Mesa に含まれるシェーダーコンパイラ
* https://github.com/mesa3d/mesa/

```
ACO
 AMDのGPU用 Vulveがファンディングします。出力 AMD
nouveau
 Nvidiea用
boroadcom
 RaspberryPiに搭載されているVideoCore4/6用 出力 VIR
lima
 ARM Mali 4xx用
panfrost
 ARM Mali Txx Gxx用
etnaviv
 Vivante GCxx用
freedreno
 Qualcomm Aderno用
zink
  Vulkan用
microsoft
  DXIL用
```

# クロスコンパイラ

## glslang
KhronosのGLSLリファレンス実装

* GLSL/ESSL to AST
* HLSL to AST
* AST to SPIR-V
* https://github.com/KhronosGroup/glslang

## clspv
GoogleのOpenCLコンパイラプロトタイプ

* 入力 OpenCL
* 出力 SPIR-V
* https://github.com/google/clspv

## Kyte
独自に定義したシェーダー言語 Kyteのコンパイラ

* 入力 Kyte
* 出力 SPIR-V
* https://github.com/MissingBitStudios/kyte

# Lava
SLを生成するライブラリ

* 入力 C++
* 出力 SPIR-V, GLSL, ESSL, HLSL
* https://github.com/mknejp/lava


# UAM - deko3d shader compiler
Nintendo Switch用シェーダーコンパイラ。
Mesa3D nouveauの派生。

* 入力 GLSL
* 出力 DEKO3D
* https://github.com/devkitPro/uam

### コメント

最近はMesa3Dのソースコードを読んだりしています。

シェーダープログラムがどうやってGPUで実行されるかちょっと分かってきました。
Next.jsでブログを作りました

(この記事は自分のブログにて公開した記事をQiitaにも投稿してみようかなーと言う軽い気持ちで投稿した物です。こいつ面白いなと思っていただけたらtwitterか僕のブログに遊びきていただけると嬉しいです。
ブログは[こちら](https://my-blog-woad.vercel.app/)、Twitterは[こちら](https://mobile.twitter.com/shou_study))

Next.js で JAMStack ブログを作ってみました。

使った技術としては

- React Hooks
- Next.js

デプロイ先は Vercel で、Google Analytics も導入してみました。

ここからは作る際に参考にしたサイトや、詰まったところ、工夫したところをつらつら書いていきたいなと思います！！

## 実際に作ってみる

まず作る際に参考にしたサイトは[こちら](https://gotohayato.com/content/517/)です。

「HTML / CSS / JavaScript / Node / React をある程度知っていて Git が使える方」を想定しているようなので、ある程度の知識を持っている方は是非やってみて下さい。

### Next.jsとは

Next.jsとは、面倒な設定なしで高いDXとUXを提供することができるReactのフレームワークです。

具体的に言うと

- パフォーマンスとSEOのためにSSGやSSRをすることができる。
- webpackやBabelの設定を自動で行ってくれる。
- 直感的なファイルベースのルーティングシステム
- 画像を自動で最適化してくれるImageコンポーネント

など。控えめに言って、最高です。

### ブログを作る手順

1. プロジェクトの作成
2. ページの作成
3. デプロイの準備
4. デプロイ

プロジェクトの作成に関しては[公式チュートリアル](https://nextjs.org/learn/basics/create-nextjs-app/setup)を参考にするのが1番手っ取り早いと思います。
ページの作成に関しては、僕には説明できるほどの知識はまだないので、先ほど1番最初に紹介したサイトを参考にしながら自分好みにスタイリングしながら楽しんでみて下さい。

デプロイに関しても同様に2つのサイトを見ながらやってみて下さい。ただ注意点として、公式チュートリアルのままデプロイするとページの言語がデフォルトの英語に設定されてしまっているので、Google翻訳がでしゃばって変なことになったりもするので、_document.jsファイルを作成して、設定を上書きして下さい。この作業も最初に紹介したサイトに詳しい方法は書いてあります。

### 詰まったところ

カテゴリー別投稿機能を作成したところ、参考にしていたサイトの通りに作っただけだと、全記事一覧ページにカテゴリー別の投稿が反映されない問題が発生しました。

そこでスプレッド構文を使ってカテゴリー別でとってきた記事の情報が入った配列を一つに結合させ、それを表示する。と言う手法で解決しました。

### 工夫したところ

少しでもサイトの表示速度を上げるために画像のフォーマットをjpegからWebPに変え、Imageコンポーネントを使用することで、[PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/)での点数を大きくあげることに成功しました。

WebPとは、Googleが開発した次世代画像フォーマットのことです。webに最適化されているらしくjpgやpngよりも軽いので、サイトスピードの改善に繋がりました。
実際にやってみたところ、元の画像のサイズが64KBだったのに対し、5KBまで軽くなりました。

サイト速度の向上を目指すのであれば、絶対にやっておくべきだと思います。

### 改善したいこと
現状lifeカテゴリーだけ挙動がおかしいところがあるので、直していきたいです。

あとは今のところスタイリングが適当で、見づらいところがあるなーと個人的に思うのでそこもボチボチ改善していきたいですね。

## 感想

やってみた感想としては、慣れれば WordPress でサイトを作るより**圧倒的に楽ができるな**と感じました。

プログラミング学習を始めてからずっと JavaScript メインに勉強してきたので、WordPress 化するために慣れない PHP を書くよりも JavaScript メインで開発できてとても楽しかったです！！

記事の更新もマークダウンで出来るので、結構楽だなと思います。

サーバのことを気にせずに脳死で高速なサイトを作れますし、ある程度Reactの学習をした方などにはぜひ一度やってみて欲しいです！

正直おバカ高校生にもできたので、真面目に勉強している方なら簡単だと思いますw

<br>

それでは頑張ってみて下さい！！ここまで読んでくださり、ありがとうございました！！！
M5StackにPS4コントローラをBluetooth接続

PS4コントローラとM5Stack接続に関するノウハウの備忘録。
基本
 https://github.com/aed3/PS4-esp32
の説明内容そのままです。

M5Stack(ESP32）のbluetooth MACアドレスの参照の仕方、MACアドレスツールの使い方、全体の流れは [こちら](http://gijin77.blog.jp/archives/21966552.html) の記事を参考にさせていただきました。（大いに助かりました。ありがとうございました）





#手順

①下記をM5Stackで実行してM5StackのBluetoothのMACアドレスをメモする。
（シリアルツールを開いて、Bluetooth Mac Address⇒赤のぐりぐり部）

```
void setup(void) {
  Serial.begin(115200);
  uint8_t bt_mac[6];
  esp_read_mac(bt_mac, ESP_MAC_BT);
  Serial.printf("Bluetooth Mac Address => %02X:%02X:%02X:%02X:%02X:%02X\r\n", bt_mac[0], bt_mac[1], bt_mac[2], bt_mac[3], bt_mac[4], bt_mac[5]);
}

void loop() {
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/daa7e4a4-daa9-6431-8211-25a18fb5ef7b.png)

②DS4にMACアドレス書込み
[sixaxispairtool](https://sixaxispairtool.software.informer.com/download/) からをダウンロードしてインストール[2021.01.30]
PS4コントローラをUSBでパソコンと接続→sixaxispairtool を起動

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/c083fd7e-8aaf-df20-9ad9-70663bce8582.png)

③M5StackにDS4をBluetootu接続
https://github.com/aed3/PS4-esp32
PS4-esp32ライブラリをダウンロード追加

```
cd （Arduinoライブラリ先）
git clone https://github.com/aed3/PS4-esp32.git
```

スケッチ例→PS4Controller→PS4ReceiveData　を開き下記、PS4.begin("xx:xx:xx:xx:xx:xx"); に①でメモしたMACアドレスを記入

```
#include <PS4Controller.h>
#include <M5Stack.h>


void setup()
{

    M5.begin();
    M5.Power.begin();

    Serial.begin(115200);
    PS4.begin("xx:xx:xx:xx:xx:xx");       //<=ここにアドレスを入れる
    Serial.println("Ready.");
    
}

（省略）
```

書き込んだ後コントローラのPSボタンを押すとリンクする。その他詳細はライブラリのスケッチ例参照。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/7ae06bf7-0d25-de98-7825-b22c3c4b2d58.png)



(2021.03.31追記）
<font color="Red">ESP32ライブラリが1.0.5以降だとエラーが出るようです。</font>
最新でなくても問題ない場合は1.0.4に戻すことで解消できます。
↑
(2022.05.24)
以前はエラーが出て1.0.4に戻す必要がありましたが、今日現在2.0.3では解消されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/60609c80-c23f-4bb5-bca1-b1462e277166.png)


以上参考になれば。　

※役に立ったら　「いいね」　よろしくお願いします。
マインドマップ Windows＆iPhoneで最適アプリ

# はじめに
プログラミングに関する思考の整理にマインドマップを使うことがあるのだが、いままではiPhoneでMindNodeを使っていた。
基本的にiPhoneは小さい方が好みなので、iPhoneSEを使っているが、マインドマップは大きな画面で作業したくなってきた。
自宅PCはWindowsなので、MindNodeが使えない。
もしMacならMindNode一択、というくらいサクサクで必要最低限の機能がそろっている完璧なアプリ。。

いろいろ探したがようやく決まったのでここにまとめる。

# 比較検討

|                                 | MindNode   | SimpleMind          | Xmind/MindMeister/<br />Coggle/Mindomo/Miro|
| ------------------------------- | ---------- | ------------------- | ------------------- |
| 無料 もしくは 買い切り          | △ ※1          |〇<br />(価格は各プラットフォーム参照)| サブスク |
| Windowsで使える                 | × (Macのみ) | 〇 (約3879円/€27.49[税込])|                   |
| iPhoneアプリがある              | 〇         | 〇 (1100円)          |                   |
| Androidアプリがある              | ×         | 〇 (880円)           |                   |
| WindowsとiPhoneで同期(クラウド) | ×          | 〇                  |                   |
| 動作が軽い                      | ◎          | 〇                  |                   |
| Webブラウザで使える ※2             | ×          | ×                   |                    |

※1 バージョンが変わるたびに追加課金？
※2 WebブラウザはChromebookでも作業できたらいいなと思ったおまけ程度の要件。SimpleMindのAndroidアプリを入れればChromebookでも使用可。

# 結論
SimpleMindを、Googleドライブ共有で使うことにした。
https://simplemind.eu/

iPhoneアプリでGoogleドライブをつかうためには、1100円の課金が必要だが、買い切りなので問題ない。
いままでのMindNodeのデータも、FreeMind形式に出力することで、SimpleMindに取り込める。

Windowsで使うときは標準のフォントArialだとちょっといまいちなので、[スタイル]－[フォント変更]で別のものにした方が見栄えが良い。
refileを使用した複数画像投稿機能を作ろう

##環境
Rails 5.2.4

##前提
refileを導入していること

##model製作
まず、実装するためのmodelを作りましょう。

```
$ rails g model post title:string comment:text
$ rails g model post_image product_id:string image_id:integer image_id:string
```

まず、複数投稿された画像を一纏めにする親のproductモデルと
複数投稿された画像を保存する子のproduct_imageモデルを作ります。
userと結び付けたい場合は、postモデルを作る際にuser_id:integerを追加してください。

次にモデル同士のアソシエーションを作ります。

```ruby:models/post.rb
has_many :post_images, dependent: :destroy
accepts_attachments_for :post_images, attachment: :image
```

```ruby:models/post_image.rb
belongs_to :post
```

##controller編集

```ruby:controllers/posts_controller
class PostsController < ApplicationController

...

 private

  def hobby_image_params
    params.require(:post).permit(:title, :comment, post_images_images: [])
  end

end
```
複数画像を投稿するために、パラメータを配列で渡してあげる必要があるので、配列[]で渡します。
post_imagesのimagesでpost_images_imagesとなります。

##投稿のview
```php:views/posts/new.html.erb
<%= form_with model: @post, local:true do |f| %>
 <%= f.attachment_field :post_images_images, multiple: true %>
 <%= f.text.area :title %>
 <%= f.text_area :comment %>
 <%= f.submit '投稿' %>
<% end %>
```
複数投稿をするので、multiple: trueを2行目に追加します。

##投稿を表示させるview

```php:views/posts/show.html.erb
<div>
 <% posts.post_images.each do |image| %>
  <%= attachment_image_tag image, :image, size: "500x500" %>
 <% end %>
</div>
```

以上で実装は完了です。
投稿してみて、エラーがないかを確認してみてください。

##終わりに

ここまで見て頂きありがとうございました。
間違いなどありましたら、ご指摘お願い致します。