OmniAICreator/Qiita-1.07M huggingface dataset:
Obsidianの小技その6｜PC上のファイル・フォルダへのリンクを貼る

## はじめに

つねに開きっぱなにしているMarkdownメモツール[Obsidian](https://obsidian.md)。1年ぐらい使ってみたので、ストレスフリーに近づける、いいかんじの小技をご紹介してみたいとおもいます。

## ファイルへのリンクを貼る

Obsidianは「リンクを貼りまくる」ことで便利になるツールです。なかでもPCに保存しているファイルにリンクを貼れて、これはめちゃめちゃ便利です。

- たとえば、PDFファイルを貼っておくと、クリックするとファイルが開きます
- さらには、フォルダも貼れて、そのばあいはクリックするとフォルダが開きます
- 文書内への画像の貼り込みにも使えます

リンクの形式は

```markdown
[表示テキスト](file://フルパス)

# 念を入れるならカッコをつけて
[表示テキスト](<file://フルパス>)
```

で、たとえばPDFの場合：

```markdown
[soramame](file:///Users/username/Desktop/soramame.pdf)
```

フォルダの場合：

```markdown
[211201_退避](file:///Users/username/Desktop/211201_退避)
```

みたいになります。

画像ファイルへのリンクを

```markdown
![soramame](file:///Users/username/Desktop/soramame.png)
```

と書いておくと、プレビューモードでは文書内で画像が見えます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/f8fc8302-5429-27cc-daf8-88673b4be44b.png" width=70%>

## フルパスのとりかた

ファイルのフルパスを取るのがわからん！めんどくさい！とおもうんですけども、macOSの場合だと、ファイルを右クリック→optionキー押すと`xxxxのパス名をコピー`とすれば簡単に取れます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/e807c81d-acc7-f142-811b-633c7141163c.png" width=30%>

Windowsは、エクスプローラに表示されているとおもいます。

## さらにラクする方法

わたしはもう右クリックもoptionキーを押すのもめんどうくさいし、`[xxxx](<file://>)`と書くのもめんどうなので、Automatorで小さなツールをつくりました。

参考：[Obsidianで便利なローカルファイルへのリンクを、Automatorに作成してもらうと楽ちんだなあ](https://qiita.com/hann-solo/items/5537e54704db48696f80)

これをクイックアクションに追加しているので、アイコン（mdStyleLink）をワンクリックで、クリップボードにMarkdownのリンク形式がコピーされます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/57d457ae-7ffe-b267-ecff-2bed2748f05b.png" width=50%>

↓

```markdown
# ペーストすると
[SS 2022-01-05 18.47.25.png](<file:///Users/username/Desktop/SS 2022-01-05 18.47.25.png>)
```

このミニツールのおかげで、わたしのノートは、リンク貼りまくりになっています。情報のソースがどこだったかを、覚えておく必要がなくなり、Obsidianのノートに貼っておくだけで済みます。記憶力がもともと弱いので、こういうことはツールが代行してくれると、脳に余白ができてたいへんに助かっています。

## おわりに

Obsidianのリンクを大別すると、３つになります。

| 種類           | 形式                        |
| -------------- | --------------------------- |
| 内部リンク     | `[[xxxx]]`                  |
| 外部リンク     | `[xxxx](https://yyyy)`      |
| ファイルリンク | `[xxxx](<file://フルパス>)` |

さいごのファイルリンクは、[Obsidianのヘルプにも載ってはいる](https://publish.obsidian.md/help-ja/高度なトピック/Obsidian+URIの利用)ものの、あまり詳しく書いていないので見逃されがちです。書いていることも、なんだかよくわかんないし。

しかしながらObsidianを思考支援ツールとして使うにあたって、必須のリンクではないかとおもっています。

次回は、プレビュー文書に画像を貼る小技を、もう少し紹介できればなとおもっています。

### ご参考

[Obsidian｜使いかたとコツ（目次）](https://qiita.com/hann-solo/items/ac8fa75394813e8adcf4)
Macの追加ダウンロードしたフォントの保存先が知りたい。

#追加ダウンロードのフォントが見つからない。


##FontBookを見るもグレーアウトしている。

Finderで見るがグレーアウトしている。
無論ダウンロードはしているのに。








##結論

ここにある。

```
/System/Library/AssetsV2/com_apple_MobileAsset_Font6
/System/Library/AssetsV2/com_apple_MobileAsset_Font7
```


このフォルダの中に沢山のフォルダがあるが、このcom_apple_MobileAsset_Font7に入って検索すれば探しているフォントが検索にかかると思う。


##原因は何なのだろう？
開発の都合上の事由なのか、はたまたAppleがあまり触って欲しくないからなのか？(でもどうせライセンス費用は払っているんでしょApple。)
昔からこの仕様なのでバグではないだろう。
謎。以上。
MacでDocker Compose V2を導入する方法。Docker Desktop使わない人へ。

## Docker Desktopを使わないMacerへ
これから話す内容はDocker Desktopユーザーにとっては関係ない話です。
Docker Desktopを入れれば`docker compose`はついてきますから。

今回はDocker Desktop有料化に伴って、Docker Desktopを使わずにLimaなどでDockerを利用している方への記事です。

## ここまでやってること前提(ググればでてくる)
1. HomebrewでLimaとdocker(Docker CLIのみ)をインストール。
2. Limaから[docker.yaml](https://github.com/lima-vm/lima/blob/master/examples/docker.yaml)をダウンロード。
3. `limactl start docker.yaml`をしてdocker環境を構築。
4. `export DOCKER_HOST=unix://$HOME/.lima/docker/sock/docker.sock`をして`$DOCKER_HOST`をLima仮想環境に変更。

例：[Docker Desktop for Mac(Windows)が有料化するから対応策を考えた](https://qiita.com/redgosho/items/43059dbc573f3aceb70d)

## MacでDocker Compose V2をDocker Desktopを使わずに入れる

[公式Docs](https://docs.docker.com/compose/cli-command/#install-on-mac-and-windows)にはMac or WindowsユーザーはDocker Desktopを使えと書いてあります。
仕方ないので諦め………なくても大丈夫です。

Docker Desktopを使いたくないMacユーザーはその下の[Linuxのやり方](https://docs.docker.com/compose/cli-command/#install-on-linux)を参考にしましょう。

DocにかかれているファイルのDL先を変更します。
例えばIntel Macの人は…

```
https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-linux-x86_64
↓
https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-darwin-x86_64
```

こんな感じです。

[docker/composeのReleases](https://github.com/docker/compose/releases)にそれぞれの環境にあったファイルが置いてあります。

各人最適なファイルをDLしましょう。

なにをやるかわかった方はDocを見ながら下記のように設定を進めてしまってください。

```
 mkdir -p ~/.docker/cli-plugins/
 curl -SL https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-darwin-x86_64 -o ~/.docker/cli-plugins/docker-compose
 chmod +x ~/.docker/cli-plugins/docker-compose
```

この設定が終わっていれば`docker compose version`が叩けるようになっているはずです。
できない人はなにかを間違えています。
頑張りましょう。
CSS変数の基本と使用例

CSS変数はその名の通りCSSで使うことのできる「変数」です。設定したスタイルを使い回すことができます。カスタムプロパティやカスケード変数とも呼ばれています。（[MDN](https://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_custom_properties)）
Web Componentsを使う上でCSS変数を組み合わせて使うのは有効ですし、Web Componentsを使わずとも便利です。この記事では、基本的な説明と特性を活かした使用例を紹介します。

# 基本
頭にハイフン2つ (--) をつけて設定し、`var()`と書いて使います。

```css
.sample {
  --color-black: #000000;
  color: var(--color-black);
  border-color: var(--color-black);
}
```
CSS変数は親から値を継承（カスケード）します。
サイト全体で使用するためには、`:root`擬似クラスを使って指定すると良いです。

```css
:root {
  --color-black: #000000;
}
```
フォールバックを設定できます。カスタム要素（例：`<custom-element></custom-element>`）を使う場合に有用です。デフォルトの値をフォールバックで設定しておき、スタイルを変更したい場合は親で設定します。

```css
/*web componentsでの使用を想定*/
:host {
  color: var(--base-color, #333);
}
```

# ダークモード設定
CSS変数はダークモード対応に使えます。使用する側（今回のbody）ではなく、設定する側（CSS変数）で条件を分けます。

```css
:root {
  --color-text: black;
  --color-bg: white;
}
@media (prefers-color-scheme: dark) {
  :root {
    --color-text: white;
    --color-bg: black;
  }
}
body {
  color: var(--color-text);
  background-color: var(--color-bg);
}
```

# レスポンシブ設定
メディアクエリを使ってCSS変数を上書きできます。

```scss
:root {
  --size: 4em;
  @media (min-width: 80em) {
    --size: 8em;
  }
}
.sample {
  width: var(--size);
}
```
Sassで変数を使う場合は変数を複数用意していました。

```scss
$sise-sm: 40em;
$size-lg: 80em;
```
CSS変数では１つの値を変化させることができます。変数に変化の条件を設定できるため、より柔軟に設計することが可能です。次のFlexboxの例を見てもらえると実感できると思います。

# CSS変数を活かしたFlexbox
Flexboxの余白（gap）と、横に並べる個数（count）を変数にしています。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="wvrXaQe" data-user="y___k" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/y___k/pen/wvrXaQe">
  Untitled</a> by T_Y (<a href="https://codepen.io/y___k">@y___k</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


```css
.list {
  --gap: 1em;
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
}
```

```scss
.item {
  --count: 1;
  width: calc((100% - var(--gap) * (var(--count) - 1)) / var(--count));
  @media (min-width: 40em) {
    --count: 2;
  }
  @media (min-width: 60em) {
    --count: 3;
  }
}
```

# まとめ
IE11対応がなくなった現在、CSS変数はpolyfill無しで使用できます。[Can I use](https://caniuse.com/css-variables)
これまではSassで書いてCSSに変換することが主流でしたが、WebComponentsを使い始めたことがきっかけでCSS変数を使い始めました。今後、CSS変数を活かしたCSS設計を考えようと思っています。
loggingをカスタマイズする

# tqdmとloggingの併用
「tqdmを使用しているときの出力にtqdm.writeではなくてloggingを使いたい！」
そう思うこと、ありますよね？

しかし、loggingを使用して出力したい場合、「print関数をtqdm.writeに置き換えて……」なんてのは出来ません

なので一手間要ります

```python
from tqdm import tqdm
import logging
import sys

class LoggingHandler(logging.Handler):
    def __init__(self, level=logging.NOTSET):
        super().__init__(level)

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.write(msg, file=sys.stderr)
            self.flush()
        except Exception:
            self.handleError(record)

logger = logging.getLogger("Log")
logger.setLevel(10)
sh = LoggingHandler()
logger.addHandler(sh)
format = logging.Formatter("%(asctime)s:[%(levelname)s]: %(message)s")
sh.setFormatter(format)

for i in tqdm(array):
    # 処理
    logger.log(20, "出力")
```

(途中で「こんなメソッド無いじゃん！」って思うかもしれませんが継承元が持ってるメソッドです)

重要なのはここです

```python
# 重要1つ目
class LoggingHandler(logging.Handler):
    def __init__(self, level=logging.NOTSET):
        super().__init__(level)

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.write(msg, file=sys.stderr)
            self.flush()
        except Exception:
            self.handleError(record)

...

# 重要2つ目
sh = LoggingHandler()
logger.addHandler(sh)
```

通常、loggingでコンソールに出力したい場合はlogging.StreamHandlerを使うと思いますが、コイツでは力量不足なので出来ません

なのでHandlerを自作します

# レベルごとに色分けする
「WARNINGだったらメッセージを黄色に、ERRORだったらメッセージを赤色で出力したい！」
そう思うこと、ありますよね？

実はこれ、さっき作ったクラスを少し変えるだけで実現できます

```python
import logging
import sys

class LoggingHandler(logging.Handler):
    colors = {"WARNING": "\033[33m{}\033[0m", "ERROR": "\033[31m{}\033[0m"}
    def __init__(self, level=logging.NOTSET):
        super().__init__(level)

    def emit(self, record):
        try:
            record.msg = LoggingHandler.colors.get(record.levelname, "{}").format(record.msg)
            msg = self.format(record)
            print(msg, file=sys.stderr)
            self.flush()
        except Exception:
            self.handleError(record)

logger = logging.getLogger("Log")
logger.setLevel(10)
sh = LoggingHandler()
logger.addHandler(sh)
format = logging.Formatter("%(asctime)s:[%(levelname)s]: %(message)s")
sh.setFormatter(format)
```

ここではWARNINGとERRORのみ色を付けましたが、LoggingHandler.colorsに、エラー名をキー、"色{}\033[0m"を値とした辞書を追加することでその他のレベルにも対応することができます

また、これを活用することで「エラー名のみ色をつける」といったことも可能です

# 結論
Handlerを自作すると、色んなことができる
CI で docker compose exec の実行結果を拾って task を失敗させる

CI で以下のような docker compose exec を実行したが、task が失敗してくれなかった。
`docker compose exec -T service bash -c "exit 1"`

`$?` には 1 が入っていたので、以下のコードで task を失敗させることができた
`if [ $? = 1 ];then exit 1 ;fi`
rubyでtwitter自動フォローボット(ランダムな時間にフォロー)

知人の依頼で作成

要件
-

- ランダムなインターバルでフォローする
    - 知人曰くBAN対策らしいけど、あまり関係ないような気もする
- 任意の検索ワードで検索して、一番上のひとをフォローする（#相互フォロー など)
    - そのユーザーがフォロー済みだった場合は、そのユーザーのフォロワーのなかからランダムで一人取得してフォローする


実装
-

- cronスケジューラでrubyスクリプトを1分に1回定期実行する
  - これだとランダムなインターバルにならないので、rubyスクリプト内で実行を絞る
    - `if rand <= FOLLOW_COUNT_PER_DAY / 1440.0`
    
```ruby
# frozen_string_literal: true

require 'twitter'
require 'logger'

FOLLOW_COUNT_PER_DAY = 200
SEARCH_WORDS         = '#相互フォロー'

class TwitterApi
  def initialize(logger)
    @logger = logger
  end

  def follow
    # 検索結果の一番上にいるユーザーをターゲットにする
    target_user_id = client.search(SEARCH_WORDS, lang: 'ja', result_type: 'recent').first.user.id
    # ターゲットユーザーがフォロー済みかどうか判定
    if client.friendship?(client.user.id, target_user_id)
      # ターゲットユーザーがフォロー済みの場合は、そのユーザーのフォロワーをランダムに取得しターゲットにする
      target_user_id2 = client.follower_ids(target_user_id).to_a.sample
      client.follow(target_user_id2)
      @logger.info("フォロー成功: #{target_user_id2}")
    else
      # ターゲットユーザーが未フォローの場合はフォロー
      client.follow(target_user_id)
      @logger.info("フォロー成功: #{target_user_id}")
    end
  end

  private
  
  def client
    @client ||= Twitter::REST::Client.new do |config|
      config.consumer_key        = 'Titter Developersで取得してください'
      config.consumer_secret     = 'Titter Developersで取得してください'
      config.access_token        = 'Titter Developersで取得してください'
      config.access_token_secret = 'Titter Developersで取得してください'
    end
  end
end

if rand <= FOLLOW_COUNT_PER_DAY / 1440.0  # 1日のフォロー数を制御する
  logger = Logger.new('./logfile.log')
  logger.info('スクリプト実行開始')
  sleep(rand(1..30))
  begin
    TwitterApi.new(logger).follow
    p 'スクリプト正常終了'
    logger.info 'スクリプト正常終了'
  rescue => e
    p 'スクリプト異常終了'
    p e
    p e.backtrace.join("\n") 
    logger.error 'スクリプト異常終了'
    logger.error e
    logger.error e.backtrace.join("\n") 
  end
end

```



実行方法
-
- デスクトップとか好きな場所にスクリプトを置く
    - 今回はデスクトップに、auto_following_botというディレクトリを作成してその中においた
    - CONSUMER_KEYなどは[Titter Developers](https://developer.twitter.com/en/portal/dashboard)で取得しておいてください
- twitter gemをインストール
    - gem install twitter
- crontabを開く
    - crontab -e
- crontabに以下を貼ります

```vim
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/home/<ユーザー名>/.rbenv/bin

*/1 * * * * cd ~/desktop/auto_following_bot && /Users/<ユーザー名>/.rbenv/shims/ruby 
 following_script.rb 
# スクリプトのパスは人それぞれなので注意

```
- auto_following_botディレクトリにて、rbenvでrubyをセットしてください。
- 1日のフォロー数を変更したい場合は`FOLLOW_COUNT_PER_DAY`を変更
    - 上限200くらいにしたほうがよさそう
    - 300にしたら、`Rate limit exceeded (Twitter::Error::TooManyRequests)`が頻出した
- 検索ワードを変更したい場合は、`SEARCH_WORDS`を変更
- ローカルPCだと、起動中しかフォローしないのでサーバを立ててその中でやれば１日中フォローします

:::note alert
ソースコード上に直接 API_KEY などをハードコーディングする場合は、githubにあげないようにご注意ください。
:::
Raspberry Pi Zero WHでSwitchBotカーテン(BLE)を動かした

# はじめに
Raspberry Piを使ってBLEでSwitchbotカーテンを動かす手順です。よく見るPythonではなく、Node.jsです。
Pythonの環境はZero WH単体では作れなかったので、Node.jsです。

# 機器
- Raspberry Pi Zero WH
- SwitchBot Curtain (https://www.switchbot.jp/products/switchbot-curtain)

# 構築
以下の公式の手順を参照しながら構築しました。ほとんどそのまんまです。

https://github.com/OpenWonderLabs/node-switchbot


## OSの準備
OSはRaspiOS(buster)のliteをインストールしました。

https://downloads.raspberrypi.org/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2021-12-02/

「2021-12-02-raspios-buster-armhf-lite.zip」を解凍してddでmicroSDに書き込み、Zero WHのスロットに差し込んで起動しました。wifi設定、パスワード設定、sshd有効化やlocale諸々の設定を済ませておきます。
OSやパッケージのアップデートはしませんでした。

```
$ node -v
v10.24.0
```

と、古いままです。

## パッケージインストール
piユーザでの作業です。githubの手順と比べてnpmのインストールが必要です。

```
$ sudo apt install bluetooth bluez libbluetooth-dev libudev-dev
$ sudo apt install npm
$ npm install @abandonware/noble
$ npm install node-switchbot
```

## スクリプト作成
switchbotカーテンが1台の場合は、以下のスクリプトで問題ないと思います。
複数台ある人はdiscoverの条件を変えてください。

```:open.js
// Load the node-switchbot and get a `Switchbot` constructor object
const Switchbot = require('node-switchbot');
// Create an `Switchbot` object
const switchbot = new Switchbot();

switchbot.discover({ model: 'c', quick: true }).then((device_list) => {
  return device_list[0].open();
}).then(() => {
  console.log('Done.');
  process.exit(0)
}).catch((error) => {
  console.error(error);
  process.exit(0)
});
```

```:close.js
// Load the node-switchbot and get a `Switchbot` constructor object
const Switchbot = require('node-switchbot');
// Create an `Switchbot` object
const switchbot = new Switchbot();

switchbot.discover({ model: 'c', quick: true }).then((device_list) => {
  return device_list[0].close();
}).then(() => {
  console.log('Done.');
  process.exit(0)
}).catch((error) => {
  console.error(error);
  process.exit(0)
});
```

# 実行
sudo付けて実行するだけです。やや時間がかかります。

```
$ sudo node open.js
Done.
$ sudo node close.js
Done.
```


# おわりに
Node-REDを使って室内と室外の照度センサーの値から、室内照明の点灯/消灯とカーテンの開閉を連動させて、完全自動管理しています。
Raspberry PiのNode-REDでCCS811(eCO2/TVOC)のデータ採取

# はじめに
部屋の空気の汚染具合を監視したくて、Raspberry Piにセンサーを付けて採取しました。

# 機器
- Raspberry Pi Zero WH (RaspiOS(Buster)「2021-12-02-raspios-buster-armhf-lite.zip」)

https://downloads.raspberrypi.org/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2021-12-02/

- KEYESTUDIO DC 5V CCS811 CO2 二酸化炭素 TVOC 大気質 センサー モジュール for Arduino

https://www.amazon.co.jp/dp/B086HCSM6N/ref=cm_sw_r_tw_dp_ZBCB85QAR1KS0JHD8R7H?_encoding=UTF8&psc=1

接続は、以下の記事を参考にしました。

https://www.itmedia.co.jp/news/articles/2109/18/news032.html

『VCCはラズパイの3.3Vに、GNDはラズパイのGNDに、SDAは3ピンに、SCLは5ピンに接続するあたりは通常のI2C接続と同じですが、これに加えてRSTをVCCに、WAKEをGNDに接続する必要があります。』とあるので、その通りに接続しました。
ブレッドボードは持ってないので、直ケーブル接続です。他の一般サイトではVCCを5Vに接続しているところもあるようですが、3.3Vで使えてます。

# 設定
「raspi-config」でi2cを有効にしておきます。よくわからんけど、spiも有効にしました。

```
$ sudo raspi-config
```

/boot/config.txtの末尾に以下のパラメータを追加します。

```
$ sudo vi /boot/config.txt
         :
dtparam=i2c_baudrate=10000
```

再起動します。

```
$ sudo reboot
```

i2c-toolsをインストールして、センサーが認識されているか確認します。

```
$ sudo apt install i2c-tools
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- 5a -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                    
```

i2cバスとして指定した「1」と、「5a」を覚えておきます。
usermodでpiユーザでi2cを利用できるようにします。

```
$ sudo ls -la /dev/i2c-1
crw-rw---- 1 root i2c 89, 1 Jan  1 18:23 /dev/i2c-1
$ sudo usermod -aG i2c pi
```

# Node-REDで利用する

```
$ sudo apt install nodered
$ sudo systemctl enable nodered
$ sudo systemctl start nodered
```

久しぶりにZeroでNode-RED起動しましたが、やっぱ遅いですね...
起動できたら、「パレットの管理」→「ノードの追加」で「node-red-contrib-ccs811-airquality-sensor」を追加します。

https://flows.nodered.org/node/node-red-contrib-ccs811-airquality-sensor

ノードを配置して設定を開くと、おそらく何も設定しなくてもi2cBusとAddressは合ってると思います。キャリブレーションも自動になっているので、そのままで良いかと思います。

![スクリーンショット 2022-01-05 18.04.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/9a49a17f-e248-8c93-2cb6-8d66d853845b.png)

あとは、payloadに「getMeasurement」と文字列を設定して定期的に実行させれば良いです。
私は後続のノードで自宅内のElasticsearchにデータを投げ込んでいます。

![スクリーンショット 2022-01-05 18.08.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/ee900b0b-fe4b-3b12-4df4-03d41a2be458.png)

センサーに通電させて、12時間後くらいから値が出始めました。センサーの仕様的には少なくとも24時間は放っておく必要があるようです。
あとは24時間毎にキャリブレーションが行われるそうなので、数日は放置しておいた方がそれっぽい値が採取できると思います。

https://twitter.com/shikasey/status/1477526477365473280?s=21

Zero WH + CCS811の最終的な外観はこちら。[SwitchBotカーテンの操作も兼ねさせています。](https://qiita.com/Y-Shikase/items/65c05d18fb169992a9b1)

https://twitter.com/shikasey/status/1477215235664920576?s=21

# おわりに

翌日はそれっぽい値が出てたのですが、さらに次の日は値が高めに出てなかなか収束しないです。
1週間くらい様子見てみようかと思います。

[追記]1週間様子みたところ、極端に大きな値が減り、そこそこ利用できそうな安定した値になってきました。

![スクリーンショット 2022-01-11 14.38.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/daad27fd-70b6-59bb-ed01-49488260a74a.png)
トイデータ(Toy Data)の作成

#はじめに
データ分析において、任意の正規分布データを作る方法を紹介する。

#やりたいこと
このようなデータを作りたい。
![Figure_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/e5e2f338-762c-5a65-7a17-d693f9dc2662.png)

#1次元の正規分布を二つ合わせてみる。
まず、X1の正規分布のデータを作成する。
同様にX2の正規分布のデータを作成する。
X1, X2を合わせて、プロットしてみる。

```python:
import numpy as np
import matplotlib.pyplot as plt

# 01.1次元データを別々に作る。

x1 = np.random.normal(loc=10, scale=50, size=1000) #loc :mean, scale : stdev
x2 = np.random.normal(loc =20, scale=10, size=1000)

```

```python:
#plot

fig, ax1 = plt.subplots()
ax1.scatter(x1, x2)
ax1.set_title('toy_data')
ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_aspect('equal')
ax1.grid()
```
グラフに書いてみると、（当たり前ですが）X1とX2の相関がないグラフが出来てしまう。
これでは、多変量分析には使えないため、次の方法に移す。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/a0621f5e-a5b3-3520-04ce-01dc49e97818.png)

念のため、X1, X2の相関係数と、分散・共分散行列を計算してみる。

```python:
correlation = np.corrcoef(x1,x2)
print('相関係数', correlation)

covariance = np.cov(x1, x2)
print('分散・共分散行列',covariance)

```

```python:結果
相関係数 
[[ 1.        -0.0434849]
 [-0.0434849  1.       ]]

分散・共分散行列 
[[2633.79021587  -23.18642097]
 [ -23.18642097  107.94668376]]
```
計算結果はやはりである。

#2次元の正規分布を作る。

2次元の正規分布を作る時、下記の二つのパラメータを指定する必要がある。（当然）

1. 各変数の平均
1. 変数群の分散・共分散行列

```python:
#平均
mu1 = 10
mu2 = 20
mean_mat = np.array([mu1, mu2])

#分散/共分散行列
var1 = 20
var2 = 20
cov_12 = 25#[-inf, inf]

cov_mat = np.array([[var1, cov_12],
                    [cov_12, var2]])

print(cov_mat)

```

```python:結果
[[20 25]
 [25 20]]
```
次に下記のコードでデータを作る。

```python

X = np.random.multivariate_normal(mean=mean_mat, cov=cov_mat, size=1000)
print(X.shape)
print(X.T.shape)

```


```python:結果
X.shape  (1000, 2)
X.T.shape　 (2, 1000)
```

可視化してみる。

```python
fig2, ax1 = plt.subplots()
ax1.scatter(X.T[0], X.T[1])
ax1.set_title('toy_data')
ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_aspect('equal')
ax1.grid()
```
期待した通りの結果で満足。

![Figure_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/df7ec83e-3c12-a10f-99e6-a72d5949179f.png)


#結論

今後、
np.random.multivariate_normal()
を活用する。

#おまけ(3次元)
3次元のデータは下記の式で作成する。n次元も基本的に同じ方法で作成可能である。

```python
# 3次元の正規分布からデータセットを作成する
#平均と分散/共分散行列を与え、正規分布を作る。

#平均
mu11 = 10
mu22 = 20
mu33 = 30
mean_mat = np.array([mu11, mu22, mu33])

#分散/共分散行列
var11 = 10
var22 = 10
var33 = 10

cov_12 = 0 #[-inf, inf]
cov_23 = 0
cov_13 = 0
cov_mat = np.array([[var11, cov_12, cov_13],
                    [cov_12, var22, cov_23],
                    [cov_13, cov_23, var33]])


#分布を作る
X = np.random.multivariate_normal(mean=mean_mat, cov=cov_mat, size=1000)


```python
print(X.shape)
print(X.T.shape)


fig3 = plt.figure()
ax1 = fig3.add_subplot(111, projection='3d')

ax1.scatter3D(X.T[0], X.T[1], X.T[2])
ax1.set_title('toy_data')
ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_ylabel('x3')
#ax1.set_aspect('equal')
ax1.grid()

plt.show()
```

```python
X.shape (1000, 3)
X.T.shape (3, 1000)

```
![Figure_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/d8c154e1-ecc2-dcf7-c210-3233a57421ed.png)
個人的にVue3の＜script setup＞に馴染めない理由

`<script setup>`が何かという話は、以下の記事でまとめてくれている方がいましたので、ご覧ください。
『[今Vue3やるなら＜script setup>を使おう](https://qiita.com/Nem-Nem/items/18afc73e1640e0a3274d)』

（まだ軽く使っただけの感想なので、何か誤っていたり、後で意見が変わって平然と`<script setup>`を使い出すかもしれませんがご容赦承ください）

# 理由1: Viewに公開したい変数とそうでない変数を明示的に区別できない

setup関数:

```vue
<script>
export default {
  setup () {
    const number1 = ref(..)
    const number2 = ref(..)
    const result = computed(() => number1.value + number2.value)
    return {
      result
    }
  }
}
</script>

// View内ではresultだけが使える
```

`<script setup>`:

```vue
<script setup>
const number1 = ref(..)
const number2 = ref(..)
const result = computed(() => number1.value + number2.value)
</script>

// View内ではnumber1もnumber2もresultも使えてしまう
```

だから何が困るかって言われると特にないんですが、ちょっと落ち着かない。

# ~~理由2: 全ての処理がインスタンス生成のたびに実行されてしまう~~

~~そうなると、以下のように、アプリ全体で1つあればいいような定数や関数を定義することができません。~~

setup関数:

```vue
<script>
// export外は、インスタンスがいくつ増えても1度しか実行されない。
// なので、アプリ全体で1つしか生成されない変数や関数を定義できる。
const NUMBER1 = 1
const sum = (...numbers) => numbers.reduce((a, b) => a + b)

export default {
  setup () {
    const number2 = ref(..)
    const result = computed(() => sum(NUMBER1, number2.value))
    return {
      result
    }
  }
}
</script>
```

`<script setup>`:

```vue
<script setup>
// インスタンス生成の度にscript内全体が実行される。
// ＝↓の変数/関数はアプリ内で1つあればいいのに、インスタンスの数だけ生成されてしまう。
const NUMBER1 = 1
const sum = (...numbers) => numbers.reduce((a, b) => a + b)

const number2 = ref(..)
const result = computed(() => sum(NUMBER1, number2.value))
</script>
```

~~共通化するだけなら、↓のように外部ファイルに置いてimportすればいいと思うんですが、
そのコンポーネントのSFCファイル内に置くのが整理の仕方として綺麗な場合も、この手段しかとれないのが辛いです。~~

```vue
<script setup>
// 例えば、NUMBER1は明らかにこのSFC内でしか使わないなら、わざわざ別ファイルに置きたくない。
import { NUMBER1 } from './constants'
import { sum } from './utils'

const number2 = ref(..)
const result = computed(() => sum(NUMBER1, number2.value))
</script>
```

## 追記

コメントで教えていただきましたが、`<script>`と併用することで`理由2`は解決できるようです！

```vue
<script>
// アプリ全体で一度だけ実行
const NUMBER1 = 1
const sum = (...numbers) => numbers.reduce((a, b) => a + b)
</script>

<script setup>
const number2 = ref(..)
const result = computed(() => {
  return sum(NUMBER1, number2.value) // ＜script＞側の変数へのscopeを持つ
})
</script>
```
for( size_t i=0, n=v.size(); i<n; ++i) が速いかどうか

# これは何？

https://twitter.com/k_nitadori/status/1478564262633422851

を見て、どんだけ違うの？　と思って試してみた。

# 簡単なケース

## n で受ける

```c++:c++
std::size_t sum1( std::vector<size_t> const & v ){
    std::size_t sum=0;
    for( std::size_t i=0, n=v.size(); i<n; ++i){
        sum += i*v[i];
    }
    return sum;
}
```

## 毎回 `.size()` を呼ぶ

```c++:c++
std::size_t sum2( std::vector<size_t> const & v ){
    std::size_t sum=0;
    for( std::size_t i=0; i<v.size(); ++i){
        sum += i*v[i];
    }
    return sum;
}
```

## 比較してみた

これを、以下のコンパイラで `-O2` でアセンブラを作って比較した。環境は macOS (intel)。

* Apple clang version 13.0.0 (clang-1300.0.29.30) / Target: x86_64-apple-darwin21.2.0
* g++-11 (Homebrew GCC 11.2.0) 11.2.0

結果は変わらず。
コンパイラは、ループ回数が変わらないことぐらいお見通し。

引数についてる `const` を外しても同じ。

# もっと面倒な例

ループ内で `vector` を別の関数に `const` 参照で渡すんだけど、関数の実装は不明という場合。

## n で受ける

```c++:c++
int foo( std::size_t x, std::vector<size_t> const & v );

int sum3( std::vector<size_t> & v ){
    int sum=0;
    for( std::size_t i=0, n=v.size(); i<n; ++i){
        sum += foo(i,v);
    }
    return sum;
}
```

## 毎回 `.size()` を呼ぶ

```c++:c++
int foo( std::size_t x, std::vector<size_t> const & v );

int sum4( std::vector<size_t> & v ){
    int sum=0;
    for( std::size_t i=0; i<v.size(); ++i){
        sum += foo(i,v);
    }
    return sum;
}
```

## 比較してみた

先ほどと同じ環境で比較してみたら、両方とも差があった。
`std::vector<size_t> const &` で要求している関数に渡してるんだから `v.size()` は変わらないということになりそうだけど、コンパイラは `const` 修飾子を信用してないらしい。


# まとめ

簡単な例しか調べてないけど、ループ内で vector を他の関数に渡したりしてなければ、コンパイラは要素数が変わらないことに気づくんじゃないかな。

一方。別の関数に vector の参照を渡すと、それが const 参照でもコンパイラは疑心暗鬼になって毎回 `.size()` を呼ぶ。

まあ呼ぶっていっても関数呼び出しコードは作られなくて、メモリを参照するだけだけどね。
C言語形式(2の補数)で表現された数値の文字列を整数に変換する

Pythonでは実行時にメモリ確保することでサイズを意識しないで整数を扱うことができる。
ただし、C言語と異なり負の値が2の補数形式で表現されないのでCの形式の二進数や十六進数を扱うのが少々面倒くさい。
本関数はC言語方式で表現された二進数の文字列を整数に変換する。

```py
import re


def strbin2intdec(valstr: str, is_signed: bool, bits: int):
    """
    2の補数形式で表現された数値を整数に変換する

    Args:
        valstr (str): 二進数表現された文字列
        is_signed (bool): signedとして評価するならTrue
        bits(int): 桁数

    Returns:
        int: 変換後の値(整数)

    Raises:
        TODO EXCEPTION: valstrから先頭の'0b'または末尾の'b'を消去して
                        残った文字列がbits個の0または1で構成されていない場合

    Examples:
        strbin2intdec('0b10001', True, 5) -> -15

    Note:
        PythonではC言語と異なり負の値が2の補数形式で表現されない
        例) -10dは  C言語では0b10110 だがPythonでは-0b1010となる
        本関数はC言語方式で表現された二進数の文字列を整数に変換する
    """

    # 先頭の'0b', 末尾の'b'をとる(いずれか一方)
    if valstr.startswith('0b'):
        valstr = valstr[2:]
    elif valstr.endswith('b'):
        valstr = valstr[:-1]
    else:
        pass    # do nothing

    # bitsと同じ数の0or1で構成されていない場合は例外を投げる
    ptn = fr'[01]{{{bits}}}'        # 5桁なら '[01]{5}' ※正規表現
    if not re.fullmatch(ptn, valstr):
        raise Exception

    # 場合分けで処理
    # ①signed かつ 先頭ビットが1のとき →桁数(bits)指定でbit反転して再反転
    # ②signedで先頭bitが0のとき →そのままintに変換(2進数として解釈)
    # ③unsignedのとき →そのままintに変換(2進数として解釈)
    if is_signed and valstr[0] == '1':
        mask_str = '1' * bits             # 111...(bitsの数の1) ※桁数重要
        mask_int = int(mask_str, base=2)  # mask_strを2進数としてint変換
        val_int = int(valstr, base=2)
        ret = ~(mask_int ^ val_int)               # 上記①の処理
    else:
        ret = int(valstr, base=2)

    return ret
```
【個人開発】Youtubeの本解説動画をいい感じに並べて見られるサービス「BookWatch」を作りました。

初投稿です。
個人開発は初めてで未熟な部分があるかと思いますが、せっかくリリースできたので記事を書いてみようと思います。


##どのようなサービスか


Youtube上の本に関連する動画をタイトルごとにまとめたサービス「BookWatch」を開発しました。
気になる本を選ぶと関連する動画を閲覧できます。また著者やカテゴリで検索することもできます。

[![Image from Gyazo](https://i.gyazo.com/8a9ce28f2703e78f32a993f88d2240f4.jpg)](https://gyazo.com/8a9ce28f2703e78f32a993f88d2240f4)

[【BookWatch】 - 書籍に関するYoutube動画まとめ](https://bookwatch.jp/)



##サービスを作成した背景


僕はYoutubeの本紹介・要約動画が好きでよく見ています。分かりやすくまとまっている
動画が多いですし、本購入前の「試し読み」感覚で視聴できてとても便利です。

そんな中ふと「**表紙を見比べながら本を選ベたらいいな**」
「**特定の著者やカテゴリの本へ楽にアクセスできたらいいな**」
なんてことを思いました。



もともと本屋さんにふらっと立ち寄って、気になる表紙の本を立ち読みしたり
気になっている著者の本をいくつか読み比べたりするのが好きなので、**そんな体験をサービスとして提供できたら面白いんじゃないか**、と思い本サービスを開発しました。


## 使い方

サービス自体は全て無料で利用いただけます。

##### 1.気になる書籍を選ぶ

[![Image from Gyazo](https://i.gyazo.com/8a9ce28f2703e78f32a993f88d2240f4.jpg)](https://gyazo.com/8a9ce28f2703e78f32a993f88d2240f4)

##### 2.「動画で学ぶ」欄から本の関連動画を選択できます

[![Image from Gyazo](https://i.gyazo.com/3fc8fbbcf917a48cc7613e3c9a30b44c.jpg)](https://gyazo.com/3fc8fbbcf917a48cc7613e3c9a30b44c)

##### 3.気に入ったらリンクより購入ページへ

また会員登録をするとお気に入りや読み終えた本のストック、コメントができるようになります。

##こだわったところ

デザイン・操作性は極力シンプルにし、本の情報が出来るだけ見やすくなるように工夫しました。
また気になる著者・カテゴリの書籍へワンクリックで飛べるようにしています。


##使用技術

バックエンド
Django

フロントエンド
Bootstrap
HTML
CSS(SCSS)
Javascript

##おわりに
サービス内のコンテンツについては随時追加していこうと思っています。
会員登録不要で見られますので、ぜひ利用してみてください。
拙い文章ですが最後までご覧いただきありがとうございました！


Twitterもやっていますのでぜひ。
[BookWatch](https://twitter.com/BookWatch_info)
[開発者](https://twitter.com/Miz__ziM)
[MacOS]SwiftUI、非同期での図形描画

　ターゲットをMacOSとしたSwiftUIで、マルチスレッド利用した重たい処理中に図形を描画するサンプルです。

##やりたいこと
　Mac環境において、重たい処理中でも処理経過などをグラフィカルにSwiftUIで簡単に表示したい。
##サンプルのイメージ

　グラフ描画開始ボタンをクリックするとウインドウ上に折れ線グラフっぽいグラフが１秒間隔で描画されます（重たい処理での計算途中結果を自動表示したいケースをイメージ）。

SwiftUI利用した計算途中状況などの図形描画サンプルが少なかったので、作成してみました。
![スクリーンショット 2022-01-05 17.33.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471383/aeeda7b1-3b0f-b327-cc49-4d315a1e6218.png)

##サンプル作成の環境
　Swift 5.5.2,  Xcode 13.2.1, M1 Mac

##コードサンプル
　MacOSをターゲットとしたSwiftUIプロジェクトで、デフォルトで作成されるソースに以下上書きすると動作するはずです。処理内容など、細かい点はコード上のコメントを参照ください。
なお、変数の排他制御は必要になることがあります。

```ContentView.swift
// 描画データの構造体
struct MyData {
    var x: CGFloat
    var y: CGFloat
}

import SwiftUI

struct ContentView: View {
    // 描画データの配列：「@State」定義の変数に変化があると画面は自動的に再描画される。
    @State var lineData: [MyData] = []
    @State var buttonEnable = true
    
    var body: some View {
        VStack {
            // 描画先のコンテキスト
            Canvas { context, size in
                // 外部関数呼び出し、描画するパスがセットされる
                let myPath = drawLine(view: self)
                // myPathにセットされた情報で描画する
                context.stroke(myPath,
                               with        : .color(.orange),
                               lineWidth   : 2)
            }
            .frame(width: 400, height: 300)
            .border(Color.blue)
            .background(Color.white)

            // 描画するためのアクション
            //  - １０秒間バックグランドでの処理結果を表示させる
            Button("グラフ描画開始") {
                // 非同期処理開始（スレッド登録＆実行）
                DispatchQueue(label: "runTask", attributes: .concurrent).async {
                    // ボタン非活性化
                    self.buttonEnable = false
                    // 外部関数呼び出し（ 重たい処理をイメージ、内部で１０秒間処理している ）
                    runTask(view: self)
                    // ボタン活性化
                    self.buttonEnable = true
                }
            }
            .padding()
            .disabled(!buttonEnable)        // ボタンの活性・非活性を変数で制御
        }
    }
}

// 重たい処理で描画データセットっぽくしたもの：通常は計測データなどセット
func runTask(view: ContentView) {
    // サンプルにランダムなデータを生成（説明略）
    view.lineData = []
    for n in 0 ... 10 {
        sleep(1)
        let x = CGFloat( n * 40 )
        let y = CGFloat.random(in: 50 ..< 250)
        let line = MyData(x: x,
                          y: y)
        // 適宜 変数などの排他ロックを行う
        view.lineData += [line]
    }
}

// データをパスとして描画
func drawLine(view: ContentView) -> Path {
    // 描画パス
    var myPath = Path()
    // 初期位置セット（キャンパスにペンを置く感じ）
    myPath.move(to: CGPoint(x: 0,
                            y: 0))
    // 配列にセットされたデータで描画
    for data in view.lineData {
        // データ毎にペンを移動させて描く
        myPath.addLine(to: CGPoint(x: data.x,
                                   y: data.y))
    }
    // 描画パスを返す
    return myPath
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```

##投稿について
　SwiftUIは経験数週間ですが、MacOSをターゲットとした記事が少ないので投稿してみました。間違いやもっと良い方法もあるかと思いますが、開発の参考になればと思います。

この方法は、Swiftでシミュレーションや計測などプログラミングした時の結果表示に使っています。
Kotlin（JavaScript ）で地図アプリ（ゴミ拾いアプリ）。（14日目）


# 今日やった事

MySQLにある位置情報をすべてWEB上の地図に表示していたのを、日付を選択して表示できるように変更。

使用言語：
HTML、CSS、JavaScript、jQuery、PHP


#完成画面

BootStrapを使う予定でしたが、HTML+CSSを自分で書いて作成しました。
地図はお見せ出来ないですが、サイドメニューのリストから日時を選択して、ボタンを押すと、地図上のマーカーが更新され、更に、右側のtextarea内に、テキストで位置情報のリストを表示するようにしています。

![イメージ75141.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503948/e393c0c7-4677-b558-e3d7-042ae3e1d0b0.jpeg)


#HTMLコード

日付表示部分のHTMLコード。

```html:index.html
    <div class="side">
      日付：
      <select name="ListDate" id="ListDate">
      </select>
      <input type="button" value="送信" onclick="clickButtonDate()"/>
      <textarea class="DateText" id="DateText"></textarea>
    </div>
```

selectタグ内に、JavaScriptから動的に要素を作成します。
textareaタグも、同様。


#JavaScriptコード

```javascript:index.html

<script>

  var ArrayDate = [];
  var json ;
  var SetDate = "";

...

  function initMap() {
    ...
    json = JSON.parse(readPHP());
    ...
    var data = new Array();
    for (let i = 0; i < json.length; i++) {
      
      var words = json[i].DATE.split(' ');
      if(!ArrayDate.includes(words[0])){
        ArrayDate.push(words[0]) //日付リスト作成
      }
    ...
    setList()
  }
  ...

  // 日付のリストを作成
  function setList() {
    const selectName = document.getElementById('ListDate');
    if(selectName.childElementCount){// 作成済み
      return;
    }

    ArrayDate.forEach(function(element){
      const option = document.createElement('option');
      option.value = element;
      option.textContent = element;
      selectName.appendChild(option);
    });
  }
  // ボタンクリックイベント
  function clickButtonDate(){
    const date = document.getElementById('ListDate');
    const num = date.selectedIndex;
    const str = date.options[num].value;
    SetDate = str;
    var data="";
    for (let i = 0; i < json.length; i++) {
      var words = json[i].DATE.split(' ');
      if(words[0] == str){
        data = data + json[i].DATE + " " + json[i].type + " "+ json[i].latitude + " " + json[i].longitude + "\n";
      }
    }
    document.getElementById("DateText").textContent = data; 
    initMap()//地図更新
  }
</script>
```
[Servicenow]Flow error handler

サービスカタログ作成時など、フローを実装する際に役立つ機能を紹介します。
フローの処理がうまくいかない場合を考慮し（いわゆる異常系）、エラー処理を定義できる機能があるので紹介します。

#Flow error handlerの設定
一連のフローの処理の途中でエラーが発生した場合の振る舞いを定義することが可能です。
https://docs.servicenow.com/bundle/rome-servicenow-platform/page/administer/flow-designer/concept/flow-error-handler.html

##環境
- インスタンスVersion：Rome

##準備
異常系の振る舞いを定義したいフローを準備します。
![正常系.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/126ab2a7-7a45-8381-e5cf-fd826808618c.png)

##エラーハンドリングの実装
作りこめばいろんなことができるみたいですが、ここでは簡単なエラーハンドリングを定義してみます。
1. まずはFlow error handlerをONにする
![異常系1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/ee995007-8aa0-5540-7e61-15f55ee46866.png)
2. 次にエラーが発生した場合の振る舞いを定義する<br>
右側にエラー情報を持った変数があるので、それをうまく活用します。
![異常系2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/15f489c9-a97b-cba2-e679-24d492d277c8.png)

私は、エラーが発生した場合、エラーの内容をメール通知するように定義してみました。

##検証
###異常系
フローのトリガ条件を満たし、かつエラーが発生するようにレコードを更新してみます。
![デモ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/58daef49-ddbc-4314-0b50-ebb29ae24252.png)

送信箱を確認すると、本文にエラーの内容がかかれたメールを確認できました！
![デモ２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/bac14d65-e336-4668-63b7-786ba36e61ff.png)

一応フローの実行履歴を確認します。
異常系の処理がcompleteになっていることが確認できます。
![実行履歴.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/e7d019c4-52a1-0016-0aaa-4421534c8279.png)
Vue.jsのtransitionでenterのアニメーションが適用されない【Vue3】

ハンバーガーメニュークリックでモーダルが表示される仕様を作成しようとし、下記コードを記述しました。

```Vue
<template>
  <div>
      <div class="menu_btn" @click="ActiveBtn = !ActiveBtn">
        <span class="line_01"></span>
        <span class="line_02"></span>
        <span class="line_03"></span>
      </div>
      <transition name="menu" appear>
        <Menubar v-if="ActiveBtn" class="menu" />
      </transition>
  </div>
</template>

<script>
export default {
data() {
    return {
      ActiveBtn: false,
    };
  },
};
</script>

<style lang="scss" scoped>
// アニメーションCSS ハンバーガーメニューのCSSは割愛
.menu-enter-active,
.menu-leave-active {
  transition: all 0.4s;
}
.menu-enter,
.menu-leave-to {
  opacity: 0;
}
.menu-enter-to,
.menu-leave {
  opacity: 1;
}
</style>
```


ハンバーガーメニューをクリックするとふわっと現れ、
もう一度クリックするとふわっと消えるようにしたかったのですが、
どうもふわっと現れる方（enter）の方のアニメーションが適用されません。

こちらの記事を参考にし、appear属性が入っていなかったのでtransitionに追加してみましたが、特に変化はありませんでした。
[Vue.js の enter トランジション/アニメーションが適用されない](https://qiita.com/blajir/items/59cd12201ac73dc0f278)

## 解決策

Vue3だと、enterのアニメーションCSSの記述が、下記に変更になったようです。

Vue2
v-enter

↓

Vue3
v-enter-from


これでenterのアニメーションも適用されました！！
かなり詰まったので残しておきます。。

## 参考サイト
[Vue.jsで下からフェードインして表示されるようなアニメーションを付けたい。
](https://teratail.com/questions/311699)
【備忘録】JestでのインターフェースとオブジェクトのMock実装方法について 

## はじめに

jestでmockを使ったテストをすることになった際、色々記事を参考にしていたらなかなかうまくいかなかったため簡易的な備忘録としてうまくいった方法を残しておきます。

詳細説明などは下記記事の方が参考になるかとおもうので、先にこちらを読むことをお勧めします。

- [Mock Functions · 公式ドキュメント](https://jestjs.io/docs/mock-function-api)
- [【備忘録】JestのspyOn()とmock()の使い方について](https://qiita.com/m-yo-biz/items/e9b6298d111ff6d03a5e)
- [[jest]DIしたオブジェクトをmockして、メソッドが呼ばれているかの確認をする](https://zenn.dev/nananaoto/articles/f0cffee3b4c0b2)

## **環境**

- node: 16.6.2
- @types/jest: 27.0.3
- jest: 27.4.5
- ts-jest: 27.1.1
- ts-node: 9.0.0
- typescript: 4.0.2

## 前提
ClazzAのexecute関数で、TestRepositoryの各関数が何回呼ばれたかをテストしたい

- **ClazzA**:  今回テストしたいクラス
- **TestRepository**: ClazzAのインスタンス化に必要
- 使用するExpect
    - 呼び出し回数のチェック: 
        - `expect(actual).toBeCalledTimes(n)`
        - `expect(actual).not.toBeCalled()`
    - 引数のチェック(今回の記事では未使用):
        - `expect(actual).toBeCalledWith()`

## 実装方法
### インターフェースを実装したMockを作成
Repository Interface の Mock を作成する

1. `jest.fn().mockReturnValue(返り値)`
任意の値を返すmock関数を作成する。

2. `jest.fn<Type, []>().mockImplementation(() => ();` 
指定した型を返すmockを作成する。

3. `mockFn.mockClear();`
モックの使用履歴などをクリアする。テストを複数書く時にモック関数の呼び出し回数がどんどん加算されてしまわないようにしておく。
4. **手順2**で作成したモックをインスタンス化して、テストしたいクラスなどに渡す

```tsx
import ClazzA from 'path/to/ClazzA';
import TestRepository from 'path/to/TestRepository';

describe("ClazzAのテスト", async () => {
  const executeMock = jest.fn().mockReturnValue(Promise.resolve());
  const Repository = jest.fn<TestRepository, []>().mockImplementation(() => ({
    execute: executeMock
  }));

  afterEach(() => {
    executeMock.mockClear();
  });

  test("executeMockが呼ばれるテスト", () => {
    const a = new ClazzA(new Repository());
    await a.execute();
		
    expect(executeMock).toBeCalledTimes(2);
  });
});
```

### オブジェクトをモックする方法(spyOnを使用する)
TestRepositoryオブジェクトの Mock を作成する

1. `jest.spyOn();`
メソッドを使い、追跡したいメソッドを指定する

2. `(Clazz.prototype.method as jest.Mock).mockClear();` 
モックの使用履歴をクリアしておく

3. `(Clazz.prototype.method as jest.Mock).mockImplementation();`
で返り値の指定などをしておく

4. **手順2**で作成したモックをインスタンス化して、テストしたいクラスなどに渡す

```tsx
import ClazzA from 'path/to/ClazzA';
import TestRepository from 'path/to/TestRepository';

describe("ClazzAのテスト", async () => {
  beforeEach(() => {
    jest.spyOn(TestRepository.prototype, 'sampleMethod');
    jest.spyOn(TestRepository.prototype, 'testMethod');
  });
		
  afterEach(() => {
    (TestRepository.prototype.sampleMethod as jest.Mock).mockClear();
    (TestRepository.prototype.testMethod as jest.Mock).mockClear();
  });
		
  test("sampleMethod の返り値が0の時 testMethod が呼ばれないテスト", () => {
    (TestRepository.prototype.sampleMethod as jest.Mock).mockImplementation(() => {
      return 0;
    });
    const a = new ClazzA(new TestRepository());
    await a.execute();		 
    expect(TestRepository.prototype.testMethod).not.toBeCalled();
  });
});
```

## おわりに

上記でインターフェースやオブジェクトをモック化することができました。
モック化するための記述量が多く、読み辛くなってしまうなあと感じたのでそのあたりを工夫していく必要がありそうです。
PC廃棄とHDDデータ消去やり方メモ

#HDDのデータ消去
実家の大掃除でノートPCを1台廃棄することになり使っていないノートがもう一台あったため両方廃棄することにした
廃棄のやり方はリネットに送るだけ。
https://www.renet.jp/
ちなみにヤマダ電機の子会社も同様のサービスを行っている。こっちでもいいかもしれない
https://www.shop-inverse.com/kaitori/haiki_page.html#haiki_link

さて、双方ともデータ消去はお金がかかるので自分でやってしまおうと思った。
USBメモリからブートして消去してやるだけっしょ！と意気込んだところ全然うまくいかなかったのでメモ

#対象となるPC
１．dynabook　R731/36B　windows7　（2013年に中古で購入）
２．lavie　LL370/H　windows　vista（2007年に新品で購入）

前者は簡単だったが、後者が大変だった・・・

前者はディスクドライブが壊れていたためUSBメモリからブートしてHDDのデータ削除
後者はCD-Rからやろうと考えていた

#最初の方針
wipeout　を使用してパパっとデータ消去を行う
http://www.wheel.gr.jp/~dai/software/wipe-out/
使い方は書いていなかったがネットで調べてみた感じUSBメモリに安定板のv1.6を書き込んで
それからブートすればよさそうである。実際１．はこれでOKだった。
書き込みソフトはwin32diskimager

さて、同様にCD-Rにもisoイメージを書き込んで起動しようとしたがうまくいかない。
ブートの順番も問題ないし、なんでだろうと思いwindows＆ubuntuのインストールdiskをつっこんでみたところ
こちらも反応なかったのでDVDドライブがダメになってる？と思いDVDからのブートは諦め、ちょうど１．のPCの削除が終わったのでUSBブートを試すことに。（ちなみにwindowsを起動させてみるとドライブはちゃんと生きていて普通にdiskは読めた）

ところが、メニュー画面で画面が焼き付いてうまく動かないことがわかった。（メニュー画面は下記リンク参照）
https://tipstour.net/data-erase-freesoft-wipe-out
何度かやってみたがすべて同じところで凍り付くため、やり方を変えることにした。

#方針変更
といっても
https://memorva.jp/internet/pc/soft_destroy_hdd_delete_rufus_usb_boot.php
を参考にdestroyというソフトに変更するだけである
ソフト自体は下記ＵＲＬ。窓の杜だったり怪しいサイトだったりあるので注意
http://wista.jp/DOSTOOLS.htm
ダウンロードしてそのままイメージをＵＳＢメモリに焼いたがうまく起動せず
（freedosの文字が出たまま進まない）
上のURLを見てみると
**Rufusでちゃんとfreedosのブートメディアを作り、そこにDESTROY.COM をコピーするのが重要！**
rufusで作ったメディア内に
・LOCALE
・autorun.ico
・autorun.inf
があるのを確認してそこに作者のHPからダウンロードしたファイルにあるDESTROY.COMをコピーする。

あとはUSBメモリをブートすれば操作画面までいける。

操作はみればわかるが大まかには
個人使用「P」⇒ディスク選択⇒消去方式選択

となる。まあ消去方式はいろいろあるがお好みで。ここで方式で悩む人はそもそも有料のやつ買ったほうが良い気がする。
np_utils.to_categoricalで index 20 is out of bounds for axis 1 with size 20というエラーが出た

タイトルの通りですが、lstm分析しているときにone-hotベクトルにするために
 np_utils.to_categoricalを使ったんですけどエラー出ました
![スクリーンショット 2022-01-05 17.06.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/956371/7e55b7fc-6241-3b0a-bf0b-495e49b8d7bd.png)

### 原因  
調べるとデータの最大値+1より小さい値を指定しているからエラーが出たそうです  
今回で言うと20って指定しているけどデータの最大値+1より小さいよ〜ということです  
そこでデータを見てみると正解ラベルを1~20にしていたのがダメぽかったです  
![スクリーンショット 2022-01-05 17.07.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/956371/74c6d86c-6fb3-36f7-43d5-2f65b7e65f3b.png)  

### 解決法
正解ラベルを0からすれば問題ないです
あとはデータラベルから0スタートになるように引いてもいけます
Y_train=DataFrame(df_train["correct"]-1).values
1からスタートさせる癖直さなきゃ  
### 参考サイト
kerasのto_categoricalを使ってみる  
https://analytics-note.xyz/machine-learning/keras-to-categorical/
Rubyの探索関連で迷った話

## なぜ
Ruby Goldの学習中に探索関連の問題（REX)でつまずいたので、その過程で簡単にメモしたものを記事にしてまとめたいと思ったから。

## 概要
メソッドの探索と定数の探索ではそもそも違う話なんだよってこと（知っている人は多数だと思いますが、私は無知故知りませんでした）。


## 結局なんなん？
#####・メソッドの場合
先人が残している様々な優良記事にも記載されているよう、あるクラスの未定義インスタンスメソッドを実行しても、そこでエラーにはならず、継承元のクラスまでそのインスタンスメソッドが定義していないかを探索した後、プログラムは実行される。（ここまではギリ知っていた）
　

```ruby:main.rb
module LibertyFish

    def method_a
        "LibertyFish"
    end

    class Liberty
        def method_a
            "LibertyFishってなに？"
        end
    end

    class Fish < Liberty
        def fish
            method_a
        end
    end
    puts Fish.new.fish          #LibertyFishってなに？
end

```

当然、継承関係似ないメソッドの呼び出しはエラー

```ruby:error.rb
module LibertyFish

    def method_a
        "LibertyFish"
    end

    # class Liberty
    #     def method_a
    #         "LibertyFishってなに？"
    #     end
    # end

    class Fish < Liberty
        def fish
            method_a
        end
    end
    puts Fish.new.fish          #undefined local variable or method `method_a'
end

```





######・定数の場合
定数の場合も、メソッドと同じようなもんだろうと高を括っていた。
以下のコードの実行結果は「**Rexを開発・運営している会社**」が実行される。

```ruby:main.rb
module LibertyFish

    CONST = "Rexを開発・運営している会社"

    class Liberty
        CONST = "Ruby gold合格したい"
    end

    class Fish < Liberty
        def fish
            CONST
        end
    end
    puts Fish.new.fish          #Rexを開発・運営している会社
end
```
モジュールLibertyFishの直下にある定数をコメントアウトすれば「**Ruby gold合格したい**」が表示される。

```ruby:main.rb
module LibertyFish

    # CONST = "Rexを開発・運営している会社"

    class Liberty
        CONST = "Ruby gold合格したい"
    end

    class Fish < Liberty
        def fish
            CONST
        end
    end
    puts Fish.new.fish           #Ruby gold合格したい
end
```


## まとめ
メソッドの探索
①継承関連　　子クラス→親クラス
②なければエラー

定数
①レキシカルスコープの内→外側
②継承関連　　子クラス→親クラス
③なければエラー


#### あとがき
メソッドや定数の探索について混ぜて考えてしまっていたので自分なりにまとめれたと思う。
あと、この記事のものになった優良記事にはさらに詳しい定数探索について記述してあった。
【以下参照】
[名前の森で定数を見つける物語](https://www.uosansatox.biz/entry/2018/07/12/070000)

定数についてはわかった。メソッドはどうなんだい？ってノリで自分でコードを書いてさらに理解が深まったので今後もやっていきたい。
Google Professional Cloud Architect認定資格を遠隔監視オンライン受験した話

#GCP認定資格試験　遠隔監視オンライン試験
Professional Cloud Architectの認定資格試験を受験するにあたり、試験会場まで行くの面倒だし、コロナ禍だしということで「遠隔監視オンライン試験」を利用してみました。
2022年1月5日現在以下の試験がオンライン受験できるようです。
- Cloud Digital Leader
- Associate Cloud Engineer
- Professional Cloud Architect
- Professional Cloud Developer
- Professional Collaboration Engineer
- Professional Data Engineer

##事前準備
[認定資格公式サイト](https://cloud.google.com/certification/cloud-architect)からGoogleアカウントとは別に試験に利用する[KRYTERION](https://webassessor.com/googlecloudjp)のアカウントを作成します。
受験の申し込みをしたら、Sentinelというアプリのインストールと顔写真の登録を済ませておきます。

##受験スペースの準備
>受験に適した静かで明るい部屋を用意してください。
室内の環境チェックに使用する反射面（スマートフォンや鏡など）を用意します。
試験エリア内に他の人が入らないようにしてください。
試験エリア内には、パソコン以外の物を置かないでください。これには、紙や筆記用具、予備のデバイスなども含まれます。
外付けモニターをノートパソコンに接続している場合は取り外し、すべてのアプリケーションを閉じてください。
試験中の飲食、ヘッドフォン / イヤフォンの使用は禁止されています。
試験中は席を立たないでください。休憩をとったり、カメラの死角に移動したりすることはできません。

「パソコン以外の物を置かない」部屋なんて我が家には確保できないです！困った。
私が普段リモートワークに利用している部屋はこんな感じ。もちろん本やらPCやら周辺機器やら雑多なものが散らかっていてこんなに整然とはしていません。
<img src="http://drive.google.com/uc?export=view&id=109vwwMWUBzIFubwepb4lM1D6wiQm_BwE" width=400>
デスクにはモニターアームも取り付けてますし、紙やら筆記用具やら予備のデバイスやらヘッドフォンやら禁止事項だらけです。片付けろったって無理な話です。
ふと見上げると部屋の真ん中を突っ切るかたちで部屋干し用のワイヤーが伸びていました。そこにテキトーな布を垂らして作業スペースと何も置いていないスペースを隔ててみました。
<img src="http://drive.google.com/uc?export=view&id=1Qh3XVw_yLVj4s2lSxDtBzxGbqjBfgd--" width=400>
取調室のような試験場が完成しました！
気の利いたデスクなど持ってないのでアイロン台がパソコンデスクがわりです。

##試験当日
予約した時刻より10分前ぐらいから開始ボタンが押せるようになっていました。
開始するとまず（確か）顔認証が行われます。
「順番待ち。少々お待ちを。」のメッセージが表示され、結構待たされます。一人の試験官の方が複数人の受験生を担当されているのでしょうか。
しばらくするとチャットで「お待たせ。自動翻訳で好きな言語で対応するけど、どうする？」と。もちろん「ニホンゴでオネガイシマスー」。
なおチャットは文字だけです。お相手の顔は見えません。声も聞こえません。

「眼鏡はずして、顔見せて」「ハーイ」

「証明書見せて」「ハイ」（パスポート見せる。証明書と申請のときの名前が同じでないとダメなので申請はローマ字名にしましょうね。）
「字が読めるようにもっと近づけて」「ハイハイ」

「じゃ、お部屋見せて」「おう！待ってました」
ちゃんと読んでましたよ。スマートフォンで写せばいいんだよね。手元にスマホ用意してました。
>室内の環境チェックに使用する反射面（スマートフォンや鏡など）を用意します。

（スマホで部屋を映しながらその画面をPCのカメラに向けるって…無理…）「ド…ドウスカ？」
「PCもちあげて360度回せる？PCのカメラで見せて。」（そうだよね、無理すぎる。）
天井やら床やらデスクの下やら全部見せます。

「スマホでPCに繋がってるケーブルの写真を撮ってみせて」「ハーイ」
そろそろ以上かな。

「もっぺん眼鏡はずして、眼鏡をよく見せて」「ハァ」（なるほどスマートグラスとか盗撮とかそんな悪いやついるのかな。）

「じゃ、パスポートとスマホをどっかにやって。」「ハイー」
「もっぺんどこにやったか見せて」「ハ、ハイー」部屋の仕切り布の向こうに放り込みます。

「ありがとね。じゃ、がんばってね。質問ある？」「ナイッス。ガンバリマスー」

ここまで15分ぐらい？すでにぐったりです。

（…試験…）

提出。ポチ。

合格。（味気ない文字で）

##で、遠隔監視試験がおすすめかどうか
受験会場が近くて、日程が合って、コロナの流行具合がおさまってれば…会場受験の方が何かと楽かも。
受験会場が遠かったり、早朝とか夜間の受験を希望される方で、お部屋がきれいな方はオンライン有りですね。
livewireでbootstrap4-datetimepickerがバインドしてくれない件

# はじめに
環境 Laravel 8.68.0 (livewireが使えるバージョンならなんでも)

使用しているライブラリ
<a href="https://getdatepicker.com/5-4/">tempusdominus-bootstrap-4</a>
使い方は名前で調べると割と記事が出てきます。

# 目次
1. [対処法](#Chapter1)
1. [備考](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 対処法
手動でバインドさせる
```html
    <input type="text" class="form-control" id="select_year" data-toggle="datetimepicker">
    {{ $selectYear }} 
    @push('scripts')
        <script>
            $('#select_year').datetimepicker({
                'format': 'YYYY',
            });
            $('#select_year').on('update.datetimepicker', function (e) {
                //手動バインド
                @this.set('selectYear', e.target.value)
            });
        </script>
    @endpush
```
<a id="#Chapter2"></a>
# 備考
<a href="https://flatpickr.js.org/">flatpicker</a>というdatepicker系ライブラリなら普通に書いてるだけでバインドしてくれるのでこっちの方がオススメ。
唯FlatPickerには「年のみ選択」出来るフォーマットが無いので仕方なくdatetimepickerを使った所ハマったという訳です。

<a id="#reference"></a>
# 参考文献
- [変更を検知してくれるイベントが記述されていたドキュメントページ](https://getdatepicker.com/5-4/Events/)
- [flatpickerドキュメント（日本語）](https://tr.you84815.space/flatpickr/examples.html)
HTML + Chromeで名刺を作ってみよう

名刺のオンデマンド印刷に使うPDFデータをHTMLとChromeで作ってみたので、その際の備忘録です。

![japanese.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/5ae6baa9-d8da-7065-6140-76c3558b7d5f.png)


## 基本的なツール

- Google Chrome -- レンダリングの確認、PDFへの変換に利用する

## 技術的なポイント

1. CSS に `@media print { @page { size: 97mm 61mm; } }` などのように [@page](https://developer.mozilla.org/en-US/docs/Web/CSS/@page) によるページサイズ指定があると、Chrome の Save as PDF 機能はページサイズとしてこの値を使用するようです。
  
    オンデマンド印刷の名刺データ入稿の際に3mmのマージン（断ち切り領域）が必要な場合が多いので、今回の実験では一般的な名刺サイズである 91x55mm に両側3mmのマージンを取ったサイズ（97x61mm）をページサイズとして指定します。

1. 上記の状態で Chrome の Save as PDF (PDFに保存) の操作を行うと、期待したサイズのPDFが生成できます。

1. バッチファイルなどで一気に変換したい場合は、Google Chromeをコマンドラインから呼び出し、オプションで `--print-to-pdf` および `--headless` を与えることで所望の処理が可能です。

    [実験で利用したスクリプト](https://github.com/aikige/html_business_card_template/blob/main/convert_by_chrome.sh) では [Google Developersの記事](https://developers.google.com/web/updates/2017/04/headless-chrome) などに従い、`--disable-gpu` オプションも指定していますが、このオプションは暫定的なのとされているので、最新の Chrome でも必須なのかは未確認です。

## 長所

1. Chromeの場合、自動的にフォントは全部埋め込もうとするので、電子入稿の際にフォントの問題が発生しづらい。
1. CSSの知識があれば比較的簡単にレイアウトが管理できる。
1. Outputはブラウザで確認しながら進められる。
1. 自動化に向いている。社内の名刺発注の自動化などのベースとして使える。

## 短所

1. フォントのレイアウトをPixel単位で調整しようとすると、ブラウザの細かい挙動はあまり文書化されていないので難しく、ある程度の諦めが必要。
   たとえば、Font Familyで日本語、英語を別フォントにした場合と、日本語のみの場合ではベースラインが変わってしまうなど謎の挙動がある。

## レイアウトする際のTips

- 全体を囲うBOX要素を一つ作って、それに対して背景指定をするとロゴなどの配置がやりやすい。
- 配置を細かく指定したい場合は、CSSの `position: absolute` を活用して箱の位置を厳密に決めるとレイアウトが崩れにくい。
- レイアウトをディスプレイで確認している場合には印刷領域をBorderで表示して、PDFに変換するときはBorderを消すように `@media print` を活用してCSSを書くと便利。

例:

```
.page_container {
  /* page size */
  width: 91mm;
  height: 55mm;
  /* margin and border (total: 3mm) */
  margin: 2.9mm;
  margin-bottom: 0mm;
  border: solid gray 0.1mm;
}
@media print {
  @page {
    margin: 0;
    padding: 0;
    size: 97mm 61mm;	/* 91x55mm + 3mm margin */
  }
  .page_container {
    margin: 3mm;
    margin-bottom: 0;
    border: none;
  }
}
```

## 動作確認した環境

- ソース一式: GitHub > [aikige/html_business_card_template](https://github.com/aikige/html_business_card_template)
- OS/Chrome

```
% sw_vers
ProductName:	macOS
ProductVersion:	12.1
BuildVersion:	21C52
% Google¥ Chrome --version
Google Chrome 96.0.4664.110
```

## Reference

- Google Developers > [ヘッドレス Chrome ことはじめ](https://developers.google.com/web/updates/2017/04/headless-chrome)