OmniAICreator/Qiita-1.07M huggingface dataset:
サクラエディタで複数のマクロを1つのファイルにまとめて使う方法


サクラエディタで複数のマクロ経由で1つのファイルを呼び出して、内部で使い分ける方法です。

VBScriptでは、下記の記事のように、`ExecuteGlobal`を使うことができます。
https://qiita.com/takahasinaoki/items/7c7554beb95f32227589

しかしJScriptには同じメソッドはありません。

ファイルから文字列を読み込んで`eval`するという方法もありますが、エラーメッセージで行番号が表示されないという問題があります。

そこで活躍するのが、`ExecExternalMacro`と`SetCookie`と`GetCookie`です。

```JavaScript:test__call_by_my_macro_abc.js
// マイマクロabc
Editor.SetCookie('window', 'test__my_macro_param1', 'abc');
var macro_path = Editor.ExpandParameter('$M');
var macro_dir = macro_path.substr(0, macro_path.lastIndexOf('\\'));
Editor.ExecExternalMacro(macro_dir + '\\test__my_macro.js');
Editor.SetCookie('window', 'test__my_macro_param1', '');
```

```JavaScript:test__call_by_my_macro_xyz.js
// マイマクロxyz
Editor.SetCookie('window', 'test__my_macro_param1', 'xyz');
var macro_path = Editor.ExpandParameter('$M');
var macro_dir = macro_path.substr(0, macro_path.lastIndexOf('\\'));
Editor.ExecExternalMacro(macro_dir + '\\test__my_macro.js');
Editor.SetCookie('window', 'test__my_macro_param1', '');
```

```JavaScript:test__my_macro.js
// 共有関数
function my_share_debug_message(str) {
//	Editor.TraceOut(str);
	Editor.InfoMsg(str);
}

function my_share_get_text() {
	var str = Editor.GetSelectedString(0);
	if (str == '') {
		Editor.SelectWord();
		str = Editor.GetSelectedString(0);
	}
	return str;
}

function my_share_output(str) {
//	Editor.InfoMsg(str);
	Editor.InsText(str);
}

// 数字をとりあえず1加算するマクロ関数
function macro_abc() {
	my_share_debug_message('マクロabcですわん');
	var str = my_share_get_text();
	str = str.replace(/[0-9]+/g, function(a){
		return a - 0 + 1;
	});
	my_share_output(str);
}

// 数字をとりあえず1減算するマクロ関数
function macro_xyz() {
	my_share_debug_message('マクロxyzですにゃ');
	var str = my_share_get_text();
	str = str.replace(/[0-9]+/g, function(a){
		return a - 1;
	});
	my_share_output(str);
}

var param1 = Editor.GetCookieDefault('window', 'test__my_macro_param1', '');
if (param1 == 'abc') {
	macro_abc();
}else if (param1 == 'xyz') {
	macro_xyz();
}else{
	my_share_debug_message('不明な呼び出し元か、直接実行されました');
}
```

こんな感じにCookie機能を使うと、マクロを横断した変数の共有ができます。

この方法では、VBScriptとJScriptを混在して実行し、文字列を渡すこともできます。
data-属性を有効活用！簡単・便利なタブメニュー

#はじめに
クリックしたボタンに応じて表示が変わるタブメニューのコードを紹介します。
JabaScriptを学習し始めた方にもおすすめです！

#コード

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="ryuji0526" data-slug-hash="JjbQqmp" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="JjbQqmp">
  <span>See the Pen <a href="https://codepen.io/ryuji0526/pen/JjbQqmp">
  JjbQqmp</a> by Ryuji Watanabe (<a href="https://codepen.io/ryuji0526">@ryuji0526</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#ポイント
このタブメニューのポイントは、押したボタンと表示するアイテムとの連携です。
以下のように行います。

```index.html
      <!--　10行目 -->
      <ul class="menu">
         <!--「data-」属性で、アイテムと同じid名を設定 -->
        <li><a href="#"  data-id="menuId1">menu1</a></li>
        <li><a href="#"  data-id="menuId2">menu2</a></li>
        <li><a href="#" data-id="menuId3">menu3</a></li>
      </ul>

      <section class="content" id="menuId1">
        メニュー①です。
      </section>
      <section class="content" id="menuId2">
        メニュー②です。
      </section>
      <section class="content" id="menuId3">
        メニュー③です。
      </section>
```
　


```main.js

      //22行目
　　　 //data-idの値と同じ値のidを持つ要素をdatasetプロパティで取得し、selectクラスを追加
      let currentMenu = document.getElementById(clickedItem.dataset.id)
      currentMenu.classList.add('select');

```

JSのdatasetプロパティを通して、data属性で指定した値を取得することができます。
これによって、押したボタンと表示するアイテムとを連携させることができます！

#おわりに
data属性はHTML要素に独自の追加情報を格納することができます！
JSと組み合わせることで、使い道が格段に増えると思うので、ぜひ使ってみてください！
macストレージ整理

#1. はじめに
私はandroidアプリとiOSアプリの開発に携わってます。
複数の開発アプリがあるため、android studioとXcodeのプロジェクトをたくさん開いたり、たくさんのapkやipaファイルを生成しているようなローカル環境です。

その結果、ストレージの容量が無くなり易くすぐに警告がでます・・・。
色々な方法で不要ファイルを削除してきたのですが、
結果、私の環境で実施している効果的なストレージ整理方法を記載します。

#2. 環境
MacBook Pro (256GB)
macOS Catalina
Xcode12.2
android studio3.4



#3. XcodeのArchiveを消す

Xcodeのメニュー
Window < Organizer 
を開く。
不要なArchiveを選択し、二本指でタップしDelete Archiveを選択

Archive作るたびに溜まっていくので、リリース後３バージョン前くらいまで残してあとは消しています。
※OrganizerからdSYMファイルを取得している場合は、Archive消す前に確認。

#4. Derived Dataを消す

~/Library/Developer/Xcode/DerivedData

こちらの配下のデータを消す。
プロジェクトごとに作成されるが、削除すると、再びプロジェクトを開いた際に再生成されます。

**参考にさせていただいたサイト**
https://dev.classmethod.jp/articles/remove-xcode8-related-unnecessary-files/

#5. Spotlightインデックス再作成

①Apple メニュー () <　システム環境設定　<　Spotlight　< プライバシー
に移動。
②左下の「+」ボタンをクリックし、MacintoshHDを選択して追加する。
③リストから、追加したばかりのMacintoshHDを選択し「-」(削除) ボタンをクリックし、リストから削除する。
④システム環境設定を終了する。
⑤macのデスクトップ右上の虫眼鏡アイコンをクリックし、何か一文字入力する。
⑥Spotlightインデックスが再作成され、正しい容量を認識し直されます。

**参考にさせていただいたサイト**
https://apple-teach.com/macroom/storage-shortage/

#6. ユーザーキャッシュを消す

~/Library/Caches/
こちらの配下のデータを消す。

#7. その他
ファイルは全てcloudストレージにアップし、なるべくローカルで持たない。
ダウンロードファイル使用後は削除する。
ただバッチでメモ用のテキストファイルを作るだけ

#はじめに
仕事でよくメモのテキストファイルを作っていたが毎回作るのもめんどくさくなったので、今更ながらテキストファイルを作るバッチを作成したのでメモ代わりとして記します。
コードは[こちら](#コード)から。

#どういうもの？
バッチを叩くと…

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/f0cbb2b2-e0c8-ce03-db6f-eb6b69229be8.png)|
|:--|
↓

今日の日付のメモが作成されます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/e8fdf7e7-a6a1-3cb6-26c5-b855d34a7411.png)|
|:--|
↓


もう1回叩くと…

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/079b53f8-6de0-dbba-7811-22b683beb006.png)|
|:--|

末尾に数字が追加されてメモが作成されます。

いっぱい叩くと…

↓

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/8285407b-d876-fd18-7d52-6c1de95cb437.png)|
|:--|
いっぱいできます。

~~ただそれだけです。~~

#コード
以下にコードを示します。

```bat:makeMemo.bat
@echo off

setlocal enabledelayedexpansion

set today=%date:~0,4%%date:~5,2%%date:~8,2%
set num=1

for %%a in (%today%*.txt) do (
  rem 今日分の対象ファイル分カウントアップしていく
  set /a num=num+1
)

rem メモファイルを作成する
if %num%==1 (
  rem 今日分のファイルがない場合はそのまま作成
  copy nul %today%メモ.txt
) else (
  rem 今日分のファイルがある場合は末尾の番号を増やして作成
  copy nul %today%メモ_!num!.txt
)
```
`setlocal enabledelayedexpansion`の宣言がないとどうやらforの中での計算が全体に反映されないようです。

#終わりに
バッチフィルは今まで避けてきましたが、私が扱ったことのある言語とは異なり半角スペースや形式にうるさいと感じました。
日々のメモ帳作成に不満を感じている方（いない）に喜んでいただけたら幸いです。
~~このバッチを作る時間で一体何個のメモファイルを手動作成できただろうか？~~
【Rails】NameError: uninitialized constant Sidekiq::Loggingの解決方法【非同期処理】

#はじめに
現場で使える Ruby on Rails 5速習実践ガイド
「Chapter 7-8 非同期処理や定期実行を行う」でタイトルのエラーが発生。
タスク管理アプリのタスクフォームからタスクを投稿した時に非同期処理が実行されるプログラムを記述するも想定通りいかず、、、
#環境
Ruby 2.6.6
Rails 6.1.3
sidekiq 6.0.4
#結論
sidekiqのバージョンが新し過ぎたせいでコマンドがうまく実行されなかった模様。
なので、以下をgemfileに記載。

````ruby:gemfile
gem 'sidekiq', '~> 5.0'
````

記入後bundleからのrails sの後にredis-serverとbundle exec sidekiqを実行。
タスク投稿後、無事出力された。

````ruby
2021-03-19T15:05:18.659Z 10221 TID-ovjc2wymp SampleJob JID-82b7b80cec1cd3c40b4592ec INFO: start
2021-03-19T15:05:18.845Z 10221 TID-ovjc2wymp SampleJob JID-82b7b80cec1cd3c40b4592ec INFO: サンプルジョブを実行しました
2021-03-19T15:05:18.846Z 10221 TID-ovjc2wymp SampleJob JID-82b7b80cec1cd3c40b4592ec INFO: done: 0.187 sec

````
参考:[teratail:NameError: uninitialized constant Sidekiq::Loggingの解決方法](https://teratail.com/questions/235628)
Amazon Redshift Spectrum とは

## 勉強前イメージ

s3のデータselect出来るとかなんとか聞いたことある
あと読み方わかんない

## 調査

### そもそも Amazon Redshift とは？

AWSのデータウェアハウスサービスで、BIツールと呼ばれています。
詳細は [こちら](https://qiita.com/miyuki_samitani/items/599cae649a00719f4248)

### Amazon Redshift Spectrum とは

読み方はスペクトルと読みます。

Redshift SpectrumS3上に保存されているデータに対してRedshiftと同様に分析を行うことができ、
これまで連携していたBIツールの利用も既存のRedshift同様に使用できます。

データウェアハウスの課題として、データを用途ごとに加工し保存しておく必要があります。
それに関して、データレイクという保存方法で無加工のまま保存することが可能になり、それに関してs3が用いられることが多くなりました。
しかし、処理を行う方法としてRedshiftにコピーしなければいけなかったのですが
s3にデータを置いたままそのデータにアクセス出来る方法としてRedshift Spectrumが登場しました。
s3のデータのレイアウトに合わせた外部テーブルを作成することによって、
Redshift上のテーブルのようにs3のデータを参照することができます。

### Athena と Redshift Spectrum の使い分け

#### Athena

- 新しく取得したデータの中身について検証
- 障害時のログ調査
- 大規模でないデータに対しての低頻度のETL処理

#### Redshift Spectrum

- 結合が含まれないようなデータに対しての高速な処理
- 大規模なデータに対してのETL処理

## 勉強後イメージ

s3のデータをRedshiftに入れて行うには結構時間かかるから、s3そのまま見たほうがいいんじゃない？みたいな感じ？
ただ、ちゃんと整形してないといけなかったり、JOINは出来ないとかいろいろ制限はありそうだけど速いんだね。

## 参考

- [「Amazon Redshift」とは？「Amazon Redshift Spectrum」の利用方法を紹介！](https://www.fenet.jp/aws/column/technique/286/)
- [[AWS Black Belt Online Seminar] Amazon Redshift Update – 最近追加された新機能と Redshift Spectrum レポート](https://dev.classmethod.jp/articles/aws-blackbelt-redshift-spectrum/)
MVCのモデルをわかりやすく説明

_現在、railsでアプリケーションを開発しながら勉強をしているのですが、
MVCモデルを使って開発をしていて、V＝View「わかる( ´∀｀)」要は画面の表示をするフロントの部分だ。
C＝Controller「わかる( ´∀｀)」routeファイルに書いたモデルの対応したアクション（メソッド）で処理内容が違うし、表示させるファイルを呼び出したり、リダレクトしたり、呼び出すモデルが違ったり対応するアクション（メソッド）によって
行う処理が全く違う。_

_ではモデルとは？？？
モデルのファイルにはbelongs_toやhas_manyなどのモデルの結びつきなどが記載されています。
よくググるとデータベースとデータのやりとりを行う機能を実装したりする。など記載されていますが
なんのこっちゃよく分からん(　ﾟдﾟ)
なので、自分なりにモデルとはこういうものだよと解説していきます。_
#モデルの概念
モデルとは日本語で、型や模型を意味しています。
この型とは？なんの型なのでしょうか？何を意味しているのでしょうか？
例えば「User」モデルがあるとします。Userとは使用者、使い手などを意味します。
この「User」とはどんなものなのでしょうか？
まず使用者と言うぐらいだから「名前」くらいはあると思います。
次に「年齢」、「住所」は持っていると過程します。
この「User」モデルは今、「名前」「年齢」「住所」というプロパティを持っています。
プロパティとは、その対象に対象にくっついている、そいつがどんなやつかを表す情報を意味しています。
（プロパティ・属性、特性を意味する）
つまり「User」がどんなものか表す情報をプロパティ（属性）といいます。
では、表す元となる「User」は何と言うのでしょうか？
これはエンティティ（概念）と呼びます。
このことからこんな形になります。
__model（情報） ＝ 「エンティティ(概念)」
modelの情報内容 ＝ 「プロパティ(属性)」__
みじかなものだと
__ニュース（情報）　＝　「エンティティ(概念)」__
__ニュース内容　　＝ 「プロパティ(属性)」__
なのでmodelとは現実世界の物体をプログラムなどのデータ世界に概念化した形だと
思えばいいのかなと思います。
##概念とは
以下wikiから抜粋

```console
概念は、命題の要素となる項が表すもの、あるいは意味づけられたものであり、
言い換えれば、それが言語で表現された場合に名辞となるもの。
人が認知した事象に対して、抽象化・ 普遍化し、思考の基礎となる基本的な形態となるように、
思考作用によって意味づけられたもの。
```
小難しく書いてますが、自分たち人が認知した物に対して思った事を意味づける事です。
例えば空飛ぶ物体とは何？と思ったら飛行機などを思い浮かべるとおもいます。
では、飛行機とはどんな物？と思ったら、翼があるエンジンがあるなどがあげられると思います。
つまり、人が認識しているものに対して抽象的なものが概念を意味しています。

#railsのモデルとは
railsではモデルを作成するとmigrateファイルが作成されます。
このmigrateには、モデルのもつ情報内容（プロパティ）を記述し、
データベースへ反映させます。
つまり、モデルが情報（エンティティ）、migrateファイルに記述した物がモデルの情報内容（プロパティ）になります。
簡潔に表すと
Userモデルを作成　User.rb（エンティティ）

```user.rb
class User < ApplicationRecord
  has_many :comments
  validates :nickname, presence: true, length: { maximum:6 }
```
Userモデルの情報内容は、 モデル作成時のmigrateファイルに記述（プロパティ）

```20200715093334_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.2]
  def change
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.datetime :remember_created_at
```
注）なぜモデルファイルとmigrateファイルが別れていて結び付くのかかなりラップされているので、私でうまく言語化して説明できないので割愛させていただきます。
#javaのモデルとは
モデルクラスが情報（エンティティ）にあたり、クラス内のメンバ変数が情報内容（プロパティ）になります。

```sample.java
class Human{ //エンティティ
    string name;//プロパティ
    int    age;//プロパティ
void setName(string aName) {
		// 自分のクラスのメンバー変数へのアクセス
		name = aName;
	}
	int getName() {
		// 自分のクラスのメンバー変数へのアクセス
		return name;
	}
void setAge(string bAge) {
		// 自分のクラスのメンバー変数へのアクセス
		age = bAge;
	}
	int getAge() {
		// 自分のクラスのメンバー変数へのアクセス
		return age;
	}
}
```
#結論モデルとは
情報（エンティティ）の大枠だと理解！！

```console
情報(エンティティ）
　├ 情報内容（プロパティ）
　│　└ 情報内容の値（プロパティ値）

User(エンティティ）
　├ name（プロパティ）
　│　└ 山田太郎（プロパティ値）
　├ age（プロパティ）
　│　└ 19才（プロパティ値）
```
OpenCV+Pillowで動画上に秒単位で変化する日本語テキストを表示する

## はじめに
業務で秒単位のセンサ情報テキストデータを動画に直接紐付けるために、動画に秒単位で日本語テキストを表示する作業を行った。
その際に少し手間取ったので、テキスト表示用のPython実行コードサンプルを備忘録も兼ねて紹介します。

## やったこと (プログラム入出力内容)
入力動画より、下の出力動画のように秒単位で変化する日本語テキストを表示できるようにした。

<b>・入力動画</b> (※ https://www.home-movie.biz/free_movie.html より取得)
![mov_hts-samp003.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138429/c89c19c5-6ae4-27ca-52f1-d9afb761600c.gif)

<b>・出力動画</b>
![outvideo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138429/f8da8ef6-4308-8274-a945-f0e19dc525f4.gif)

## 実行コード
動画のフレーム入出力にOpenCV (v4.5.1)、日本語テキスト書き込みにPillow (v7.0.0)を利用している。
※ OpenCVでも[putText](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.html#id8)メソッドによりテキスト書き込みは可能だが、日本語・改行に非対応

フォントはプログラム内の定数「FONT_PATH」にてお好みで変更して実行してください。

```write_text_on_video.py
"""動画へのテキスト書き込みプログラムサンプル"""
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont

# Windows
FONT_PATH = "C:\Windows\Fonts\meiryo.ttc"
# Linux(Ubuntu)
# FONT_PATH = "/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf"


def main():
    # 入出力動画ファイルパス
    video_infile = "./mov_hts-samp003.mp4"
    video_outfile = "./outvideo.mp4"

    # 動画読み込み
    cap = cv2.VideoCapture(video_infile)

    # 動画の各プロパティ取得
    print("# Video Property List")
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = round(cap.get(cv2.CAP_PROP_FPS), 2)
    bitrate = int(cap.get(cv2.CAP_PROP_BITRATE))
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    print(f"FrameCount:{frame_count}, FPS:{fps}, BitRate:{bitrate}")
    print(f"Width:{width}, Height:{height}")

    # 出力用の動画(MP4)オブジェクト設定
    fourcc = cv2.VideoWriter_fourcc("m", "p", "4", "v")
    outvideo = cv2.VideoWriter(video_outfile, fourcc, fps, (width, height))

    while True:
        # フレーム読み込み
        ret, frame = cap.read()
        if ret is False:
            break

        # フレーム読み込み時点の再生時間[秒]を取得
        frame_pos = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
        video_sec = int(frame_pos / fps)

        # フレームへテキスト書き込み
        text = f"動画ファイル：{video_infile}\n再生時間：{video_sec}秒"
        frame = write_text_on_frame(frame, text, width, height)

        # 編集フレーム出力
        outvideo.write(frame)


def write_text_on_frame(
    frame: np.ndarray, text: str, width: int, height: int
) -> np.ndarray:
    """入力フレームに指定テキスト書き込み

    Args:
        frame (np.ndarray): フレーム
        text (str): 書き込みテキスト
        width (int): フレーム幅
        height (int): フレーム高

    Returns:
        np.ndarray: テキスト書き込みフレーム
    """
    image = Image.fromarray(frame)
    draw = ImageDraw.Draw(image)

    # テキスト書き込み
    font = ImageFont.truetype(font=FONT_PATH, size=72)
    draw.rectangle(xy=(0, 0, width, int(height / 5)), fill=(255, 255, 255))
    draw.text(xy=(10, 10), text=text, fill=(0, 0, 255), font=font)

    return np.array(image)


if __name__ == "__main__":
    main()

```

## 参考

- [Python動画編集!動画に位置制御したテロップを入れる方法](https://watlab-blog.com/2019/09/01/movie-telop/)
- [【Python】Pillow ↔ OpenCV 変換](https://qiita.com/derodero24/items/f22c22b22451609908ee)
Rakeタスクが、本当にWheneverを使ってcronで実行できているか試してみた。


Rakeタスクを作成して、Wheneverでcronの実行スケジュールを定義したけど・・・これって本当に実行できてるの？と思ったので、簡単なタスクとスケジュールを作って実行しログを確認してみました。

Rakeタスクを編集
---

```publish.rake
namespace :publish do
  desc "指定した時刻からの経過時間を表示"
  task test: :environment do
    time_now = Time.current
    time = Time.local(2021,3,19,21,00,00)
    puts "#{((time_now - time)/60).to_i}分が経過しました"
  end
end
```
今回はお試しなのでとりあえずシンプルな検証です。とはいえただ文字を出力させるだけじゃ味気ないので、ある時点の時刻 Time.local(2021,3,19,21,00,00) から、現在の時刻 Time.current までの経過時間を出力させる処理を記述します。時刻の差分は秒数で出力されるので、秒数を分数に直して整数化（.to_i）します。

スケジュールの編集
---

```schedule.rb
require File.expand_path(File.dirname(__FILE__) + "/environment")
rails_env = ENV['RAILS_ENV'] || :development
set :environment, rails_env
set :output, "#{Rails.root}/log/cron.log"

every 1.minute do
  rake "publish:test"
end
```
今回は、結果をすぐに確認したいので、1分毎にRakeタスクを走らせます。

Cronのログを確認
---
![スクリーンショット 2021-03-19 23.36.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044144/e5fbf3a6-72af-d89d-e254-78b064514754.png)

無事にRakeタスクが実行できていることが確認できました！
Laravel8.xでBreezeを利用したメール認証の実装で見落としていたこと

#目的
- Laravel8.xにおいて，認証のスターターキットとしてBreezeを導入した。
- メール認証機能を追加しようと思ったが，うまくいかなかった。
- 試行錯誤してうまくいった方法と，その理由をこの記事に供養します。

#前提
- 以下のコードでBreezeをLaravelプロジェクトに導入していること.
- 以下の環境です。MAMPでサーバーを立ち上げています。

| ハードウェア | OS |
|:-:|:-:|
| macbookAir2020(Intel) | BigSur 11.3 Beta |

|項目|バージョン|
|:-:|:-:|
|PHP|7.4.2| 
|Laravel|8.29.0| 
|MySQL|5.7.26| 
|MAMP|-|

```console:console
$ curl -s https://laravel.build/example-app | bash
$ cd example-app
$ php artisan migrate
$ composer require laravel/breeze --dev
$ php artisan breeze:install
$ npm install
$ npm run dev 
```

#方法
以下では，Breezeを用いてメール認証をする方法を記載します。

##Userの変更
モデルUserに Illuminate\Contracts\Auth\MustVerifyEmail を追加する

```php:app\Models\User.php
+ use Illuminate\Contracts\Auth\MustVerifyEmail;

- class User extends Authenticatable
{
   ...
}
+ class User extends Authenticatable implements MustVerifyEmail
{
   ...
}
```

## ルーティングの変更
ここが他記事と異なる部分です。Laravel/uiを用いている場合は

```php:routes/web.php
+ Auth::routes(["verify"=>true]);
```
とすればいいところなのですが，Breezeの場合は

```php:routes/web.php
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
```
となります。というのも，Breezeの場合はLaravel/UIをインストールしていないためです。

#参考文献
https://qiita.com/nekyo/items/03e50b4d0dd6f09287d6
https://dev.to/dendihandian/laravel-email-verification-3lfa
FuelPHP HelloWorld表示する

[FuelPHPのインストール](https://qiita.com/machiryu/items/7e1bd25125b23636b9cf)を事前にやりました。

# 初期設定
### 言語の設定
下記へ変更する。

```php:fuel/core/config/config.php
215行目　'language' => 'ja',
237行目　'locale' => 'ja_JP.UTF-8',
```
### タイムゾーンの設定
下記へ変更する。

```php:fuel/core/config/config.php
270行目 'default_timezone' => 'Asia/Tokyo',
```

# Hello world
ファイルを作成する。

```php:APPPATH/classes/controller/hello1.php
<?php
class Controller_Hello1 extends Controller {
  public function action_indexi() {
    return 'Hello world!';
  }
}
```
で、`http://localhost/myproject/hello1/index`にアクセスしてみる。
がエラー発生。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/f7c7070e-db05-81e9-c58b-58983a3c5c83.png)

hello1.phpのコードミス。
誤　`public function action_indexi() {`
正　`public function action_index() {`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/d65f53a9-ed93-97e6-5512-9db45ce0799b.png)
表示された！

hello.phpを作ってviewsフォルダに置く。

```php:APPPAH/views/hello.php
 <!DOCTYPE html>
 <html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <h1>Hello World!</h1>
  </body>
 </html>
```

hello2.phpのコントローラーを作る。

```php:APPPATH/classes/controller/hello2.php
<?php
class Controller_Hello2 extends controller {
  public function action_index() {
    return View::forge('hello');
  }
}
```
で、`http://localhost/myproject/hello2/index`にアクセスしてみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/73e236a1-c5fe-0f8d-e49c-afa797991561.png)
表示された。

ブラウザからはコントローラが呼び出されて、コントローラからビューが呼び出される。

# 参考サイト
[とりあえずやってみる！FuelPHP第5回~まずは、やっぱり「Hello World!」~](https://mynavi-agent.jp/it/geekroid/2018/01/fuelphp5hello-world.html)
【UiPath】Excel - シートをクリアする

# はじめに

この投稿は、RPAツールのUiPathで、Excelのシートをクリアする方法についての投稿です。

「Excel操作を.NETのコードでやってみよう」シリーズです。他の投稿はこちら。

https://qiita.com/miya_g/items/02230dc5774818f24e90

https://qiita.com/miya_g/items/8341d6cc0cf0fb77ac31

https://qiita.com/miya_g/items/e36f7b5da5bc994a49d7

https://qiita.com/miya_g/items/e4bf3de19c8b0c4225ca


---

# シートの内容を全消去したい時がある

Excelの操作をしていると、シートの内容を全部消してやり直すことがあります。
手で操作する場合は、以下のような操作です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/e5f7e564-7674-a9db-591a-cd65ad0cebff.png)

これをUiPathでやろうとすると、以下のように「クリック」と「ホットキーを押下」で実施するのが多いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/871297fc-2349-3f69-ff7a-cd855a752a09.png)

ですが、他にも実施する方法があります。

| No | 方法 | コメント |
|:-:|:-|:-|
| 1 | Click＆SendHotkey送信で操作をする | 王道だが「Hotkey送信」は気が引ける  |
| 2 | 空行を大量に入れたDataTableで範囲を書き込み | DataTableの容易が面倒  |
| 3 | シートを削除して再追加する | Sheet1しか無いときはシート名変更も必要  |
| 4 | InvokeVBAで実行する | VBAセキュリティ設定が必要  |
| 5 | InvokeCodeで実行する| 情報が少ない  |
| 6 | カスタムアクティビティで実行する| カスタムアクティビティの追加が必要  |

本当は「UiPath標準アクティビティ」で「シートクリア」があれば良いのですが、ありません。
5のInvokeCodeで実行できれば良いのですが、なぜか情報が少ないです。（VBAのコードはたくさんあるのに）
多分、そんなに難しくないので、自分で書いてみます。

# .NETコードで、Excelシートの内容をクリアする

Vb.NETで、指定のエクセルシートをクリアするコードです。
　※ 移植しやすいように、Actionで匿名関数にしています。
　※ 値だけでなく書式もクリア、フィルタもクリア、オートシェイプも全削除　をしています。

```VB
Dim ClearSheet As Action(Of String, String, String, String) = 
	Sub(bookPath As String, sheetName As String, clearFrom As String, clearTo As String)
		Dim ap As New Microsoft.Office.Interop.Excel.Application
		Dim wb As Microsoft.Office.Interop.Excel.Workbook
		Dim ws As Microsoft.Office.Interop.Excel.Worksheet 
		Dim sp As Microsoft.Office.Interop.Excel.Shape
		Try	
			'// Excelブックを開く
			wb = ap.Workbooks.Open(IO.path.GetFullPath(bookPath))
			'// シートループ
			For idx As Integer = 1 To wb.Sheets.Count
				'// シート名一致判定
				ws =  CType(wb.Sheets(idx), Microsoft.Office.Interop.Excel.Worksheet)		
				If ws.Name = sheetName Then
					'// フィルタークリア
					ws.AutoFilterMode = False
					'// セルの値書式クリア
					ws.Range(clearFrom, clearTo).Clear
					'// オートシェイプ削除
					For sidx As Integer = 0 To ws.Shapes.Count -1
						sp = CType(ws.Shapes(sidx), Microsoft.Office.Interop.Excel.Shape)
						sp.Delete
					Next
					'// A1選択（カーソル位置初期化）
					ws.Range("A1").Select 
				End If
			Next
			'// 保存して閉じる
			wb.Save
			wb.Close
		Catch ex As Exception
			Console.writeLine(ex.ToString)
			Throw(ex)
		Finally
			'// エクセル終了
			If Not(wb Is Nothing) Then wb = Nothing
			ap = Nothing
		End Try
	End Sub

Call ClearSheet("C:\test\Book3.xlsx", "Sheet1", "A2", "E9999")
```


# 終わりに

InvokeCodeで実施すると、デザイン変更や実行中のマウス操作でエラーになることがありません。
シートをクリアしたい場合に、引き出しの一つとして参考になれば幸いです。

最後までお読みいただき、ありがとうございました。
Fatal error: Allowed memory size of 1610612736 bytes exhausted...の一時的な対処法

#概要

Composerでインストールを試みた際にタイトルのエラーが出たので、その一時的な対処法をメモします。

#対処法
このエラーはメモリ不足でインストールできないよと言われているので、メモリの制限を取らなければいけません。

Composerの前に`COMPOSER_MEMORY_LIMIT=-1`をつけます。

```
COMPOSER_MEMORY_LIMIT=-1 composer require xxxx/xxxx
```

COMPOSER_MEMORY_LIMIT=-1 とつけることで一時的にphp.iniで設定したメモリを無制限にすることができます。
ページ内ページを作成することで、一覧には表示させず、無闇矢鱈にページを乱作できる

#はじめに
素直に、初めから整理すればいいのだが、思いつきでページを増やしてしまう今日この頃。
ページを増やすことのデメリットとしては、左のページ一覧がいっぱいになって、
目的のページを探しにくくなってしまう点です。
そこで、

##ページは増やすけど、ページの一覧には入れたくない時

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/219ca752-7982-92c8-98ff-6e1285713e07.png)
このボタンを使うと、一覧のところにページが生成されてしまうので、

ページの中で、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/304c52a2-f15a-279a-8fb9-fd067b9d5de5.png)
`/`を打ち、Pageを選ぶことで、
そのページの中に、ページが出来るので、一覧に並ぶことはありません。
いいね機能実装中にルートエラーmissing required keys: [:id]で時間が溶けた。

#いいね機能実装中にmissing required keys: [:id]がでた。

![スクリーンショット 2021-03-19 19.10.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933066/dc59cbc8-1c02-ab2f-d9f9-ca441ff2735c.png)





上記のようにいいね機能（recommend）を実装しrecommendボタンを押すと中間テーブルにuser_idとmicropost_idが保存され、redirect_backされて、下記のようにrecommend件数が増えるはずが
![スクリーンショット 2021-03-19 21.16.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933066/a63cee47-d636-b950-5800-2a2e58437248.png)


上記のようにはならず下記のようなエラーが発生。

![スクリーンショット 2021-03-19 17.26.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933066/9d7cb4b3-9aa0-d3bf-d52c-4537cad3894b.png)

いいねしたあとのコードdestroyときにいいねの中間テーブルの主キーが見つからないと吐いているらしいとはわかったが、どうしたら主キーを入れられるかがわからず時間が溶けた。
#問題は中間テーブルに主キーがないこと
エラー発生時のroutesは以下。

```
 micropost_recommend DELETE /microposts/:micropost_id/recommends/:id(.:format) recommends#destroy
```
よく見るとDELETEのパスのurlにrecommendsのidが入っている。しかし調べても主キーの渡し方がわからん。
色々調べると、中間テーブルからdeleteする際に、user_idとmicropost_idでfind_byしたものなので、urlに中間テーブルの主キー渡さなくてもよくね？となった。

#route.rbファイルのresouceとresoucesの違い
さてこのルートのurlに主キーを渡さなくてもいい方法調べるていくうちに下記の記事が見つかった。

https://qiita.com/wacker8818/items/1ba526fcbc73e065a511

今まで私はルートを下記のように記載していたが

```routes.rb
 resources :microposts, only: [:show, :create] do
    resources :recommends, only: [:create, :destroy]
  end
```
下記のように変更。変えたのは:recommendsの左記のresourcesからresourceへ単数形にした。

```routes.rb
 resources :microposts, only: [:show, :create] do
    resource :recommends, only: [:create, :destroy]
  end
```
するとルートが

```
 micropost_recommend DELETE /microposts/:micropost_id/recommends/:id(.:format) recommends#destroy
```
上記から下記へ変わった。

```
micropost_recommends DELETE /microposts/:micropost_id/recommends(.:format) recommends#destroy
```

そうdeleteのルートurlにrecommendsの主キーである:idが消えたのである。

これでバッチリ動いたし、別のユーザーがいいねを取り消しても他のユーザーのいいねが取り消されたりもしなかった。

中間テーブルだとresouce(単数形)の方でいい気がするが複数形使う時ってどんな時なんだろう。
【Rails】N+1問題とその解決方法

#はじめに
本記事ではRailsのアプリケーションを作成した際にN+1問題に直面したので、N+1問題の概要とその解決方法を紹介します。

#N+1問題とは？
N+1問題とはループ処理を行う際にSQLの発行がたくさん行われてしまい、サイトのパフォーマンスが下がってしまう現象です。

SQLの発行はサーバーの負担が大きいので、なるべく少ない回数にすることが望まれます。

# N+１問題の例
わかりやすくするために、以下のような記事を投稿できるアプリケーションを例にします。

usersテーブル

|id  |name  |
|---|---|
|1  |佐藤  |
|2  |鈴木  |
|3  |高橋  |
|4  |田中  |
|5  |伊藤  |


postsテーブル

|id  |user_id  |text  |
|---|---|---|
|1  |3  |こんにちは  |
|2  |4  |おはよう  |
|3  |1  |おやすみなさい  |
|4  |5  |ありがとう  |
|5  |1  |さよなら  |
|6  |2  |もしもし  |
|7  |4  |楽しい  |
|8  |1  |悲しい  |

一人のユーザーからたくさんの投稿があるため、userモデルとpostモデルは以下のようになります。

```user.rb
class User < ApplicationRecord
  has_many :posts, dependent: :destroy
end
```
```post.rb
class Post < ApplicationRecord
  belongs_to :user
end
```

またposts_controllerは以下のようにします。

```app/controllers/posts_controller.rb
class PostsController < ApplicationController
    def index
        @posts = Post.all
    end

    def new
        @post = Post.new
    end

    def create
        Post.create(post_params)
    end

    private
    def post_params
        params.require(:post).permit(:text)
    end
end
```

viewは全ての投稿の投稿者名と投稿内容を表示するようにします。

```app/views/posts/index.html.erb
<% @post.each do |post| %>
  <p><%= post.user.name %></p>
  <p><%= post.text %></p>
<% end %>
```
このコードの実行ログは以下のようになります。

実行ログ

```sql
Post Load (1.1ms)  SELECT `posts`.* FROM `posts`
  User Load (1.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
  User Load (0.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 4 LIMIT 1
  User Load (3.1ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  User Load (1.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1
  User Load (3.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  User Load (0.5ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 4 LIMIT 1
  User Load (0.7ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
```
はじめにpostsテーブルに1回SQLが走り、その後usersテーブルに記事数である8回SQLが走っています。

今回は記事数がそれほど多くないのでサイトパフォーマンスはあまり下がりませんが、記事数が大量になっていくとサイトパフォーマンスが大幅に低下して、ユーザーが使いにくいアプリケーションになってしまいます。

#N+1問題の解決方法
今回はincludesメソッドを使用して解決します。

方法は簡単で、controllerのindexアクションにincludesメソッドを追加するだけです。

```app/controllers/posts_controller.rb
class PostsController < ApplicationController
    def index
        #indexアクションにincludesメソッドを追加
        @posts = Post.includes(:user)
    end

    def new
        @post = Post.new
    end

    def create
        Post.create(post_params)
    end

    private
    def post_params
        params.require(:post).permit(:text)
    end
end
```

このようにすると、実行ログは以下のようになります。

```sql
Post Load (0.3ms)  SELECT `posts`.* FROM `posts`
User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IN (5, 1, 3, 4, 2)
```

先ほど9回SQLを発行していましたが、今回は2回で完了しました。

これはcontroller側でincludesメソッドを使うことで、すでにpostsテーブルのレコードに関連するusersテーブルのレコードが取得されているからです。

#まとめ

- n+1問題はSQLが大量に発行されてしまい、サイトのパフォーマンスが下がってしまう事である。
- controller側でincludesメソッドを使うことで解消できる

アプリケーションではレスポンス速度を少しでも短くすることが大事なので、Railsエンジニアを目指している方はぜひ覚えておきましょう。
redirect_stdout  で標準出力をキャプチャ (ondryaso/pi-rc522 ライブラリの標準出力を抑制する)



「RaspberryPi + ondryaso/pi-rc522 ライブラリで MyFare を操作する」


では、Mifare NFC リーダ/ライタモジュール RFID-RC522 を RaspberryPi / Python3 で使うライブラリとして ondryaso/pi-rc522 を使いました。

大体はうまくいくのですが、時折 E1 とか E2 という文字列が勝手に標準出力されます。python で CUI プログラムを作っていると致命的。

# 原因

ライブラリのソース中、以下のように特定の条件で無造作に E1 と E2 が print されるようになっています。

https://github.com/ondryaso/pi-rc522/blob/master/pirc522/rfid.py

```

.
.
.
        if i != 0:
            if (self.dev_read(0x06) & 0x1B) == 0x00:
                error = False

                if n & irq & 0x01:
                    print("E1")
                    error = True

                if command == self.mode_transrec:
                    n = self.dev_read(0x0A)
                    last_bits = self.dev_read(0x0C) & 0x07
                    if last_bits != 0:
                        back_length = (n - 1) * 8 + last_bits
                    else:
                        back_length = n * 8

                    if n == 0:
                        n = 1

                    if n > self.length:
                        n = self.length

                    for i in range(n):
                        back_data.append(self.dev_read(0x09))
            else:
                print("E2")
                error = True
.
.
.
```

仕方ないですねえ

# ライブラリに手を加える → やめました

上記の print("E1") だとか print("E2") をコメントアウトしたり、print("E1", file=sys.stderr) のようにすれば良い。
そのようにライブラリを書き換えようかな？ と思って、インストールしている場所をしらべてみたら・・・

```

/usr/local/lib/python3.7/dist-packages/pi_rc522-2.2.1-py3.7.egg
```


にありました。egg形式・・・ ALZip アーカイブ形式かと思いきや、python の setuptools に使われる単なるZipファイルだそうです。
めんどくさそうなので別のやり方で対処することにしました。

# redirect_stdout を呼び出し側で使う

ライブラリ呼び出し側の Python プログラム中で対処する方法です。

redirect_stdout を使うと、標準出力を Python プログラム上でリダイレクトすることができます。
Python 3.5 以降で導入されたらしいです。

以下は、https://github.com/ondryaso/pi-rc522/blob/master/README.md から UID を表示する部分を抜粋したものです。

```

from pirc522 import RFID
rdr = RFID()

f = io.StringIO()

while True:
  rdr.wait_for_tag()
  (error, tag_type) = rdr.request()
  if not error:
    print("Tag detected")
    (error, uid) = rdr.anticoll()
    if not error:
       print("UID: " + str(uid))

# Calls GPIO cleanup
rdr.cleanup()

```
上記を redirect_stdoutを導入して書き直すと以下のようになります。

```

import io
import os
from contextlib import redirect_stdout

from pirc522 import RFID
rdr = RFID()

f = io.StringIO()

while True:
  rdr.wait_for_tag()
  with redirect_stdout(f):
      (error, tag_type) = rdr.request()
  # print(f.getvalue())  # if need print "E1" or "E2"
  if not error:
    print("Tag detected")
    with redirect_stdout(f):
      (error, uid) = rdr.anticoll()
    # print(f.getvalue())  # if need print "E1" or "E2"
    if not error:
       print("UID: " + str(uid))

# Calls GPIO cleanup
rdr.cleanup()

```

上記では E1,E2のエラーをキャプチャーするために、


```

f = io.StringIO()

```
としていますが、キャプチャーする必要が無く捨てるだならば

```

f = open(os.devnull,'w')
```

とするのでもOKです。




参考
「Pythonで外部ライブラリが標準出力に吐くメッセージを抑制する」
https://qiita.com/zophos/items/2d3aee100eb4f17bd147
【理系＆WEBオタク向け】数式や化学式で使えそうなHTML手法5選

# HTMLで作れる、使えそうな数式や化学式を書くときの方法5選

プログラミングをやってる人ってなんとなく理系が多いイメージ（あくまで個人の感想です）。
さらにこの記事を見ているのはほとんどWEB系のエンジニアだということを考えれば理系×WEBエンジニアというニッチな層の人向けの記事になります。

（数学も科学も大ッキライな人、すみません。。。いや、むしろ理系科目が苦手な人のほうがコピペで使えるから役に立つ記事かも？！）

## 上付き文字（例:平方メートル）

### 平方メートル = 10m<sup>2</sup>

```sample.html
10m<sup>2</sup>
```

## 下付き文字（例：水 化学式等）

### 水 = H<sub>2</sub>0

```sample.html
H<sub>2</sub>0
```

## 分数

分数作成ツールで作成可能。
テーブル組みで表現されます。

![スクリーンショット 2021-03-16 2.02.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/1fdc1757-6554-8385-b0b4-50635a62d938.png)

```html
<table class="BunsuTbl"><tbody><tr class="trBunshi"><td class="Sei0" rowspan="2"></td><td class="Bunshi">1</td></tr><tr class="trBunbo"><td class="Bunbo">100</td></tr></tbody></table>
```
ツール：http://atm-tkd.sakura.ne.jp/math/etc/bunsu/bunsuhyoki110218.html

## 二次関数とかで使うようなかっこいい「f」や「x」

![スクリーンショット 2021-03-16 2.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/a3fb031a-2f1c-cdd2-df31-fbb3beb988b6.png)


```sample.html
<em>f</em>(<em>x</em>)
```

```style.css
em {
  font-family: Times New Roman, Times, sans-serif;
}
```

## グラフなど

読みたい人だけ読んでください。。。

https://kurage.ready.jp/jhp_g/html5/canvas.html

https://qiita.com/Haruka-Ogawa/items/59facd24f2a8bdb6d369

## おまけ

「MathML」というHTMLで数式を書くためのマークアップ方法もあるみたいですね。
私は使ったことはありませんが、普通のWEBサイトを作るだけならおそらく使う機会はこないような気がします。。。
こちらも読みたい人だけ読んでください。。。

https://www.wakuwakubank.com/posts/524-html-css-mathml/

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
【Laravel】Unitテストでユーザー認証をさせる

#はじめに
業務で既存のアプリケーションに通知機能を追加することになり、その途上のFeatureテストで便利なヘルパーがあることを知った
ので、そのメモです！

###actingAsヘルパメソッドを使って現在認証済みのユーザーを指定させる（基本文法）
```php

        $user = factory(User::class)->create(); // ユーザーモックを作り

        $response = $this->actingAs($user) //　actingAsヘルパーで認証
```


###使うことになったきっかけ
既存のコントローラに通知オブジェクトのcreate処理ロジックを組み込むため、その部分のテストを書いた。
しかし、そのpost操作の際にユーザー認証ができておらず４００番台エラーがでた！
postリクエストをさせるにはまず認証を通過させる必要があるということ！

### 使い方は簡単
例として、モデルファクトリでユーザーを生成し、actingAsヘルパメソッドにそれを引数で渡してあげるだけで認証状態をつくれる！

```php

        $user = factory(\App\Model\User::class)->create();// ユーザーのモックをつくって
        $response = $this->actingAs($user) //actingAs($user)とかくだけでユーザーがログインした状態にできる
            ->post("/api/survey/answer/complete",
                [
                   //post対象カラム
                 ]);
```
以上です！

参考記事：https://readouble.com/laravel/6.x/ja/http-tests.html
【Rails】rails db が見づらいのでクライアントツールを使おう

### 環境

MacOS
Rails 6.1.3
SQLite version 3.28.0

# Problem
railsを使っていてDBの中身を見たくなったり、SQLを流したいことは多々あります。
そんなとき使うのが「rails db(console)」コマンドですね。でもこれ、とっても見づらくありませんか？

```sql
sqlite> SELECT * FROM relationships LIMIT 1;
1|3|1|2021-03-04 08:19:13.390480|2021-03-04 08:19:13.390480
```

改行文字が含まれていればそのまま改行されて見えますし、ヘッダもありません。
SQLiteに慣れていないのもありますが、やはりこれでは可読性が高いとは言えません。
なんとかSQLiteのオプションで見やすくならないかと試行錯誤してみました。

# Try
```sql
-- ヘッダを表示
sqlite> .headers ON
sqlite> SELECT * FROM relationships LIMIT 1;
id|user_id|follower_id|created_at|updated_at
1|3|1|2021-03-04 08:19:13.390480|2021-03-04 08:19:13.390480

-- カラム毎に左揃えで表示
sqlite> .mode column
sqlite> SELECT * FROM relationships LIMIT 1;
id          user_id     follower_id  created_at                  updated_at
----------  ----------  -----------  --------------------------  --------------------------
1           3           1            2021-03-04 08:19:13.390480  2021-03-04 08:19:13.390480

-- カラム毎に改行して表示
sqlite> .mode line
sqlite> SELECT * FROM relationships LIMIT 1;
         id = 1
    user_id = 3
follower_id = 1
 created_at = 2021-03-04 08:19:13.390480
 updated_at = 2021-03-04 08:19:13.390480
```
だいぶ見やすくなりましたが、大量にデータを取得したいときや、カラムの数が多い場合上記の方法でもツライところがあります。

# Solve
データベースを可視化するクライアントツールを使いました。
https://tableplus.com
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189781/c8e9a441-6a27-ae1f-9abc-2f1b32c207ee.png)

設定は至って簡単です。
画面左下の「Create a new connection...」をクリックして「SQLite」を選択します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189781/7a33bca3-819b-6967-95c4-c1454e7752ee.png)

「Select file...」をクリックするとFinderが開くのでお使いのrailsプロジェクトに移動し、「db/development.sqlite3」を選択します。あとは「Connect」を押下で完了です。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189781/f201f460-9290-32e5-08ec-274035f47774.png)

登録・更新・検索すべてがGUIで操作可能になりました。
とっても見やすいUIですね！もちろん生のSQLも流せるので便利です。ハイライトが地味に嬉しいポイント。

# Summary
筆者の語彙力が乏しく「rails db 見づらい」「rails db 見やすく」とか検索してもヒットしなかったので記事を書いてみました。
余談ですが正式には「rails dbconsole」というのですね。短縮形で覚えると検索が大変ですね。
どなたかの助けになれば幸いです。
【Flutter環境構築】

# はじめに

Mac を使用していることを前提とした記事なので，Windows をお使いの方は戻るボタンを押していただき別の記事をご覧ください．  
手順はたった３ステップ．[公式ドキュメント](https://flutter.dev/docs/get-started/install/macos)を参照しながら進めていきます．  
さっそく環境構築を始めていきましょう！

# Flutter のインストール

1. [SDKをダウンロード](https://flutter.dev/docs/development/tools/sdk/releases?tab=macos)  
基本的にはStable 版の最新バージョンをダウンロード  
2. Flutterの保存先ディレクトリを作成して，ダウンロードしたzipを解凍  
※保存先場所は好きなところにディレクトリを作成してください．

~~~ bash
$ mkdir /Users/(user name)/bin/flutter
$ cd /Users/(user name)/bin/flutter
$ unzip ~/Downloads/flutter_macos_2.0.2-stable.zip
~~~

# パスを通す

1. 使用しているシェルを調べる

~~~ bash
$ echo $SHELL
~~~

2. 使用してるシェルに応じてパスを設定する

~~~ bash
// zshの場合
$ echo 'export PATH="$PATH:[PATH_TO_FLUTTER]/flutter/bin"' >> ~/.zshrc
$ source ~/.zshrc
~~~

~~~ bash
// bashの場合
$ echo 'export PATH="$PATH:[PATH_TO_FLUTTER]/flutter/bin"' >> ~/.bash_profile
$ source ~/.bash_profile
~~~

~~~ bash
// fishの場合
$ echo 'set -x PATH ~/bin/flutter/bin $PATH' >> ~/.config/fish/config.fish
~~~

3. 新しいターミナルを開き下記を実行し，パスが通っていればOK

~~~ bash
$ which flutter
~~~

# 開発環境に必要なものを確認する

~~~ bash
$ flutter doctor
~~~

上記を実行することで足りないもの，問題があるところを教えてくれる
- ✔︎マーク：問題なし
- ✖︎マーク：開発環境が不足
- ！マーク：問題あり

# Android Studio

## Android Studioをインストール
1. [Android Studioをダウンロード](https://developer.android.com/studio/index.html)  
2. Android Studioを起動し、表示にしたがってインストール．  
※基本的には全部Next, Finishをクリック

Welcome to Android Studioの画面が出れば成功です．

## Android Studioにプラグインをインストール
Android StudioにFlutterとDartのプラグインをインストール．
起動画面から
1. Configure->Pluginsを選択
2. 検索ボックスにFlutterと入力
3. Flutterをインストール
※DartプラグインはFlutterプラグインのインストールと同時にインストールされます．

## デバイスのエミュレータをインストール
Android Studioでデバイスのエミュレータをインストール．

起動画面から
1. Start a new Flutter projectを選択
2. Flutter Applicationを選択してNextをクリック
3. Project nameは任意の名前で入力しNextをクリック
4. Company domainは任意の名前で入力しFinishをクリック
5. エディタが表示されたら、メニューバーのTools->AVD Managerを選択
6. Create Virtual Deviceをクリック
7. Category->Phoneを選択されていることを確認し、任意のDeviceを選択してNextをクリック
8. 任意のOSをDownloadをクリックしてダウンロード
9. ダウンロードした項目を選択し、Nextをクリック
10. 設定画面が出てきますが、何もせずにFinishをクリック

これでデバイスのエミュレータのインストールが完了しました．

## Androidのライセンスを許可
Androidのライセンスを許可しないと実行した際に，！マークが出るので許可する．

~~~ bash
$ flutter doctor --android-licenses
~~~ 

上記コマンドを実行するとライセンス認証画面が出てくるので yを入力し，Enterを押して許可．

flutter doctorを実行し、Android toolchainの部分に✔マークがついていれば成功．

# Xcode

## Xcodeをインストール
AppStoreから入手できるので，そこからダウンロードしてインストール．

# CocoaPods

## CocoaPodsをインストール
CocoaPodsが必要なのでインストール．

~~~ bash
$ sudo gem install cocoapods
~~~


# VSCode

## VSCodeをインストール
1. [VSCodeをダウンロード](https://code.visualstudio.com/)
2. 特に難しいところはないので，解凍してアプリケーションフォルダに移動

## Flutterの拡張機能をインストールする
Shift+Command+Xで拡張機能を表示  
検索ボックスにFlutterと入力  
Flutterの拡張機能をインストール  

# 最終チェック

## flutter doctorで確認する  

~~~ bash
$ flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.0.1, on macOS 11.2.3 20D91 darwin-x64, locale en-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.1)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.0)
[✓] VS Code (version 1.52.1)
[✓] Connected device (1 available)

• No issues found!
~~~

一番最後にNo issues found!　と表示されていれば環境構築完了
PHP5上級試験/準上級試験の上級合格に挑戦(12) 上級落ちました

# 結果は

今日が試験。
結果はタイトルの通り。

前が８００点ちょうど、で、今回が８２５点。まあ準上級だけど。
正直前よりかなり自信があっただけ結構ショックだった。
もちろん受かるまでチャレンジし続けるので、続ける。
ここまできたらもう受からないとお金がもったいない。（落ちるのももったいないんだけど）

ひとまず、結果を見比べてみようと思う。


# 結果内訳

３章から１３章までは全部１００％を目指してやってきたが、
それでもそのままのところもあったり、逆に前回よりも悪かったところもあった。
↑が６個、→が９個、↓が４個と、以前と比べると上がってるところが多くなってきている。
感想としては、なかなか劇的に点数アップが図れておらず、現状維持なところが多い。
特にフィルターはかなり勉強しただけあってちょっと０点なのはびっくりした。
どんな問題だったかは忘れたのだが。。。

| 目次| 出題割合     |前回|今回|判定|
|:----|:------------|:--|:--|:--|
| １章 PHPについて |0 |-|-|-|
| ２章 PHP言語の基本 |0 |-|-|-|
| [３章 関数](https://qiita.com/Atsulabo/items/1697299314441ff22105)|0.02|50%|50%|→|
| ４章 文字列|0.02 |0%|50%|↑|
| ５章 配列|0.04 |0%|33%|↑|
| ６章 オブジェクト|0.1 |50%|33%|↓|
| ７章 ウェブに関するテクニック|0.12 |75%|63%|↓|
| ８章 データベース|0.08 |50%|40%|↓|
| ９章 グラフィック|0.04|50%|50%|→|
|10章 PDF|0.04|50%|100%|↑|
|11章 XML（＆XML系で追加された関数） |0.06|75%|100%|↑|
|12章 セキュリティ|0.12|71%|43%|↓|
|13章 アプリケーションに関するテクニック|0.08|60%|80%|↑|
|14章 PHPの拡張|0.04|0%|0%|→|
|15章 WindowsでのPHP|0.02|50%|50%|→|
|予備 SPL（Standard PHP Library）/日付クラス/PEAR（管理系のコマンドなど） |0.04|0%|50%|↑|
|予備 名前空間/クロージャー/リフレクション/Late Static Binding|0.04|100%|100%|→|
|予備 JSON|0.02|100%|100%|→|
|予備 PDOとネイティブモジュールの違い/mysqlndドライバについて|0.04|0%|0%|→|
|予備 正規表現（pcre, posix, mbstring）|0.02|100%|100%|→|
|予備 APD/Xdebug/memcache|0.04|50%|50%|→|
|予備 フィルター|0.02|100%|0%|↓|

#振り返り
+ 全体的に問題集を読んだだけではわからない問題が多かった。とくに見慣れないワードがあったりする。
+ PHPマニュアルで調べたところ、わからない問題やワードについて書いてあった、というのが多かった
+ 問題集からさらに発展した応用問題が多い
　→たとえば、配列のソートを、もっと複雑な連想配列のソートにしてみたり、など。
　→数値と文字列を同時にソートしたらどうなるか、とか。
　→他の方だと、整数の０はfalseとか、＝TRUEはfalseとか、abc < xyzはtrueだとか、php.iniの中の「error_reporting」「display_errors」なども抑えないといけないとかいうのもありました。（[参考](https://proengineer.internous.co.jp/content/columnfeature/4550#section303)）
+ どうやったら合格できるかっていうのをリサーチし続けていたら、<b>「問題よりも解説をじっくり読んでそこに書いてあることを覚える」</b>、<b>各テーマのPHPマニュアルを読んで、気になったところを調べておく</b>というのがあった。
+ 今後の方針として、<b>全体の復習はやりつつ、１〜１４章で的を絞ってPHPマニュアルで多く説明されている箇所を読み込むのと、各テーマの解説で新規に覚えるところがないか確認する</b>
+ PHPマニュアルは難しいのでQiitaで箇条書きでまとめつつやっていきたいところ
+ ３月４月はPHPマニュアルと、解説を読み込み、５月に再び受ける。申込みが殺到するので、４月１日から申込みできるようにして土日に受験できるようにする
+ 仕事にもちゃんと知識を使えるようにする

# 上級試験範囲を再び読み返す
https://www.phpexam.jp/summary/expert/

これを読み返すと。。。
>
『プログラミングPHP 第3版』を主教材とし、一般的な知識やPHPオンラインマニュアルなどからも出題します。

え？　黒本じゃなくて？？
正直黒本しか勉強してなかった。。。

読んでみると、黒本には書いてない情報があった。
配列だと、トレイトとか。
こちらも並行して勉強しないとだめ、らしいです。


# というわけで

+ 今後の方針として、<b>全体の復習はやりつつ、１〜１４章で的を絞ってPHPマニュアルで多く説明されている箇所を読み込むのと、各テーマの解説で新規に覚えるところがないか確認する</b>
+ プログラミングPHP第３版も読み、黒本にないところを確認しつつ、取り込むようにする

今日から再出発。
でもゼロベースからではなく、更に積み重ねて行くようにしたい。
ひとまず今日はおつかれ、自分。
寝る前の筋トレして明日からまた頑張っていこう
え、Google Cloud Platformで謎に３万円請求されたんですけど。。。その原因は・・・

皆さんこんにちは！

アッキーです

つい先日まで居酒屋でアルバイトをしていたのですが、緊急事態宣言と共にお店が閉店してしまい今無職の大学生です。

そんな僕に悲報が。。。

今友人のお店経営を手伝うのにサブスクリプションを使ったWEBサイトを制作しています。

主にFirebaseとStripeを使っています。

そんなFirebaseで請求が生じていないか調べたところ、およそ２円だったのでホっとしました。

ですが、請求先はGoogleアカウントになるので表示して見るとなんと**３万円**ほどの請求が！！！

確かにFirebaseは頻繁に使っているが、他に何かを使った覚えは一切ない。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954754/292d4627-1154-f8e1-d39d-0a1bfd5dcf8d.png)


内訳を見てみると、、、

なんと知らぬ間に**Cloud SQL**が追加されていた。

恐らく何かの手違いでCloud SQLを作成してしまった模様。

しかもこのCloud SQLは24時間稼働型のインスタンスらしい。

それが毎日動いていたらしく、毎日1000円前後の請求が発生していました。

それが一月積み重なれば、、、

3万円！！！！！！！！！！！！

3万円の請求に気づかない俺ってどんだけ鈍感なんだと感じました。

確かに思い返せば、外で買い物した記憶が無いのにクレジットの請求に3万円ほどの請求があったような。。。

まぁ起こってしまったことは仕方がないです。

皆さんも気を付けて下さい！！！

請求額は定期的に見よう！

僕はこれから毎朝AWSとGoogleの請求額を見ることをここに決意します！

めんどくさがらずに、毎朝見ます！！！

皆さんも手遅れになる前に今一度確認して見ましょう！！

以上、「え、Google Cloud Platformで謎に３万円請求されたんですけど。。。その原因は・・・」でした！

Thank you for reading
WordPress REST API タグのslug名でデータを取得する

# 概要
- REST APIをつかったpostの取得の話です。
- wordpress4.7以降は、セキュリティ上の都合で、それまでできていたタグのslug名での直接の絞り込みができなくなったそうな。[参考リンク](https://wordpress.org/support/topic/call-wordpress-rest-api-using-multiple-tags/)
- いろいろ調べてうまくいった方法があった、かつ(多分)日本語でズバリの情報がなかったので、記録しておきます。もっといいやり方があれば、教えてください！


# 実装
1. まずは、タグのidを突き止めます
1. 取得したidを使ってfetch!以上！


```js
  // 指定したslugでタグ(今回は"hoge")のid取得 
  let res = await fetch('https://sample.com/wp-json/wp/v2/tags?slug=hoge');
  let tags = await res.json();

  // 上記idをもとにアイテムを取得
  let tag = tags[0];
  if (tag) {
    let res = await fetch(`https://sample.com/wp-json/wp/v2/news?tags=${tag.id}`);
    let posts = await res.json();
  }
```
500 Internal Server Error

###500 Internal Server Errorとは
プログラム自体へのアクセスは行えているが、
実行ができない（処理が完了しない）場合に発生するエラーです。
ウェブサーバーに何らかの問題が発生しているものの、具体的なエラーや根本原因が明確ではなく、複数の原因が考えられます。

<a href="https://blog.hubspot.jp/http-500-internal-server-error">参照記事</a>


[![Image from Gyazo](https://i.gyazo.com/1d0daa142adb4db8eef31040f68fbadb.png)](https://gyazo.com/1d0daa142adb4db8eef31040f68fbadb)

[![Image from Gyazo](https://i.gyazo.com/1ec58767f6199a170968664a22cb245e.png)](https://gyazo.com/1ec58767f6199a170968664a22cb245e)
Pythonでコメント付きのJSONファイル(JSONC)を読み込む

##はじめに
JSONの詳細は[ウィキペディアの記事](https://ja.wikipedia.org/wiki/JavaScript_Object_Notation)をご参照ください。
このJSON形式ですが、本来の仕様にはコメントを記述するための仕様がありません。

読み込みも書き出しもソフトウェアで行う場合はコメントは要らないと思います。
一方で、設定ファイルにJSONを採用し、ユーザーがメモ帳等で変更するようなスタイルのソフトにおいては、**設定値の仕様が分かり易いのが望ましい**かつ**ファイルは読み込みさえできればOK**という場面が多く、コメントの需要が出てきます。

本記事では、全く大したコードではないですが ~~たまに欲しくなる自分のために~~
「コメントが書かれたJSON」を読み込むためのPythonコードを載せておきます。



##JSONCとは？
JSONにコメントを記述するための仕様が追加されたもの・・・という私の認識です。

[こちらのQiita記事( JSON にもコメントを書きたい )](https://qiita.com/yokra9/items/1ac03876415d7fd47a65)で紹介があります。
もともとはVisual Studio CodeのJSON形式の設定ファイルにコメントを書くために生まれたものだそうです。

C言語のように`//` や `/*  */` の形式でコメントが書けます。
まさに欲しいのはこれですね。以下の感じです。

```jsonc
{
  /*
    コメント
  */
  "Sample":{
        "Param1": 0.019,   //浮動小数点
        "Param2": 0,       //整数
        "String": "str"    //文字列
  }
}
```

##JSONを読み込む
まずは普通のJSONファイルを読み込むためのコードです。
Pythonではモジュールが提供されているので読むだけなら簡単です。

```Python
import json

with open("JsonFile.json", 'r', encoding='utf-8') as f:  # ファイルを開く
      text = f.read()                                    # 文字列を取得する
json_obj = json.loads(text)                              # JSONとして解釈 → 辞書形式で戻ってくる
```
簡単ですね。


##JSONCを読み込む
C言語のようなコメントが書かれたJSONです。
従って、C言語のようなコメントを取り除けば普通に解釈できるので**正規表現で消し去ってやります**。

マッチさせるための正規表現は下記Qiita記事を参照
[C/C++のコメントにマッチする正規表現](https://qiita.com/itsmypleasure/items/a79c210bae23a29d4ff1)

全ての材料は揃いました。以下でOKです。

```Python:jsonc.py
import json, re

def ReadJSONC(filepath:str):
    with open(filepath, 'r', encoding='utf-8') as f:      # 開く
        text = f.read()                                   # 文字列を取得
    re_text = re.sub(r'/\*[\s\S]*?\*/|//.*', '', text)    # コメントを削除
    json_obj = json.loads(re_text)                        # JSONとして解釈
    return json_obj                                       # 辞書形式を返す
```

別のpythonファイルから呼び出して使うときは、上記ファイルを置いて、
`from .jsonc import ReadJSONC`とか書いて呼び出せば使えますね。

以上です。
Salesforce組織をVScordに接続する手順解説

【初心者向け】SalesforceのApexをVS環境で編集できるよう環境構築します。うまくいかない方はこちらをみてトラブルシューティングしてください。
※ForceCode: ForceCode Menuaは古い方法で使用しないのでとりあえず無視してください。
###準備運動
####ローカルにインストールするもの
１. VisualStudioCode
https://azure.microsoft.com/ja-jp/products/visual-studio-code/
２. Java 
参考:https://techacademy.jp/magazine/8998
３. Salesfoece CLI 
https://developer.salesforce.com/docs/atlas.ja-jp.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm

####VisualStudioCodeにインストールするもの
１．Salesforce CLI
２．Salesforce Extension Pack
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/eca8d3e9-b915-48e2-890d-0e59c9b20add.png)


(！)Versionが最新の状態であるかも確認して下さい。
確認、更新方法→ターミナルに`SFDX update`を入力、Enter

###手順①
コマンドパレットを開く(Ctrl+Shift+P)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/2e1fed2e-36b7-3db6-c520-d2a50cea34f5.png)
コマンドパレットで以下を選択(上の方に出てこなければ検索してください)
`SFDX:マニフェストファイルを使用してプロジェクトを作成`
`SFDX: create Project with manifest`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/81f427ff-1dc3-c319-4389-9496f1a96774.png)
続いて標準のテンプレートを選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/1ddf81e8-00cf-6862-45df-f7ed1bdf8003.png)
プロジェクト名を任意で入力(`TestProject`にしました)
→保存して土台作りは完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/45cf0164-a7c0-3657-8b36-1d9c27cf226c.png)

次は**salesforce組織と接続**していきます。
(！)IDとパスワード、その組織の環境(本番かSandBoxか等)を把握している前提です。
###手順②
コマンドパレット(Ctrl+Shiht+P)で**組織を認証**を選択
上の方に出てこなければ検索してください↓
`SFDX:組織を認証`(英語にしてる方は`SFDC:Authorize an Org`)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/bbfbe468-ff1f-b7a0-4785-b682a3dd8fed.png)
使用する**salesforceの環境**を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/61f39eef-741f-e61f-eed6-c4d55ec6893f.png)
↓は何も入力せずEnter
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/72c9d5f4-f05d-390a-6f16-b205ac09a1ab.png)
組織に接続するための**ログイン画面**がWeb画面で開きます。
※ここでIDパスが合っているのにログイン失敗するといバグも起こりえますが、VScordで認証成功してればOKです。

###手順③
manifestのpackege.xmlを右クリ、**組織から取得**してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941408/3c425e52-04fb-c0fa-a134-e3b62da0119f.png)
####これで手順は以上です！
最後にちゃんと接続できているか不安な場合は、**デプロイ、取得**が正常にできるか確認しましょう。VScordで任意のクラスを更新、デプロイ、次に実際のsalesforce環境に戻って`設定>Apexクラス>任意のクラス`　
更新したコードが反映されているか確認でOKです。お疲れ様でした！

**備考：**また、チーム開発の場合は悲劇が起こらないよう、ちゃんと毎朝VSを開いたら組織のforce.appとpackage.xmlを更新(組織か取得)を忘れないようにしましょう。
検証のためにカスタムROMをスマホに入れるサマリ

開発をやっていると、Androidバージョンによる動作の違いなども見たくなる。
エミュレータでは見えないようなトラブルが合ったりするので、非常に大変。

星の数ほど機種があるAndroid、全機種を持つのは不可能。
ただ全バージョンとまでは行かなくても、
ある程度自由にバージョンは変えられると開発時の検証になったりするので、
非常に助かる。

ということで、カスタムROMを使ってみようと思った。
（Root化はやってません。）

#OEMロックを解除する
これに関しては機種によって違うから、ググったほうがいいです。
自分が持っている端末だと、機種のホームページ（中国のサイト）に行き、
ユーザ登録をし、解除用のコードか解除用ファイルをもらったような…（数年前にやったのでうろ覚え。


#ドライバを用意する
Windows10での方法。Macは持ってないからわからんです。

１．Android ADB Interface：起動時のADBコマンドを受け付けてくれる。
２．Android Bootloader Interface：Fastbootモードで接続した際にコマンドを受け付けさせるためのもの

#ADBコマンドとfastbootコマンドを使う準備をする
ここからダウンロードできる。
https://forum.xda-developers.com/t/tool-minimal-adb-and-fastboot-2-9-18.2317790/
インストールしたら、デスクトップのショートカットを実行。

#TWRPを準備
リカバリモードというのがあり、Fastbootモードで起動・接続したときにUSB経由でインストールする。
https://twrp.me/
ここからダウンロードできる。

#fastbootでTWRPをインストールする。
電源を切った状態から、ボリューム下げるボタンを押しながら電源を入れるとなる。
USBでスマホとPCを接続し、デバイスマネージャで「不明なデバイス」となってなければOK。
コマンドは忘れた。

#カスタムROMを準備する。
ここで使ってる機種のメーカから探してみる。
無かったら諦めるしかないかも。
https://forum.xda-developers.com/

#GAPPSを用意する。
GooglePlayストアがついてないものが多い。
https://opengapps.org/
ここで機種のCPUアーキテクチャとAndroidバージョンを指定し、
ダウンロードする。
※Playストアだけ入ってればいい人は、Picoでよい。


#リカバリモード（TWRP）でOSをインストールする。
まずデータをクリアする。
消去→高度な消去
Dalvik/ART Cache
Cache
system
Data
の4つをチェックし、削除する。

USBでPCに接続し、エクスプローラでROMファイル（Zip形式）とGappsファイル（Zip形式）をスマホにコピーする。
（見えなかったらドライバがインストールされていない）
ケーブルは、データ通信可能なものを使うこと。

インストールで、ROMファルを指定する。
Zip追加でGAPPSファイルを追加する。

インストールを実行。
インストールが終わったら、再起動する。


#再起動するとブルースクリーンになる。
ROMのインストールが失敗してる（らしい。）
諦めて別のやつを試してみるしかなかった。


#あとがき
特に悪さをしようとは思ってなく、
純粋に「今でも使えるのにAndroidバージョンが古くてゲームができない」という
そんな方々の状況には良いと思います。
かつて2万円で購入したZuk Z2 (Plusらしい)を今でも玩具として使えてるので
記録を残そうと思って書きました。