OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】動画からサムネイル画像を切り出してUIImageとして返す

```swift:ViewController.swift
func thumnailImageForFileUrl(fileUrl: URL) -> UIImage? {
        let asset = AVAsset(url: fileUrl)

        let imageGenerator = AVAssetImageGenerator(asset: asset)

        do {
            let thumnailCGImage = try imageGenerator.copyCGImage(at: CMTimeMake(value: 1,timescale: 60), actualTime: nil)
            print("サムネイルの切り取り成功！")
            return UIImage(cgImage: thumnailCGImage, scale: 0, orientation: .right)
        }catch let err{
            print("エラー\(err)")
        }
        return nil
    }
```

```swift:AVAsset+.swift
import AVFoundation
import AVKit

extension AVAsset {
    
    func generateThumbnail(completion: @escaping (UIImage?) -> Void) {
        DispatchQueue.global().async {
            let imageGenerator = AVAssetImageGenerator(asset: self)
            let time = CMTime(seconds: 0.0, preferredTimescale: 600)
            let times = [NSValue(time: time)]
            imageGenerator.generateCGImagesAsynchronously(forTimes: times, completionHandler: { _, image, _, _, _ in
                if let image = image {
                    completion(UIImage(cgImage: image, scale: 0, orientation: .right))
                } else {
                    completion(nil)
                }
            })
        }
    }
}

```
fileUrlに動画のURLを渡すとサムネイルを生成して返してくれます。
pythonとyoutube-dlで簡単にmp4を部分ダウンロードする！

##目的
pythonとyoutube-dlで簡単にmp4を`部分ダウンロード`する！

##環境
```bash
$python3 --version
Python 3.7.3
```

## mkv,mp4変換のためのffmpegをインストールする
```bash
$brew install ffmpeg
```

## DLフォルダ作成
```bash
$mkdir mp4-download
```

## Python用仮想環境
```bash
$cd mp4-download
$python3 -m venv venv
$source venv/bin/activate
```

## youtube-dlをpipでインストール
```bash
$pip install youtube-dl
```

## 動画(mkv)を`部分ダウンロード`
```bash
$ ffmpeg $(youtube-dl -g 'https://www.youtube.com/watch?v=Nyg2qysqgpg' | sed "s/.*/-ss 03:55:00 -i &/") -t 00:01:00 -c copy out.mkv
```

## mkvをmp4に変換
```bash
$ for f in *.mkv;do ffmpeg -i "$f" -c:v copy -c:a aac -b:a 256k -strict -2 "${f%mkv}mp4";done
```

##ダウンロード結果確認
```
$ open out.mp4
```


----
よかったよかった
WSL2でCrosstool-NGをインストール

#目的
「BareMetalで遊ぶRaspberryPi」の環境構築で詰まったため備忘録

#環境
・WSL2 (Ubuntu-20.04)
・windows10 (ver2004)

#手順
```
$sudo git clone https://github.com/crosstool-ng/crosstool-ng
$./bootstrap
$sudo ./configure --prefix=(任意のPATH)
$sudo make
$sudo make install
```

#注意点
・case-sensitive
　・WSL上ではcase-sensitive関係でct-ng buildできないことがある
　・解決策はコマンドプロンプト上で以下のコマンドでcase-sensitiveを有効化

```
$fsutil set fsutil file setCaseSensitiveInfo (パス) enable
```

・build中にYou must NOT be root to run crosstool-NGとなる問題
　・以下、参考資料②「You must NOT be root to run crosstool-NG」を参照

#参考

①「BareMetalで遊ぶRaspberryPi」
https://tatsu-zine.com/books/raspi-bm

②How to solve “You must NOT be root to run crosstool-NG” when using ct-ng?
https://stackoverflow.com/questions/17466017/how-to-solve-you-must-not-be-root-to-run-crosstool-ng-when-using-ct-ng
【Swift】CoreLocationで現在地取得

CoreLocationを使って現在地の緯度経度を一瞬取得するためのextensionです。
```swift:ViewController.swift
import CoreLocation
```

```swift:Viewcontroller.swift
override func viewDidLoad() {
        super.viewDidLoad()

        //CLLocationManagerDelegateのセットアップ
        locationManager.delegate = self
        //位置情報使ってもいい？
        locationManager.requestWhenInUseAuthorization()
        
    }
```

```swift:Viewcontroller.swift
extension ViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            
            locationManager.stopUpdatingLocation()
            var lat = location.coordinate.latitude
            var lon = location.coordinate.longitude
            //緯度・経度を渡す
            parseLocation(lat: lat, lon: lon)

        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error)
    }
    
    
}
```

```swift:Viewcontroller.swift
@IBAction func buttonPressed(_ sender: UIButton) {
        //位置情報の取得開始
        locationManager.startUpdatingLocation()
    }
```
【Swift】Firebase Authを使って爆速でログイン機能を作るためのスニペット

firebaseでユーザー登録・ログイン機能を爆速で作るsnippetです。

##ユーザー登録

●Firebaseの公式ドキュメントはこちら
https://firebase.google.com/docs/auth/web/manage-users?hl=ja



```swift:RegisterViewController.swift
import UIKit
import Firebase

class RegisterViewController: UIViewController {

    @IBOutlet weak var emailTextfield: UITextField!
    @IBOutlet weak var passwordTextfield: UITextField!
    
    @IBAction func registerPressed(_ sender: UIButton) {
        //ユーザーを生成
        if let email = emailTextfield.text, let password = passwordTextfield.text {
            Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
                if let e = error {
                    //エラー分をローカルの言語で表示
                    print(e.localizedDescription)
                } else {
                    //ログイン後の画面に遷移
                    self.performSegue(withIdentifier: "segue identifier" , sender: self)
                }
            }
          
        }
        
    }
    
}

```

##ログイン

```swift:LoginViewController.swift
import UIKit
import Firebase

class LoginViewController: UIViewController {

    @IBOutlet weak var emailTextfield: UITextField!
    @IBOutlet weak var passwordTextfield: UITextField!
    

    @IBAction func loginPressed(_ sender: UIButton) {
        //ユーザー認証
        if let email = emailTextfield.text, let password = passwordTextfield.text {
            Auth.auth().signIn(withEmail: email, password: password) { authResult, error in
                if let e = error {
                    print(e.localizedDescription)
                } else {
                    self.performSegue(withIdentifier: "segue identifier", sender: self)
                }
              // ...
            }
        }
        
    }
    
}

```

##ログアウト
```swift:LogoutViewController.swift
import Firebase
//中略

@IBAction func logOutPressed(_ sender: UIBarButtonItem) {
        
            let firebaseAuth = Auth.auth()
        do {
          try firebaseAuth.signOut()
            //navigationControllerの先頭に遷移させる
            navigationController?.popToRootViewController(animated: true)
            
        } catch let signOutError as NSError {
          print ("Error signing out: %@", signOutError)
        }
        
    }
```
Docker memo

ロケールを日本語にする

```
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        language-pack-ja && \
    apt-get clean && \
    update-locale LANG=ja_JP.UTF-8
ENV LANG=ja_JP.UTF-8
ENV LANGUAGE=ja_JP:ja
```

--no-install-recommends : 必須ではない関連パッケージは入れない
--git clean: パッケージをインストールするために拾ってきたアーカイブファイル（ *.tar.gz とか）を削除
Mac OS Catalinaでnvmを利用してnode.jsのインストールができない

#症状
nvmを利用してnode.jsのインストールを行うと下記のエラーが出る。

```
$ nvm install stable
mkdir: /alias/lts: Read-only file system
mkdir: /alias/lts: Read-only file system
mkdir: /alias/lts: Read-only file system
Downloading and installing node v14.1.0...
mkdir: /.cache/bin/node-v14.1.0-darwin-x64/files: Read-only file system
Binary download from https://nodejs.org/dist/v14.1.0/node-v14.1.0.tar.xz failed, trying source.
------------中略------------
grep: /.cache/src/node-v14.1.0/node-v14.1.0.tar.xz: No such file or directory
Provided file to checksum does not exist.
```
#環境
Mac OS Catalina v10.15.4
nvm v0.35.3

#原因
Catalinaの仕様であるシステム整合性保護（SIP）が原因であると思われる。
具体的にはここ。

```
mkdir: /.cache/bin/node-v14.1.0-darwin-x64/files: Read-only file system
```
インストール時にルート直下の/.cacheディレクトリを使用しようとしているが、CatalinaではSIPによりルート直下はRead-Onlyとのこと。
[SIPを無効にする方法](https://support.intego.com/hc/ja/articles/115003523252-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E6%95%B4%E5%90%88%E6%80%A7%E4%BF%9D%E8%AD%B7-System-Integrity-Protection-SIP-%E3%81%AE%E7%84%A1%E5%8A%B9%E5%8C%96)もあるようですが、再起動時にまた有効になるようですね。

これを機にnodebrewに移行しようと思います。
解決法もありそうですが、私はとりあえず諦めました。
Mac × Vagrant ： RubyEncoder Loader - Incompatible loader version.

Mac と Vagrant でフォルダ共有するため、プラグイン「vagrant-vbguest」をインストール後、Vagrant をリロードしようとすると、RubyEncoder のエラーが発生した。
無視して vagrant up を試みたが、同様の RubyEncoder が発生した。

## 環境

* maxOS High Sierra (version 10.13.6)
* VirtualBox 5.2.6 r120293
* Vagrant 2.0.1

## エラー内容

```
$ vagrant reload
Vagrant failed to initialize at a very early stage:

The plugins failed to load properly. The error message given is
shown below.

RubyEncoder Loader - Incompatible loader version. This protected script has been encoded with a newer version of RubyEncoder. Please download and install the latest loaders http://www.rubyencoder.com/loaders/ Error code [19]
```

## 解決方法

1. [Ruby Encoder](http://www.rubyencoder.com/loaders.html)のページから MacOS 用 zip ファイルをダウンロードする。
2. /Users/<ユーザ名>/.vagrant.d/rgloader を zipファイルの内容で上書きする（インストール先によりパスは変わるかも）。

備考：zip ファイル内の loader.rb の作成日は 2019/11/18 でした。

## 参考

フォルダ共有については、以下サイトを参考にさせていただきました。
[Vagrant ファイル共有　決定版](https://qiita.com/yusk24/items/96a0000716fed7ca62f6)
DockerでTomcatのサンプルアプリをデプロイする

# 実現したこと
Dockerの公式tomcatイメージをもとに、tomcatのサンプルアプリを含むイメージをビルドしてコンテナをデプロイする

# 環境
Windows 10 Home 1903
Docker Toolbox version 19.03.1 

# 手順
##1.Docker Toolboxをインストールして起動する
以下からダウンロードしてインストールする
https://docs.docker.com/toolbox/toolbox_install_windows/

##2.Dockerfileを作って、作業用フォルダに格納する
ここではDocker Hubにある公式のtomcatイメージをpullしてくる。tomcatのサンプルアプリをダウンロードしてくるために、wgetを事前にインストールして、tomcatの公式サイトからダウンロード。curlでもダウンロードできると思われるが、練習のためwgetをあえてダウンロード。

```sh:Dockerfile
FROM tomcat:8.5.54-jdk11-adoptopenjdk-hotspot
RUN apt-get update && apt-get install -y wget
WORKDIR /usr/local/tomcat/webapps/
RUN wget http://tomcat.apache.org/tomcat-8.5-doc/appdev/sample/sample.war
```

##3.イメージをビルドする
以下、hogehogeはDockerfileを作成した作業用フォルダ。ビルドすることで、tomcatのサンプルアプリを搭載したtomcat:sampleというイメージが作られる。

```sh:Terminal
cd hogehoge
docker build -t tomcat:sample .
```

##4.コンテナを起動してブラウザで確認
ターミナルから先ほどビルドしたtomcat:sampleイメージを使ってtomcat_sampleという名前のコンテナを起動する。Tomcat側のポートは8080で起動しており、そこに対してホスト側からも8080でアクセスできるようにする。

```sh:Terminal
docker run --name tomcat_sample -p 8080:8080 -d tomcat:sample
```

![cap01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517010/309df0d6-74e3-cf8d-e21d-c0c63d6287cd.png)

アクセスするIPアドレスはTerminal起動時に表示されるdefalutのホストマシンのIPアドレスを指定する。わからなければ、以下のコマンドを打つことで確認できる。(この構成の場合、localhostではアクセスができない)

```sh:Terminal
docker-machine ip
```
[memo] Flask Configuration

Flaskは自由度が高い分、もっとも良い設定が施されてなくても動かす分には問題がないです。
しかし、環境が変わったり新規作開発がにスムージに行うためにはきちんとプロセスを決めたほうが得策です。

### 気になるところ
- PythonのPath
- development/production
- debug mode
- logの出力先
 

### configuration

- export FLASK_ENV=development
- config.py

```
class Development(object):
    DEBUG = True
    DB_URI = "開発環境の設定"

class Testing(object):
    TESTING = True
    DB_URI = "テスト環境の設定"

class Production(object):
    DB_URI = "本番環境の設定"
```



##参考
- [いまさらながら Flask についてまとめる 〜Configuration〜](https://www.subarunari.com/entry/2018/03/17/%E3%81%84%E3%81%BE%E3%81%95%E3%82%89%E3%81%AA%E3%81%8C%E3%82%89_Flask_%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%BE%E3%81%A8%E3%82%81%E3%82%8B_%E3%80%9CConfiguration%E3%80%9C)
「memo」VscodeでFlaskをremote debugする方法

### リモート接続の拡張機能の種類
- SSH
- Containers (今回はこれを使う)
- WSL

### 拡張機能は
- Remote - Containersをインストールしておきます。


### リモート接続設定
- 「remote-containers: Add Development Container Configuration Files...」を選択
[image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72076/bdaf6857-6ff0-db02-46f6-d47e08425888.png)

- 「Docker in Docker Compiose debian:9」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72076/758e2066-6b0b-80df-03a1-f722fea37ec4.png)

- ここまで進めると.devcontainerフォルダーと３つのファイルが生成される
    - .devcontainer
        - devcontainer.json
        - docker-compose.yml
        - Dockerfile

### docker compose
- devcontainer.jsonを編集
    - "ms-azuretools.vscode-docker"　⇒　"ms-python.python"

```
{
	"name": "Flask Remote Sample",
	"dockerComposeFile": "docker-compose.yml",
	"service": "web_flask",
	"workspaceFolder": "/projects",
	"extensions": [
	  "ms-python.python"
	]
}
```


### 動かして見る
- 「Remote-Containers: Open Folders in Container...」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72076/03062fc3-7e24-fad2-ca9c-aef7cfc3fa6a.png)


### 
- 

### 
- 



## 参考
[VS CodeのRemote DevelopmentでFlaskアプリをデバッグしてみた](https://dev.classmethod.jp/server-side/python/vscode-remote-development-flask/)
[Flask Tutorial in Visual Studio Code](https://code.visualstudio.com/docs/python/tutorial-flask#_run-the-app-in-the-debugger)
[microsoft/python-sample-vscode-flask-tutorial
](https://github.com/Microsoft/python-sample-vscode-flask-tutorial)

docker.for.mac.localhost
Flaskの例外処理

Flaskで発生するエラーを上手く処理する方法

- エラー種類
    - AssertionError
    - AttributeError
    - TypeError
    - ValueError

- Exception種類
    - HTTPException

# @mod.errorhandler(InvalidUsage)
mod.register_error_handler(InvalidUsage, handle_invalid_usage)


Ref:
[Implementing API Exceptions](http://flask.pocoo.org/docs/1.0/patterns/apierrors/)
[Application Errors](
http://flask.pocoo.org/docs/1.0/errorhandling/)
[memo] git


## submoduleの追加
  - git submodule add https://github.com/twbs/bootstrap.git bootstrap

## submoduleを最初に取り込む
- ローカルの設定を初期化して、プロジェクトからのデータを取得する
  - git submodule init
  - git submodule update

## main project, submoduleを同時に取り込む (--recursive)
  - git clone --recursive https:///xxxxx

## submoduleの更新を取得しmergeする。
- git submodule update --remote --merge



## Gitが管理されているファイルのローカル変更を無視する。（サーバーで設定ファイルをいじったりする時に便利）
```
git update-index --skip-worktree path/to/file
git ls-files -v | grep ^S
```

## reset url
```
git remote set-url origin https://ユーザ名:アクセストークン@github.com/ユーザ名/リポジトリ名.git/
git remote -v
```

## 未使用なコンテナ, イメージ, ネットワークを一括削除
```
docker system prune --volumes
```
[devise]アカウントの新規登録の際に権限を自動的に設定する[Rails]

# 3行で分かる本記事の概要
- アカウントの新規登録の際にメールアドレスのドメイン名に応じた権限を自動的に設定した。
- permissionモデルを作成し、userモデルとアソシエーションを組んだ。
- registrations_controller.rbのcreateに処理を追加した。

---

# 動機
筆者は、現在Railsの勉強のためにWebアプリケーションを制作しています。
そのアプリケーションは学内で利用することを想定しており、学内の関係者かそれ以外かの区別をどのようにつけるか、
それらのアカウントの権限をどのように設定しようか悩んでいました。
そこで、学生及び学内関係者のメールアドレスの独自なドメイン名を利用して権限を設定したいと考えました。

# 環境
|||
|:--:|:--:|
|Ruby|2.6.5|
|Rails|5.2.4.2|
|devise|4.7.1|

# 方針
1 ユーザ名、メールアドレス、パスワードを入力して、アカウントを新規登録させる
2 入力させたメールアドレスの中に既定のドメイン名が含まれているかを比較する
3-A 含まれていれば、そのドメイン名に応じた権限を付与させる
3-B 含まれていなければ、最低限の権限を付与させる

# 実装
コマンドを用いて権限テーブルを作成する

```bash:cmd
rails g model Permission A_flag:boolean B_flag:boolean C_flag:boolean
```

基本の状態やnullを禁止するように設定する

```ruby:db/migrate/[Timestamp]_create_permissions.rb
class CreatePermissions < ActiveRecord::Migration[5.2]
  def change
    create_table :permissions do |t|
      t.boolean :A_flag, default: false, null: false
      t.boolean :B_flag, default: false, null: false
      t.boolean :C_flag, default: false, null: false
    end
  end
end
```

あらかじめ、権限テーブルの中身を作成しておく

```ruby:db/seeds.rb
Permission.create([
    {:A_flag => true},
    {:B_flag => true},
    {:C_flag => true}
])
```

作成したマイグレーションファイルとseeds.rbを実行

```bash:cmd
rails db:migrate
rails db:seed
```

アソシエーションの設定(validatesは冗長かも)

```ruby:app/model/permission.rb
class Status < ApplicationRecord
  has_many :users
  validates :A_flag, inclusion: { in: [true, false] }
  validates :B_flag, inclusion: { in: [true, false] }
  validates :C_flag, inclusion: { in: [true, false] }
end
```

```ruby:app/model/user.rb
class User < ApplicationRecord
  (略)
  belongs_to :permission
  (略)
```

deviseで生成したregistrations_controller.rbに対して追記した

```ruby:registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
(略)
# POST /resource
  def create
    set_permission_id
    super
  end
(略)
protected
(略)
 def configure_sign_up_params
    # permission_idをストロングパラメータに追加
    devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute, :permission_id])
  end
(略)
 def set_permission_id
    # 新規登録したアカウントのメールアドレスをemailに代入
    email = params.require(:user)[:email]
    # emailに@example.jpが含まれていればpermission_idを1に設定する
    if email.include?("@example.jp")
      params.require(:user)[:permission_id] = 1
    # emailに@hogehoge.comが含まれていればpermission_idを2に設定する
    elsif email.include?("@hogehoge.com")
      params.require(:user)[:permission_id] = 2
    # 該当するものがなければpermission_idを3に設定する
    else
      params.require(:user)[:permission_id] = 3
    end
  end
(略)
emd
```

# 最後に
今回、実装したコードはセキュリティ的に強固であるとは保証できません。参考にする際は自己責任でお願いします。

# 参考
[note / しん / deviseのコントローラをカスタマイズしてウィザード形式の新規登録画面を作成する](https://note.com/vixer93/n/nac92cc4c0983)
[github / heartcombo / devise](https://github.com/heartcombo/devise/blob/master/app/controllers/devise/registrations_controller.rb)
[Qiita / @mao-0901 / superって一体なんなんだ？？(Ruby on Rails)](https://qiita.com/mao-0901/items/906587ad9c4108d70b62)
[nakamulog / deviseによる認証](https://nakamulog.org/rails-devise)
簡単にMarkdownの表を作成する方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/46bfbfef-fb86-8cec-b812-3f68c538a09e.png)

# 確認したこと
　Markdown で表を直接記述すると、「|（パイプ）」をたくさん記入しないといけないため煩わしい。そこで、自分がよく使う情報蓄積アプリから、表形式を保ったままMarkdownを作成し、Qiitaへアウトプットする経路を確認した。
# 結論
　[Typora（WYSIWYGなマークダウンエディタ）](https://typora.io/)を経由すればたいていのアプリから表形式を保ったままアウトプットできた。
IBM i (旧AS400）の自己学習メモ　番外編０２　PUB400.comを使う際の注意（再起動とIPL）

# 自己学習メモインデックス

[IBM i (旧AS400）の自己学習メモ　インデックス](https://qiita.com/You_name_is_YU/items/3964849e7803c8eaf767)

# 概要

PUB400.comを使って自己学習を進めていると、気がついたら接続できなくなっていて、作業中のものが消えてしまったりすることがあります。
しばら〜くすると接続できるようになるんですが、何が起きているのか分かったので記事にしました。

# スケジュールされたAS400の再起動

突然ビープ音が鳴り、`Display Message`の画面に以下のメッセージが出力されました。
<img width="1088" alt="スクリーンショット 2020-05-03 13.32.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/e338c640-c967-ef6b-6e57-c5e88b604631.png">

これを読むと、2020年5月3日の5:00にパワーオフするよ。ということのようでした。
このメッセージが出てきたのが、大体13:40頃だったと思うのですが、5:00って何を基準にしているんだろう？という疑問があり、すぐに作業をやめてSignOffしました。

するとログイン画面に以下のようなメッセージが出ておりました。
<img width="1088" alt="スクリーンショット 2020-05-03 13.41.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/27b070ec-eb6f-d092-0f1b-7aa408a4e924.png">

UTC（協定世界時）の5:00、つまり日本時間でいうところの14:00にパワーオフされ、起動時にIPLを行っているようです。

なので、昼間14:00をまたいで何か開発などの作業を進めるのはやめておいた方がいいと思います。
15:00前には使えるようになっていると思いますので、その間は休憩時間にしちゃうのがいいでしょうね。

# IPLって？

IPLとは初期プログラム・ロード (Initial Program Load)のことを指し、以下のことをやってくれるみたいです。

- スプールされた作業用に QSPL サブシステムを開始します。
- QS36MRT および QS36EVOKE ジョブ待ち行列が保留されていた場合は、これらの待ち行列を解放します (これらは、System/36 環境で使用されます)。
- 操作援助機能クリーンアップを開始します (許可されている場合)。
- すべての印刷プログラムを開始します (ユーザーが IPL オプション画面で印刷プログラムを開始しないよう指定してある場合を除く)。
- QSERVER および QUSRWRK サブシステムを開始します。
- 制御サブシステムが QCTL の場合、QINTER、QBATCH、および QCMN サブシステムを開始します。

なんかよくわからない。。。待ち行列にたまりっぱなしのいろんなゴミをきれいにして心機一転元気いっぱいにAS400を起動することなんだろうなぁと軽く理解しておこうと思いますw

参考：https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rzaks/rzakspdf.pdf?view=kc
RX72N Envision KitとESP32-WROOM-32Dで現在時刻を取得する

ATコマンドで時刻を取得
---
RX72N Envision Kitに搭載されているESP-WROOM-32Dをシリアル通信経由で"AT"コマンドを送信し、応答が正常に戻る("OK")ことまでは確認できていましたが、そのあと何をしようか考えていました。
いくつかサイトを見ていると現在時刻を取得できるとありましたので、Wifiルータへの接続などの確認も兼ねて試行しました。

結果、下記の通りNICTのサーバから時刻を取得することが出来ました。

![ATコマンドで時刻取得.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624954/7672dade-994b-4fb5-9ff9-a00f2a08b04c.png)

参考サイト
---
今回参考にさせて頂いたのは下記のサイト様です。ATコマンドの解説と設定手順が分かりやすく記載されていました。
http://hello.world.coocan.jp/ARDUINO4/arduino4_5.html

こちらの時刻取得までの流れを参考に、シリアル通信でコマンドを送信しました。

プログラム
---
ATコマンドを送信するまでの設定は前のエントリと同じです。
メイン関数内でATコマンドを順に送信し、設定を進めていきます。

```
	ee_printf_eps("AT+CWMODE=1\r\n");
	serial_eps32_get();

	ee_printf_eps("AT+CWMODE?\r\n");
	serial_eps32_get();

	ee_printf_eps("AT+CWJAP=\"***SSID***\",\"***PASSSWORD***\"\r\n");
	serial_eps32_get();

	ee_printf_eps("AT+CWJAP?\r\n");
	serial_eps32_get();

	ee_printf_eps("AT+CIPSNTPCFG=1,-9,\"ntp.nict.jp\"\r\n");
	serial_eps32_get();

	ee_printf_eps("AT+CIPSNTPTIME?\r\n");
	serial_eps32_get();
```
* ESP32をステーションモードに設定
* Wifiアクセスポイントに接続
* SNTPでNICTのサーバから時刻を取得

という流れです。
CWMODEなどはESP32に設定が保存されるため、戻り値が正常なら省略可能とのことです。

試行中に色々なコマンドを送信するとエラーが発生したため、原因を確認していました。
結果戻り値をすべて受信バッファに貯める前に(EPS32->RX72Nへの送信中に)次のコマンドを送っていたのが原因でした。
ATコマンドの戻り値はセンサー類のように文字数が決まっているわけではないため、受信割り込み抜きで何かやるのは無理がありました。
ただ今回はとりあえずデータが取れればよいので、受信完了フラグが一定時間立たなければループを抜けるという原始的な方法を取りました。

```serial_eps32_get.
int serial_eps32_get(void) {
	int i,j;
	uint8_t Return_Value[256];

	for(i=0;i<10;i++) {}

	i = 0;
	j = 0;

	while(SCI1.SSR.BIT.RDRF == 0);
	Return_Value[i] = SCI1.RDR;
	while(1) {
		if (SCI1.SSR.BIT.RDRF == 0) {
			j++;
		}
		else if(SCI1.SSR.BIT.RDRF == 1) {
			Return_Value[i] = SCI1.RDR;
			i+=1;
		}
		if (j>100000000) break;
	}
	for(j=0;j<i;j++) {
		ee_printf("%c", Return_Value[j]);
	}
	return 0;
}
```
jの比較対象の数字がものすごく大きいですが、一桁足りないとCWJAPなどのコマンドでエラーになります。
受信したデータをその都度PCにシリアル転送すると、ボーレートの差のためMCUの受信のスピードに送信が間に合わず途中でおかしくなります。このため配列に格納して一気に送信しています。
待ち時間がものすごく長いため、本格的に運用する時は受信割り込みを使用するつもりです。


感想
---
センサーからのデータ取得、サーバからの時刻取得とくると、今度はLCDにデータを表示して時計のようにしてみたくなりました。大画面なので身構えてしまいますが…
CakePHP4 で手っ取り早くログを出す方法

CakePHP4 でログを依存関係なく簡単に出す方法です。
あくまで調査目的で、急いでいるときに利用することを想定しています。

```php
   \Cake\Log\Log::write('debug', 'デバックログにメッセージを出力する');
   \Cake\Log\Log::write('error', 'エラーログにメッセージを出力する');
```
【Swift】無限ループ背景動画を作る際のテンプレ【コピペでOK】

```swift:ViewController.swift
import UIKit
import AVFoundation

class LoginMovieViewController: UIViewController {
    
    var player = AVPlayer()
    

    override func viewDidLoad() {
        super.viewDidLoad()
        //ファイルパス
        let path = Bundle.main.path(forResource: "ファイル名", ofType: "拡張子")
        player = AVPlayer(url: URL(fileURLWithPath: path!))
        
        //AVPlayer用のレイヤーを生成
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
        
        playerLayer.videoGravity = .resizeAspectFill
        playerLayer.repeatCount = 0 //無限ループ(終わったらまた再生のイベント後述)
        playerLayer.zPosition = -1
        view.layer.insertSublayer(playerLayer, at: 0)
        
        //終わったらまた再生
        NotificationCenter.default.addObserver(
            forName: .AVPlayerItemDidPlayToEndTime, //終わったr前に戻す
            object: player.currentItem,
            queue: .main) { (_) in
                
                self.player.seek(to: .zero)//開始時間に戻す
                self.player.play()

        }

        self.player.play()

    }
```
オフラインインストール可能な Kubernetes インストーラを作った

# 概要

いろいろ必要に迫られて、完全オフラインな環境に Kubernetes をインストールする必要がでてきました。

Kubernetes のオフラインインストールは手動でやるとかなり面倒です。そこで、完全にオフラインな環境(オンプレ)に Kubernetes をインストールするためのインストーラを作りました。

* CentOS 7, RHEL 7, Ubuntu 18.04 に対応しています。
* 内部的には kubeadm を使用しています。
* Ansible を使用してインストールします (スクリプトベースのインストーラも一応あり)
* オフラインインストールをする場合は、事前にオンライン環境で RPM / DEB ファイルの取得とコンテナイメージをダウンロードしておき、これを外付けHDDなりでオフライン環境に持ち込む、という手順になります。
* Kubernetes 以外に、Rook NFS/Ceph、Private Registry、Nginx Ingress Controller、Metrics Server、Helm のインストールもできます。

Kuberspray に似ていますが、完全オフラインでインストールができるという点が異なります。

# ダウンロード

作ったものは https://k8s-installer.github.io/ においてあります。マニュアルもここにありますので、使い方はこちらを見てください。

Git レポジトリは https://github.com/k8s-installer/k8s-installer です。

# 使い方

使い方はマニュアルを見てもらうとして、ここでは簡単な使い方のみ記載します。

## オンラインインストール

インストーラを Github から入手します。

次に、Ansible インストールと、Inventory file および vars ファイルのコピー・編集を行います。

```shell
$ cd ansible
$ pip install -r requirements.txt
$ cp samples/* inventory/
```

Inventory ファイル(inventory/hosts) には、デプロイ先のホストを指定します。
master_first にマスタノードの１台目、master_secondaryにマスターノードの2台目以降(HA構成の場合)、worker にワーカーノードを指定します。

```ini
[master_first]
master-0  ip=10.240.0.10

[master_secondary]
master-1  ip=10.240.0.11
master-2  ip=10.240.0.12

[worker]
worker-0  ip=10.240.0.20
worker-1  ip=10.240.0.21

[master:children]
master_first
master_secondary
```

HA 構成にする場合は inventory/group_vars/all/main.yml の lb_apiserver_address にロードバランサのIPアドレス or ホスト名を指定します。

Ansible playbook を実行してデプロイを行います。sudo パスワードが必要な場合は -K オプションを追加してください。

```shell
$ ansible-playbook -i inventory/hosts site.yml
```

## オフラインインストール

オンライン環境で offline-generator ディレクトリの `generate-offline.sh` を実行してオフラインファイル一式を収集します。
(オフライン環境は、デプロイ先のノードと同一の OS で稼働している必要があります)

k8s-offline-files.tar.gz というファイルができますので、本インストーラと本ファイルを外付けHDDなどを使用してオフライン環境で Ansible を実行するノードに転送します。
(ノードには別途 Ansible のインストールが必要です)

あとは、オンラインインストールの時と同様に Ansible を実行してインストールを行います。
一箇所だけ、`inventory/group_vars/offline.yml` の offline_install の値を yes に変更する必要があります。

# 設計指針

軽く設計方針などについて記載しておきます。

Kubeadm を活用して Ansibleインストールする、という点は Kubespray などと同じなので、特に説明は不要と思います。

問題はオフラインインストールをどうやって実行するか、という点です。これについては、1) RPM/DEB などのパッケージのオフラインインストールをどうするか、2) コンテナイメージをどう各ノードに投入するか、が問題になります。

## RPM/DEB のオフラインインストール

必要な RPM なり DEB を依存関係を含めダウンロードしておき、全ノードに Ansible で転送してオフラインリポジトリを作る、という戦略を取ります。
(ローカルに Web サーバを立てて yum/apt リポジトリにするという手もあるのですが、面倒なので)

依存関係含めて RPM / DEB を取得する方法、およびオフラインリポジトリを生成する方法は以下です。具体的な手順は `create-repo-*.sh` を見てください。

* RHEL/CentOSの場合:
    * RPM の取得は `repotrack` で一発です。
    * リポジトリ生成には `createrepo` を使います。
* Ubuntu の場合:
    * DEB ファイルの依存関係は `apt-cache depends` で取れます。ダウンロード自体は `apt download` です。
    * リポジトリ生成には `apt-ftparchive` を使います。

## コンテナイメージの取得・投入

コンテナイメージの取得は `docker pull` で行い、`docker save` で tar.gz 形式でイメージ化できます。
これを各ノードに転送して、`docker load` でロードします。

ちょっとやっかいなのは必要なコンテナイメージの洗い出しです。Kubernetes 本体のコンテナイメージは `kubeadm config image list` で取得できます。
それ以外のものについては、yaml ファイルから "image:" で grep して引っこ抜くしかありません。
Angualrで同じURLをログイン状態に応じて切り分けmemo


# URLmatcherを使う

```typescript

function isLoggedIn(url: UrlSegment[]): UrlMatchResult | null {
    /*TODO: implement is logged in*/
    const result = localStorage.getItem('address');
    return (url.length === 0 && result) ? ({consumed: [] as UrlSegment[]}) : null;
}

const routes: Routes = [
    {path: 'dev', loadChildren: () => import('./dev/dev.module').then(m => m.DevModule)},
    {
        /* matcher should be function style. Otherwise, loadChildren of undefined error happens*/
        matcher(url: UrlSegment[]) {
            return isLoggedIn(url) as UrlMatchResult;
        },
        loadChildren: () => import('./home/home.module').then(v => v.HomeModule)
    },
    {
        path: '',
        pathMatch: 'full',
        loadChildren: () => import('./top/top.module').then(v => v.TopModule)
    },
];
```
MySQLの設定と機能を浅く狭く理解する

はじめに
===
MySQLの設定を機能を踏まえてふんわり理解できればなと思います

メモリ
===
サーバ自体にも利用される重要な項目ですね。すごくざっくり分けると以下に分類されるかなと思います。

- クライアント接続処理のサイズ (スレッドバッファサイズ)
- サーバで利用されるデータキャッシュのサイズ (グローバルバッファサイズ)

ストレージエンジンにもよりますが、こんな感じで設定します。

```
innodb_buffer_pool_size=xxxM
read_buffer_size=xxM
read_rnd_buffer_size=xxM
sort_buffer_size=xxM
query_cache_size=xxM
query_cache_limit=xxM
max_allowed_packet=xxM
join_buffer_size=xxM
```

このあたりは別途深くやっていきたいですね。。。(遠目)

文字コード
===
MySQLでは、サーバ全体、データベース、クライアントのように各所で細かく設定する事が可能です。設定には **character_set_server=文字コード** のように設定します。(この例ではMySQLサーバの文字コードを設定します)

MySQL(5.7の場合)は「latin1」という文字コードがデフォルトで設定されており、日本語を取り扱う事ができません。そのため日本語を含むデータを取り扱う場合は、「サーバ」および「クライアント」側の文字コードを変更する必要があります。最近だと「utf8mb4」になるかと思います。

照合順序
===
文字(データ)の比較とかに必要になります。文字コードには複数に照合順序(collation)が存在しています。下記に例を記載します。

|説明|collation名|補足
|:---:|:---|:---|
|大文字小文字を区別しない|utf8mb4_general_ci|末尾が ci (case insensitive)
|文字のバイナリ値で比較|utf8mb4_bin|末尾が bin|
|大文字小文字を区別する|utf8mb4_bin|utf8_mf4_general_csというものはない|

ログ
===
MySQLのログには6つの種類があります。

|種類|拡張子|デフォルト出力
|:---:|:---:|:---:
|エラーログ|.err|有効|
|バイナリログ|.bin.xxxxx|無効|
|一般クエリログ|.log|無効|
|スロークエリログ|.slow.log|無効|
|リレーログ|host_name-relay-bin.xxxxx|有効？(操作不能？)
|DDL(メタデータ)ログ|ddl_log.log|有効(操作不能)


ファイル名は明示的にシステム変数で設定する事が可能ですが、指定しない場合は一部にホスト名が利用されます。
少しですが、それぞれ掘り下げていきたいと思います。

## エラーログ
サーバ起動・停止といった読んで字の如くではありますが、エラーに関するログです。

## バイナリログ
更新系の処理や処理に要した時間などのメタデータを記録しているログです。このログは下記の重要な役割にも利用されています。

- レプリケーション
    - マスターサーバはバイナリログに格納されている情報をスレーブサーバに送信します。スレーブサーバはその情報をリレーログに書き出し、処理を実行。
- データリカバリ操作

こんな感じで有効化します。

```
log_bin
binlog_format = 'STATEMENT' {'STATEMENT'|'ROW'|'MIXED'}
```

## 一般クエリログ
クライアントからの接続や解除時に受け取ったSQLステートメントを記録します(MySQLの実行内容を記録しているログ)。このログはバイナリログとは違い、実行されたSQLステートメントとログに格納されている順序が異なる場合があります。**バイナリログは実行された後にロックリリース前に書き込むため順序が異なる事はありません**

こんな感じで有効化します。

```
general_log=1 {0|1}
general_log_file=ファイルパス
```

## スロークエリログ
実行に要した時間がシステム変数(**long_query_time**)秒を超えたSQLステートメントを記録しているログです。

```
slow_query_log=1 {0|1}
slow_query_log_file=ファイルパス
long_query_time=xx (デフォルト10s)
```

ここには記載していないですが、記録する・しないといった制御がもっと細かく設定する事ができます。

## リレーログ
バイナリログのレプリケーションの項目で説明しているはず。。。。なので割愛(いつかどこかで深くやりたいなと思っています)

## DDLログ
データ定義ステートメント(データベースに対して発行されたオブジェクトの作成や変更)によって生成されるメタデータを記録しているログです。

まとめ
===
「collationとか全く意識せずに適当に設定していたな・・・・・・・」
Monaca Localkitを使用したハイブリッドアプリの作成

自分が手を動かした際のメモ
ハイブリッドアプリはおろか、モバイルアプリ開発の経験なしの状態です。

##monacaとGitの連携について
[MonacaDocs GitHub との連携](https://docs.monaca.io/ja/products_guide/monaca_ide/version_control/github_integration/)
基本的には上記を参考に

##開発環境の構築
①Monaca Cloud IDEは使用せずにMonaca Localkitをインストール
【開発環境構築】
↓ここからLocalkitのダウンロード
[Monaca公式](https://ja.monaca.io/localkit.html)
(理由)
・Cloud IDEだとエディターをはじめとする既存の開発ツールと連携しづらい
・バージョン管理をより整合性をもって行うため(ローカルからGitに差分をpushするシンプルな仕組みとする)

②インストールはウィザードに沿って進めていくだけ（完了、Desktopにショートカットアイコンが作成されると思う）

③CloudIDEまたはzipからプロジェクトのimportを行う
これはどっちでもいい。
基本的にCloudIDE上のプロジェクトとは同期した状態にしておくつもりだし、Gitからzipをダウンロードして行うでも可
(今回はCloudIDEからインポートしてみた。結構時間かかる。。。)
※やってみてわかったこと
Monaca Localkitは開発環境ではなく、サーバになるようなもの
スマホのMonacaデバッガーとWindows/Mac OSXにあるMonacaプロジェクトを結びつけてくれる
これはappstoreから「Monaca」というアプリを落とす必要がある

④MonacaデバッガーをつかってPCとiphoneを同期させる
同じLANの中にiphoneとPCが存在すれば、ペアリングを促すアラートが表示される
→ペアリングを選択
これが成功すればMonacaデバッガー側でもMonaca Localkitがインポート（作成）したプロジェクトが表示される
Monaca Localkit側のコードを修正して保存すると、Monacaデバッガー側で自動的にリロードが行われて最新のコードが反映される。
Web開発で言うところのオートリロード機能みたいなイメージ

##開発するためのMonaca Localkit機能
「プレビュー」・・・プロジェクトをモバイルサイズでPC上で実行
「実行」・・・ペアリングしているiphoneでプロジェクトの実行
「アップロード」・・・変更したプログラムをクラウドにアップロード(これをしないとペアリングしているモバイルでの実行に反映されない)
基本的にはこれで開発できる

CLIコマンドでも実行できる
[Monaca CLI コマンド](https://docs.monaca.io/ja/products_guide/monaca_cli/cli_commands/)
Monacaプロジェクトの階層はwwwフォルダ直下に配置したindex.htmlがhome画面として実行されるイメージ
基本的にアプリケーションプログラムはここに配置する
「AnimeGAN」をGoogle Colab上で試してみる

この記事は　[「AnimeGAN」を試してみる](https://qiita.com/karaage0703/items/e90eba45bab604da21c5)　に触発されて、Colabほぼほぼ未経験者が、モデル生成済みのGANをGoogle Colab上で使ってみたときに引っ掛かったところをメモしたものです。

利用するリポジトリは[AnimeGAN](https://github.com/TachibanaYoshino/AnimeGAN)

引っ掛かったところは以下
- Google ColabではGPUを設定する
- Google Colabでカレントディレクトリを移動するのは%cd

# Google Colabを開く
[Google Colab](https://colab.research.google.com/?hl=ja)を開く。
GPUを設定する。これ忘れててすごく遅くなったけど@0206kzkさんに教えてもらいました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">GPU設定入れると、GPU使えるライブラリの場合、動作早くなるので、設定してみるといいですよ🤤無料ですし <a href="https://t.co/qn7sgUD7eB">pic.twitter.com/qn7sgUD7eB</a></p>&mdash; 能登一樹@小売業向けシステム屋 (@0206kzk) <a href="https://twitter.com/0206kzk/status/1256623394042175490?ref_src=twsrc%5Etfw">May 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```python
uploadPath = "test" 
styleName = "Shinkai" 
```
変換したいファイルの保存先とアニメのスタイルを指定します。新海、駿とかあるみたい。

```python
!git clone https://github.com/TachibanaYoshino/AnimeGAN
%cd AnimeGAN
```
GitHubからリポジトリをクローンする。

```python
%rm -rf checkpoint
!wget https://github.com/TachibanaYoshino/AnimeGAN/releases/download/Haoyao-style_V1.0/Haoyao-style.zip
!unzip Haoyao-style.zip
```

git cloneしたリポジトリの中にチェックポイントフォルダがあって、
あとのzip展開処理でエラーになったので削除する。
学習済みのモデルをダウンロードして、展開する。
学習済みモデルを切り替えるならwgetの向き先を変える必要がある。
[このリンク](https://github.com/TachibanaYoshino/AnimeGAN/tree/master/dataset)のあたりをみるともう少し分かりそう。

```python
%mkdir $uploadPath
%cd $uploadPath
from google.colab import files
uploaded = files.upload()
%cd ../
```

画像ファイルをアップロードする。

```python
!pip install utils
!pip install tensorflow==1.14
```

必要なライブラリをインストールする。
TensorFlowは新しいバージョンではコケるので、バージョンを指定してインストール。

```python
%run -i test.py  --checkpoint_dir ./ --test_dir  $uploadPath --style_name $styleName
```

画像生成処理を実行する。

```python
from google.colab import files
zipName = uploadPath + '.zip'
!zip -r $zipName results/$styleName
files.download(zipName)
```

生成した画像ファイルをダウンロード。

駿で試したのが以下。もう少し、アニメっぽく、元が分からないようにしたいなと思いました。

## 1枚目
![IMG_20190712_143449.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26331/a1b8c6e7-c080-b5d3-5e73-37f756d9a87e.jpeg)

## 2枚目
![20170531_105859.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26331/621e8d5c-770e-87de-debe-280e5c6abfb2.jpeg)
ancestryについて

#ancestryとは
AncestryはRuby on RailsのActiveRecordモデルのレコードをツリー構造（階層）として編成することを可能にするGemのことです。
親・子・孫等の、すべてのツリー構造の関係の編成を簡単に出来ます。

##使い方
※親子孫のツリー構造を作成するとします。

1.Gemfaileに以下を記述する。

```
gem 'ancestry'
```

忘れず実行する

```
$ bundle install
```

2.モデルを作成する

```
$ rails g model category name:string
```

忘れず実行する。

```
$ rails db:migrate
```

3.先ほど作ったcategoriesテーブルにancestryのカラムを作成する

```
$ rails g migration add_ancestry_to_category ancestry:string:index
```

忘れず実行する。

```
$ rails db:migrate
```

4.モデルにancestryを明示する

```category.rb
class Category < ApplicationRecord
   ~省略~
   has_ancestry
end
```

5.ancestryのメソッドを用いてデータ挿入する

Ancestryモデルを操作するには、以下のインスタンスメソッドを使用できます。

| method | return value |
|:--|:--|
| parent | 親レコードを取得 |
| parent_id | 親レコードのIDを取得 |
| root | レコードのルートを取得 |
| root_id | レコードのルートIDを取得 |
| root? |
| is_root? | レコードがルートであれば、trueを返す |
| ancestors | ルートで始まり、親で終わる、レコードの祖先を返す |
| ancestors? | レコードに祖先（ルートノードではない）がある場合はtrueを返す |
| ancestor_ids | レコードの祖先のIDを返す |
| path | ルートで始まり、自己で終わる、レコードのパスを返す |
| path_ids | ルートIDで始まり、 自己のIDで終わるパスのIDをリストで返す |
| children | 子レコードを取得 |
| child_ids | 子レコードのIDを取得 |
| has_parent? |
| ancestors? | レコードが親を持っていれば、trueを返す |
| has_children? |
| children? | レコードが子を持っていれば、trueを返す |
| is_childless? |
| childless? | レコードが子を持っていなければ、trueを返す |
| siblings | 兄弟レコード（同じ階層のレコード）を返す |
| sibling_ids | 兄弟レコード（同じ階層のレコード）のIDを返す |
| has_siblings? |
| siblings? | レコードの親に複数の子がある場合はtrueを返す |
| is_only_child? |
| only_child? | レコードが親の唯一の子である場合はtrueを返す |
| descendants | 子レコード、孫レコード、曽孫レコード... を返す |
| descendant_ids | 子レコード、孫レコード、曽孫レコード... のIDを返す |
| indirects | 孫レコード以下を返す |
| indirect_ids | 孫レコード以下のIDを返す |
| subtree | 子孫と自己のモデルを返す |
| subtree_ids | レコードのサブツリーのIDをリストで返す |
| depth | ノードの深さを返す |

レコードがルートの場合、他のルートレコードは兄弟と見なされます。兄弟はレコード自体を返す。
2つのノード間の関係を判別するインスタンスメソッドもあります。

| method | return value |
|:--|:--|
| parent_of?(node) | このレコードを(node)の親にする |
| root_of?(node) | このレコードを(node)のルートにする |
| ancestor_of?(node) | (node)の祖先にはこのレコードが含まれる |
| child_of?(node) | (node)はレコードの親 |
| descendant_of?(node) | (node)はこのレコードの祖先の1つ |
| indirect_of?(node) | (node)はこのレコードの祖先の1つですが、親ではない |

上記の表を見本としてseeds.rbにデータを入れていく

```seeds.rb
#一階層目
lady = Category.create(name: "レディース")

#二階層目
lady_1 = lady.children.create(name: "トップス")

#三階層目
lady_1.children.create([{:name=>"すべて"}, {:name=>"Tシャツ/カットソー（半袖/袖なし）"},{:name=>"Tシャツ/カットソー（七分/長袖）"}])

```

データを入れ終わったら、、、

```
$ rails db:seed
```
この表のようなデータが作成される。


|  id  |         name           |　    ancestry    |
|:-----|------------------------:|:------------------:|
| 1    |          レディース          |        nil       |
| 2    |          トップス         |       1       |
| 3    |           すべて           |        1/2        |
| 4    | Tシャツ/カットソー（半袖/袖なし）  |         1/2        |
| 5    | Tシャツ/カットソー（七分/長袖）   |       1/2       |
CSSでselectboxを装飾する方法

###はじめに

cssでセレクトボックスを装飾するexampleです。
デフォルトのselectboxだとなんとなく味気がないと個人的には感じているので、cssで装飾するのが好みです。

ネットでいちいち検索するのも面倒なのでメモもかねて。


```
select{
    font-size:12px;
    border:2px solid #ddd;
    border-radius: 4px;
    height: 25px;
}
```
html cssの呼び出し

<link>要素で外部CSSファイルを呼び出して適用する
スタイルシートを記述したCSSファイルをHTMLファイルとは別に作成して、HTMLファイル内から呼び出します。 呼び出しには、HTML文書の<head>要素内に<link>要素を記述して、外部CSSファイルを指定します。 適用されるスタイルがCSSによるものであることをブラウザなどに知らせるために、<link>要素のtype属性の値にはtext/cssを指定します。 XHTMLとの互換性やスタイルの修正のしやすさなどを考慮すると、この方法でスタイルシートを設定するのがおすすめです。

スタイルシート部分は外部ファイル（xxx.css）に記述。
p {color:blue; line-height:1.5;}

HTMLソース
<html>
<head>
<link rel="stylesheet" type="text/css" href="xxx.css">
</head>
<body>
<p>段落となります。</p>
</body>
</html>
『リーダブルコード』を読んで心に刺さったことをまとめてみた

##はじめに
エンジニア歴２年目のエンジニアです。
かの名著**『リーダブルコード』**を読んで、備忘録もかねて心に刺さったことを章毎にまとめました。

1.理解しやすいコード

```
・コードは他の人が最短で理解できるように書かなくてはならない
```

2.名前に情報を詰め込む

```
・getやfetch,allowやdisallow,letなど、よりコードの意味が明確になる変数名を心がける
・変数名でコードの内容が推測できるのが望ましい
・具体的な名前を用いて、コードの機能を詳細に説明する
```

3.誤解されない名前

```
・名前が他の意味と間違えられないか何度も自問自答する
・最善の名前は誤解されない名前
```

4.美しさ

```
・改行等を揃える。
・関数が長い場合、意味ごとのブロックに分ける
・コードを段落に分割する。長いコードは誰も読む気になれない。
```

5.コメントすべき事を知る

```
・自分の考えを記録する
・「監督のコメンタリー」を入れる
・読み手の立場になって考える、質問されそうなことを想像する
```

6.コメントは正確で完結に

```
・コメントは高レベルで記述する。（例；「int,desc」といったコメントより「価格の高い順」と行ったコメントの方が望ましい）
・「それ」や「これ」などの代名詞を用いるのは避ける
・コメントは簡潔に保つ
```

7.制御フローを読みやすくする

```
・if/else文の順序を適切に保つ。基本原則は、[肯定系、単純、目立つもの]を先に書く
・三項演算子、do/whileは読みにくくなることが多いので、あまり使わない。代替方法が必ずあるのでそちらを使う方が望ましい方が多い
・ネストはなるべく浅くする。関数を早めに返すようにするとネストを削除できる
```

8.巨大な式を分割する

```
・式を簡単に分割するには、式を表す変数を使う。これを説明変数という。
・管理や把握を簡単にする変数のことを要約変数という。
```

9.変数と読みやすさ

```
・変数のスコープはできるだけ小さくする
・一度だけ書き込む変数を使う
```

10.無関係の下位問題を抽出する

```
・エンジニアリングとは大きな問題を小さな問題に分割して、それぞれの解決策を組み立てることに他ならない
・プロジェクト固有のコードから、汎用コードを分離する
・関数は小さく独立していれば、機能追加、読みやすさの向上・汎用性の向上・エッジケースの処理がしやすくなる
・ただし分割のやりすぎには注意。コードの可読性が下がる。
//エッジケース：極端な動作で発生する問題
```


11.１度に一つのことを

```
・長く読みにくいコードはタスクを把握し、関数（クラス）に分割してみる。
・読みにくいコードがあれば、機能を全て列挙する。
・別の関数やクラスに分割できないか考える
```

12.コードに思いを込める

```
・簡単な言葉で書く。プレゼンとコードは同じ
・実際に声に出して、コードを説明してみる。デバックの際これだけで問題が解決することもある
```

13.コードを短く

```
・コードを追加する以上に、削除してコードを軽くすることも大事
・標準ライブラリを利用し、実装の時間を短縮する
```

14.テストを読みやすくする

```
・確認したいポイントを簡単な言葉にしてみる。
・テストが失敗した際のエラーメッセージは、バグの発見や修正がしやすいものを心がける
・テストの関数に説明的な名前をつけて、何をテストしているのか明らかにする
``````

##最後に
折に触れて読み返し自身の業務に役立てていきたいと思います。
プログラマとして当たり前のことが書かれていますが、こうした当たり前のことこそ大切にしていきたいです。
Excel×Pythonで作業フローを効率化する方法を調べてみた②

#今回の目的
Excelを取り込んで、編集してExcel,CSVファイルを出力するPythonプログラムを組んでみました。

###プログラムの流れ
①sample.xlsxを取り込む
②編集
③sample2.xlsx　と　sample.csvを出力

プログラムには、コメントをちりばめていますのでそちらをご確認いただければと思います。

あとは、これを応用して仕事の作業をPythonにやらせる事で作業を効率化できればばっちりです。

##取り込むエクセル（sample.xlsx）
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350277/dee0c60a-a0bf-5ff3-b7d6-1ed5b0bbfea6.jpeg)

#プログラム
```python:file_edit.py
import pathlib
import openpyxl
import csv

#エクセルファイルを取得
wb = openpyxl.load_workbook("./data/sample.xlsx")

#sheet「名：Sheet1」を取得
ws = wb["Sheet1"]

#セルA1のデータを出力　※パターン１
print(ws["A1"].value)  #A1セルを指定して取得

#セルA1のデータを出力　※パターン２
row1 = ws[1]           #sheet「名：Sheet1」の1行目を取得
print(row1[0].value)   #1行目の1列目を取得⇒結果、A1のセル

#全データを出力
print("全データ>")
for row in ws.rows:
	for cell in row:
	    print(cell.value)

#セルA1のデータを書き換え
ws["A1"].value = "★A1です"

#読み込んだエクセルを別名で保存
#※上書きの場合は読み込みファイルパスを指定
wb.save("./data/sample2.xlsx")

#CSVファイルを出力
with open("./data/csvsample.csv", "w", encoding="utf_8_sig") as fp:
    writer = csv.writer(fp, lineterminator="\n")
    for row in ws.rows:
        writer.writerow([col.value + "csv" for col in row])
```
##実行結果
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350277/c6305628-6e9d-e396-6496-68f2bb1ab63a.jpeg)

##出力ファイル（sample2.xlsx）
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350277/27375e18-e8d1-ada2-0889-16950e82b86c.jpeg)

##出力ファイル（sample.csv）
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350277/a061f71e-6de9-1086-0771-29a43bdad174.jpeg)
Ruby on Rails チュートリアル 21日目

今日は、昨日出たエラーの修正をしていました。
が、一つだけエラー文を読んでも何をどう修正すればいいかわかりませんでした。
エラーが出てきたのは[リスト 13.56](https://railstutorial.jp/chapters/user_microposts?version=5.1#sec-micropost_tests)です。

```
$ rails t
Running via Spring preloader in process 14198
Run options: --seed 26388

# Running:

................E.................................

Finished in 1.784464s, 28.0196 runs/s, 147.9436 assertions/s.

  1) Error:
MicropostsInterfaceTest#test_micropost_interface:
ActionView::Template::Error: Missing partial shared/_micropost_form with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
  * "/home/ec2-user/environment/sample_app/app/views"

    app/views/static_pages/home.html.erb:8:in `_app_views_static_pages_home_html_erb___1379375082338279699_58267200'
    test/integration/microposts_interface_test.rb:11:in `block in <class:MicropostsInterfaceTest>'

50 runs, 264 assertions, 0 failures, 1 errors, 0 skips
```

このエラー文が出てきたときに何を修正すればいいのか教えてくれると嬉しいです。
#Nuxt (Vueフレームワーク) でダイナミックなURLルーティングを試す

nuxtプロジェクトで、デフォルトで生成されたページを、てきとうに別ファイルとして保存する

```
cp pages/index.vue pages/some.vue
```

確認のため、てきとうに表示する文字を書き換えておく

yarn dev でサーバー起動している場合

```
yarn dev
```

ページ名がそのままURLに利用される

http://localhost:3000/some

でページにアクセスできる

![image](https://user-images.githubusercontent.com/13635059/80855008-ff461000-8c77-11ea-989d-609ca577dba9.png)



参考

[Routing - NuxtJS](https://nuxtjs.org/guide/routing/)

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3119











<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
#git add  ( error: '<directory>/' does not have a commit checked out )

git管理するディレクトリがネストしている場合
例えば次のような場合

```
directory1/.git
directory1/directory2.git
```

directory2 のコミットは、カレントディレクトリが directory2 以下のときにしかコミットできないっぽい

```
cd directory1/directory2
git commit add .
```

あまり良い構成ではないので、ディレクトリをネストしての git管理早めたほうが良いかも

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3118











<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Golang シェル実行

```golang
package main

import (
    "fmt"
    "os"
    "os/exec"
    "strings"
)

func getstatusoutput(args ...string) (status int, output string) {
    exec_command := exec.Command(args[0], args[1:]...)
    std_out, std_err := exec_command.Output()
    status = exec_command.ProcessState.ExitCode()
    if std_err != nil {
        output = std_err.Error()
    } else {
        output = string(std_out)
    }
    return
}

func main() {
    // command := []string{"echo", "-n", "HelloWorld"}
    command_line := "echo  -n   HelloWorld"
    command := strings.Fields(command_line)
    shell := os.Getenv("SHELL")
    status, output := getstatusoutput(command...)
    fmt.Printf("--- Result ---------------\n")
    fmt.Printf("Shell        : %s\n", shell)
    fmt.Printf("Command      : %s\n", command)
    fmt.Printf("StatusCode   : %d\n", status)
    fmt.Printf("ResultMessage: %s\n", output)
    fmt.Printf("--------------------------\n")

}
```

結果

```
--- Result ---------------
Shell        : /bin/bash
Command      : [echo -n HelloWorld]
StatusCode   : 0
ResultMessage: HelloWorld
--------------------------
```

意図的に失敗させる
(typo echo -> echa)

```
--- Result ---------------
Shell        : /bin/bash
Command      : [echa -n HelloWorld]
StatusCode   : -1
ResultMessage: exec: "echa": executable file not found in $PATH
--------------------------
```

# 参考
Package exec
https://golang.org/pkg/os/exec/

Goでコマンドを実行して終了コードを取得する方法
https://qiita.com/hnakamur/items/5e6f22bda8334e190f63

In Golang, how to convert an error to a string?
https://www.systutorials.com/in-golang-how-to-convert-an-error-to-a-string/
【SQL】 基礎(メモ)

##1.SQL（Structured Query Language）とは
リレーショナルデータベース（RDB）の操作を行うための言語
命令は大きく分けて２つ
**①データベースを定義するDDL（Data Definition Language）**

| 命令   | 機能                         |
| :----- | :--------------------------- |
| CREATE | データベースやテーブルの作成 |
| ALTER  | データベースやテーブルの更新 |
| DROP   | データベースやテーブルの削除 |

**②データを操作するDML（Data Manipulation Language）**

| 命令　  | 機能　　　　　|
| :----- | :--------- |
| INSERT | データの登録 |
| UPDATE | データの更新 |
| DELETE | データの削除 |
| SELECT | データの検索 |



##2.データベース構造の操作

```sql
/*DBへ接続*/
mysql -u root
/*DBを一覧で表示*/
SHOW DATABASES;
/*指定した名前のDBの作成*/
CREATE DATABASE データベース名;
/*作業するDBを選択*/
USE データベース名
```
**SHOW DATABASES文**:DBを一覧で表示するSQL文
**CREATE DATABASE文**:DBやテーブルを作成するSQL文
**USE文**:DBを選択するSQL文
##3.テーブルの操作

```sql
/*選択したDBに存在するテーブルを一覧表示*/
SHOW TABLES;
/*テーブルを作成*/
CREATE TABLE テーブル名 (カラム名 カラム名の型, ……);
```
**SHOW TABLES文**:選択したデータベースに存在するテーブルを一覧で表示するSQL文
**CREATE TABLE文**:テーブルを作成するためのSQL文
テーブルを作成する際にカラムの型を選択する必要がある。
参考：[MySQL 5.6 リファレンスマニュアル 第 11 章 データ型](https://dev.mysql.com/doc/refman/5.6/ja/data-types.html)
例）商品の情報を保存することを想定し、"goods"という名前のテーブルを作成する。
テーブルには商品idを数字で保存するidカラム、商品名を文字列で保存するnameカラムが必要。

```sql
CREATE TABLE goods (id INT, name VARCHAR(255));
```
意味：goodsテーブルにidカラム、nameカラムを作成。それぞれの方はINTとVARCHAR(最大２５５文字数)。



##4.テーブル構造を確認
```sql
/*構造の確認*/
SHOW columns FROM テーブル名;
```

##5.カラムを追加(ALTER TABLE文)
```sql
/*カラムを１つ追加*/
ALTER TABLE テーブル名 ADD カラム名 カラムの型;
/*カラムを複数追加*/
ALTER TABLE テーブル名 ADD (カラム名 カラムの型, ……);

/*カラムの修正*/
ALTER TABLE テーブル名 CHANGE 古いカラム名 新しいカラム名 新しいカラムの型;

/*カラムの削除*/
ALTER TABLE テーブル名 DROP カラム名;
```


##6.テーブルにデータを保存(INSERT文)
**INSERT文**：テーブルにデータを登録するためのSQL文

```sql
/*全てのカラムに値を入れる場合と特定のカラムに値を入れる場合*/
INSERT INTO テーブル名 VALUES(値1, 値2, 値3);
INSERT INTO goods VALUES(1, "ペン", 120);/*意味：goodsテーブルにid:1,nema:"ペン",price:120を登録*/

/*特定のカラムのみに値を入れる場合*/
INSERT INTO テーブル名(カラム名1, カラム名2) VALUES(値1, 値2);
INSERT INTO goods(id, name) VALUES(2, "消しゴム");/*意味：goodsテーブルにidカラムに２,nemaカラムに"消しゴム"を登録*/
```
デフォルト値を設定していないカラムのデフォルト値はNULLとなる。




##7.データを更新（UPDATE文）

```sql
UPDATE テーブル名 SET 変更内容 WHERE 条件;
UPDATE goods SET price = 100 WHERE id = 2;/*goodsテーブルのid2のpriceを100に更新*/
```
##8.データを削除（DELETE文）

```sql
DELETE FROM テーブル名 WHERE 条件;
DELETE FROM goods WHERE id = 2;
```

##その他

```sql
/*テーブルにあるレコードを全て表示*/
SELECT * FROM テーブル名;
```
footerのデザイン

position absollute VS ブロック要素

解説　footerを作るとき、必ずしも「position absolute」を使用する必要はありません。2番の場合はposition absoluteは使用しないほうが良いでしょう。

１．footerにposition absoluteを使用するとき
メインコンテンツの量が　デフォルトのブラウザ画面の高さ　＞　コンテンツ量　な時

２．footerにposition absoluteを使用しないとき
メインコンテンツの量が　デフォルトのブラウザの高さ　＜　コンテンツの量　な時
AWS ChatbotがGAになったのでまた試してみた

AWS ChatbotがGAになったので、再び試してみました。
https://aws.amazon.com/about-aws/whats-new/2020/04/aws-chatbot-now-generally-available/


## どんなもの
SNS経由でアラートをAmazon ChimeやSlackに通知したり、SlackからAWSのコマンドを実行できる環境を提供するサービスです。


## 設定
設定はとても簡単です。Betaの頃から手順は変わっていないようです。
https://docs.aws.amazon.com/chatbot/latest/adminguide/getting-started.html

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/23838e53-4749-7063-f023-dbeb2c1ed75a.png">

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/32db059f-9365-9757-bd81-4e48bebf72e6.png">

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/76ea94cb-4a9a-5e71-a1e8-00d75f6fdcbc.png">


## アラートの例　(CloudWatch Synthetics)

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/5d30e8dc-5d12-54ec-82c9-dbb1eb9bf458.png">

## コマンド実行の例

ヘルプ

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/b357eb4e-4446-89d2-6b06-22e8162b78f8.png">

Read系

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/56242aa0-46dc-2738-77e9-cb15bc0a623d.png">

Create系のコマンドは禁止されているようです。
IAM RoleにAdministratorAccess権限を付与してもダメでした。

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/ad82f622-4fad-2915-1199-878c3433e23c.png">

## 雑感

- AWS CLIになれている方なら、コマンド実行結果を簡単にシェアできるのでとても便利
- 実運用するなら、lambdaの実行対象はIAM Policyで絞った方が安全かなぁ
- Slackのユーザ単位でキュリティレベルを変更する仕組みがないので、SlackのユーザとChatobotに適用しているIAM policyが紐付けられるといいな
ViVi Robot Control Boardのセッティング

#前回のあらすじ
https://qiita.com/GetQ/items/ab1360036d0ea06edf7c

ViVi Robot Control Boardは、ESP8266を積んだサーボコントローラ。
Aliから中華PLEN2を買ったので、その忘備録
#ファームのダウンロード
まずは、[how to download the firmware](https://github.com/SmartArduino/ESPboard/blob/master/builtinfirmware.pdf)を見ながらセッティングしていく。
- PCとシリアル接続するときはUSB-Serial変換ボードの設定を3.3Vにすること。
- 書き込みモードにするときは、S1押しっぱなしでS2を押して、S2を離してS1を離す（爪楊枝必須）

まずここでいきなりハマった。
Aliexpressの販売ページから貼られているVIVI PLENのGithubのリンク
https://github.com/SmartArduino/SZDOITWiKi/wiki/ViVi-Robot?spm=a2g0o.detail.1000023.1.b28b531aDgq8wV
はバージョンが7.19で古い。
ファームの導入はできるのだが、バージョンが古いせいかAndroidのPLENアプリから見つけられない。
あちこち探し倒して、ようやく最新と思しきバージョン(7.3)を発見。
https://github.com/Nicholas3388/ViVi-Robot

ところがbinファイルを導入しようとするとエラーが出る。
じゃぁ、ArduinoIDEでソースから入れるか、と思ったが今度は「「Servo.h」に対して複数のライブラリが見つかりました」とかいうエラーを吐いて止まる。

ぐぬぬ。

#動作確認
仕方がないので、[PLEN Playground - Wiki](http://plen.jp/playground/wiki/index.html)の[Top » Specifications » Protocol](http://plen.jp/playground/wiki/specifications/protocol)を見ながら、シリアルポートとTCP/IPの23番ポートから「<vi」と送信する。結果がこちら。
![SharedScreenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628546/c39a7f28-b10e-3921-19d9-879b6d6e1f23.jpeg)
動作チェックとキャリブレーションはこれでやるしかないかな。

2020/05/17追記
https://qiita.com/GetQ/items/838a778f081642b90104
ここでさんざん試して、一通り動くようになったところで、LEFT KneePitchとLEFT FootPitchのサーボモータが常に同時に動くことに気が付いた。ViVi PLENの純正ファームでも同じ。

ボードがハズレじゃねぇか！

ちょっと別の方法考えるか。