OmniAICreator/Qiita-1.07M huggingface dataset:
jQueryとCSSでマウスカーソルを良い感じに


最近ちょくちょく見かけるマウスカーソル
2つの円形を作って、1つは通常のカーソルの動き、2つは少し遅らせ追従するような動きになるように作りました。

![画面収録-2021-01-11-14.38.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671043/f788bfdf-05c0-6f35-e498-3a14582243cc.gif)



### HTML
dot1とdot2で大きい円と小さい円

```haml:html
<div class="cursor">
  <span class="dot1"></span>
  <span class="dot2"></span>
</div>
```

### jQuery
- ` $(window).mousemove `でカーソルのホットスポットが要素内（body）で動いた時の処理
- ` left: e.pageX , top: e.pageY `で座標を取得
- ` $('a').on('mouseenter', function () { } ` でaタグにホバーしたときに`active`というクラスを追加


```js:jquery
$(window).mousemove(function (e) {
  $('.cursor span').css({
    left: e.pageX,
    top: e.pageY
  })
})
$('a').on('mouseenter', function () {
  $('.cursor span').addClass('active');
})
$('a').on('mouseleave', function () {
  $('.cursor span').removeClass('active');
})
```

### CSS

- `cursor: none;`でデフォルトのカーソルを非表示 
- `.cursor span { } `の中で基本的な形（今回だと円形）を作る
- dot1とdot2にそれぞれの形を作る
- `.active`でホバー時の形を作る





```css:css
* {
  cursor: none;
}
.cursor span {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  transform: translate(-50%, -50%);
  position: absolute;
  z-index: 1;
  pointer-events: none;
}
.cursor span.dot1 {
  background: rgba(98, 77, 112, 0.8);
  transition: width 0.2s, height 0.2s;
}
.cursor span.dot1.active {
  height: 50px;
  width: 50px;
  background: rgba(98, 77, 112, 0.3);
}
.cursor span.dot2 {
  height: 20px;
  width: 20px;
  border: solid 1px #624d70;
  transition: top 0.2s, left 0.2s, width 0.5s, height 0.5s;
  transition-timing-function: ease-out;
}
.cursor span.dot2.active {
  height: 80px;
  width: 80px;
}
```


## 2つ目の円形の動きの遅延
円形の1つの動きを ` transition: top 0.2s, left 0.2s, width 0.5s, height 0.5s; ` で少し遅らせて、後を追うような動きにしています。


- 追従の遅延は `top 0.2s, left 0.2s`
- 大きさの遅延は `width 0.5s, height 0.5s`

それぞれの数字を変えると動きを変えることができます。

transitionについて詳しくは以下
https://developer.mozilla.org/ja/docs/Web/CSS/transition



#### ipadのようにテキスト部分にホバーすると縦棒になるようにカスタマイズ

![gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671043/d053c972-a3e8-cee5-854b-35cd6c9bbbd6.gif)


CSSとjQueryに以下を追加

```css:css
.cursor span.dot1.text_active {
  height: 1.4em;
  width: 2px;
  border-radius: 0;
}
.cursor span.dot2.text_active {
  display: none;
}
```
```js:jquery
$('p').on('mouseenter', function () {
  $('.cursor span').addClass('text_active');
})
$('p').on('mouseleave', function () {
  $('.cursor span').removeClass('text_active');
})
```
YouTubeアプリからのshareがFlutterアプリで受け取れずにハマった話

ShareExtensionを利用したFlutterアプリを作っていて、なぜかYouTubeアプリからのshareだけ受け取れなくてハマった...という、誰の役に立つのか分からない、とてもニッチなお話。
（普段iOS開発してないエンジニアの備忘録）

### 解決したかったこと

[receive_sharing_intentプラグイン](https://pub.dev/packages/receive_sharing_intent)を利用したアプリを作っている。
（[こちらの記事](https://qiita.com/popy1017/items/808b156ac09c037c941a)を参考にさせてもらった）

URLを受け取りたいアプリなので、サンプルに倣い、URL部分だけを使ってほぼほぼ問題なく動くようになった:open_hands:
ただ、__なぜかYouTubeアプリからだけURLが受け取れない__ :frowning2:



shareの候補としてアプリは表示されるものの、アプリを選択してもなぜか何も起こらない。

どうやらSwiftレベルで、何かがうまく動いてない様子。 :thinking: 


### ログを仕込んでデバグしたいのだが...
Swiftまわりデバグしてていつもハマるのはログ。
Swiftで`print`等でログを仕込んでも、Flutterのコンソールには何も表示されず。
何が起きてるのかさっぱりわからん:ghost:

「じゃあ、XCodeで実行したらなんか見えるかなー」となり、実行してみるが
「XCodeのコンソールも何も出ねーじゃーん」...となりーの、
`View -> Debug Area -> Activate Console`をして初めてログが見えることを知る。
ただ、それでも`print`や`NSLog`で仕込んだログは表示されず。
（見落としてるだけかなぁ。。。）

### ひとまずの打開策
辿りついた自分のwork aroundは、"`NSLog`を使ってコンソールアプリでログを見る"。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13189/0c06a57d-4b15-ebd6-e7d7-79c68df8f911.png" width="200">
`NSLog`ならここに表示された:raised_hands:

### で、本筋の問題
問題だったのは、typeの判定。
サンプルで言えば、`if attachment.hasItemConformingToTypeIdentifier(urlContentType)`のところで引っかかってた。

iPhoneのYouTubeアプリからshareは、なぜかURLではなく、Plain Textとしてシェアされていた。
なので、`if attachment.hasItemConformingToTypeIdentifier(textContentType)`の部分も実装することで解決。

何故なのかはいまいちよくわからぬ。
渡ってくるのは間違いなくURLなのだが... :thinking:
markdownでH:m:sと記述すると:m:が絵文字になってしまう

普通に以下のように記載すると

```
H:m:s
```

こんな感じで「H:m:s」絵文字になってしまう。

以下のように記載することで解消できる

```
H:<zero-width space>m:<zero-width space>s
```

実施の表示
H:<zero-width space>m:<zero-width space>s
Python基本文法・アルゴリズム

毎回忘れるのでメモ．随時更新．

# 基本文法
## タプル
(1, 2, 3)など．変更不能．リストは変更可能．

## リストの受け取り方
```
L = [[1, 2], [3, 4]]
for x, y in L:
    print(x, y)

# 1, 2
# 3, 4
```

## リストのスライス
```
[start:end:step]

# 逆順
[::-1]
```

## ソート
```
L.sort()
L = sorted(L)
```

## 割り算の商と余りを同時に取得する
```
a, b = divmod(10, 3)
print(a, b)
# 3 1
```

## x**yをzで割ったあまりを返す
```
pow(x, y, z)
```

## nは最大でも10
```
min(10, n)
```

## 階乗
```
math.factorial(5)
```

## 順列
```
# p = n! / (n-r)!より
def permutations_count(n, r):
    return math.factorial(n) // math.factorial(n - r)
```

## 組み合わせ
```
# c = n! / (r! * (n - r)!)より
def combinations_count(n, r):
    return math.factorial(n) // (math.factorial(n - r) * math.factorial(r))
```

## 最大公約数
```
# a>b
def gcd(a, b)
    while b:
        a, b = b, a % b

# もしくは
import math
print(math.gcd(6, 4))
```

## 最小公倍数
```
def lcm(a, b):
    return a * b // gcd(a, b)

# もしくは
import math
print(math.lcm(6, 4))
```

## 約数
```
def divisor(n):
    lower_divisors, upper_divisors = [], []
    i = 1
    while i * i <= n:
        if n % i == 0:
            lower_divisors.append(i)
            if i != n // i:
                upper_divisors.append(n // i)
        i += 1
    return lower_divisors + upper_divisors[::-1]
```

## 素因数分解
```
def prime_decomposition(n):
  i = 2
  table = []
  while i * i <= n:
    while n % i == 0:
      n /= i
      table.append(i)
    i += 1
  if n > 1:
    table.append(n)
  return table
```

## 素数判定
```
def is_prime(n):
    for i in range(2, n+1):
        if i * i > n:
            break
        if n % i == 0:
            return False
    return n != 1
```

## 8進数の文字列に変換
```
str.format(i, 'o')
```
Colaboratoryでセルをファイル出力する

`Colaboratory セル ファイル　出力`でググっても出てこなかったので。

元ネタ: [Cell magics@ipython](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cell-magics)

#やり方
```python:yesno.py
%%writefile yesno.py
#!/usr/bin/env python

import re

def main():
  check=input('YesかNoを入力してください　：')
  print(YN(check))

def YN(string):
  if re.match('(?i)ye?s?',string):
    return 'YESです'
  elif re.match('(?i)no?',string):
    return 'NOです'
  else: return 'Yes/Noじゃないよ'

if __name__ == '__main__':
  main()
```
`%%writefile yesno.py`がコマンド

`!cat -n yesno.py`で確認すると

     1	#!/usr/bin/env python
     2	
     3	import re
     4	
     5	def main():
     6	  check=input('YesかNoを入力してください　：')
     7	  print(YN(check))
     8	
     9	def YN(string):
    10	  if re.match('(?i)ye?s?',string):
    11	    return 'YESです'
    12	  elif re.match('(?i)no?',string):
    13	    return 'NOです'
    14	  else: return 'Yes/Noじゃないよ'
    15	
    16	if __name__ == '__main__':
    17	  main()
コマンドの直後からファイル出力されるので、シバンを記述する場合は気を付ける。

これにより

```python:check.py
import yesno

if yesno.YN(('Yes')) == 'YESです': print('Yeah')
```

結果：　`Yeah`

と使えるようになる。

#まとめ
Pythonの勉強をColaboratoryでやっているとローカルファイルを元に書いてある課題をどうやってやるのか困る時があります。

[Pythonでファイルをダウンロードする](https://qiita.com/toshikawa/items/2d535906b42b9332b743)と合わせて使うと、大体はColaboratoryでできると思います。
Raspberry Piのシステムモニタリング

#1.この記事の内容

RaspberryPiのCPUやメモリ等のシステム状況をモニタリングする方法として，Netdataの導入方法を紹介します．
NetdataはDockerコンテナでHTTPサーバを起動し，ネットワーク内のWindows PCなどからブラウザでアクセスしてモニタリングする仕組みです．
Dockerを使用できる環境であれば，RaspberryPiでなくてもLinux環境上で利用できると思います．

##1-1.使用環境

* Raspberry Pi 3 Model B+
* Windows 10（ブラウザでRaspberry Piのシステム状況をモニタリング）

#2.Netdataの導入手順とモニタリング方法

1. Raspberry PiにDockerをインストールする
<pre>
$ curl -sSL https://get.docker.com | sh
</pre>
1. dockerグループにユーザを追加
<pre>
$ sudo usermod -aG docker pi
</pre>
1. Dockerの動作確認
<pre>
$ docker run hello-world
</pre>
1. Netdata起動
<pre>
docker run -d --name=netdata \
  -p 19999:19999 \
  -v /proc:/host/proc:ro \
  -v /sys:/host/sys:ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  --cap-add SYS_PTRACE \
  --security-opt apparmor=unconfined \
  netdata/netdata
</pre>
1. ブラウザからアクセス（http://<Your RPi IP address>:19999/）  
CPUやRAMなどの推移がブラウザ上でリアルタイム（約1秒間隔）で更新されます．  
![Netdata画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/675dc267-f5b3-808e-371b-1d1e391ae13c.png)

docker run後，Netdataの停止と再開については，下記の手順で実行できます．

* 停止
<pre>
$ docker stop netdata
</pre>
* 再開
<pre>
$ docker start netdata
</pre>

#3. Netdataのアンインストール

Netdata自体はDockerイメージを取り込むだけの為，Dockerをアンインストールするだけです．

<pre>
$ sudo apt purge docker-ce
$ sudo rm -rf /var/lib/docker
$ sudo apt autoremove --purge
</pre>

#4.さいごに

Raspberry Piのシステム状況をリアルタイムで確認するためにNetdataを導入しました．
ページ右上からエクスポートや印刷ができますので，スナップショットの記録はこれらの機能で実現可能です．

Raspberry Pi 1にも導入しようと試みましたが，下記のメッセージが表示され，Dockerコンテナを起動できませんでした． 
ARMv6に対応していないようです．Raspberry Pi Zeroでも同様かもしれませんので，ご注意ください．

#5.関連リンク

* [組込みLinuxのメモリ使用率をリアルタイムに監視する方法](https://hldc.co.jp/blog/2020/06/04/4130/)
* [Raspberry Piの負荷や温度をモニタするにはNetdataが便利です](https://signal-flag-z.blogspot.com/2019/12/raspberry-pi-netdata.html)
* [Raspberry PiにDockerをインストールする](https://signal-flag-z.blogspot.com/2019/09/raspberry-pi-docker.html)
Hardhatチートシート（使えるコマンドまとめ）

# 公式ドキュメント

https://hardhat.org/getting-started/

## コンパイル
```
npx hardhat compile
```

## デプロイ（スクリプト実行）
```
npx hardhat run scripts/sample-script.js
(network指定)npx hardhat run scripts/sample-script.js --network mainnet
```

## テスト
```
npx hardhat test test/sample-test.js
```

## コンパイルのキャッシュクリア
```
npx hardhat clean
```

## flatten（複数ファイルのコントラクトを１ファイルにまとめる）
```
npx hardhat flatten
```

## abiの場所

↓の配下

```
artifacts/contracts/
```
MacからXamppをアンインストールする方法


MacでBigsurにアップデートしたら、xamppが起動できなくなってしまいました。

## エラーの詳細

Xamppを起動しようとしても、「１４３エラーで起動しません」というエラーが出るようになりました。
それが出たあとはダブルクリックしてもなんの反応もしなくなりました。

## 対処

再度Xamppをインストールすることとに。
本来はデータを取り出した後にやりたかったのですが、意外に方法が面倒そうでした。今回はXamppにしかないファイルはなかったのでクリーンなものをインストールするようにしました。

https://stackoverflow.com/questions/45962354/error-starting-xampp-stack-cannot-calculate-mac-address-signal-killed


## アンインストール方法

普通にアプリケーションフォルダから削除し、そのあと残ったファイルを削除

```
% rm -rf ~/.bitnami/stackman 
```

## 感想

いやー、やはりOSアップデートは気をつけたほうが良いですね。。
MacでNASや外付けドライブを使用せずにTimeMachineを設定する

Macには「TimeMachine」というバックアップ機能が標準搭載されている。
Windowsでいうところの「ファイルの履歴」機能と同様。
基本的にはこの機能はNASや外付けHDDなど外部デバイスにバックアップをとることを想定しているっぽいが、昨今のリモートワークの状況もあり、ネットワークや外部デバイスに接続しない状況で使う場合でもMac単体でTimeMachineを使用する設定をメモしておく。
__OSはmacOS 11.1 big sur。__
__(注)Macのディスク上にバックアップをとるので最低でもバックアップ容量と同程度以上の空きが必要。__


# 1. パーテーションを分割する。
Macのディスクのパーテーションをディスクユーティリティを使用して分割する。
ディスクユーティリティはアプリケーション＞ユーティリティにある。
ディスクユーティリティを起動するとMacのディスクの管理画面が表示される。

ここでパーテーション作成へ進む。
![image003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577614/82a7e0fd-d5c8-d0d0-b9ec-9b9845509e9a.jpeg)

ボリュームを追加ボタンとパーテーションを作成ボタンが表示されるのでパーテーション作成ボタンを押す。
![image004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577614/098aa6e9-1ed6-81f2-e53c-2a8e44bfec67.jpeg)

デバイスとパーテーションの情報が表示される。
＋ボタンでパーテーションを追加する。
パーテーションの名前とサイズを設定して適用すればパーテーション作成は完了。
![image005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577614/20f2f705-dca9-76b5-af04-f3a40f3bbead.jpeg)


# 2. TimeMachineを設定する。
バックアップ用パーテーションを用意したらあとは普通にTimeMachineを設定する。
TimeMachineはシステム環境設定から設定できる。
バックアップを自動生成にチェックを入れてディスクを選択ボタンからバックアップ用パーテーションを指定。
TimeMachineをメニューバーに表示にチェックを入れておけばメニューバーからTimeMachineに入ってファイルの復旧もできる。
![image006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577614/e31cf839-3c80-bc21-a772-60fbd5c80524.jpeg)
Dart: Redis のデータを更新 (Update)

```dart:redis_update.dart
// -------------------------------------------------------------
/*
	redis_update.dart

					Jan/11/2021
*/
// -------------------------------------------------------------
import 'dart:io'; 
import 'dart:convert';

import 'package:dartis/dartis.dart' as redis;

// -------------------------------------------------------------
void main(List<String> arguments) async {
	stderr.writeln ("*** 開始 ***");
	String key = '${arguments[0]}';
	int population = int.parse ('${arguments[1]}');

	print (key + '\t' + population.toString ());

	final client = await redis.Client.connect('redis://localhost:6379');

	final commands = client.asCommands<String, String>();

	String value = await commands.get(key);
	Map unit_aa = jsonDecode(value);

	var today = new DateTime.now();

	unit_aa['population'] = population.toString();
	unit_aa['date_mod'] = today.toString();

	String json_str = jsonEncode(unit_aa);
	await commands.set(key,json_str);

	await client.disconnect();

	stderr.writeln ("*** 終了 ***");
}

// -------------------------------------------------------------
```

実行コマンド

```bash
dart redis_update.dart t1855 892300
```
Dart: Redis のデータを読む (Read)

```dart:redis_read.dart
// -------------------------------------------------------------
/*
	redis_read.dart

					Jan/11/2021
*/
// -------------------------------------------------------------
import 'dart:io';
import 'dart:convert';
import 'package:dartis/dartis.dart' as redis;

// -------------------------------------------------------------
disp_unit_proc (key,value) {
	String str_out = key + "\t" + value["name"] + "\t"
		 + value["population"].toString ()+ "\t" + value["date_mod"];
	print (str_out);
}

// -------------------------------------------------------------
void main(List<String> arguments) async {
	stderr.writeln ("*** 開始 ***");
	final client = await redis.Client.connect('redis://localhost:6379');

	final commands = client.asCommands<String, String>();

	List<String> ll = await commands.keys('t*');
	for (final key in ll)
		{
		String value = await commands.get(key);
		Map unit_aa = jsonDecode(value);
		disp_unit_proc (key,unit_aa);
		}

	await client.disconnect();

	stderr.writeln ("*** 終了 ***");
}

// -------------------------------------------------------------
```

実行コマンド

```bash
dart redis_read.dart
```
Dart: Redis のデータを作成 (Create)

ライブラリーのインストール

```yaml:pubspec.yaml
name: test01
environment:
  sdk: '>=2.10.0 <3.0.0'
dependencies:
  dartis: ^0.5.0
```

```bash
pub get
```

```dart:redis_create.dart
// -------------------------------------------------------------
/*
	redis_create.dart

					Jan/11/2021
*/
// -------------------------------------------------------------
import 'dart:io'; 
import 'dart:convert';

import 'package:dartis/dartis.dart' as redis;

// -------------------------------------------------------------
dict_append_proc (dict_aa,key,name,population,date_mod)
{
	var unit_aa = new Map ();

	unit_aa["name"] = name;
	unit_aa["population"] = population.toString();
	unit_aa["date_mod"] = date_mod;
	dict_aa[key] = unit_aa;

	return	dict_aa;
}
// -------------------------------------------------------------
data_prepare_proc ()
{
	var dict_aa = new Map ();

	dict_aa = dict_append_proc (dict_aa,'t1851','福井',42761,'1957-2-20');
	dict_aa = dict_append_proc (dict_aa,'t1852','敦賀',17895,'1957-8-15');
	dict_aa = dict_append_proc (dict_aa,'t1853','小浜',71564,'1957-12-14');
	dict_aa = dict_append_proc (dict_aa,'t1854','大野',93672,'1957-5-9');
	dict_aa = dict_append_proc (dict_aa,'t1855','勝山',72351,'1957-6-4');
	dict_aa = dict_append_proc (dict_aa,'t1856','鯖江',35187,'1957-3-21');
	dict_aa = dict_append_proc (dict_aa,'t1857','あわら',31246,'1957-10-23');
	dict_aa = dict_append_proc (dict_aa,'t1858','越前',65792,'1957-8-26');
	dict_aa = dict_append_proc (dict_aa,'t1859','坂井',74139,'1957-2-15');

	return	dict_aa;
}

// -------------------------------------------------------------
void main(List<String> arguments) async {
	stderr.writeln ("*** 開始 ***");
	final client = await redis.Client.connect('redis://localhost:6379');

	final commands = client.asCommands<String, String>();

	var dict_aa = data_prepare_proc ();

	dict_aa.forEach((key,value) async{
		String json_str = jsonEncode(value);
		await commands.set(key,json_str);
		});

	await client.disconnect();

	stderr.writeln ("*** 終了 ***");
}

// -------------------------------------------------------------
```

実行コマンド

```bash
dart redis_create.dart
```
GetComponetsInChildren は孫も対象になるのか？

Unity 初心者向けの記事です。

Unity で開発していて、画面上に表示している TextMeshPro の値を変更したい場合が出てくると思います。
動的に生成したオブジェクトの場合など、インスペクターから設定できない場合に、コンポーネントを検索して設定する場合などがあると思いますが、そういう場合の変更方法になります。

# TL;DR
getComponetsInChildren は一段階下の階層だけではなく、さらに下の孫階層なども検索してくれます。
ので、孫にある TextMeshPro の文字を変更した場合も、GetComponetsChildren で取得した結果から変更することができます。

# 前提
* Unity 2019.4.9f1

# やったこと
## 流れ
1.こんな感じのGameObjectを準備しておきます
![2020-12-28_13h10_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/057ea453-bb84-6eb5-1730-befad55071a8.png)
2. 階層を検索して孫が取れることを確認しています
3. 孫が取れている前提で、TextMeshPro の文字の値を変更しています

## サンプルプログラム
``` C#
    [SerializeField] private GameObject root;
    private void TestGetComponentsInChildren()
    {
        var r = Instantiate(root);

        // 生成したオブジェクト（root）から、TextMeshPro を持っているオブジェクトを検索する
        var children = r.GetComponentsInChildren<TextMeshPro>();
        if (children == null)
        {
            Debug.Log("children is null");
        }
        else
        {
            Debug.Log("children is NOT null");
            Debug.Log(children.Length);
            // 今回は Leaf1 と Leaf2 が TextMeshPro を持っているので、
            // 1つ下の階層も2つ下の階層も検索してくれていれば Leaf1, Leaf2 と出力されます
            Debug.Log(string.Join(",", children.Select(x => x.gameObject.name)));
        }

        // ↑ で取得できている前提で、Leaf2 のオブジェクトを持ってきます
        var grandChild = children.First(c => c.gameObject.name == "Leaf2");
        if (grandChild == null)
        {
            Debug.Log("grandChild is null");
        }
        else
        {
            Debug.Log("grandChild is NOT null");
            grandChild.GetComponent<TextMeshPro>().text = "grandChild";
        }
    }
```

## 結果
コンソールには孫まで取れていることがわかるログが出つつ、
![2020-12-28_13h27_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/030cc2ee-d9ca-515a-4900-d82555dd0406.png)
Leaf2 の TextMeshPro には grandChild が設定されています。
![2020-12-28_13h28_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/2382f390-ed87-72c4-e996-2a0fc65d1cfb.png)


## おまけ
* name で指定して対象のオブジェクトを取得しているので、一文字でも間違っているとエラーになります。
nvidia製ドライバを入れようとするとUbuntu 20.04 が起動しなくなる問題

#はじめに
ちょっと古いノートPCにUbuntu20.04を入れて再利用していたのですが、何度か設定変更のタイミングでGUIが表示されなくなる（ログイン画面までたどり着かない）トラブルが多発したので備忘録がてらメモ。

## 環境
Vaio VPCZ1（Geforce GT 330M, Coreシリーズ1世代目の化石PC)
Ubuntu 20.04.1 LTS

## 現象
nvidia のドライバーを、こんな感じでGUIからインストールしようとしたところ
（最近は勝手に必要なドライバを見つけてくれて、GUIでインストールできるんですね...）
![Screenshot from 2021-01-09 15-05-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280257/0b0bde69-deae-d7cc-26bb-0136c4071c4a.png)

下記のようなエラーでインストール失敗する
![Screenshot from 2021-01-09 15-07-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280257/09ecc8b6-211a-7adc-0c72-544c824fb23d.png)

次に再起動するとログイン画面が出てこない
真っ黒画面にアンダースコア（キャレット）が点滅


## 原因
nVidia 340ドライバ（最新は340.108）は、Linuxカーネル5.4以上での動作をサポートしていない[^patch]。
この影響で無理やりインストールするとGUI表示ができなくなってしまうようだ。
[Support timeframes for Unix legacy GPU releases](https://nvidia.custhelp.com/app/answers/detail/a_id/3142/%7E/support-timeframes-for-unix-legacy-gpu-releases)

[^patch]: [ここ](https://launchpad.net/ubuntu/+source/nvidia-graphics-drivers-340/340.108-0ubuntu1)にあるように、有志が使用できるようにパッチを開発しているようではあるが、2021月1月現在linuxカーネル5.8ではうまくいっていない？

## 対処
起動時に Escキーを押してリカバリーモードで起動
メニューから「root」を選択して以下を入力、nvidiaのドライバを削除する。

```
$ sudo apt-get purge nvidia*
$ sudo service lightdm stop
```
今（2021年1月）現在はLinuxカーネル5.8では動かないようなのでドライバのインストールはあきらめるか、より古いバージョンのカーネルの使用を検討する。

# まとめ
特に古いPCにnvidiaドライバを入れるときは、
そのドライバが使用するLinuxカーネルのバージョンに対応するか確認すべし。

# 参考
[Nvidia ドライバのせいで Ubuntu の GUI が起動しない時の対策](https://lookbackmargin.blog/2020/03/15/nvidia-ubuntu-gui-unshowed/)

[The installation of the NVIDIA display driver 340 fails in Kubuntu 20.10](https://askubuntu.com/questions/1284266/the-installation-of-the-nvidia-display-driver-340-fails-in-kubuntu-20-10)
ここがわかりやすかった。
初めて使ってみたSelenium

# 概要

Seleniumというツールを聞いたことはあるが、今まで使う機会がなかった。
が、Web上である単調作業を繰り返すことになり、しかもその数が膨大で非常に面倒くさい。

そこで自動化しよう！　…という話になって、Webの自動化ツールとしてSeleniumを使ってみた。その導入。
以下ではOSはWindows10、ブラウザは[Google Chrome](https://www.google.com/chrome/)、プログラミング言語はPython3.9を使っている。

# 導入

Seleniumを使うには以下が必要である。

- Selenium自身
- ブラウザ
- ブラウザのDriver

以下ではChromeDriverの実行ファイルをダウンロードする方法と、chromedriver-binaryをimportする方法を書いた。
どちらでも動作に問題はないが、後者は開発環境でimportしたものが使われてない旨の警告が出るのが嫌なので、私は前者を使っている。

## ChromeDriverをダウンロードする方法

[ChromeDriverの開発ページ](https://chromedriver.chromium.org/)から、対象のOSとChromeのバージョンに合わせたドライバーを拾って来て、任意の場所に置く。
（以下では C:\git\project\driver\chromedrive.exe に置いたと仮定して話を進める）

利用中のChromeのバージョンは「ヘルプ」＞「GoogleChromeについて」で確認できる。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915263/d1b43306-7044-29e4-68fe-2dd6e25b206c.png)

pipでSeleniumをインストール。

```bash
pip install selenium
```

Python（test.py）のサンプルコードは以下。

```python
from selenium import webdriver
import time

driver = webdriver.Chrome('C:\git\project\driver\chromedrive.exe')
driver.get('https://www.google.co.jp/')
time.sleep(5)
search_box = driver.find_element_by_name("q")
search_box.send_keys('ChromeDriver')
search_box.submit()
time.sleep(5)
driver.quit()
```

あとはPythonを叩けば、Chromeが開き、Googleのページを表示。
5秒後に「ChromeDriver」で検索、5秒後に閉じるという自動化ができる。

```shell
python test.py
```

## chromedriver-binaryを使う方法

pipでSeleniumとchromedriver-binaryをインストール。

```bash
pip install selenium
pip install chromedriver-binary==87.0.4280.88
```

chromedriver-binaryでバージョンを指定しているのは、その時インストールされているChromeのバージョンに合わせたかったから。
何も指定しないとその時の最新版がインストールされ、Chromeのバージョンと合わない場合、エラーが発生する。

```python
from selenium import webdriver
import time
import chromedriver_binary

driver = webdriver.Chrome()
driver.get('https://www.google.co.jp/')
time.sleep(5)
search_box = driver.find_element_by_name("q")
search_box.send_keys('ChromeDriver')
search_box.submit()
time.sleep(5)
driver.quit()
```

起動や動作方法については上と同様。

```shell
python test.py
```

# その他

上の方法では、Google Chromeのバージョンが更新されると、ドライバーとのバージョンが合わず起動時にエラーが出ることがある。
試しに使うだけならブラウザもドライバーも最新版を使えば良いが、そうでない場合は、ブラウザの自動更新を止めておいたほうがいい。
例えばGoogle Chromeの場合はGoogleUpdate.exeが実行されないようにする。

- [Google Chromeの自動アップデートを止める方法　超簡単版](https://ameblo.jp/shakarin00/entry-12510731757.html)

ただし、ブラウザが自動更新されないと、バグや脆弱性が残ってしまう。
そのため、例えば常用のブラウザはEdge、自動操作させるブラウザはChromeなどと、区別しておいたほうが良さそうではある。
【Rails入門】form_with（local: true）

Rails5.1より推奨されている`form_with`について、今回はオプションの1つ`local: true`について簡単に説明します。

#local: trueとは
```erb
<%= form_with(model: @user, local: true) do |f| %>
```
https://railsdoc.com/page/form_with
こちらのRailsドキュメントにオプション一覧が記載されているが、ここの説明によると「リモート送信の無効（デフォルトはfalse）」とのこと。
つまり、`local: true`を入力していない場合、非同期通信(Ajaxによる通信)が行われる。
`local: true`を入力すれば、非同期通信をキャンセルし、HTMLとしてフォームの送信が可能になる。

Ajaxについては、以下の記事が大変わかりやすかったです。
https://pikawaka.com/word/ajax

補足などありましたら、是非コメントお願いします！
AtCoder ABC188 Python

```A.py
X, Y = map(int, input().split())

if max(X, Y) - min(X, Y) < 3:
    print("Yes")
else:
     print("No")
```

```B.py
N = int(input())
A = list(map(int, input().split()))

ans = 0

for i in range(N):
    ans += A[i]*B[i]

if ans == 0:
    print('Yes')
else:
    print('No')
```

```C.py
N = int(input())
A = list(map(int, input().split()))

l = [A]

for i in range(1, N+1):
    # print('---')
    a = []
    for j in range(1, 2**(N-i)+1):
        # print(j*2-1, j*2)
        a.append(max(l[i-1][j*2-1-1], l[i-1][j*2-1]))
    l.append(a)

p = min(l[-2][0], l[-2][1])
print(A.index(p)+1)
```

```D.py
N, C = map(int, input().split())

event = []
for i in range(N):
    a, b, c = map(int, input().split())
    a -= 1
    event.append([a, c])
    event.append([b, -c])

event.sort()
# print(event)
ans = 0
fee = 0
t = 0
    
for x, y in event:
    if x != t:
        ans += min(C, fee) * (x - t)
        t = x
    fee += y

print(ans)
```
AtCoder ABC187 Python

```A.py
A, B = map(str, input().split())

a = list(map(int, A))
b = list(map(int, B))

suma = sum(a)
sumb = sum(b)

if suma >= sumb:
    print(suma)
else:
    print(sumb)
```

```B.py
N = int(input())
ab = [map(int, input().split()) for _ in range(N)]
a, b = [list(i) for i in zip(*ab)]

ans = 0

for i in range(N):
    ai = a[i]
    bi = b[i]
    for j in range(i+1, N):
        aj = a[j]
        bj = b[j]
        m = (bj-bi)/(aj-ai)
        if m >= -1 and m <= 1:
            ans += 1
print(ans)
```

```C.py
N = int(input())
S = list(input() for i in range(N))

# print(S)

s1 = []
s2 = []

for s in S:
    if s[0] == '!':
        s2.append(s[1:])
    else:
        s1.append(s)

# print(s1, s2)
s1 = list(set(s1))
s2 = list(set(s2))

l = [k for k, v in Counter(s1 + s2).items() if v > 1]

if l == []:
    print('satisfiable')
else:
    print(l[0])
```

```D.py
N = int(input())
X = 0
x = []
for i in range(N):
    A, B = map(int, input().split())
    X -= A
    x.append(2*A + B)
print(X)
x.sort()
print(x)
ans = 0
while X <= 0:
    X += x.pop()
    ans += 1

print(ans)
```
[TypeScript] constructorの省略記法

## 開発環境
- typescript (v 3.7.5)
- ts-node (v 8.5.4)

## javascriptのように書くと
```javascript
class Member {
  public name: string;
  protected age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
```

## typescriptで書くと
```javascript
class Member {
  constructor(public name: string, protected age: number) {}
}

//   constructor(アクセス修飾子 引数名: 引数の型名) {
//   }
```

※アクセス修飾子のデフォルトは「public」ですが、初期化をする上記の場合、省略できない。
※今回のようにインスタンスメンバーの作成と初期化を1箇所で行う
処理を**「パラメータープロパティ宣言」**と呼ばれています。
## まとめ
初期化処理をシンプルに記述できますね。

**「アクセス修飾子をコンストラクタの引数に書くだけで
typescriptでは自動で初期化処理まで実行してくれる」**ことをしっかり理解しておきたいと思います。

## 参考記事
[TypeScriptのClassについて – 公式ドキュメント日本語訳](https://mae.chab.in/archives/59843)
Generated Photosを使って顔認識を試すよ

この記事は[リンク情報システム](https://www.lis.co.jp/)の「2021新春アドベントカレンダー TechConnect」のリレー記事です。
engineer.hanzomon のグループメンバによってリレーされます。
（リンク情報システムのFacebookは[こちら](https://ja-jp.facebook.com/lis.co.jp/)から）

2021新春アドベントカレンダー Tech Connect インデックスは[こちら](https://qiita.com/dgkz/items/eabde6515457d8acec9b)

15日の記事を担当しますshinmoです。よろしくお願いします。

---------

あけましておめでとうございます。
私事ですが、最近スマホをiPhone12に買い換えました。
このiPhone12はFaceIDという顔を識別する機能があって、これでロックを解除できるんですね。

そんなわけで、今年は顔認識の勉強（といってもさわりだけですが）をしてみたいと思います。
（去年は[文字認識](https://qiita.com/shinmo/items/9fbb4f444f55c9b0d69a)でした）

2019年頃に、AIが存在しない人物の顔を作成してくれるサイトが出来た、というニュースがあったのをご存じでしょうか？
それまでにも似たようなサイトは存在していたのですが、その時に紹介されていたサイト[Generated Photos](https://generated.photos/)
はかなり出来がよく、かつてそれまでの他のサイトにあったような不自然さがないという点で話題になっていました。
（実際のサイトの画面）
![genP_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295384/e3e9a30b-83ac-afa2-6e5d-5763081cfbf6.png)

自分の顔をネットの海に流さなくてもよい、肖像権の侵害もない。
これは顔認識を試すのにちょうどよいのでは…？

というわけで、 Generated Photos を使って顔認識を試してみようと思います。

##準備
今回使う環境とライブラリは下記です。
Python3.7.4
openCV

openCVは次のコマンドでインストールします。

```text:コマンドプロンプト
python -m pip install -U opencv-python
```

次に分類器というものを用意します。
分類器というものを簡単に言うと、これは顔である／でないを振り分けるフィルターに当たるものです。
下記のopencvにデフォルトのものがいくつか用意されていますので、そちらを使います。
https://github.com/opencv/opencv/tree/master/data/haarcascades
今回は haarcascade_frontalface_alt_tree.xml を使用します。

##実行する
使う画像はこれ。(引用：https://generated.photos/)
![generate_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295384/688f3182-3f50-bd4b-6692-7d4997a10720.jpeg)

あとは下記のように実装して、実際に動かしてみます。

```faceRcg.py
import cv2

cascade_path = "./cascade/haarcascade_frontalface_alt_tree.xml"

# 使用ファイルと入出力ディレクトリ
image_file = "generate_1.jpg"
image_path = "./in/" + image_file
output_path = "./out/" + image_file

#ファイル読み込み
image = cv2.imread(image_path)

#グレースケール変換
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#分類器の取得
cascade = cv2.CascadeClassifier(cascade_path)

#検出実行
facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=10, minSize=(30, 30))

#枠線の色指定：赤
color = (0, 0, 255)

# 検出した場合
if len(facerect) > 0:

    #検出した顔を囲む枠線の作成
    for rect in facerect:
        cv2.rectangle(image, tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]), color, thickness=2)

#認識結果の出力
cv2.imwrite(output_path, image)
```

結果は…
![generate_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295384/0fbf2b02-d6c9-db07-41e5-6a919f45e99f.jpeg)

うまくいったようです。
ちなみに、 Generated Photos には顔の向きとかも指定できるようなので、ちょっと変えてみます。
入力：
(引用：https://generated.photos/)
![generate_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295384/a5863b03-8e2f-e503-4605-84ce8455bc59.jpeg)

出力：
![generate_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295384/aaca8ccf-949f-0f71-fc93-c01226fd3255.jpeg)

…ダメ見たいです。あまり正面に向いてないからですかね？
ただ、iPhone12でも斜めすぎるとロックが解除されなかったので、斜めの顔判定は難しいのかもしれないですね。

##終わりに
前回も今回もですが、作るのが大変そうだなあと思ったものが、調べてみると案外お手軽に実装出来たりするので
驚きです。次やるときには、機械学習用のモデルを作るところにも手を付けたりできると面白そうですね。

あとGenerated Photosがすごすぎて小1時間くらい遊んでました。

ここまで読んでいただきありがとうございました。
東京都福祉保健局の新型コロナウイルス感染症の都内感染者の状況のPDFをCSVに変換

東京都福祉保健局の[新型コロナウイルス感染症の都内感染者の状況](https://www.fukushihoken.metro.tokyo.lg.jp/iryo/kansen/todokedehcyouseisya.html)のPDFをCSVに変換

```python
import pathlib
from urllib.parse import urljoin

from bs4 import BeautifulSoup
import pandas as pd
import pdfplumber
import requests
from tqdm.notebook import tqdm

def fetch_file(url, dir="."):

    r = requests.get(url)
    r.raise_for_status()

    p = pathlib.Path(dir, pathlib.PurePath(url).name)
    p.parent.mkdir(parents=True, exist_ok=True)

    with p.open(mode="wb") as fw:
        fw.write(r.content)
    return p

url = "https://www.fukushihoken.metro.tokyo.lg.jp/iryo/kansen/todokedehcyouseisya.html"

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
}

r = requests.get(url, headers=headers)
r.raise_for_status()

soup = BeautifulSoup(r.content, "html.parser")

tag = soup.select_one("div#main p.filelink > a.pdf")

link = urljoin(url, tag.get("href"))

path_pdf = fetch_file(link)

dfs = []

# PDFを変換
with pdfplumber.open(path_pdf) as pdf:

    for page in tqdm(pdf.pages):

        table = page.extract_table()

        df_tmp = pd.DataFrame(table[1:], columns=table[0])

        dfs.append(df_tmp)

# すべてのページを結合
df = pd.concat(dfs)

df.shape

# 前後の空白文字、正規化
for col in df.select_dtypes(include=object).columns:
    df[col] = df[col].str.strip().str.normalize("NFKC")

# 拡張子をCSVに変更
path_csv = path_pdf.with_suffix(".csv")

df.to_csv(path_csv, encoding="utf_8_sig", index=False)

df1 = df.copy()

# データラングリング

import datetime

dt_now = datetime.datetime.now()

# 月日を現在の年で補完し年月日に変換、現在より未来の日付の場合は１年前にする
def str2date(s: pd.Series) -> pd.Series:

    df = s.str.extract("(\d{1,2})月(\d{1,2})日").rename(columns={0: "month", 1: "day"}).fillna(0).astype(int)

    df["year"] = dt_now.year

    tmp = pd.to_datetime(df, errors="coerce")

    df["year"] = df["year"].mask(tmp > dt_now, df["year"] - 1)

    return pd.to_datetime(df, errors="coerce")

df1["リリース日YMD"] = str2date(df1["リリース日"])
df1["発症日YMD"] = str2date(df1["発症日"])
df1["確定日YMD"] = str2date(df1["確定日"])

p = path_csv.with_name(path_csv.name.replace(".csv", "_c.csv"))

df1.to_csv(p, index=False, encoding="utf_8_sig")

# ダウンロード

from google.colab import files

files.download(str(p))
```

# コロナ関係

+ [東京都の新型コロナウイルスに関連した患者の発生についての別紙PDFから表を抽出しJSONに変換](https://qiita.com/barobaro/items/6303d6bcdb2bf9adb8db)
+ [新型コロナウイルス接触確認アプリのダウンロード数と陽性登録件数をスクレイピング](https://qiita.com/barobaro/items/99f1d60bd06189938c6e)
Missing Project ID Because you are not a member of this project this build will not access Unity services. Do you want to continue?


Missing Project ID
Because you are not a member of this project this build will not access Unity services.
Do you want to continue?

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/1562807b-6161-62e0-c0da-c013ab2f2c59.png)


解決策
ステップ１　NewLinkを押す
ステップ２ Createする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/91e3e04b-2b5e-0d88-4dd4-1e9c04fdab5e.png)


＜参考＞

https://qiita.com/nonkapibara/items/808834465b6d0157cfc6

Unityの公式マニュアルの方法にも対処方法が記載されていました。
https://docs.unity3d.com/ja/2019.1/Manual/UnityAnalyticsMismatchedProjectId.html
【ギリ初心者向け】Laravel Docker AWS(EC2) Webアプリ（PHP)を0から簡単にデプロイする方法（無料）②　ーDocker開発環境構築編ー



#※内容はこちらのサイトに移動しました！

https://sg-report.com/laravel-docker-awsec2-web2/
zsh: command not found: yarnについて

Homebrewのyvmでyarnをインストールするだけでは使用できなかったため、環境変数を追加してみました。

## 実行環境
- OS: MacOS Catalina v10.15.7
- Shell: zsh


## この記事で分かること

```zsh: command not found: yarn```の解決策

## こんな人に読んで欲しい
Homebrewのyvmでyarnをインストールにも関わらず、```zsh: command not found: yarn```が出る人。

## 解決策 

環境変数を追加します。

```command:ターミナル

% source $(brew --prefix yvm)/yvm.sh
% echo 'source $(brew --prefix yvm)/yvm.sh' >> ~/.zshrc
```
yvmが使えるようになったか確認します。

```command:ターミナル
% command -v yvm
↓
yvm
```

これでyvmが使えるようになり、yarnも使えるようになります。

## 何をしているのか
ターミナルから.zshrcにsource $(brew --prefix yvm)/yvm.shを書き込みました。(echoコマンドが書いてくれるコマンド)

```command:ターミナル
% vim ~/.zshrc
```
を開くと、source $(brew --prefix yvm)/yvm.shが書き込まれているのが確認できます。



## 参考記事
[nvm(Node Version Manager)を使ってNode.jsをインストールする手順](https://qiita.com/ffggss/items/94f1c4c5d311db2ec71a/)
こちらの記事はnvmをインストールする際の記事ですが、nvmをyvmに変えて使用させていただきました。
huskyのpre-commitフックがSourceTreeでコミットするときに動かない

# 問題
huskyのpre-commitフックを設定したが、コマンドラインで `git commit` した時は動くのに、SourceTreeでコミットする時はフックされてない、という事象に遭遇した。

# エラーログ

![スクリーンショット 2021-01-11 14.54.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70000/a741b3ac-37ab-b88d-34b1-291062bde16b.png)
SourceTreeの設定を「すべてのコンソール出力を常に表示する」に変えて、コミットした時のログを確認してみると...

```
Can't find npx in PATH: /Applications/Sourcetree.app/Contents/Resources/git_local/libexec/git-core:/Applications/Sourcetree.app/Contents/Resources/bin:/Applications/Sourcetree.app/Contents/Resources/git_local/bin:/Applications/Sourcetree.app/Contents/Resources/git_local/gitflow:/Applications/Sourcetree.app/Contents/Resources/git_local/git-lfs:/usr/bin:/bin:/usr/sbin:/sbin Skipping pre-commit hook
```

:thinking: 

# 対処

https://github.com/typicode/husky/issues/639#issuecomment-573281096
npxの場所にPATHを通せば良いっぽい。

https://github.com/typicode/husky/issues/639#issuecomment-624147148
>the file must be created in your home folder (~/.huskyrc) not at your project root.

`.huskyrc` はprojectのrootではなく、 `~/` に置く点に注意。

というわけで
私のエラーログの場合
>Can't find npx in PATH

とのことなので

```
$ which npx
/Users/miyuki/.nodebrew/current/bin/npx
```
ここにあるようなので

`~/.huskyrc` には

```
PATH="/Users/miyuki/.nodebrew/current/bin:$PATH"
```

と記述して、解決した :tada: 

# 参考

- https://github.com/typicode/husky/issues/390
- sourcetreeのissue
    - https://jira.atlassian.com/browse/SRCTREE-7184
ActiveRecord::RecordNotFound

##Couldn't find Genre without an ID のエラー解決法

編集画面へのリンクを作成中に起こったエラー。
ParamsでID取得できてませんよーということでした。

:eye:確認したこと１
ルーティングの確認

```rudy:routes.rb
  resources :genres
```
うん。問題なさそうですね

:eye:確認したこと２
コントローラーの確認

```rudy:genres_controller.rb
　def edit
    @genre = Genre.find(params[:id])
  　end
```
うん。これも問題なさそうですね。

:eye:確認したこと３
link_to のpathにidを持たせているか

```rudy:genres/index.html.erb
　<%= link_to "編集する", edit_genre_path(@genre.id) %>
```
うん？問題ないと思うんだけどなーーーー


##結論

```ruby:genres/index.html.erb
<% @genres.each do |genre| %> 
 <%= genre.name %>
 <%= link_to "編集する", edit_genre_path(genre.id), class: "btn btn-secondary" %>
<% end %>
```

eachの中に入れてあげたらいけました。

外だったら何がダメだったのかいまいち分からず、、
要復習ですね:sweat_smile:


p.s. quiitaの記事もっと上手に書けるようになりたいなー:star:
ActionView を単体で使用する(6.0以降対応)

ActionView を単体で利用する場合は、ActionView 5.2 までは次のようなコードを書いていました。

```ruby
def html
  view_context.assign(staffs: [{ name: 'Alice', position: 'supervisor' }])
  view_context.render(template: 'index',
                      prefixes: 'staffs')
end

def lookup_context
  return @lookup_context if @lookup_context

  @lookup_context = ActionView::LookupContext.new('./views')
  @lookup_context.cache = false
  @lookup_context
end

def view_context
  @view_context ||= ActionView::Base.new(lookup_context)
end

p html
```

ActionView 6.0 からは同じコードを利用していると、次のような WARNING が発生していました。

```
DEPRECATION WARNING: ActionView::Base instances must implement `compiled_method_container` or use the class method `with_empty_template_cache` for constructing an ActionView::Base instance that has an empty cache. (called from html at app.rb:13)
```

また、2020/12にリリースされた ActionView 6.1 からは `ActionView::Base.new` でシンタックスエラーが発生するようになりました。

```
Traceback (most recent call last):
	7: from app.rb:41:in `<main>'
	6: from app.rb:6:in `execute'
	5: from app.rb:6:in `open'
	4: from app.rb:7:in `block in execute'
	3: from app.rb:12:in `html'
	2: from app.rb:27:in `view_context'
	1: from app.rb:27:in `new'
/Users/soruma/program/only_action_view_6_1_example/vendor/bundle/ruby/2.7.0/gems/actionview-6.1.1/lib/action_view/base.rb:230:in `initialize': wrong number of arguments (given 1, expected 3) (ArgumentError)
```

WARNING に書かれている通り、

> ActionView :: Baseインスタンスは、 `compiled_method_container`を実装するか、空のキャッシュを持つActionView::Baseインスタンスを構築するためにクラスメソッド` with_empty_template_cache`を使用する必要があります。

に変更しなければなりません。

Google先生に聞いても答えが出てきませんでいたが、 [ActionView のテスト](https://github.com/rails/rails/blob/576fb33ba3c1cf0a0c3e83ffac56c46a83d7a57f/actionview/test/template/render_test.rb#L15-L21)にヒントが書かれていました。

```ruby
@view = Class.new(ActionView::Base.with_empty_template_cache) do
  def view_cache_dependencies; []; end

  def combined_fragment_cache_key(key)
    [ :views, key ]
  end
end.with_view_paths(paths, @assigns)
```

今回、私はRails 6.1対応するにあたって次のように実装しました。

```ruby
def html
  view(staffs: Staff.new.execute).render(template: 'index',
                                         prefixes: 'staffs')
end

def view(assigns)
  Class.new(
    ActionView::Base.with_empty_template_cache
  ).with_view_paths('./views', assigns)
end
```

今回のソースは[Github](https://github.com/soruma/only_action_view_6_or_newer_example)に保存しています。

## 参考

* [ActionView を単体で使ってみる | そんなこと覚えてない](https://blog.eiel.info/blog/2014/07/18/action-view/)
* [rails/actionview/test/template/render_test.rb | Github rails/rails](https://github.com/rails/rails/blob/576fb33ba3c1cf0a0c3e83ffac56c46a83d7a57f/actionview/test/template/render_test.rb#L15-L21)
* [Move compiled ERB to an AV::Base subclass | Github](https://github.com/rails/rails/pull/35036)

## 追記(2022/6/21)

Rails 7 でも動作確認しました。
【AWS】VPC

#インターネットゲートウェイ
サブネット内の他のインスタンスはインターネットに接続できるため、ネットワークACLの設定に問題はない
通信は行きと戻りが必要。インターネットゲートウェイでの通信いおいて、戻りの通信はインスタンスのプライベートIPアドレスではなくパブリックIPv4アドレスまたはElasticIPアドレスが必要

#セキュリティグループ
・インスタンスの仮想ファイアウォールとして機能し、インバウンドトラフィックとアウトバウンドトラフィックをコントロールする
・ネットワークインターフェイスあたりの最大数は５
・インスタンスに設定できるインバウンドトラフィックとアウトバウンドトラフィックを制御する
・ステートフルフィルタリング

◆デフォルト
・同じセキュリティグループに割り当てられたインスタンスからのインバウンドトラフィックを許可、
　すべての発信トラフィックを許可
　インバウンド：許可せず
　アウトバウンド：全て許可

#ネットワークACL
・サブネットレベルで動作し、サブネットへ出入りするトラフィックを検証する
・ステートレスフィルタリング


#メモ
◆VPCのサブネットのインスタンスでインターネットアクセスを有効にするには以下を実行する必要がある
　・VPCにインターネットゲートウェイをアタッチする
　・サブネットのルートテーブルがインターネットゲートウェイにつながっていることの確認
　<font color="red">・サブネットのインスタンスに、グローバルに一意なIPアドレス（パブリックIPv4アドレス、ElasticIPアドレス、IPV6アドレス）が割り振られてることの確認</font>
　・ネットワークアクセスコントロールとセキュリティグループルールがインスタンス間で関連するトラフィックを許可していることの確認

◆インターネットへ接続する手順
１）サブネット作成
２）インターネットゲートウェイをアタッチ
３）カスタムルートテーブルを作成
４）セキュリティグループルール更新
　デフォルト設定ではインターネットへのアウトバウンドトラフィックは全て許可しているが、インバウンドトラフィックは全て許可していないため許可する必要がある
５）ElasticIPアドレスを追加

◆クラスタープライスメントグループ
・単一のAZ内のインスタンスを論理的にグループ化したもの。
同じリージョン内のピアVPCにまたがることが可能
クラスタープライスメントグループの主な利点は、１０Gbpsのフロー制限に加えて、非ブロッキング、非オーバサブスクライブの完全に２分割されている接続であること
つまり、プレイスメントグループ内の全てのノードは、他の全てのノードと対話可能
オーバーサブスクリプションによる遅れなしに１０Gbpsフローと２５アグリゲートのフルラインレートで行われる
<font color="red">→多数のインスタンスを起動し並列処理を行う際にレイテンシーを低く抑えることが可能</font>

◆サブネット
・単一のサブネットは、単一のAZで利用可能。AZ及びリージョンを跨って利用することはできません
・デフォルトサブネットのネットマスクは常に/20

◆VPCピアリング
・2つのVPC間でプライベートなトラフィック のルーティングを可能にするネットワーキング機能
どちらのVPCのインスタンスも同じネットワーク内に存在しているかのように相互通信できる
・VPCピアリング接続は自分のVPC、別のAWSアカウントのVPC、別リージョンのVPCに作成可能
・トラフィックはプライベートであるため暗号化されない

#メモ
・インスタンス起動後のロードバランサーの認識時間
VPCインスタンスを停止して起動し他場合、、インスタンスが再起動されたことをロードバランサーが認識するまで時間がかかることがある
→再起動後にインスタンスをロードバランサーに再登録することで解決
Laravelで　【composer install 】した時に　【command not found: composer】と表示された時

###composer install時の、エラー処理方法

【状態】
Laravelをdockerで環境構築し、下記コマンドでコンテナを立ち上げた状態


```
docker-compose up -d --build
```

〜補足説明〜

``-d``
→デタッチド・モード: バックグラウンドでコンテナを実行するということ。

``--build``
→Dockerfileの再読み込みをしてくれて、更新した情報を反映してくれる。



【問題】
コンテナが立ち上がったので、 [http://localhost/] (http://localhost/)にアクセスすると、下記のようなエラー文が表示された！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/928468/c1afb74f-7018-70d8-ce1d-2d12688248a1.png)



【原因】
composer が　install できていなかった、、、



【解決策】
1.Laravelが入っているディレクトリに移動

(``cd ``でディレクトリを変更しながら``app``や``bootstrap``が入っているフォルダに移ってください)


2.インストールを実行

```
composer install
```

or

```
composer update
```

で実行できます。

※上記で指定したディレクトリでないと、``command not found: composer``と表示されてしまうので、注意してください！！


【感想】
最近は調べる力ばかり、伸びている気がしますね、、、



*There is no shame in not knowing; the shame lies in not finding out*

知らないことは恥ではない。知ろうとしないことこそ恥である

と言い聞かせて、
electron-forgeでSass / SCSS

## はじめに

この記事は、electron-forgeで作成したアプリケーションにおいて、CSSをSass/SCSS化する手順を記録、共有するためのものです。

Electronアプリケーションは、UIをWebブラウザで描画します。アプリケーションが複雑になるのにあわせて、CSSが肥大化しメンテナンスが難しくなります。Sass/SCSSを使えばアプリケーションのメンテナンス性を維持できます。

また、electron-forgeはwebpackを使ってアプリケーションをバンドルしています。Sass/SCSSをサンプルとして、この仕組みを理解すれば、好きなloaderをelectron-forgeに組み込めます。

### 想定する読者

この記事はすでにElectronで開発をしているユーザーに向けて書かれています。そのため、Electron自体の解説やインストール、開発環境構築に関する内容は取り扱いません。

### 想定する環境

- node.js : 14.15.0
- yarn : 1.22.5
- electron : 11.1.1
- electron-forge : 6.0.0-beta.54
- sass : 1.32.2
- sass-loader : 10.1.0

バージョンが異なる場合、この記事の内容はそのまま適用できない場合があります。お手元の環境のバージョンを確かめてからお読みください。

## electron-forgeにおけるwebpack

webpackオプションを指定して`create electron-app`コマンドを実行すると、electron-forgeはwebpackを組み込み済みのアプリケーションを生成します。

```shell
yarn create electron-app my-new-app --template=webpack
                                    ~~~~~~~~~~~~~~~~~~
```

- webpack.main.config.js
- webpack.plugins.js
- webpack.renderer.config.js
- webpack.rules.js

`create electron-app`コマンド後、メインプロセスとレンダラープロセス用のwebpack設定ファイルが生成されます。rulesとpluginsは2つのプロセスの共通設定です。

このwebpack設定ファイルを修正することで、好きなプラグインやローダーをelectron-forgeに組み込めます。

## electron-forgeでSass/SCSS

レンダラープロセス用のwebpack設定に、sass-loaderを組み込みます。

### sass-loaderのインストール

`sass-loader`をインストールします。sass-loaderには`Dart Sass`が必要なため、Dart Sassのnpmパッケージ`sass`も同時にインストールします。

```shell
yarn add -D sass-loader sass
```

### webpack.renderer.config.jsの編集

`webpack.renderer.config.js`を編集します。この設定がレンダラープロセス用のスクリプトファイルをバンドルしています。

_▼webpack.renderer.config.js_

```js
const rules = require("./webpack.rules");

rules.push(
  {
    test: /\.css$/,
    use: [{ loader: "style-loader" }, { loader: "css-loader" }],
  }
);
```

`webpack.rules.js`から読み込んだ共通ルールに、CSSローダーを追加しています。ここにsass-loader用のルールを追加します。
ルールの追加方法はsass-loaderの[README](https://github.com/webpack-contrib/sass-loader#getting-started)を参照します。

_▼webpack.renderer.config.js_

```js
const rules = require("./webpack.rules");

rules.push(
  {
    test: /\.css$/,
    use: [{ loader: "style-loader" }, { loader: "css-loader" }],
  },
  {
    test: /\.s[ac]ss$/,
    use: [
      { loader: "style-loader" },
      { loader: "css-loader" },
      { loader: "sass-loader" },
    ],
  }
);
```

webpackの処理対象となる拡張子を設定に追加します。

_▼webpack.renderer.config.js_

```js
module.exports = {
  ...
  resolve: {
    extensions: [".js", ".ts", ".jsx", ".tsx", ".css", ".scss", ".sass"],
                                                       ^^^^^^^^^^^^^^^^
  },
};
```

これでwebpack.renderer.config.jsの修正は完了です。

### renderer.jsから読み込み

`webpack.renderer.config.js`のエントリーポイントはrenderer.jsです。webpackはrenderer.jsを起点に、JavaScript内で読み込まれているファイルを追跡してバンドルします。

_▼src/renderer.js_

```js
import "../src/index.scss";
               ^^^^^^^^^^^
```

インポートするファイルをcssからsass/scssに変更します。

`electron-forge start`コマンドで、修正が反映されていれば組み込み作業は完了です。

以上、ありがとうございました。
【徹底検証】Outlook for Macのバックアップ及び復元

メーラーはMicrosoft365のOutlook for Macを利用しています。筆者はWindows時代からOutlookをメーラーとして利用してきました。ところが、Mac版のOutlookに乗り換えて気付いたことはメールの仕分けルールや受信拒否リストなどをインポート・エクスポートする機能が搭載されていない[^imex]:scream:ことです。これでは苦労して仕分けルールなどを作っても、いざという時に環境を復元できなくなってしまいます。そこで本記事ではMac版Outlookにおける各種データのバックアップ方法を検証し、別途用意したmacOSのVM上でバックアップデータから復旧出来るかの検証も行いたいと思います。

# 検証環境
* macOS 11.1 Big Sur
* Microsoft Outlook for Mac 16.44

# データの格納先の探索
[参考](https://www.too.com/support/faq/mail/22935.html)より、以下のPathにOutlook関連のファイルが格納されていることが分かりました。
`/Users/$USER/Library/Group\ Containers/UBF8T346G9.Office/Outlook/Outlook\ 15\ Profiles/Main\ Profile/Data/`

## 実際に覗いてみる
`ls`コマンドでディレクトリ内を覗いてみます。

```bash
$ ls /Users/$USER/Library/Group\ Containers/UBF8T346G9.Office/Outlook/Outlook\ 15\ Profiles/Main\ Profile/Data/
BlockLocks.sqlite      Contacts               Message Attachments    Outlook.sqlite-shm     RecordLocks.sqlite-shm Signatures
BlockLocks.sqlite-shm  Folders                Message Sources        Outlook.sqlite-wal     RecordLocks.sqlite-wal UIDs
BlockLocks.sqlite-wal  Mail Accounts          Messages               Recent Addresses       Rules
Categories             Main                   Outlook.sqlite         RecordLocks.sqlite     Saved Searches
```

# バックアップの作成
`tar`コマンドでアーカイブファイルを作成し、Outlookの各種ファイルをバックアップします。作成したtarファイルを外付けHDなどに移動させます。

```bash
cd /Users/$USER/Library/Group\ Containers/UBF8T346G9.Office/Outlook/Outlook\ 15\ Profiles/Main\ Profile/
tar cvzf ~/backup.tgz Data
```

# バックアップの復元
tarファイルを展開してOutlookの環境が復元できるか試みます。実験のためにMacのVMをFusionで作成し、実験しました。結果は以下の様になりました。

* 復元が成功した内容
    * メール(署名付きのメールも復元可)[^sign]
    * メールフォルダ
    * 仕分けルール
    * 署名

* 復元出来なかった内容
    * 受信拒否リスト
    * 並べ替えルール

* 復元を試みていない内容
    * 予定表
    * アドレス帳
    * タスク

# まとめ
今回Outlook for Macのバックアップ方法について検討しました。一部復元出来なかったものも有りますが、再度作成するのが大変な仕分けルールや作り直しが面倒な署名については復元が出来ました。メールについてもフォルダ分けした状態で復元出来たのでもしもの時の復旧が楽になりそうです。但し、受信拒否リストなど一部復元出来なかったものは今後も調査を続けたいと思います。

# Reference
* [Outlook2011/2016のメールデータの保存場所はどこですか？](https://www.too.com/support/faq/mail/22935.html)
* [tar.xz・tar.gzコマンドメモ](https://qiita.com/aminosan000/items/3bb1a4fac3533f6b0e5b)
* 新版zsh&bash対応 macOSxコマンド入門(西村めぐみ著;2020年;技術評論社)

[^imex]: Windwos版では仕分けルールや受信拒否リストは操作画面からインポート及びエクスポート出来ますが、Mac版にはそういった昨日は2020年12月現在搭載されていません。
[^sign]: 署名付きのメールをインポート/エクスポート機能で復元した場合は、文字化けなどが発生し正しく復元出来ない場合が有ります。
AWS CLIでAWSアカウント間のドメインの移管をする時のパスワードについて

AWS CLIを使うと、あるAWSアカウントから別のAWSアカウントにドメインを移管できます。作業の中で、あるAWSアカウントでまず`transfer-domain-to-another-aws-account`を使って移管準備を行うのですが、このコマンドが出力するpasswordに"|"が含まれていると、次の`accept-domain-transfer-from-another-aws-account`によるコマンドが、正しいパスワードを入れても`password is incorrect`となって失敗してしまいます。

この時は、いったん`cancel-domain-transfer-to-another-aws-account`を使って移管処理を中止した後に、もう一度`transfer-domain-to-another-aws-account`を実行して"|"がpasswordに含まれていないことを確認してから、作業を続けると良いです。
ログインシェルについての概要まとめ

## ログインシェルとは

ログイン直後に起動するシェルのこと。

## 環境

```sh
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.15.6
BuildVersion:	19G2021
```

## 利用できるログインシェル一覧を表示

```sh
$ cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
```

## 使用中のログインシェルを表示

`bash` であることがわかる。

```sh
$ echo $SHELL
/bin/bash
```

## ログインシェルの変更

`zsh` に変更する場合は下記のようにする。

```sh
$ chsh -s /bin/zsh
Changing shell for username.
Password for username:
```

再ログインすると、下記のようにデフォルトのプロンプトが `%` になり、ログインシェルが `/bin/zsh` となっていることがわかる。

```zsh
username@hostname ~ % echo $SHELL
/bin/zsh
```

## バージョンを調べる

ログインシェルが `bash` の場合

```sh
$ echo $BASH_VERSION
3.2.57(1)-release
```

ログインシェルが `zsh` の場合

```zsh
% echo $ZSH_VERSION
5.7.1
```
huskyをmonorepo環境に導入した


# ディレクトリ構成

こんな感じのmonorepo

```
project
- .git
- /api
- /ui （←　Next.js + TypeScript）
```

# やりたいこと
- `project/ui/` 配下で、コミットするときに、prettierやlintをフックしたい


# 入れたもの

- husky 4.3.7
- lint-staged 10.5.3

# はまった点

最初、`project/ui/` 配下のpackage.jsonにhuskyとlint-stagedを入れてたら、フックされなかった。
monorepoの場合、huskyはroot（`.git/` と同階層）に入れておかないといけないようだ。
https://typicode.github.io/husky/#/?id=monorepo

ちなみにhuskyでなくpre-commitでやる場合も同様のようだ。
https://stackoverflow.com/questions/42864386/npm-pre-commit-not-working


# これで動いた

```project/package.json

  "scripts": {
    "precommit-ui": "npm run precommit --prefix ./ui"
  },
  "husky": {
    "hooks": {
      "pre-commit": [
        "npm run precommit-ui"
      ]
    }
  },
  "devDependencies": {
    "husky": "^4.3.7"
  }
```

```project/ui/package.json
  "scripts": {
    "eslint": "eslint --ext .ts,.tsx ./",
    "format": "prettier --write ./pages",
    "precommit": "lint-staged"
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "format",
      "eslint"
    ]
  },
```

huskyのフックはrootのpackage.jsonに記述し、下の階層のpackage.jsonのnpm scriptを呼び出している。

# まとめ

monorepoにhuskyを入れる場合、projectのrootに入れないと動かない。
Cloud9(Amazon Linux)でmysqlのバージョンアップ(5.5から5,7)

## MySQLを停止する
`sudo service mysqld stop`

## MySQLをアンインストールする
5.5系のMySQLをアンインストールする場合は以下のよう「55」になります。
`sudo yum -y remove mysql-config mysql55-server mysql55-libs mysql55`

## MySQLをインストールする
5.7系をインストールする場合、「57」を指定します。
`sudo yum -y install mysql57-server mysql57`

## 再度バージョンを確認する
ちゃんとインストールされたかバージョンを確認します。
`mysql --version`