OmniAICreator/Qiita-1.07M huggingface dataset:
WSL環境下でRailsを動かしたときの小ネタ

# 初めに
WSL1環境下で、Railsを動かしたときにちょっと引っかかった小ネタを紹介します。

# 環境設定
- OS: Windows10 Pro 64bit
    - Version: 1909
    - OS build: 18363.1256
- WLS
    - Ubuntu 20.04
- Ruby 2.7.2
- Rails 6.0.3.3

# BCrypt::Errors::InvalidHash: invalid hash
[devise](https://github.com/heartcombo/devise)を利用しており、またMacからWindows環境へ乗り換えたときに発生する可能性が高いのがこのエラーです。
[Rails: BCrypt::Errors::InvalidHash (invalid hash) Devise 1.5.4 Rails 2.2.5](https://stackoverflow.com/questions/46010754/rails-bcrypterrorsinvalidhash-invalid-hash-devise-1-5-4-rails-2-2-5)

```sh
$ vi Gemfile
# To use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.13'

$  bundle update bcrypt-ruby
```
バージョンアップ以外にも、MacからUbuntu環境などに移行したときなどにも発生するようです。
該当gemのバージョンアップで解決できます。私の環境下では**bcrypt (3.1.16)**で正常に動くようになりました。

# デーモンの自動起動設定

実はWSL1/及びWSL2環境下ではUbuntuのsystemctlが上手く動作しません。
WSL2環境下だとsystemctlを動かして、デーモンの自動起動設定ができるみたいですが
WSL1だと動かせないようです。

[Windows 10 or 11 Home（WSL2）のUbuntuでsystemctlを利用する方法（systemdをPID1で動作させる方法） | Snow System](https://snowsystem.net/other/windows/wsl2-ubuntu-systemctl/)

かといって、毎回デーモンを起動させるのは面倒なので

[Windows10のWSL上にあるServiceを簡単に自動起動させる](https://qiita.com/nashi2603/items/d0645305b137017b91b0)

こちらを試してみます。

- Windows + R で「ファイル名を指定して実行」を表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149438/6c5fb6e0-1edb-1bc1-5018-aa6532b31e03.png)
- shell:startup と入力してEnter
- `C:\Users\[ユーザ名]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup` が開く

```sh
# file名 enable_wsl_service.bat
@echo off
wsl -u root -- service memcached start
wsl -u root -- service mysql start
```
上記ファイルを作成後は、Windows起動直後にサービスが立ち上がるようになります。

# Letter Openerの設定
WSL環境上で[letter_opener](https://github.com/ryanb/letter_opener)のGemを利用する場合、メール送信時にWebブラウザが起動してメールを表示してくれません。

以下の
[Add Windows 10 WSL Support #157](https://github.com/ryanb/letter_opener/issues/157)

```shell
# WSL上で実行 Chromeのパスを指定
export BROWSER='/mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe' 
```
こんな感じで、環境変数にブラウザのパスを指定してあげれば、動くようにはなりますが...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149438/e80f7cd6-8f2b-5dd3-1b0b-2b7da03a2ccd.png)

WSL側のパスを認識できない...本当なら`/wsl$/Ubuntu-20.04/`というのが先頭についていてほしい...そこまで重要じゃなかったので今回はスキップします。[letter_opener_web](https://github.com/fgrehm/letter_opener_web)を使えばなんとかなりますし、最悪[letter_opener](https://github.com/ryanb/letter_opener)のファイル保存パスをWindows側にすることで解決できます。

試してませんが[wslu](https://github.com/wslutilities/wslu)という解決策もあるみたいです。

# 最後に
WSL1でRails試してますが、概ね良好という感じです。
IBM Cloud APIKEYの作成(取得)方法

IBM Cloud APIKEYはユーザーの ID と関連付けられていて、ユーザーに割り当てられているアクセス権限に応じて、クラウド・プラットフォームやクラシック・インフラストラクチャー API にアクセスするために使用できます。

ユーザーIDとパスワードの代わりに使用でき、複数作成できて削除もできるので、アプリ別に管理も可能になります。

ここではこのAPIKEYの作成(取得)方法を説明します。

#1. IBM Cloudにログイン
https://cloud.ibm.com/　 からIBM Cloudにログインします。

#2. 上部メニューから「管理」→「アクセス(IAM)」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/c255e496-58d4-c289-fc94-108e1068d35d.png)

#3. 左のメニューから「APIキー」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/a889e58b-d437-2493-d907-eedeb0c3493d.png)

#4. 「IBM Cloud APIキーの作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/0abf0279-a505-9d32-c17d-537978f7c426.png)

#5. 「名前」と「説明」(オプション)を入力して、「作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/aae3e003-03e6-83bf-2bcf-518960a348fc.png)

#6. API キーをコピーするか、「ダウンロード」をクリックしてキーを保存
この **API キーは再度表示されないため、後で取り出すことはできない**ので、ダウンロードして保存を推奨します。できればファイル名にわかりやすい名前をつけましょう。
ダウンロードはjson形式ファイルになります。

ダウンロードする場合は「ダウンロード」をクリックして保存します。
コピーで良い場合は、コピーをクリックしてコピーします。
値をみたい場合は目のアイコンをクリックすると値が見えます。

尚、ダウンロードもコピーも300秒でできなくなるようですので、300秒以内に実施しましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/0e5b80e2-0882-139d-2f52-cf020f932f0d.png)


jsonファイルの中身：　**apikeyの値がAPIキーです(本物でなはなく伏せ字にしてあります)。APIキーの値が必要な場合はこの値を使用します。**

```json
{
	"name": "My API Key for Application A  ",
	"description": "Application A  用のAPIキー",
	"createdAt": "2021-08-23T08:28+0000",
	"apikey": "XXXXX_7XxXXXXXxXXX-xxxxXXXXX12XXXX"
}
```

リストにも表示されました：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/044234e5-b935-c06a-f401-d698a397544f.png)

リストの右側にある3点メニューからできるのは以下です。

- 詳細: 詳細の表示(APIキーは表示されません)
- 編集: 名前と説明が編集できる
- ロック: 一時的に使用不可にできる
- 削除: APIキーを削除


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/8099b2f3-ba98-31f3-497e-9fca2db1d43b.png)



**APIキーの値が取得できるのは300秒以内ですので、ここだけ注意しましょう。もし取得忘れやその後忘れてしまっても、削除、再作成で取得するしかないことに注意しましょう。**

以上です。
botton,textviewなどのスタイルの変え方

## 方法
`drawable.xml`ファイルに使いたいスタイルを新規作成し、xmlの`android:background`に設定するだけ


## 例
自作androidアプリ　[Flexible Dice](https://play.google.com/store/apps/details?id=com.chelak.dice)　の場合。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344513/6102ee3d-9058-12b2-3bac-ab0bcc81101c.png" width="160" height="326" class="jop-noMdConv"> <a href='https://play.google.com/store/apps/details?id=com.chelak.dice&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Google Play で手に入れよう' src='https://play.google.com/intl/en_us/badges/static/images/badges/ja_badge_web_generic.png'/ width="200"></a>
このアプリではTextViewのスタイルを変更してダイスを表示しています。

**1.`drawable.xml`の新規作成**
まずはスタイルを指定するdrawableファイルを作成します。
ここへ新規作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344513/fde7e5c7-0cfc-0dc0-d975-f5b1a12e3360.png)
中身はこんな感じ。背景色・枠線の丸み、幅、色を設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344513/60e71a61-7a73-1b9b-1518-1faa829a662a.png)

**2.設定したい箇所への設定**
こんな感じで、設定したい箇所のxmlに`android:background`を追記
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344513/1ac8a990-9cc0-5a72-0d24-5828aa1b8548.png)

**3.結果**
textviewに設定するとこんな感じになります。[Flexible Dice](https://play.google.com/store/apps/details?id=com.chelak.dice)　ではこれをダイスのUIとして使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344513/91862846-d729-97d0-8dd4-a1d54bee244a.png)
RealmのcreateOrUpdateはオンメモリ側のプロパティに値をセットしなければその項目はnilになる

# はじめに

タイトルを悩んだが適切なタイトルの表現が難しい。

RealmSwiftのcreateOrUpdateこと`create(_:value:update:)`メソッドにおいて、`update`パラメータに`.modified`もしくは`.all`を指定した場合かつプライマリキーを持つオブジェクトを更新する場合にその際の挙動について書いておく（後述するがCore Dataとほぼ同じ挙動だった）。

公式のリファレンスに従ってやや冗長に言い換えると、『主キーを持つオブジェクトによって既存を更新する場合は、新しいオブジェクト自体でプロパティが更新される』といったところかもしれない。

https://docs.mongodb.com/realm-sdks/swift/latest/Structs/Realm.html#/s:10RealmSwift0A0V6create_5value6updatexxm_ypAC12UpdatePolicyOtSo0aB6ObjectCRbzlF

>  If an object already exists in the Realm with the specified primary key and the update policy is .modified or .all, the existing object will be updated and a reference to that object will be returned.

# 前提

- RealmSwift
- v10.12.0

（おそらくRealmの出た当初からこの挙動は変わっていないのであまり重要ではない）

# createOrUpdate実例

## nameプロパティにセットしない場合

まずRealm.Objectの説明から

```swift
class Person: Object {
    @objc dynamic var id = 0
    @objc dynamic var name: String? // この値をセットしなかったりしてみる

    override static func primaryKey() -> String? {
        #keyPath(Person.id)
    }
}
```

このPersonのidを1にしたものを作成しnameをp1とする。そしてさらにid: 1を更新し、nameをセットしない。

```swift

func createPerson() {
    let realm = try! Realm()

    func debug(_ person: Person) {
        print("---")
        print("person.id:", person.id)
        print("person.name:", person.name ?? "nil")
    }

    do {
        let person = Person()
        person.id = 1
        person.name = "p1"

        try! realm.write {
            realm.create(Person.self, value: person, update: .modified)
        }

        debug(realm.object(ofType: Person.self, forPrimaryKey: 1)!)
    }

    do {
        let person = Person()
        person.id = 1
//            person.name = "p1" // ここでセットしないことでどうなるのかを検証したい

        try! realm.write {
            realm.create(Person.self, value: person, update: .modified)
        }

        debug(realm.object(ofType: Person.self, forPrimaryKey: 1)!)
    }
}
```

出力は次の通りとなり、新しいPersonによってデータがnameなしに上書きされたのがわかる。

```
---
person.id: 1
person.name: p1
---
person.id: 1
person.name: nil
```

- Person
    - id
        - 1
    - name
        - nil


# おわりに

（試せばわかると思うので）上記では細かく書いてないが、リレーションする内容もセットされていなければnameと同じようにnilになる。

# 関連

## Core Dataはどうなるのか

https://qiita.com/yimajo/items/426c54062cf0101f69bf
JavaScriptでエスケープ処理したい

## やりたいこと
HTMLのフォームから送られてきた文字列を変数に格納し、それをinnerHTMLに挿入し、HTMLに反映させたい。

1. HTMLのフォームに`<u>アンダーライン</u>`と入力
1. JavaScriptの変数に格納
1. innerHTMLなどで変数の中身をページに表示

## 発生する問題
\<u>アンダーライン\</u>
と表示したいが

アンダーライン
￣￣￣￣￣￣￣
と表示される。

## コード
```JavaScript
//フォームから変数に格納時に使用
function deEsc(str){
  str=str.replace(/'/g, "\'");
  str=str.replace(/"/g, '\"');
  str=str.replace(/&lt;/g, "\<");
  str=str.replace(/&gt;/g, "\>");
  str=str.replace(/&amp;/g, "\&");
  return str;
}

//変数をinnerHTMLなどで表示するときに使用
function enEsc(str){
  str=str.replace(/'/g, "&#39;");
  str=str.replace(/"/g, '&quot;');
  str=str.replace(/</g, "&lt;");
  str=str.replace(/>/g, "&gt;");
  return str;
}
```
以下解説
deEscはフォームから受け取った文字を変数に代入する際に使う。
enEscはinnerHTMLに挿入する際に使う。
環境によって\が¥になる場合がある。


いつも汚くてすんません。
AWS SDK for Ruby のVersionを知りたい時

例えば、インストール済のディレクトリで以下のような形で確認可能。

```ruby
# bundle exec irb
> require "aws-sdk-core"
> Aws::CORE_GEM_VERSION
=> "3.114.1"
```

ドキュメントには記載が無かったので、将来的には使えなくなる可能性もある。
SDKコードの以下を元に確認。

https://github.com/aws/aws-sdk-ruby/blob/6088447362144b02ddfd60f80c8df5bb6fd968a4/gems/aws-sdk-core/lib/aws-sdk-core.rb#L99
BeautifulSoupで最上層／最下層のタグを選択的に抽出する方法（暫定）

# 概要
- divのみで情報が収納されているhtml(一部分)からtextを抽出したい
- div群の深さ・並列数など構造が可変であり位置指定は難しい
  - かろうじて「最上層のdivは大項目」「最下層のdivは個別要素」というルールは信頼できそう
  - 最上層divの内部にいくつの最下層divがあるかはまちまち
  - 各最下層divのdiv深さは3だったり4だったりまちまち
  - ~~このクソ構造を作ったのは誰だァ！~~
- Beautifulsoupで最上層divおよび可変深さの最下層divを抽出する方法のメモ

# 詳細

## 最上層div
 - `soup.find_all('div', recursive=False)` で最上層のdivのみ抽出できるらしいが、私の環境では機能しなかった
 - htmlの一部分からsoupを作成する際にはbodyタグが全体を囲うように付与される
 - `divtops = soup.select('body>div')` でbodyタグ直下のdiv（必然的に最上層）のみを抽出できた

## 最下層div
 - 最上層divをdivtopとする
 - `divdiv = divtop.find_all('div')` でdivtop内の全てのdivタグを拾ってくる
 - `divbtms = list(filter(lambda x: len(x.find_all('div')) == 0, divdiv))` で、その下に更にdivタグを持たないdivタグ＝最下層のdivタグを抽出

## その他
 - divtopsはtype:`class bs4.element.ResultSet`(要素はtype: `class 'bs4.element.Tag'`)
 - divbtmsはtypeがlistになってしまっている(要素はtype: `class 'bs4.element.Tag'`)
 - typeが変更になってしまうのはモヤモヤする、もっとスマートな方法が絶対にある気がする……

## 参考
 - [Select all div siblings by using BeautifulSoup - Stackoverflow](https://stackoverflow.com/questions/27826883/select-all-div-siblings-by-using-beautifulsoup)
 - [BeautifulSoup4で親子、兄弟、前後要素の検索方法 - せなブログ](https://senablog.com/python-bs4-search)
 - [BeautifulSoup4の引数と要素の絞り込みについて - せなブログ](https://senablog.com/python-bs4-argment/)
 - [BeautifulSoupのfindAllではrecursiveが設定できる - bonlife](https://bonlife.hatenadiary.org/entry/20080413/1208093657)
初心者がArduinoでライントレースカーを作ってみた

前回の記事[組み込み初心者がキッチンタイマーをArduinoで作ってみた](https://qiita.com/Bakio202076/items/26e4678b67a9f0b8d5e5)のあとに製作したのがライントレースカーになります。

完成品がこちら

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">デモ動画 <a href="https://t.co/OCAapufFCi">pic.twitter.com/OCAapufFCi</a></p>&mdash; バキオ (@Bakio202076) <a href="https://twitter.com/Bakio202076/status/1429696420550873090?ref_src=twsrc%5Etfw">August 23, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

黒い線をトレースしてくれてます。

# 開発環境
Windows
マイコン:ATmega328P
センサー:AE-NJL5901AR-8CH([秋月電子](https://akizukidenshi.com/catalog/g/gM-13416/))
モータードライバー:AE-DRV8835-S([秋月電子](https://akizukidenshi.com/catalog/g/gK-09848/))
本体:FT-DC-002([秋月電子](https://akizukidenshi.com/catalog/g/gK-13651/))
ArduinoIDE(C言語)
基盤はオリジナル品です

# ハードウェア面
4人班で2台作るという課題だったので、私ははんだ付けをやらないで本体のキットを組み立ててました。
![005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693083/ac5a73a5-0923-0a1d-b3e3-955176c5c9cb.jpeg)
~~何回もテスト走行した後の写真なのではんだがもげかけてます~~

セレクトスイッチで電源ONOFF。
タクトスイッチでスタートストップです。
LEDは電源がONの状態で光るようになってます。
![007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693083/ba4a20b6-b5d8-0c50-35b7-09ff8b61a710.jpeg)


# プログラム

プログラムを非公開に変更しました、私が卒業した職業訓練校の生徒が本記事のプログラムを見てしまう事例が発生したので...


# 改善点
クラスの他の人がタイマー1と2を使い割り込み処理をしてタイムを縮めていたのでなるほどなあと思いました。後退の動作を割り込み処理に入れればもっとスムーズに動かせそうな気がします。

# おわりに
前回のキッチンタイマーの時より

このレジスタを比較対象にしたいならこう書いて～
ここで動きが変になるならこのあたりのプログラムを変えて～

といったことがスムーズにできるようになったので若干成長を感じることが出来ました。
JavaScriptでRGBをHEXに変換するコード

## やりたいこと
JavaScriptでRGB`rgb(rr, gg, bb)`からHEX`#rrggbb`に変換したい。

## コード
```JavaScript
//HEX変換
function toHexColor(c){
  c=c.replace(/[rgb(|)]/g,"");
  c=c.split(", ");
  hex="#" + toHex(c[0]) + toHex(c[1]) + toHex(c[2]);
  return hex;
}
//16進変換
function toHex(n) {
  var x = Number(n).toString(16);
  return n.length == 1 ? "0" + x : x;
}
```

かなり汚いが気にしないでいただきたい。
canvasで描画した内容をSkyWayで共有

## やりたかったこと

機械学習を簡単に利用できるml5を利用しているとcanvasを使った画面をSkyWayを利用して共有したくなってくる

## いきなりソースコード

```html:index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>SkyWayでcanvas共有</title>
  </head>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
    <script src="https://cdn.webrtc.ecl.ntt.com/skyway-latest.js"></script>
    <script src="main.js"></script>
  </body>
</html>
```

```js:main.js
let myColor;
let myCanvas;
let myStream;

function setup() {
  myCanvas = createCanvas(480, 320);
  myColor = color(random(255), random(255), random(255));
  background(myColor);

  // skywayのインスタンスを作成
  let peer = new Peer({
    key: 'SkyWayのAPIキー',
  });
  // skywayでドメインを許可していれば実行される
  peer.on("open", () => {
    console.log("open! id=" + peer.id);
    createP("Your id: " + peer.id);
  });

  // id入力タグの生成
  let idInput = createInput("");

  // 送信ボタンの生成
  createButton("Call").mousePressed(() => {
    // ボタンが押されたら
    const callId = idInput.value(); //id入力欄の値を取得
    console.log("call! id=" + peer.id);
    const call = peer.call(callId, myStream); //id先を呼び出し
    setEventListener(call);
  });

  // // 相手から呼び出された実行される
  peer.on("call", (call) => {
    console.log("be called!");
    call.answer(myStream); //呼び出し相手に対して返す
    setEventListener(call);
  });

  // 相手の映像を追加処理
  function setEventListener(call) {
    call.on("stream", (theirStream) => {
      console.log("stream!");
      let theirVideo = createVideo();
      // theirVideo.parent("#video-area");
      theirVideo.elt.autoplay = true;
      theirVideo.elt.srcObject = theirStream;
    });
  }
}

function draw() {
  if (mouseIsPressed) {
    ellipse(mouseX, mouseY, 10, 10);
  }
}

let isFirstClick = true;
function mousePressed() {
  if (isFirstClick) {
    // 画面をマウスクリックした後じゃないと実行できない
    myStream = myCanvas.elt.captureStream(frameRate()); // 60
    isFirstClick = false;
  }
}

```

大事なとこ、詰まったとこは

```js
let isFirstClick = true;
function mousePressed() {
  if (isFirstClick) {
    // 画面をマウスクリックした後じゃないと実行できない
    myStream = myCanvas.elt.captureStream(frameRate()); // 60
    isFirstClick = false;
  }
}
```

なぜか `画面をマウスクリックした後じゃないと実行できない` でした。

## 結果

[![Image from Gyazo](https://i.gyazo.com/b8ddaf10d6dbffa56989b0b29be20c15.gif)](https://gyazo.com/b8ddaf10d6dbffa56989b0b29be20c15)

マウスで描いたcanvasの内容を共有してます！

## 機械学習と合わせて

[![Image from Gyazo](https://i.gyazo.com/ab0b4ca6831ce439665118514ab23e64.gif)](https://gyazo.com/ab0b4ca6831ce439665118514ab23e64)

透過背景を写真やループ画像に飽きた人は是非canvasを透過背景にしてみてください！

ソースコードはGitHubにありますので是非御覧ください

[SkyWayP5/main.js at master · tkyko13/SkyWayP5](https://github.com/tkyko13/SkyWayP5/blob/master/skyway_unet/main.js)
59日後にITパスポートを受けるFラン私大文系既卒(26日目)

# 過去問(1回目)
ようやく一周したので過去問を解いてみた
## 結果
![スクリーンショット 2021-08-23 17.03.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1787362/60677780-aa6d-fbad-44cc-5579d0308463.png)

一応合格点超えた！わーい！
【Python】日付を入力してもらうプログラムができました

Pythonの標準ライブラリのみを使って
ユーザーに入力してもらった日付を `［"2021","01","01"］` みたいに扱えるようにするプログラムができました。
一度Qiitaに投稿してみたかったので、自分の運営しているサイトから誰が使うねん的な記事を持ってきてみました:)

1. ユーザーに日付を入力してもらう
2. 入力した日付をチェック
  - 整数であるか
  - 桁数に問題がないか
  - 入力した日付が未来の日付になっていないか
  - 存在しない日付となっていないか
3. 問題がなければリスト形式で日付が返ってくる（例：`［"2021","01","01"］`）

といったプログラムのコードを書きました。

```py
import datetime

def input_year():
# input_year　では、年の入力をしてもらう
    inputyear = input("年（例：2021）を入力し、エンター ")

    
    """strptimeで入力した数値にエラーが発生するかどうかで、正しい形式の年が
    入力されたか確認を行う"""
    try:
        Check = datetime.datetime.strptime(inputyear,"%Y")
    except:
        print("4桁の整数で年を入力しましょう")
        return input_year()
            
    return inputyear

def input_month():
# input_month　では、月の入力をしてもらう
    inputmonth = input("月（例：01）を入力し、エンター ")

    """strptimeで入力した数値にエラーが発生するかどうかで、正しい形式の月が
    入力されたか確認を行う"""
    try:
        Check = datetime.datetime.strptime(inputmonth,"%m")
    except:
        print("1～12のうちの整数で入力してください")
        return input_month()
            
    return inputmonth.zfill(2)

def input_day():
# input_day　では、日の入力をしてもらう
    inputday = input("日（例：01）を入力し、エンター ")
    
    """strptimeで入力した数値にエラーが発生するかどうかで、正しい形式の日が
    入力されたか確認を行う"""
    try:
        Check = datetime.datetime.strptime(inputday,"%d")
    except:
        print("1～31のうちの整数で日を入力しましょう")
        return input_day()

    return inputday.zfill(2)

def input_date():
# input_dateを呼び出すと、年月日の入力をしてもらい、その年月日が未来の日付や
# 存在しない日付になっていないかのチェックを行ってから、問題なければ
# &#91;'yyyy', 'mm', 'dd']　といったリスト形式で吐き出すようになっている

    print("年月日で入力しましょう")
    inputdate = &#91;]


    
    
    inputdate.append(input_year())
    inputdate.append(input_month())
    inputdate.append(input_day())

    try:
# date関数に入力された日付を差し込み、存在する日付を入力しているかのチェックに使った
        hikakuinput = datetime.date(int(inputdate&#91;0]),int(inputdate&#91;1]),
                int(inputdate&#91;2]))
        hikakunow = datetime.date.today()
    except:
        print("存在しない日付を入力しています。最初から入力し直してください")


    if hikakunow &gt; hikakuinput:
        pass
    else:
        print(inputdate&#91;0] + "年" + inputdate&#91;1] + "月" + inputdate&#91;2] + "年")
        print("誤った日付が入力されたようです。最初から入力し直してください")
        return input_date()
    
    try:
        Check = datetime.datetime.strptime(inputdate&#91;0] + inputdate&#91;1] + inputdate&#91;2],"%Y%m%d")
    except:
        print("誤った日付が入力されたようです。最初から入力し直してください")
        return input_date()

    return inputdate


a = input_date()
print(a)
```

Pythonの勉強始めてからまだ僅かなので、ツッコミどころがあったらぜひ教えて下さい！
誰が使うねんみたいなコードですが、もし使ってくれたら喜びます
Windows上で開発する時のWSL（Ubuntu）とWindowsの役割分担2021年版

2022-01-10 加筆
2022年になると、いよいよWSL2だけで完結することが増えてきたので、本記事は意味をなしません。過去アーカイブとして残します。

WindowsでもWSLが登場したことで、ほぼ「実質Ubuntu」が使えるようになって嬉しい。ただし、「WindowsにもWSLにも入るアプリはどっちに入れたらいいの？」って迷いはある。そこで整理してみた。

## 大前提としてWSL1を使う

この文書をみなくちゃいけない人はWeb開発初心者も多いはずなので、WSL2ではなくWSL1を前提にする。WSL2になると知っておかなくちゃいけないことが増える。WSL1を使いこなしてからでもいい。

## 使い分けマップ

以下、Web開発するにあたって「どっちにinstallすべきか」の分類。Ubuntuとあるのは、WSL1上のUbuntuのこと。

原則として、GUIはWindows,CUIはUbuntuでやる。CUIをUbuntuでやるのはUTF8をデフォルト文字コートして扱いたいから。日本語Windows上のCUI（コマンドプロンプトやPowerShell）は2021年でも未だにSJISがデフォルト。


| プログラム | どっち？ | 背景 |
|-----------|----------|------|
| Chrome | Windows | 普段使いのChromeがいいし、WSL1には最新のChromeは入らない|
| ChromeDriver | Windows | ChromeがWindows側にあるから |
| WSL-Terminal | Windows | ターミナルはWindows上にインストールする。WSL-Terminalは賢くて、Windows上のファイルをドロップするだけで、WSLのパスに変換してくれるので、UbuntuのコマンドにWindowsのファイルを引き渡すのが楽。なおBashコマンドでもターミナルっぽく動くけどUTF8mb4を通さないので仕事には使い物にならない | 
| Ruby  | Ubuntu | rbenvでバージョン切り替えるのがスタンダードだがWindows版のrbenvがない | 
|Python | 両方 | テキストを扱うならUbuntu。カメラデバイスに直接アクセスするようなPythonスクリプトはWindows上のPython。|
| Git | Ubuntu | WSL上のGitコマンドで一括管理する。|
| VSCode | Windows | Ubuntu上のソースはVScodeのWSLプラグインで直接編集できる。VScode上にもターミナル機能があるが機能限定だと思ったほうがいいので、WSL-Terminalは必要|
| ssh | Ubuntu | sshコマンドもUbuntuのものが直接使えたほうがいい。.ssh/config なども使えるし、sftpやポートフォワードともホスト名が共有できて便利。Ubuntu上のポートフォワードで開いたポートはWindow上のアプリも使えるので、Windowsでputtyなどのsshクライアントは使う場面がなくなる  | 
| MySQL | Ubuntu | MySQL（MariaDB）は素直にUbutuのものが入る。mysqldumpなどのコマンドも使うことを考えるとUbuntu上でbashスクリプトとして組み込めたほうがいい |
| AWS CLI | Ubuntu | bashスクリプトとして組み込まれることが多いので | 
| gsutil  | Ubuntu | 同上 | 
| DBeaver | Windows | MySQLのGUIクライアントはWindows上に入れる。ただDBeaverの公開鍵認証を使いたい場合は、Ubuntu上のsshが使ってる秘密鍵をDBeaverからも参照する必要あり |
| XServer | Windows | VcXsrv を入れておくとUbuntu上のXアプリがWindowsのDISPLAYに対して描画してくれる。Ubuntu上のPythonのmatplotlib経由の描画もWindows上で描画される | 
| OpenCV | Ubuntu | Ubuntu直で入れるのも大変で、実際にはUbuntu上のPython3にpip経由でopencv-python をインストールするのが便利。 OpenCVもGUIを使うことがあるが、それはWindows上のVcXsrv 経由でWindows上に描画できる |
| VNCクライアント | Windows | GUIのツールなのでWindows　| 

 

あれ？Dockerは？という疑問がわくとは思う。WSL1上ではDockerは動かないので、その場合にはWSL2にするか、VirtualBoxなどの仮想マシンの上でDockerを動かすしかない。

ちなみにWSL2にすると、Windowsとは別マシン扱いになるので、localhostが同じマシンを差さない。Ubuntu上のrubyからSelenium経由で「自分のマシンのChromeDriverがlistenしてるポート」を探しても見つからないし、Ubuntu上のmatplotlibが「localhostの0番ディスプレイ」を探しても見つからない。WSL1ならそれができる。ちょっとうれしい。

あとは、どんなに頑張っても所詮は手元の「開発環境」なので、動作確認はさっさと本物のサーバー上で確認したほうがいい。sshで入ってガシガシvimでファイルを編集してtmuxで重めの処理を実行してPCを閉じてご飯を食べに行きましょう。
hoverイベントについて

JQueryの学習中、つまずいた所のメモ。

```html:index.html
<div class="lesson">
  <div class="lesson-icon">
    <img src="https://prog-8.com/images/html/advanced/html.png">
    <p>HTML & CSS</p>
  </div>
  <p class="text-contents">ウェブページの作成に使用される言語です。HTMLとCSSを組み合わせることで、静的なページを作り上げることができます。</p>
</div>
```

```css:stylesheet.css
.text-contents {
  margin: 3% auto;
  width: 80%;
  font-size: 12px;
  color: #b3aeb5;
  display: none;
}

.text-active {
  display: block;
}

```

```javascript:script.js
$('.lesson').hover(
  function(){
    $(this).find('.text-contents').addClass('text-active');
  },
  function(){
    $(this).find('.text-contents').removeClass('text-active');
  }
);
```

##問題点##

hoverのセレクタを`$('.lesson-icon')`にしていて、プログラムが反応しなかった。
恐らくfindのセレクタ`('.text-contents')`を内包していないため。

##解決法##

**hoverのセレクタを`$('.lesson')`にすることで、`('.text-contents')`を内包し、作動した。**

##ポイント##
hoverイベントのセレクタはfindのセレクタを内包しているか確認する。






:::note warn
【Progate】JQuery　道場コース　中級編　2.レッスン一覧をつくろう
:::
JUnit 4.xをEclipseで実行するとNullPointerException

新しいEclipseで古いJUnit 4を起動するとNullPointerExceptionになる。新しい・古いは曖昧な表現だが、たとえば、この現象が発生する具体的なバージョンの例は以下の通り。

# 環境
* jdk 1.8
* Eclipse 2021-06(4.20.0)
* Junit 4.3

# 現象
エラーログは以下の通り。

```java
java.lang.NullPointerException
	at org.eclipse.jdt.internal.junit4.runner.SubForestFilter.shouldRun(SubForestFilter.java:84)
	at org.junit.internal.runners.TestClassMethodsRunner.filter(TestClassMethodsRunner.java:84)
	at org.junit.runner.manipulation.Filter.apply(Filter.java:47)
	at org.junit.internal.runners.TestClassRunner.filter(TestClassRunner.java:64)
	at org.junit.runner.manipulation.Filter.apply(Filter.java:47)
	at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:34)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:83)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:74)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:49)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:513)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
```

# 対策
このエントリ執筆時点では4.x系の最新が4.13.2なのでそれに変更する。
Drive KitでHUAWEI Driveからファイルをダウンロードする方法

# HUAWEI Driveからのダウンロード手順
1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. [ファイルオブジェクトを取得する](https://qiita.com/Rei_2020/items/15f6bbc9f5d48c471a03)
3. HUAWEI Driveのダウンロードリクエストを実行する

<b>注意点</b>
1. ファイルサイズが20MB以下の場合、isDirectDownloadEnabledをtrueに設定できます。

<b>サンプル</b>

```kotlin
private var drive: Drive? = null

fun load(filename: String, dest: File, isApplicationData: Boolean) {
    getFile(filename, false, isApplicationData)?.let { file ->
        download(file, dest)
    }
}

private fun download(file: com.huawei.cloud.services.drive.model.File, dest: File) {
    drive?.let { drive ->
        val size: Long = file.getSize()
        val isDirectDownload = file.getSize() < DIRECT_DOWNLOAD_MAX_SIZE
        drive.files()[file.id].let { get ->
            get.mediaHttpDownloader.setContentRange(0, size - 1).isDirectDownloadEnabled = isDirectDownload
            get.executeContentAndDownloadTo(FileOutputStream(dest))
        }
    }
}
```

# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Drive KitでデータをファイルとしてHUAWEI Driveにアップロードする方法

# HUAWEI Driveへのファイルアップロード手順
1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. 親フォルダのオブジェクトを[取得](https://qiita.com/Rei_2020/items/15f6bbc9f5d48c471a03)/[生成](https://qiita.com/Rei_2020/items/c2dde3245c8659d16047)する
3. com.huawei.cloud.services.drive.model.Fileオブジェクトを作る
4. ファイル名、mimeType、親フォルダを設定する
5. InputStreamを指定し、HUAWEI Driveのファイルアップロードリクエストを実行する

<b>注意点</b>
1. アップロード先にすでに同じファイル名のファイルが存在する場合、アップロード先のファイル名が勝手に{ファイル名}(次の番号).{拡張子}に置き換わります。

<b>サンプル</b>

```kotlin
private var drive: Drive? = null

fun saveBuffer(driveFilename: String, folderName: String, isApplicationData: Boolean, inputStream: InputStream, inputStreamLength: Long, mimeType: String): com.huawei.cloud.services.drive.model.File? {
    drive?.let { drive ->
        // ドライブにフォルダを作成
        var directoryCreated = getFile(folderName, true, isApplicationData)
        if (null == directoryCreated) {
            directoryCreated = createFolder(folderName, isApplicationData)
        }

        directoryCreated?.let { directoryCreated ->
            // 既存ファイルを削除
            val oldFile = getFile(driveFilename, false, isApplicationData)
            if (null != oldFile) {
                deleteFile(oldFile)
            }

            // 中身をアップロード
            val streamContent = InputStreamContent(mimeType, inputStream).apply {
                length = inputStreamLength
            }

            val content = com.huawei.cloud.services.drive.model.File()
                .setFileName(driveFilename)
                .setParentFolder(listOf(directoryCreated.id))

            val request = drive.files().create(content, streamContent)
            return request.execute()
        }
    }

    return null
}
```

# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Drive Kitで端末のファイルをHUAWEI Driveにファイルをアップロードする方法

# HUAWEI Driveへのファイルアップロード手順
1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. 親フォルダのオブジェクトを[取得](https://qiita.com/Rei_2020/items/15f6bbc9f5d48c471a03)/[生成](https://qiita.com/Rei_2020/items/c2dde3245c8659d16047)する
3. com.huawei.cloud.services.drive.model.Fileオブジェクトを作る
4. ファイル名、mimeType、親フォルダを設定する
5. アップロード対象ファイルを指定し、HUAWEI Driveのファイルアップロードリクエストを実行する

<b>注意点</b>
1. ファイルサイズが20MB以下の場合、isDirectUploadEnabledをtrueにして、ダイレクトダウンロードが選べます。
2. ダイレクトダウンロードのサポート上限サイズは20MBですが、5MB以下の場合に使ったほうがよいです。
3. アップロード先にすでに同じファイル名のファイルが存在する場合、アップロード先のファイル名が勝手に{ファイル名}(次の番号).{拡張子}に置き換わります。

<b>サンプル</b>

```kotlin
companion object {
    private const val DIRECT_UPLOAD_MAX_SIZE = 20L * 1024L * 1024L
}

private var drive: Drive? = null

fun saveFile(localFile: File, driveFilename: String, folderName: String, isApplicationData: Boolean): com.huawei.cloud.services.drive.model.File? {
    drive?.let { drive ->
        // ドライブにフォルダを作成
        var directoryCreated = getFile(folderName, true, isApplicationData)
        if (null == directoryCreated) {
            directoryCreated = createFolder(folderName, isApplicationData)
        }

        directoryCreated?.let { directoryCreated ->
            // 既存ファイルを削除
            val oldFile = getFile(driveFilename, false, isApplicationData)
            if (null != oldFile) {
                deleteFile(oldFile)
            }

            // 中身をアップロード
            val mimeTypeMap = MimeTypeMap.getSingleton()
            val extension = MimeTypeMap.getFileExtensionFromUrl(localFile.name)
            val mimeType = mimeTypeMap.getMimeTypeFromExtension(extension)
            val content = com.huawei.cloud.services.drive.model.File()
                .setFileName(driveFilename)
                .setMimeType(mimeType)
                .setParentFolder(listOf(directoryCreated.id))

            val isDirectUpload = localFile.length() < DIRECT_UPLOAD_MAX_SIZE
            val request = drive.files().create(content, FileContent(mimeType, localFile)).apply {
                mediaHttpUploader.isDirectUploadEnabled = isDirectUpload
            }

            return request.execute()
        }
    }

    return null
}
```


# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
SQLite3 で、各テーブルのレコード数を列挙する


# 環境

- Ubuntu 20.04
- sqlite3 3.31.1

```
sqlite3 -version

3.31.1 2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837balt1
```

# 方法

- SQLiteのスキルが不足しすぎていて、理屈を把握できていないが、以下のコマンドを入力すると取得できる
  - （心の余裕があるときに調べてみる）

```bash
# DBファイルのパス 
$ dbfile="/usr/local/var/db/turndb"

$ echo "SELECT 'SELECT count(*), \"' || name || '\" FROM ' || name || ';'  FROM sqlite_master WHERE type = 'table';" |     sqlite3 -readonly $dbfile | sqlite3 -readonly $dbfile
```

## 実行結果

- 件数とテーブル名が表示される

```bash
0|turnusers_lt
0|turn_secret
0|allowed_peer_ip
0|denied_peer_ip
0|turn_origin_to_realm
0|turn_realm_option
0|oauth_key
0|admin_user
```

# 参考にしたサイト

https://stackoverflow.com/questions/58298886/find-the-number-of-rows-in-each-table-in-a-large-sqlite-database
Drive KitでHUAWEI Driveのファイルとフォルダを削除する方法

# HUAWEI Driveのファイルとフォルダの削除手順
1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. [ファイルまたはフォルダを検索し、対象のcom.huawei.cloud.services.drive.model.Fileを取得する](https://qiita.com/Rei_2020/items/15f6bbc9f5d48c471a03)
3. HUAWEI DriveにオブジェクトのIDを渡し、削除命令を実行する

<b>サンプル</b>

```kotlin
private var drive: Drive? = null

fun deleteFile(target: com.huawei.cloud.services.drive.model.File) {
    drive?.let { drive ->
        val deleteFile = drive.files().delete(target.id)
        deleteFile.execute()
    }
}
```

# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Drive KitでHUAWEI Driveでファイルとフォルダを検索する方法

# HUAWEI Driveのファイルとフォルダの検索手順
1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. 検索クエリを作成する
3. HUAWEI Driveに検索クエリを渡し、検索を実行する

<b>注意点</b>
1. 検索対象はファイルの場合、検索クエリに"mimeType != 'application/vnd.huawei-apps.folder'"を追加する
2. 検索対象はフォルダの場合、検索クエリに"mimeType = 'application/vnd.huawei-apps.folder'"を追加する
3. 検索対象はアプリケーションデータの場合、DriveRequestのcontainersに"applicationData"をセットする

<b>サンプル</b>

```kotlin
private var drive: Drive? = null

fun getFile(fileName: String, isFolder: Boolean, isApplicationData: Boolean): com.huawei.cloud.services.drive.model.File? {
    drive?.let { drive ->
        val queryFile = "fileName = '$fileName' and mimeType " + (if (isFolder) "=" else "!=") + " 'application/vnd.huawei-apps.folder'"
        val files = drive.files().list().setQueryParam(queryFile)
            .setOrderBy("fileName")
            .setFields("category,nextCursor,files/id,files/fileName,files/size").apply {
                if (isApplicationData) {
                    containers = "applicationData"
                }
            }
            .execute()

        return files.files.firstOrNull { it.fileName == fileName }
    }

    return null
}
```


# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Drive KitでHUAWEI Driveでフォルダを作る方法

# HUAWEI Driveのフォルダの種類
1. ユーザーに見える普通のフォルダ
2. ユーザーに見えないアプリケーションフォルダ（隠しフォルダ）

上記の2種類あります。

# HUAWEI Driveのフォルダの作成手順
1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. com.huawei.cloud.services.drive.model.Fileオブジェクトを生成する（フォルダはファイルの一種）
3. com.huawei.cloud.services.drive.model.FileオブジェクトをHUAWEI Driveに渡して、実行する

<b>注意点</b>
1. mimeTypeに"application/vnd.huawei-apps.folder"をセットする
2. アプリケーションフォルダの場合、親フォルダのパラメータに{"applicationData"}をセットする

<b>サンプル</b>

```kotlin
private var drive: Drive? = null

fun createFolder(folderName: String, isApplicationFolder: Boolean): com.huawei.cloud.services.drive.model.File? {
    drive?.let { drive ->
        val appProperties: Map<String, String> = mutableMapOf("appProperties" to "property")
        val file = com.huawei.cloud.services.drive.model.File()
            .setFileName(folderName)
            .setMimeType("application/vnd.huawei-apps.folder")
            .setAppSettings(appProperties).apply {
                if (isApplicationFolder) {
                    parentFolder = listOf("applicationData")
                }
            }
        return drive.files().create(file).execute()
    }

    return null
}
```


# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Drive KitでHUAWEI Driveの容量を調べる方法

# HUAWEI Driveの容量を調べる手順

1. [HUAWEI Driveに接続する](https://qiita.com/Rei_2020/items/bb17a8fedb4849eaaa95)
2. HUAWEI Driveの情報を取得する
3. 取得した情報から、容量の項目を選ぶ

<b>HUAWEI Driveの情報を取得するサンプル</b>

```kotlin
private var drive: Drive? = null

val about = drive?.about()?.get()?.setFields("*")?.execute()
```

<b>容量を取得するサンプル</b>

```kotlin
// ドライブ容量
val total = about.storageQuota.userCapacity
// 使用済み容量
val used = about.storageQuota.usedSpace
// ドライブ空き容量
val free = total - used
```


# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Vue.jsのコンポーネントのsrcの書き方

## 画像が表示されない。
Vue.jsのコンポーネントのsrcの書き方がわからなかったので備忘録
下記だとパスが文字列としてそのまま渡されてしまい画像が表示されない。

```html
<img :src="@/assets/img/${filename}" />
```


## 結論
こう書けば良い

```html
<img :src="require(`@/assets/img/${filename}`)">
```
HUAWEI Driveについてと利用制限

# HUAWEI Driveについて
HUAWEI DriveはファーウェイがHUAWEI IDユーザーに提供しているクラウドデータ保存サービスであり、次のような使い方があります。

1. 端末のファイルをHUAWEI Driveにアップロードする
2. HUAWEI Driveのファイルを端末にダウンロードする
3. アプリデータの同期・保存

# 利用制限
ほぼすべての地域で使えますが、日本ではまだ未提供です。

https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/support-regions-0000001050151041

# GitHub
HMS Drive Kit Demo : https://github.com/Rei2020GitHub/MyPublicProject/tree/master/DriveKitDemo

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Drive Kitの紹介：https://developer.huawei.com/consumer/jp/hms/huawei-drivekit
* HMS Drive Kitのドキュメント：https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/introduction-0000001050039630
* Huawei Developers：https://forums.developer.huawei.com/forumPortal/en/home
* Facebook Huawei Developersグループ：https://www.facebook.com/Huaweidevs/
Trend Micro Cloud One Workload Security の無償版を有償版にアップグレードする


## はじめに

初めに無償版のCloud One Workload Securityを使い始めて、有償版にするための手順の紹介です。難しい作業ではないですが、一つだけ注意点があります。



## 無償版とは

Cloud Oneは使用開始から30日間、[無償版を提供しています](https://cloudone.trendmicro.com/docs/jp/billing/free-trial/)。

WorkloadSecurityであれば5台までなど制限がありますが、本番環境でも制限事項の範囲内であれば使っていきたいですよね。



## 前提

無償版を使用している状態から、[AWS MarketPlaceの有償版](https://aws.amazon.com/marketplace/pp/prodview-g232pyu6l55l4)を使用することとします。



## 有償版にする

CloudOneにログイン後のTop画面から、「サブスクリプションの管理」をクリックします。
![C1WS ACT08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925739/348fc495-1c50-f82f-f9ed-b1fcd569c1a7.png)




次に「AWS Marketplaceからのサブスクリプションを申し込む」ボタンをクリックします。
![C1WS ACT06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925739/c87f594f-f27a-78c6-28e7-522166638b85.png)


画面が遷移「Continue to Subscribe」をクリックします。

※ここでAWSにログインしていない場合は、MarketPlaceでサブスクライブする権限を持ったユーザでログインする必要があります
![C1WS ACT05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925739/7551715c-2684-84fc-0fc3-c600fe6b8c4c.png)




「Subscribe」をクリックします。
![C1WS 09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925739/06ac2508-88a8-5687-6f46-6aeaa9610ad7.png)




サブスクリプション管理の画面に戻ってみましょう。下記のようにサブスクリプション列が「登録済み」となっていればOKです。
![C1WS ACT07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925739/57917923-bdf1-b5a8-d1f9-6173455d986b.png)


## 【注意点】 アクセスドメインの許可について

特殊な環境しか発生しないのですが、有償版にする際に注意しなければいけない点があります。

作業端末から、AWSおよびTrendMicroドメインへのアクセス許可をする必要があるのです。
![AccessImg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925739/54785443-6d6d-aff7-4e7e-de9c6402c1e0.png)



今回、有償版にする際の端末が送信先アクセス制限がかかっている端末で作業をしました。

あらかじめAWSおよびCloudOneの操作のため「 https://cloudone.trendmicro.com/ 」は開けていたのですが、これだけでは足りず、有償化オペレーションをしてもうまくサブスクライブできない現象が発生しました。



サポートに問い合わせをすると、AWSとTrendmicroのドメインの両方に対してアクセス許可された端末からアクセスする必要がある回答をいただき、最終的には「https://\*.trendmicro.com/」を許可してサブスクライブに成功しました。

あまりないケースかと思いますが、ご注意ください。



## おわりに

有償版にする手順は[公式ページにも記載](https://cloudone.trendmicro.com/docs/jp/billing/sign-up/)がありますが、今回ご紹介した手順の方が画面遷移が少なく、わかりやすいです。この記事がどなたかのお役に立てれば幸いです。
SouceTreeで「高度な設定」が出てこない

言語設定が日本語だと表示されない。
Englishに変更すると出てくる


新しいMacに変えてSoucetreeの設定をしていたら、
ID/PWを間違えて入力してしまった。

該当のキーチェンを削除して、再度クローンすると、
ID間違えたもので、パスワードを要求される。

IDはどこで変えるのかのsoucetreeの環境設定を探すも項目が見当たらない。

調べると言語設定が日本語だと「高度な設定」が表示されないバグがあるとのこと
一旦Englishに変更してみると「高度な設定」の項目が表示された。
ActionController::UrlGenerationErrorに遭遇しました

オリジナルのアプリを製作中に始めて遭遇したエラーです。
今までは教材の通りにルーティングを組んで、パスもそれに会うように指定していました。
忘れないように記録しておきます。


```
ActionController::UrlGenerationError
```
さて今回遭遇したエラーですが、読んだ感じ、Urlの作成でミスがあるんだと思いルーティングを確認してみました。

エラーが出た場面ですが、ヘッダーからマイページに遷移するときでした。
なのでマイページのアクションを指定した箇所をチェック、、、

```rb
resources :users, only: [:update, :mypage] do
    member do
      get 'mypage', :to => "users#mypage"
      get 'mypage/edit', :to => "users#edit"
      put 'mypage', :to => "users#update"
    end
  end
```

resourcesとmemberで各アクションを行う際にidを含めることを指定しています。
今だからわかるのですが、何で動かへんの？？と結構ハマってました
memberを外して、collectionにした場合は上手く遷移できたのでlink_to
に渡しているパスとコントローラーがルーティングと合っていないのかなと思いました

＊この辺調べながらだったので間違って書いていたら教えていただけると幸いです

```erb:_header.html.erb
    <ul class="navbar-nav">
        <% if user_signed_in? %>
          <li class="nav-item list-inline-item mypage-link">
             <%= link_to mypage_user_path, class: "nav-link " do %>
               <i class="fas fa-user-circle mr-2"><label>マイページ</label></i>
             <% end %>
             <%= link_to "ログアウト", destroy_user_session_path, method: :delete, class: "nav-link" %>

　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　〜(以下略)〜
```

これだけじゃ上手くいってるような気がしてならなかったのですが、エラー文で検索していたところ同じエラーに遭遇している人がいらっしゃったので記事を参考にして訂正したら上手くいきました。

結果から言うと、memberで動かないのにcollectionで動いたのは違いがあるようで、memberで指定したルーティングはurlにidを含めて、collectionは含めないようです。

だからmypage_users_pathだとどこのidを取ってくるか指定していないからmemberでは動かないみたいです。

そこでmypage_user_pathに引数として,
current_user(deviseで使えるようになるヘルパーメソッドでログインしているユーザーのこと)を指定してマイページに遷移するときはcurrent_userのidを取ってきてねという風になると思います！

そしてマイページにはUserモデルのカラムを表示させてマイページを作りました。
ルーティング難しいですね。。。。
そもそもidを含める時と含めない時でどう使い分けるのか分かっていないからこんなエラーが出てしまうのだと思います
自分で調べてみますが、有識者の方ご教示いただけると幸いです。

間違いがある場合も教えていただきたいです！
samでlambdaのデプロイ

# 目次
・samの導入
・sam init
・sam build
・samconfig.tomlの作成
・sam deploy

# samの導入
brewによるインストール

```
$ brew tap aws/tap
$ brew install aws-sam-cli
```

もしくはpipによるインストール

```
$ pip install aws-sam-cli
```

# sam init
対話形式でプロジェクトを作成します。

```
$ sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1
What package type would you like to use?
        1 - Zip (artifact is a zip uploaded to S3)
        2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1

Which runtime would you like to use?
        1 - nodejs14.x
        2 - python3.8
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs12.x
        8 - nodejs10.x
        9 - python3.7
        10 - python3.6
        11 - python2.7
        12 - ruby2.5
        13 - java8.al2
        14 - java8
        15 - dotnetcore2.1
Runtime: 1

Project name [sam-app]: Test

Cloning from https://github.com/aws/aws-sam-cli-app-templates

AWS quick start application templates:
        1 - Hello World Example
        2 - Step Functions Sample App (Stock Trader)
        3 - Quick Start: From Scratch
        4 - Quick Start: Scheduled Events
        5 - Quick Start: S3
        6 - Quick Start: SNS
        7 - Quick Start: SQS
        8 - Quick Start: Web Backend
Template selection: 1

    -----------------------
    Generating application:
    -----------------------
    Name: Test
    Runtime: nodejs14.x
    Dependency Manager: npm
    Application Template: hello-world
    Output Directory: .
    
    Next steps can be found in the README file at ./Test/README.md
```

# sam local invoke
簡易的なプロジェクトが立ち上がったので、さっそく動かしてみます。

```
$ sam local invoke
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}
```
dockerが立ち上がってローカル環境による検証をすることができます。


```
$ sam local invoke -e path/event.json
```

-eを指定するとlambdaが実行される時のイベント情報を指定して実行させることができます。

# samconfig.tomlの作成
```
$ sam deploy --guided
```
対話形式でデプロイ設定ファイルsamconfig.tomlを作成します。

# sam deploy
```
$ cd .aws-sam/build
$ sam deploy
```
これでデプロイが成功すればOKです。

CloudFormationの管理コンソールからデプロイの確認ができます。
また、Lambdaでは関数の実行をテストすることもできます。

いろいろ試すことができるので、情報がまとまり次第更新していきます。
Laravel SaleでのPHPのパス解決

## 概要
WSL2上でLaravel Sailで環境を構築しVSCodeを使用した際に、PHP関連のエクステンションを動かしたいが、PHPのパスが解決出来ていないと動作しないエクステンションがあり、その解決で動いた方法のメモ。

WSL環境はWindows10、Ubuntu-20.04

## 方法

PHPを実行するファイルを作成する。

```shell
sudo vi /usr/local/bin/php
```

以下の内容を記載して保存する。  
内容的には、実行時のディレクトリ名を取得して、それを`Docker exec`の際のコンテナ名に使用して、PHPを実行する。

コンテナ名はLaravel Sailのデフォルトになっているので、もしコンテナ名が異なれば適宜修正する。

```shell
path=$(printf '%s\n' "${PWD##*/}")
command="docker exec ${path}_laravel.test_1 php "$@""
$command
```

実行権限を付ける

```
sudo chmod +x /usr/local/bin/php
```

これで、Laravel Sailのプロジェクト直下に移動して、`php -v`などのコマンドを打てば実行される。

あとはVSCodeのエクステンションの設定でも動作するようになる。  
例えば、以下のPHPMDのエクステンションは、

https://marketplace.visualstudio.com/items?itemName=ecodes.vscode-phpmd

この設定で動くことが確認できた。

```
"phpmd.command": "php ./vendor/bin/phpmd"
```
組み込み初心者がキッチンタイマーをArduinoで作ってみた

# はじめに
Arduinoを使いセレクトスイッチによる切り替えでキッチンタイマー、ストップウォッチになるタイマーを作りました。

![010.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693083/b0fb481e-20aa-d303-413f-fd19d5417c72.jpeg)

デモ動画

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">デモ動画 <a href="https://t.co/9BR0ounBDn">pic.twitter.com/9BR0ounBDn</a></p>&mdash; バキオ (@Bakio202076) <a href="https://twitter.com/Bakio202076/status/1429653041376989188?ref_src=twsrc%5Etfw">August 23, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ブザー音 <a href="https://t.co/EMEz3dQnUh">pic.twitter.com/EMEz3dQnUh</a></p>&mdash; バキオ (@Bakio202076) <a href="https://twitter.com/Bakio202076/status/1429653199489683459?ref_src=twsrc%5Etfw">August 23, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

7セグをダイナミック点灯で動かしているので、動画だと確認し辛いですがなんとなくはお判りいただけるかと。

# 開発環境

Windows
マイコン:ATmega328P
ArduinoIDE(C言語)
基盤はオリジナル品です

# 実際の作業量
この成果物は職業訓練校の授業で取り組んだもので、一から全部私が組んだわけではないので実際に私が作成した部分を説明します。

#### ハードウェア面

完成している基盤をもらい、回路図を見ながら部品を取り付けはんだ付け

#### ソフトウェア面
授業で作ってきたプログラムを組み合わせキッチンタイマーを製作
ストップウォッチの機能を追加

# ハードウェア面の解説

軽くハードウェア面の解説をすると左上のセレクトスイッチでストップウォッチ、キッチンタイマーの機能切り替えをしています。
右上の7セグLEDで時間を表示。
右下の青ボタンがスタートストップスイッチ。
左下の緑ボタンがリセット、ブザーストップボタン。
Arduino左にあるタクトスイッチはリセットピンに繋がっています。

# プログラム

プログラムを非公開に変更しました、私が卒業した職業訓練校の生徒が本記事のプログラムを見てしまう事例が発生したので...


# 実装したかった機能
本当はタイマーのカウントが0になった際、鳴るブザー音はリズミカルな音(例えばチャルメラの音)にしたかったのですが、7セグの表示がおかしくなる等のバグが取り切れずに断念しました。

# さいごに
私のプログラマー人生で初めて形になった成果物なので喜ばしい反面、今コードを見直すと汚いコードになってしまいました。
変数名やファイルの分け方、コメントのつけ方、不要なコードはすぐに消すなどなどの基礎的なことを気を付けないといけないと実感しました。
Eloquentで複数テーブルをjoinする

#やりかた
例えば棚卸システムを作るにあたって、以下のように３つのテーブルを作ったとする。
・stocks（在庫リスト）
・purchases（仕入リスト）
・materials（素材の基本情報をまとめたリスト）
※`stocksにはpurchase_id`が、`purchasesにはmaterial_id`がそれぞれ設定されている。
※materialsは材料を仕入れたときに材料名、仕入値、サイズなどが格納されている。

これを`stocks -> purchases -> materials`の順番でjoinしたい。
たとえstocksの方にmaterial_idが設定されていても、やることは一緒。

```StockController.php
// （namespaceやuseは省略）

// 2つのテーブルを普通にjoinする方法
$stocks = Stock::join('purchases', 'stocks.purchase_id', '=', 'purchases.id')->get();

// 3つ以上の複数テーブルをjoinする方法
$stocks = Stock::join('purchases', 'stocks.purchase_id', '=', 'purchases.id')
  ->join('materials', 'purchases.material_id', '=', 'materials.id')
  ->get();
```

これで`dd($stocks);`すると1つのテーブルから取得してきたように、複数のテーブルがまとまって確認できる。

#joinとwhereなどを組み合わせる場合
普通にwhereやoderByを行う場合、以下のように記述する。

```StockController.php
$stocks = Stock::where('カラム名', '条件の値')->get();
$stocks = Stock::orderBy('カラム名', 'desc')->get();
```

これはテーブルが１つだけなら問題ないが、複数テーブルを使う記述をする場合は、以下のように記述しないと、エラーの原因になる。
例えエラーにならなかったとしても、可読性が悪い。

```StockController.php
$stocks = Stock::where('テーブル名.カラム名', '条件の値')->get();
$stocks = Stock::orderBy('テーブル名.カラム名', 'desc')->get();
```

#以上を踏まえて、以下の条件でjoinする場合の記述方法

・`stocks`の`display`に`0`が格納されているレコードのみ取得する。
・`stocksにはpurchase_id`が、`purchasesにはmaterial_id`がそれぞれ設定されている。
・`stocks -> purchases -> materials`の順番にjoinする。
・`materials`の`material_id（材料名）`で昇順にソートする。

```StockController.php
$stocks = Stock::where('stocks.display',0)
  ->join('purchases', 'stocks.purchase_id', '=', 'purchases.id')
  ->join('materials', 'purchases.material_id', '=', 'materials.id')
  ->get();
```

#joinの条件にwhereなどを追加する場合の記述方法

[上記](#以上を踏まえて、以下の条件でjoinする場合の記述方法)のstocksとpurchasesをjoinする際に、`purchasesのカラム名:
test_clmが(int)99以上のレコードのみ`といいう条件を加える場合は以下のように記述する。

```StockController.php
$stocks = Stock::where('stocks.display',0)
  ->leftJoin('purchases', function($join){
    $join->on('stocks.purchase_id', '=', 'purchases.id')
      ->where('purchases.test_clm', '<=', 99);
   })
  ->join('materials', 'purchases.material_id', '=', 'materials.id')
  ->get();
```

以上！
これで複数テーブルをjoinする基本はOKかな？（たぶん）