OmniAICreator/Qiita-1.07M huggingface dataset:
STM32L010のPortAで遊ぶ(IN)


目的
GPIOのテスト


![o_con181.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/bbacc670-f5ea-ce7b-cd2d-5b0567223997.jpeg)



```c++


//I2C_EXPANDER_IN_1

#include "mbed.h"

DigitalOut TX(PC_14);

//仮想シリアルへの一文字出力 1200bps
int pc_putc(char ch)
{

    TX=1;
    TX=0;//Start
    wait_us(832);

    for(int ii=0; ii<8; ii++) { //Data x 8
        TX=(ch>>ii)&1;
        wait_us(832);
    }; //for

    TX=1;//Stop
    wait_us(832);

    return(0);

} //pc_putc


PortIn     p(PortA, 0x000000FF);   // PA0-PA7

char HEX_C[] =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } ;

//メインルーチン
int main()
{

    char buf[10];

    TX=1; //ポートの初期化

    //無限ループ
    while(1) {

        int pins = p.read();

        //buf[0] = 0x12;
        buf[0] = pins;
        

        //HEX出力
        char cc = buf[0];
        pc_putc(HEX_C[ cc >> 4    ]);
        pc_putc(HEX_C[ cc &  0x0f ]);
        pc_putc('\r');
        pc_putc('\n');

        //1秒の待ち
        wait_ms(1000);

    }//while

}//main

//容量削減
void error(const char* format, ...) {}





```
PowerShellで特殊フォルダのパスを取得する

PowerShellで特殊フォルダの一覧だったり、そのパスを取得する方法を毎回しらべている気がするのでまとめます。

`.Net`では`System.Environment`クラスから特殊フォルダパスを取得する事ができるため、これを利用します。

## ドキュメント

[Environment クラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.environment?view=net-6.0)

## 特殊フォルダの一覧を取得する

[Environment.SpecialFolder 列挙型](https://docs.microsoft.com/ja-jp/dotnet/api/system.environment.specialfolder?view=net-6.0)

EnvironmentクラスではSpecialFolder列挙型に特殊フォルダの定数が格納されているので下記で表示できます。

```pwsh:特殊フォルダの一覧を取得する
[Environment+SpecialFolder].GetEnumNames()
```

ちなみにEnvironmentとSpecialFolderの区切り文字として`+`を利用していますが、これは入れ子になっている内部クラスにアクセスする際の区切り文字が`+`なためのようです。

[完全修飾型名を指定する](https://docs.microsoft.com/ja-jp/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names)

## 特殊フォルダのフルパスを取得する

[Environment.GetFolderPath メソッド](https://docs.microsoft.com/ja-jp/dotnet/api/system.environment.getfolderpath?view=net-6.0#System_Environment_GetFolderPath_System_Environment_SpecialFolder_)

Environmentクラスに　GetFolderPathメソッドがあり、このメソッドに`Environment+SpecialFolder`を渡すとフルパスが取得できます。

```pwsh::Windowsのフォルダパスを取得する
[Environment]::GetFolderPath([Environment+SpecialFolder]::Windows)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/5d63e506-d67b-f7ba-169d-c11e73d0c619.png)

すべての特殊フォルダのフルパスが取得したい場合は下記のように実行すれば取得できます。

```pwsh:すべてのフルパスを取得
[Environment+SpecialFolder].GetEnumNames() | Sort-Object | Select-Object @{Name="Name";Expression={$_}} , @{Name="Path";Expression={[Environment]::GetFolderPath($_)}}
```

## 参考

[Why is a plus operator required in some Powershell type names?](https://stackoverflow.com/questions/57228424/why-is-a-plus-operator-required-in-some-powershell-type-names)
[Plus (+) in .NET Class Names](https://devblogs.microsoft.com/powershell/plus-in-net-class-names/)
[Explore Your [Environment]](https://devblogs.microsoft.com/powershell/explore-your-environment/)
[PowerShellで入れ子のクラス(内部クラス)を示すには + を使う話](https://blog.shibata.tech/entry/2016/12/15/221024)


## 総評

毎回ぐぐっている気がするのでまとめました。

.NETクラスで`+`って入れ子の内部クラスにアクセスするための文字で`PowerShell`だと`+`にしないと動かないというのは、そうなの？　って感じがするところではあるかと思います。
Gstreamerのtutorialsビルド(Visual Studio)

# Gstreamerインストール
https://gstreamer.freedesktop.org/
## Install
サイトからインストーラをダウンロードします。
https://gstreamer.freedesktop.org/download/

1. Runtime installer
   
        gstreamer-1.0-msvc-x86_64-{VERSION}.msi

2. Development files installer

        gstreamer-1.0-devel-msvc-x86_64-{VERSION}.msi

## 環境変数追加

例
インストール先：`D:\gstreamer`

1. ユーザ環境変数
変数名:`GSTREAMER_1_0_ROOT_MSVC_X86_64`
変数値:`D:\gstreamer\1.0\msvc_x86_64\bin`
2. システム環境変数
変数名:`GST_PLUGIN_SYSTEM_PATH`
変数値:`D:\gstreamer\1.0\msvc_x86_64\lib\gstreamer-1.0`

## テスト
CMD起動、以下コマンド実行
    
    gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink

# VS2019ビルド

1. `gst-docs-master\examples\tutorials\vs2010\tutorials.sln`をVS2019で開く
2. アップグレードするメッセージが表示され、YESを選択
3. `basic-tutorial-1`をビルドすると、エラーが表示される
4. `basic-tutorial-1`を右クリックして、プロパティを選択する。ダイアログでDebugging（デバッグ）をクリックして、`Working Directory`を選択する
5. `Working Directory`に`D:\gstreamer\1.0\msvc_x86_64\bin`を追加して、OKボタン
6. `C/C++`を選択して、`Additional Include Directories`をクリックする。以下ファイルパスを追加
   
        D:\gstreamer\gst-docs-master\examples\tutorials\vs2010\include
        D:\gstreamer\1.0\msvc_x86_64\lib\glib-2.0\include
        D:\gstreamer\1.0\msvc_x86_64\include\gstreamer-1.0
        D:\gstreamer\1.0\msvc_x86_64\include\glib-2.0\
        D:\gstreamer\1.0\msvc_x86_64\include\glib-2.0\glib
7. `Linker（リンカー）`を選択して、`General`をクリックする。以下パスを追加
    
        D:\gstreamer\1.0\msvc_x86_64\lib

8.  `Linker（リンカー）`を選択して、`Input（入力）`をクリックする。以下のlib追加（使用Libに応じて追加）
    
        gobject-2.0.lib
        glib-2.0.lib
        gstreamer-1.0.lib
        gstaudio-1.0.lib
        gstpbutils-1.0.lib
        gstvideo-1.0.lib
9. 再度ビルド

# 参考
1. https://gstreamer.freedesktop.org/documentation/installing/on-windows.html?gi-language=c
2. https://homanhuang.medium.com/back-to-the-gstreamer-basic-1-c-vs2019-d516c35c9e2f#14cd
【Django】{% static %} タグ内で変数を使う方法

# 【Django】{% static %} タグ内で変数を使う方法

staticから画像を読み込むとき、view.py から持ってきた変数を使って、
静的ファイルの表示を切り替えようと思って、ちょっと苦戦したのでやり方をいくつか紹介

## 詳しく

- ユーザの個人ページにて、ユーザのトップ画像をユーザごとに表示する実装を行っている

```py:views.py
def index(request):
    image_path = request.user.set_image_path
    return render(request, 'main/index.html', {'image_path': image_path})
```

Requestしたuserのset_image_pathフィールド(CharField)をimage_pathという変数に入れて
template に 渡す
image_path の中身 例 : `user1_icon.jpg`

- template ファイル内の {% static '' %} 内で変数を入れようとしたけど、表示できない

```html:index.html
{% extends 'main/base.html' %}
{% block content %}
{% load static %}
<h2>UserImage↓</h2>
<img src="{% static 'assets/userimages/{{ image_path }}' %}">
{% endblock %}
```

→これだと変数ではなく文字列`{{ image_path }}`と認識されるので、
当然そのようなファイルはなく404のエラーが返ってきて表示できない

```
↓エラー内容
[29/Dec/2021 18:10:10] "GET /static/assts/userimages/%7B%7B%20image_path%20%7D%7D HTTP/1.1" 404 1870
```

## 変数の使い方

参考にしたページ:
- [django 1.5-静的タグ内で変数を使用する方法](https://www.webdevqa.jp.net/ja/django/django-15%E9%9D%99%E7%9A%84%E3%82%BF%E3%82%B0%E5%86%85%E3%81%A7%E5%A4%89%E6%95%B0%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/1073407235/)
- [Djangoのテンプレート内で変数を設定する方法](https://hodalog.com/how-to-set-a-value-of-a-variable-inside-a-template-code/)

### 方法1. テンプレートタグ「with」 & ビルトインフィルター「add:」 を使って変数をセットする 

```html:index.html
{% with 'assets/characters/'|add:image_path as image_static %}
<img src="{% static image_static %}" class="monster-img">
{% endwith %}
```

with タグは 変数を事前に設定して、タグ内だけで利用できる
add: フィルターは、指定した内容を`|`より前のものにadd する
    今回はCharなので、連結されるけど、数字の場合は足し算される ( {{ 4|add:2 }} → 6になる)
    他にもいろいろフィルターある→[公式リファレンス](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#add)

### 方法2. ビルトインフィルター「add:」を活用する

↑の省略形？みたいな感じ
今回はこちらを採用
一番すっきりしてるし、スマートな表記かなと思う

```html:index.html
<h2>UserImage↓</h2>
<img src="{% static 'assets/characters/'|add:image_path %}" class="monster-img">
```

### 方法3. `as`を使って static の ベースURLを変数として最初に宣言 → {{ 変数 }}/{{ 変数 }}の形にする

これもなかなかすっきりして良い

```html:index.html
{% static "assets/userimages" as baseUrl %}
<h2>UserImage↓</h2>
<img src="{% static '{{ baseUrl }}/{{ image_path }}' %}">
```

## 終わりに

`as` が便利だなと思った 今後活用する機会たくさんありそう
ビルトインフィルターも、使い方覚えれば応用が利きそう！
useRoutes() may be used only in the context of a <Router> component. エラーが起こる問題について

自分がハマったので記録に。
react-router-dom のv6を利用する際に

```react
ReactDOM.render(
  <Routes>
    <Route exact path='/' element={<Top/>} />
    <Route path='/App' element={<App/>} />
  </Routes>,
  document.getElementById('root')
);
```
この書き方をしたところ、Chromeのデバッグツールで

```
useRoutes() may be used only in the context of a <Router> component. 
```
というエラーが起こった。

```react
ReactDOM.render(
  <BrowserRouter>
    <Routes>
      <Route exact path='/' element={<Top/>} />
      <Route path='/App' element={<App/>} />
    </Routes>
  </BrowserRouter>,
  document.getElementById('root')
);
```
BrowserRouterタグで囲んであげることで解決した。
Ubuntu 20.04.3 LTSにVitis/Vivadoをインストールする

#はじめに
FPGAを弄りたくてUbuntu 20.04.3 LTSにVitis/Vivadoをインストールした時のメモです。

#OSとVitis/Vivadoのバージョン
|OS           | Ubuntu 20.04.3 LTS |
|-------------|--------------------|
|Vitis/Vivado | 2019.2             |

##Vitis/Vivadoのバージョンについて
2021年12月29日現在におけるVitis/Vivadoの最新版はML Edition 2021.2です。

ML Edition 2021.2のインストールに必要なディスク容量はフルインストールで

・Download Size : 64.48GB
・Disk Space Required : 257.37 GB

対象デバイスをZynq-7000とSpartan-7に絞っても

・Download Size : 50.34GB
・Disk Space Required : 166.93GB

なのですが、空き容量不足だったので断念。

あと、参考にしたサイトが2019.2をインストールされていたのでそちらに合わせました。

#参考サイト
基本的に下記の2つのサイトの合わせ技です。

[参考サイト 1]
Vivado のインストールと使いかた (3) HLx Edition WebPACK の概要とインストール (Linux編)
https://www.acri.c.titech.ac.jp/wordpress/archives/3403

[参考サイト 2]
Ubuntu20.04にVitis IDE2021.1とVivado ML2021.1をインストール
https://phys-higashi.com/2094/

#インストールと起動
インストール方法は基本的に[参考サイト 1]に従います。
Ubuntu 20.04.3 LTSは対象OSではないため警告のポップアップが出ますが、[Continue]を押せば継続できます。
インストールする開発環境の選択で[参考サイト1]ではVivadoを選択していますが、VitisをインストールすればVivadoもインストールできます。

インストールや設定が終われば、下記のコマンドを実行します。

```
$ sudo apt install libtinfo-dev
$ sudo ln -s /lib/x86_64-linux-gnu/libtinfo.so.6 /lib/x86_64-linux-gnu/libtinfo.so.5
```
上記のコマンドを実行せずにVivadoを起動しようとすると下記のエラーが発生して起動できません。

```
application-specific initialization failed: couldn't load file "librdi_commontasks.so": libtinfo.so.5: cannot open shared object file: No such file or directory
```
ここまでの作業を完了し、下記のコマンドを実行すればVivadoがGUIで起動します。

```
$ vivado
```
WSLで音を出す。最新版

#WSLで音を出す、で調べてもダウンロードできない

ここで記載されている方法は、今現在できる方法(2021年12月）を紹介しています。

#ここでやっていることと似ています。参考にしてみてください。

*[完全版 WSL2にTeraTermでアクセスし、かつX-Windowアプリを簡単に起動する方法](https://qiita.com/nanakochi123456/items/0f4951632e9a0bdfa6ba)

#Windowsでの作業
##pulseaudio-1.1 Windows版バイナリをダウンロードする。

おそらくここで引っかかった方がいらっしゃるかもしれません。

サーバーのオーナーが変更され

http://bosmans.ch/pulseaudio/pulseaudio-1.1.zip


からダウンロードできません。

Webアーカイブの以下のURLからダウンロードします。
[https://web.archive.org/web/20200112041213/http://bosmans.ch/pulseaudio/pulseaudio-1.1.zip](https://web.archive.org/web/20200112041213/http://bosmans.ch/pulseaudio/pulseaudio-1.1.zip)

##C:\WSL配下に展開する


C:\WSL\pulseaudio-1.1 の中に

* bin
* etc
* lib
* share

フォルダが確認できます。

##pulseaudioの設定ファイルを変更する

C:\WSL\pulseaudio-1.1\etc\pulse\default.paの61行目

```
変更前　#load-module module-native-protocol-tcp
変更後　load-module module-native-protocol-tcp auth-anonymous=1
```

C:\WSL\pulseaudio-1.1\etc\pulse\daemon.confの39行目

```
変更前　; exit-idle-time = 20
変更後　　exit-idle-time = -1
```


##コマンドプロンプトから起動する

Windows で「cmd」を起動して

```
C:
cd c:\wsl\pul*\bin
pulseaudio
```

と入力します。

##Windows ファイアーウォールを定義する

![2021-12-29 (31).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149448/f1b6c706-c27a-4ee6-7279-9d3a1b36c53c.png)

裏でアラートが出ていますが、気にする必要はありません。
このままアクセスを許可します。

なお、このコマンドウィンドウは起動したままにします。

#Ubuntuでの作業
##Pulseaudioのコマンドラインのインストール
```
sudo apt-get install pulseaudio-utils
```

##.bashrc への追加

```
export __BASEIP=192
export __XSERVERHOST=NANOKO
export PULSE_SERVER=tcp:$(nslookup $__XSERVERHOST | grep " $__BASEIP" | awk '{print $2}');
```

##動作確認をする
chrome でも起動してみます。

[この動画はこちらにあります。](https://www.youtube.com/watch?v=5kF76asW4i0)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149448/c8a3a474-a82e-b7a4-0121-49f8ff71d399.png)


Youtubeでは音がならないと動画として動かないと思います。

#Windowsで自動起動をする設置をする

##pulseaudio-vbs.vbsを作成します。
C:￥WSL\pulseaudio-1.1\pulseaudio-vbs.vbs を作成します。

コマンドプロンプトのウィンドウが一切表示されないようにします。

```pulseaudio-vbs.vbs
Set ws = CreateObject("Wscript.Shell")
ws.run "c:\wsl\pulseaudio-1.1\bin\pulseaudio.exe", vbhide
```

##pulseaudio-bat.batを作成します。
C:￥WSL\pulseaudio-1.1\pulseaudio-bat.bat を作成します。

```pulseaudio-bat.bat
@echo off
wscript c:\wsl\pulseaudio-1.1\bin\pulseaudio-vbs.vbs
```

##pulseaudio-bat.batのショートカットを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149448/48280477-c9ea-c8ab-62da-d4c917b82333.png)

##Windows で pulseaudio-bat.lnk を[Windows NT用AUTOEXEC.BAT](https://qiita.com/nanakochi123456/items/0bd346df592f85f5a7ce)の startup\normal に登録する

実は

c:\users\%USERNAME%\appdata\roaming\microsoft\windows\start menu\programs\startup

に上記のショートカットをおいてもかまいません。

# Windowsを再起動する

# Windows 起動後、WSLのubuntu とかのブラウザでYoutubeとかで試してみる。

#動作確認済ブラウザ
* firefox
* opera
* chrome
* edge
* palemoon
#MicrosoftTeams の NDI 機能を使って OBS Studio での配信をとても簡単にするTips

Microsoft Teams にて NDI という機能が追加されました。
これは、TeamsのWeb会議で使用している映像や音声をそれぞれOBSのソースとして登録する機能となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/cb3a07ad-67c1-aee7-452f-0481c9733ed1.png)

実際にどういう感じになるか見てみましょう

**Teams の会議**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/65196354-8ead-ddfd-09fd-09b646459c41.png)

**NDI を使ってOBSに出力した画面**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/2e86fb35-88a8-b94d-26e3-31dc9fe54f31.png)

実際、こんな感じで参加者のカメラや共有画面ごとにソースとして登録できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/338fc478-b229-0742-c7e1-1e4827721047.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/6488b618-2b45-28e1-1cd7-93d3811775dc.png)

なので、これまでのように、Teamsの画面をクロップしたりして抽出するような作業が不要となりますので、配信画面の作成がとてもスムーズになると思います。

# 前提条件

## Teams 側

配信対象のWeb会議を作成するユーザーに、この会議ポリシーが当たっている必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/c8eff104-4f3e-2f91-e6b0-d577cde0544e.png)

配信するPC上のTeamsクライアントに以下の設定が有効化されている必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/3c6ddb3c-11c9-efef-ce39-66182e28ce0c.png)

配信対象のWeb会議にて以下をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/fd99200c-22dd-b2f3-5d9d-1c73023f9eac.png)

## OBS 側

以下のプラグインがインストールされている必要があります

[GitHub:Palakis-obs-ndi](https://github.com/Palakis/obs-ndi)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/e40a3f4a-5aa3-98b5-5a87-01e3b1a66b85.png)

ダウンロード先は[こちら](https://github.com/Palakis/obs-ndi/releases)です

:::note warn
NDI の設定の詳細情報からおすすめされる NDI Tools は使いません。インストールも不要です。
:::

インストール後に OBS Studio を立ちあげると、ソースの新規追加にて、NDI Source が追加されているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/0ad957b1-0fb5-7419-e3bf-2b5026f3d9bb.png)

# NDI ソースの種類

NDIのソースには以下の4つがあります

* ローカル（配信端末側の映像・音声）
* 各参加者の名称（参加者側の映像・音声）
* 共有画面（共有されている画面、ただし配信端末が共有した場合は表示されません）
* アクティブスピーカー（現在しゃべっている人の映像・音声、ただし配信端末は除外されます）

# ここからが重要

Teams は、映像の提供元との通信状況などによって、映像の解像度をリアルタイムに変更します。
そのため、配信端末以外の映像ソースのサイズが自動的に変更されてしまい、OBSの配信レイアウトが頻繁に崩れたり、映像と音声が一致しないなどといった可能性が出てきます。
従って、NDI ソースを追加する際は以下の設定を変更して、できるだけ低解像度になるように変更します

* Bandwidth
* Sync
* Latency Mode

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/1ec2731a-5ee6-02a0-2687-4c9cb9aa8ccb.png)

ただし、イベントの趣旨やソースの種類によって、この設定はいろいろマチマチだと思いますので、事前に調整しておくのが良いと思います。
NVIDIAドライバをubuntu18.04にインストール(備忘録)

タイトル通り、ubuntu18.04にNVIDIAドライバをインストールしようとした色々手間取ったので備忘録がてら誰かの助けになれば
※2021年12月において僕はこのようにしてやったらうまくいったというだけでやり方を丁寧に説明するものではないです
# 環境
* ASUS TUF Dash F15
    * GeForce RTX 3070 Laptop
* ubuntu18.04 LTS

# 参考にさせて頂いたサイト
これらのサイトなどを参考にさせて頂いたのですが、僕の環境ではうまく行きませんでした。
今回はこれらをうまく組み合わせつつ少しいじくった手順です
(とても参考になりました、ありがとうございます)

* [Ubuntu18.04にNVIDIAドライバーをインストール](https://qiita.com/kannkyo/items/c506437704cd62b31077)
* [ubuntu18.04にnvidiaドライバを入れるの苦労した](https://qiita.com/kawazu191128/items/8a46308be6949f5bda57)

# うまくいった手順
## 1. Secure Boot(セキュアブート)をDisabledにする
* Biosの設定からSecure Bootをdisabledに設定する
* 詳しいやり方は調べればたくさん出てくると思います

## 2. gccのインストール
* インストールにはgccがインストールされてなければいけないのでインストールする
```
$ sudo apt install build-essential
```

## 3. nouveauの無効化
* 現在使われているドライバを一度無効化します
* ```/etc/modprobe.d/blacklist-nouveau.conf```を新たに作成し以下の二行を書き込み保存する

```
blacklist nouveau
options nouveau modeset=0
```
* 以下のコマンドで再読込の後再起動を行う

```
$ sudo update-initramfs -u
$ reboot
```
* 再起動後に以下のコマンドでしっかりと無効化されているか確認する

```
$ lsmod | grep -i nouveau
```

## 4. ドライバをダウンロードする
様々なやり方があったが直接ダウンロードしたやり方のみでうまくいきました

* [NVIDIA公式](https://www.nvidia.co.jp/Download/index.aspx?lang=jp)から自分の環境にあうように選択して.runファイルをダウンロードしてくる
* 僕の環境では以下のような感じでした
![Screenshot from 2021-12-29 18-07-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255633/41760310-477c-d062-bdb9-3dfe8ce8ebd7.png)
![Screenshot from 2021-12-29 18-11-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255633/a528225b-1f1f-f884-08ad-01804300a008.png)

## 5. GUIをオフにする
#### 注意
ここではGUIを一度無効にするので最後にGUIを再起動するまでこれ以降の手順はすべてCUIで行います
CUIを扱えないのにこの手順を行ってしまうと取り返しのつかないことになってしまうので十分注意してください
また、このサイトを別のPCやスマホなどで閲覧しながらの作業をおすすめします

* 以下のコマンドでDisplay Managerを無効にします

```
$ systemctl isolate multi-user.target
```
* すると画面が真っ暗になるのでCtrl + Alt + (f1 or f2 or ...)でCUIでのログイン画面に入ります
* そしてログインした後以下のコマンドで念の為、すでにインストールされているかもしれないNVIDIAドライバをアンインストールしておきます

```
$ sudo apt --purge autoremove nvidia*
```

## 6. ドライバをインストールする
* 3でダウンロードされたrunファイルを実行します
* まず以下のコマンドでrunファイルに実行権限を付与します(ファイル名は適宜よしなにしてください)

```
$ chmod +x ./NVIDIA-Linux-x86_64-470.94.run
```

* 以下のコマンドでsudoを用いてrunファイルを実行します

```
$ sudo sh ./NVIDIA-Linux-x86_64-390.77.run
```
* 上記のコマンドを実行すると、英語でいくつか選択を求められますが「もっと便利なインストール方法があるけどこの方法で良いの?」的な話などなので、適宜読んで選択すれば問題なく進めるはずです

## 7. GUIを再起動する
* 無事にインストールが終わったならば最後に以下のコマンドでGUIを再起動します

```
$ systemctl start graphical.target
```
* こうして再起動したGUIのターミナルで以下のコマンドで無事インストールできているか確認して終了です！

```
$ nvidia-smi
```

# 最後に
今回は上記の手順で無事にnvidiaドライバをインストールできました。
本来ならば、もっと簡単なコマンドだけでもインストールできるはずだったのですが、最初に載せた参考にさせて頂いたサイトやその他のサイトの手順では、GUIが全く動かなくてCUIのみになってしまったり、nvidia-smiコマンドを使ってもGPUを認識できなかったりといったバグ？が発生しうまくいきませんでした。
<br>
時間が経っているのでどこか変わってしまっていたり、環境が異なっていたりするのが原因なのかなと思っています。
同様にこの手順も一年後に違う環境であればうまく行かないこともあると思うので悪しからずお願いします。
node-sassでPHP StormのSCSSの自動コンパイル設定

久しぶりにSCSSでコンパイルをしようかとPHPStormを開いたが、PCを変えたのを忘れていて、1から設定する必要性があった。
設定方法が分からずに苦戦していたが、3時間の格闘の末、ようやく動いた。
今回は、成功したSCSSのやり方を記載していく。

# 環境
Mac Big Sur バージョン11.4

*Catalina移行はシェルをBashではなくてzshを利用していた*ので、
.bashrcや.bash_profileに記載しても適応されなかったようでした。

# Homebrewのインストール
[インストールパスは公式を参照](https://brew.sh/index_ja)


このあと、npmをインストールやパスを通してターミナル上では動くようになったものの、
PHP Storm 上では

```
env: node: No such file or directory
```

と表示され、動いていないようだった。
そこで[とある記事](https://qiita.com/sugasaki/items/ad4d5d88965057840a04)を参考に、nodebrewを入れてみることにした。

# nodebrew インストール

```
brew install nodebrew
nodebrew -v
```

nodebrewがインストールされていることが確認できたら、最新版をインストール。

```
mkdir -p ~/.nodebrew/src
nodebrew install-binary latest
```

ダウンロードされているnodebrewのバージョンを確認し、任意のバージョンを選択

```
nodebrew list
nodebrew use vX.X.X(listで記載されているバージョン)
```


その後パスを通すのだが、.bashrcではなくて.zshrcに記載する必要があったようだ。

```
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc
exec $SHELL -l
node --version
```

.zshrcを確認すると、きちんとパスが指定されているのが分かる。
バージョンが指定されたバージョンと同様であることを確認。

# node-sass の導入

```
npm install --global --save-dev node-sass
node-sass -v
```

バージョンが確認できたら成功。

# PHP Storm での設定
本来の設定方法とは違う可能性が高いが、私はこの方法がわかりやすいと思う。

![スクリーンショット 2021-12-29 18.12.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225361/b5147182-3903-4ff0-bace-4b85267e5ce5.png)

プログラム：
`node-sass`を指定。
プログラムが動かなければ

```
which node-sass 
```

をターミナルに入れて出てきたパスを設定する。

因数:
`$FileName$ $FileNameWithoutAllExtensions$.css`を指定。

意味としては
`$FileName$`:コンパイルする対象のファイル名
`$FileNameWithoutAllExtensions$`:コンパイルする対象のファイル名から拡張子を除いたものを示す。

上2つをあわせると、ターミナルで

```
node-sass $FileName$ $FileNameWithoutAllExtensions$.css
```

と一緒の意味になる。
つまり、コンパイルするファイル名がstyle.cssの場合、

```
node-sass style.scss style.css
```

をターミナル上でコンパイルしたのと一緒の意味になる。

他の設定項目は特に設定したりしていないが、
「コンソールの表示」を常時にすることで、きちんとコンパイルされているかが確認出来て便利だと思う。

# 参考
[Mac > node.jsをインストール](https://qiita.com/sugasaki/items/ad4d5d88965057840a04)

[Sassコンパイル環境をつくる（PHPStorm + node-sass）](https://qiita.com/J_Sugar__/items/9eb2386db7f3dad54174)
コミュニティ「自由研究室 AIRS-Lab」の意義と今後の展望について

今年2021年の8月、「自由研究室 AIRS-Lab」というWeb上のコミュニティを設立しました。
https://www.airs-lab.jp/
コミュニティのAdvent Calendar、最後ということでWeb上のコミュティを設立した意義とコミュニティの今後の展望について書いていきます。
今後コミュニティを設立したいエンジニアなどの方にとって、何らかの参考になれば嬉しいです。

## なぜコミュニティを始めたか
UdemyでAIを扱うコースを複数展開しており、現在約7.5万人の受講生がいます。
他にも企業研修や大学の講義を担当しているのですが、どうしても一方的な講義になってしまい受講生同士が交流したり創造する場に欠けていることは感じていました。
そこで、例えば大学の研究室、サークル、あるいはゼミのようなものを作れないかと思い、コミュニティの設立に至りました。
といっても、メンバーに特に義務があるわけではなく、各自が欠けているものをこのコミュニティで補えればいい、という緩いスタンスで運営しています。
これからAI（人工知能）を学びたい方、何らかのテクノロジーの専門家の方、様々な背景の方が共に学び、交流し、創造する機会を提供しています。
また、参加資格に理系・文系、学歴などは問わず、AIに関わり活動する機会を広く開放する方針です。

そして、コミュニティに心地よさを感じていただくためにも、メンバー対する誹謗中傷やマウント行為は禁じています。
メンバーが心理的安全性を保って楽しく活動できるようにする、というのも運営方針の一つです。

もう一つの設立理由は、「知能」に対する本質的な理解を深め、「汎用人工知能」へアプローチする「iLUCAプロジェクト」の開始です。
iLUCAはintelligence of Last Universal Common Ancestorの略で、研究室のメンバーは、誰でも参加することができます。
iLUCAは、なるべくシンプルかつ汎用的な人工知能の雛形を作ることが目的の、産声を上げたばかりのプロジェクトです。
LUCAとは生物の共通祖先のうち最も新しいもののことですが、このプロジェクトはAIでLUCAに相当するものを作り出すことを目的としています。
AIの専門家だけではなく、様々な背景の方の参入をお待ちしています。

## 使用しているサービス
コミュニティを運営するためのインフラとして、以下のサービスを使っています。

* Slack: 普段のコミュニケーション、ディスカッション用
* Zoom: 勉強会、イベント用
* Googleサイト: ウェブサイトの管理
* Googleフォーム: 参加申し込み用
* PayPal: 月額会費の徴収用

非エンジニアの方でも運営に参画できるように、なるべくノンコードでインフラを構築しました。
CAMPFIREやDMM オンラインサロンなどの既存のサービスを使うことも考えたのですが、微妙な使い勝手が方向性に合わなかったので自前で構築することにしました。

## 今後の展望
コミュニティを設立したのは今年2021年の8月後半なので、設立から4ヶ月経ったことになります。
メンバーの数は、運営メンバーを除いて34名まで増えました。
ソフトウェアエンジニア、特許技術者、生命科学者、脳外科医、大学教員、翻訳者、経営コンサル、土木技術者などの様々な背景の方に参加していただくことができて、とても多様性の高いコミュニティとなっています。

来年に実現したいことはいくつかありますが、例えばウェブアプリ、ネイティブアプリを手軽に公開できるインフラを整えたいと考えています。
StreamlitやFlutterなどを活用し、AIのアイディアを形にすることをサポートしていきたいです。
また、iLUCAプロジェクトのGitHubレポジトリも、徐々に整えていきたいです。

来年はメンバー数100名を目指し、コミュニティがさらに活性化するように仕組みを整えていきます。
まだ至らない点も多くありますが、これからも「[自由研究室 AIRS-Lab](https://www.airs-lab.jp/)」をぜひよろしくお願いいたします。
Rails 7.0で"DEPRECATION WARNING: image/jpg is not a valid content type"のようなエラーが出た場合

## 発生した問題
Rails 7.0にバージョンアップしてテストを実行したら以下のようなエラーメッセージが出ました。

```
DEPRECATION WARNING: image/jpg is not a valid content type, it should not be used when creating a blob, and support for it will be removed in Rails 7.1. If you want to keep supporting this content type past Rails 7.1, add it to `config.active_storage.variable_content_types`. Dismiss this warning by setting `config.active_storage.silence_invalid_content_types_warning = true`. (called from public_send at /Users/jnito/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/factory_bot-6.2.0/lib/factory_bot/attribute_assigner.rb:16)
```

## 原因

FactoryBotのコードで書いたContent typeが不正でした（`'image/jpg'`）。

```ruby 
FactoryBot.define do
  factory :note do
    message { "My important note." }
    association :project
    user { project.owner }

    trait :with_attachment do
      attachment { Rack::Test::UploadedFile.new("#{Rails.root}/spec/files/attachment.jpg", 'image/jpg') }
    end
  end
end
```

## 修正方法

Content typeを修正したら直りました（`'image/jpeg'`）。


```diff_ruby
 FactoryBot.define do
   factory :note do
     message { "My important note." }
     association :project
     user { project.owner }
 
     trait :with_attachment do
-      attachment { Rack::Test::UploadedFile.new("#{Rails.root}/spec/files/attachment.jpg", 'image/jpg') }
+      attachment { Rack::Test::UploadedFile.new("#{Rails.root}/spec/files/attachment.jpg", 'image/jpeg') }
     end
   end
 end
```

NOTE: English version is also available:

https://gist.github.com/JunichiIto/9b736949da79c416e3fadd56c5211946
[Xcode/iOS] 実機ビルドでエラーになる unable to build chain to self-signed root for signer "..."

 エミュレータではビルドできるけど、実機ビルドしたらエラーになった場合は、証明書を疑いましょう。

今回はエラーログに

```
unable to build chain to self-signed root for signer "..."
```

![Screen_Shot_2021-12-29_at_12_50_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/c9d7ae93-002a-1412-6219-3ab1875fcd3a.png)

というのを見つけたので、Keychain Accessを開いてみると、 `certificate is not trusted` というのを発見。
いつのタイミングでこうなっていたかは不明。

![Screen_Shot_2021-12-29_at_12_51_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/e934b079-19dc-ab1b-aa95-4eece1e24bc4.png)

Xcodeの `Manage Certificates...` を開いても `Untitled`になっていて、なんか怪しい。

![Screen_Shot_2021-12-29_at_12_52_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/48b0526e-a1fa-f469-1481-20f7a9848069.png)

Apple Developerのサイトから該当証明書を削除します。

![Screen_Shot_2021-12-29_at_12_51_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/c5c3a02f-a702-46df-fa70-d93689ba5861.png)

![Screen_Shot_2021-12-29_at_12_51_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/ae97cb4d-5de9-90b5-9219-b408ddbd0f6d.png)

Keychain Accessに戻って、該当証明書を削除します。すると自動的に新しい証明書が作成されました。（前からこうだったけ？）

![Screen_Shot_2021-12-29_at_12_53_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/f2e2b1ce-ccb0-d1c5-2001-e35480f16b3d.png)

ということで、Xcodeからも証明書が新しくなったことが確認でき、無事実機ビルドが通りました。

![Screen_Shot_2021-12-29_at_12_54_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92539/af7641cf-fb1e-b856-ea3e-da27cd0b572a.png)
Rails7のlink_toでmethod: :deleteする

Rails7で

```erb
<%= link_to t("sign_out"), sign_out_path, method: :delete %>
```
しようとしたら動きませんでした。

代わりに

```erb
<%= link_to t("sign_out"), sign_out_path, data: { turbo_method: :delete } %>
```

を使えば良いようです。

**※コントローラーのレスポンスに`status: :see_other`をセットしないと悲惨なことになるようです。**

詳しくは以下の記事にあります。

https://qiita.com/jnchito/items/5c41a7031404c313da1f#destroy%E3%81%AE%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%AB-status-see_other-%E3%82%92%E4%BB%98%E3%81%91%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B
PowerShellのプロンプトの視認性を向上させる


## やりたいこと
PowerShellのデフォルトのプロンプトは、カレントフォルダのパスが長くなると視認性が著しく低下するため、下記のように変更する。

- コマンド行を2行に分割する（1行目にカレントフォルダを表示、2行目をコマンド行にする）
- コマンドの実行後に改行を挟む

### デフォルトのプロンプト
```
PS C:\Users\*****> "hoge"
hoge
PS C:\Users\*****> "fuga"
fuga
PS C:\Users\*****>
```

### 変更後のプロンプト
```
PS C:\Users\*****
> "hoge"
hoge

PS C:\Users\*****
> "fuga"
fuga

PS C:\Users\*****
>
```

## プロンプトをカスタマイズする
prompt関数を上書きすることでプロンプトの表示をカスタマイズできる。

### prompt関数を確認する
関数の情報は`Get-Item`コマンドレットで取得でき、
`Definition`プロパティで関数の内容を確認できる。

```
> (Get-Item function:prompt).Definition

"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";
# .Link
# https://go.microsoft.com/fwlink/?LinkID=225750
# .ExternalHelp System.Management.Automation.dll-help.xml
```

### プロファイルを編集する
プロファイルに同名の関数を定義することで、デフォルトの関数を上書きすることができる。
プロファイルのパスは`$profile`で確認できる。

```
> $profile
C:\Users\*****\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
```

```powershell:Microsoft.PowerShell_profile.ps1
function prompt { "`r`nPS " + $(Get-Location) + "`r`n> " }
```

### プロファイルを適用する
PowerShellを再起動するとプロファイルが適用される。

### prompt関数が上書きされていることを確認
```
> (Get-Item function:prompt).Definition
 "`r`nPS $(Get-Location)`r`n> "
```

## 参考
- [about_Prompts](https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_prompts?view=powershell-7.2)
AndroidTVに任意の通知(Notifications)を表示する

# 背景
TVで録画番組を再生していると緊急地震速報を受け取れないのが気になっていた。
（我が家の緊急地震速報受信システムについては別途記載）
その前段として、TVに任意のメッセージを表示させる方法を知りたかった。
調べたものの、Androidスマホの通知をAndroidTVに表示させるAppは存在するものの、任意のメッセージを表示させるAppは存在しなかった。
AndroidTV自体にもそのようなAPIは存在しなかった。

# 必要なもの
* Android TV ( Sony Bravia X8000Hを利用）
* Notifications for Android TV（Android TVに通知を表示させるApp）
* 任意のHTTPリクエストを発行できる端末

# 準備
* 手持ちのAndroid端末にNotifications for Android TV をインストール
* TVにNotifications for Android TVをインストール

# 調査
まずはAndroid端末でからプッシュされた通知がAndroidTVで表示されることを確認しました。
次にAndroid端末でpcapを取得し、どのような通信をすることでNotificationを表示させているのかを確認。

Notifications for Android TV をインストールすることで、AndroidTVはポート7676でHTTPサーバを立ち上げることが判明。
HTTPリクエスト内のPOSTパラメータに表示文字のサイズ、位置、メッセージ等を含めることで任意のNotificationを表示させることが可能だった。

# サンプルリクエスト
| パラメータ名 | パラメータ値 |
|:-:|:-:|
| type | 0 |
| title | 表示させたいタイトル |
| msg | 表示させたいメッセージ |
| duration | 表示させたい時間(s) |
| fontsize | フォントサイズ：3 |
| position | 表示位置：4 |
| width | 横幅：4 |
| bkgcolor | 背景色：#F44336<br> （任意の色が設定可能なわけではない）|
| transparency | ？：1 |
| offset | 位置？：0 |
| offsety | 位置？：0 |
| app | ？：Notifications |
| force | ？：true |
| file1 | アイコンの画像ファイル：pngでOK |

```
#Sample.py
import requests

# Parameters
files = {
    'type': (None, '0'),
    'title': (None, 'TITLE'),
    'msg': (None, 'MESSAGE'),
    'duration': (None, '1'),
    'fontsize': (None, '3'),
    'position': (None, '4'),
    'width': (None, '4'),
    'bkgcolor': (None, '#F44336'),
    'transparency': (None, '1'),
    'offset': (None, '0'),
    'offsety': (None, '0'),
    'app': (None, 'Notifications'),
    'force': (None, 'true'),
    'file1': ('icon.png', '1',  'application/octet-stream'),
 }
response = requests.post('http://***.***.***.***:7676/', files=files,timeout=3.5)
```

# 結果
ちゃんと表示された。（キャプチャは別途貼る）

# その他
緊急地震速報は (1) SinalNowX -> (2) SynSNE -> (3) Zabbix -> (4) Pythonスクリプト -> (5) AndroidTV and (6) NW型Patlite で表示＆音声案内をしています。
今回記載したのは(4)～(5)へのつなぎの箇所でした。
【Javascript】remove()で要素を削除する

#はじめに
割り勘額を計算してくれる簡易Webアプリを作成中に学習したことを書き留めておく。
当方、初学者のため記事の内容に間違いや改善点などございましたら、ぜひコメントでご指摘ください。

#要件
「削除」ボタンをクリックしたとき、一人分のフォームが削除される機能を作りたい。(フォームの数は、1行以上8行以下)
「追加」ボタンでのフォームの追加方法に関しては、「[templateタグを使ってフォームを複製]」をご覧ください。
[templateタグを使ってフォームを複製]:https://qiita.com/cookiesand1023/items/d7e25d51e3a9143879f6[https://qiita.com/cookiesand1023/items/d7e25d51e3a9143879f6]


![スクリーンショット (15).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388451/9d2e880e-7f38-d243-2fac-eda25d7ef9a4.png)
　　　　　　　　　　　　　　　　⇩
![スクリーンショット (16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388451/3bb93a48-c73f-5506-4447-af3cd88596ab.png)

##フォームのHTML
フォームから値を受け取って計算をする予定なので、inputタグのname属性にインデント番号を付与している。
フォームを複製、削除する場合は、n行目のフォームのインデント番号がnになるようにする。

```HTML:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="addForm.js"></script>
    <script type="text/javascript" src="deleteForm.js"></script>
</head>
<body>
    <div class="input-form" id="input-form">
        <!--テンプレート化-->
        <template id="form-template">
            <div class="member" id="member">
        <!--入力した値を計算したいのでname属性にインデント番号を付与-->
                <input type="text" size="20" name="" placeholder="名前">
                <input type="text" size="3" name="" placeholder="年齢">
                <label>
                    <input type="radio" name="sex" value="男性" id="male">男性
                </label>
                <label>
                    <input type="radio" name="sex" value="女性" id="female">女性
                </label>
            </div>
        </template>
    </div>
    <!--「追加」ボタンをクリックしたらJavascriptファイル内の関数addForm()を実行する-->
    <div class="bt_addForm">
        <input type="button" value="追加" onclick="addForm()">
    </div>
    <!--「削除」ボタンをクリックしたらJavascriptファイル内の関数deleteForm()を実行する-->
    <div class="bt_deleteForm">
        <input type="button" value="削除" onclick="deleteForm()">
    </div>    
</body>
</html>
```

#remove()を使用して、フォームを削除する

##remove()とは
JavaScript で HTML 要素を削除するメソッド。
使用方法としては、HTMLから要素を取得しremove()メソッドで削除する。
削除する要素が子要素をもっていた場合、子要素ごとすべて削除される。
(子要素だけを削除したい場合は、removeChild()メソッドを使用する。)
※IEではremove()メソッドは使用できない。

```Javascript:使用例
const element = document.getElementById('aaa'); 
element.remove();
```



##実装
```Javascript:deleteForm.js
function deleteForm() {
    //フォームの数を取得
    const form_length = document.querySelectorAll("div.member").length;

    //フォームが1個なら処理終了
    if (form_length === 1) {
        return;
    
    } else {
        //div#input-form内の一番下の要素を取得
        const delete_form = document.getElementById("input-form").lastElementChild;
        
        //要素を削除
        delete_form.remove();

    }
}

```


#まとめ
3行目の「フォームの数」を取得する部分だが、div#input-formの子要素の数を取得する方法を試したが、実際のフォームの行数+1の数が取得された。どうやらtemplateタグが子要素としてカウントされているみたい。なのでdiv#memberをquerySelectorAllですべて取得し、その個数を割り出した。

また、削除する要素は、単純にdiv#input-formの子要素div#memberの内一番最後にあるものを指定した。
pyenv+ansibleでModuleNotFoundError: No module named 'ansible'にはまりました

## サマリ

* 背景
  * ansibleでローカル開発環境をセットアップしていた。
  * pyenvをansible使ってインストールした。
* 課題
  * pyenvでpythonをglobalで使うpythonをインストールしてからansibleを実行すると、ModuleNotFoundError: No module named 'ansible'とでるようになった。
  * Errorとなるためansibleが使えない状況になった。
* やったこと
  * ~~対処としてansibleは絶対パスで実行するようにした`/usr/bin/ansible`~~
    * 2022-04-19 修正。嘘書いていました。ごめんなさい。`pyenv global system`などansibleをインストールしているpythonに切り替えないとダメです。
  * 他にやり方を思いつかなかったため、案募集中。

## 実施環境

* Windows 11 バージョン 21H2(OSビルド22000.376)
* Ubuntu 20.04LTS on wsl
* python 3.8.10
  * ※pyenvインストールしてglobal設定していたpythonは3.10.1
* ansible 2.9.6

## なぜエラーがでるようになったか調べる

以下のようにglobalで使うpythonを設定して、ansibleを実行するとエラーが発生を再確認。

```bash
$ pyenv global 3.10.1
$ ansible
Traceback (most recent call last):
  File "/usr/bin/ansible", line 34, in <module>
    from ansible import context
ModuleNotFoundError: No module named 'ansible'
$
```

ansibleはpipでインストールされている。

```bash
$ pip freeze | grep ansible
ansible==2.9.6
```

今この環境にはpyenvで複数のpythonがあるため、ansibleはどのpythonのライブラリとして入っているか調べた。

```bash
$ ls -l /usr/bin/ansible
lrwxrwxrwx 1 root root 68 Mar 17  2020 /usr/bin/ansible -> ../lib/python3/dist-packages/ansible/cli/scripts/ansible_cli_stub.py
$ ls -l /usr/bin/ansible
lrwxrwxrwx 1 root root 68 Mar 17  2020 /usr/bin/ansible -> ../lib/python3/dist-packages/ansible/cli/scripts/ansible_cli_stub.py
$ head -n1 /usr/lib/python3/dist-packages/ansible/cli/scripts/ansible_cli_stub.py
#!/usr/bin/env python3
$
```

## わかったこと

ansibleは`/usr/bin/ansible`からシンボリックリンクをはられていて、
実態は`/usr/lib/python3/dist-packages/ansible/cli/scripts/ansible_cli_stub.py`だとわかった。
そして、このpythonファイルはシバンが`#!/usr/bin/env python3`となっている。

pyenvは
[githubリポジトリのREADME](https://github.com/pyenv/pyenv/blob/master/README.md#understanding-shims)にかかれているとおりPATHを上書きすることで動く。

> pyenv works by inserting a directory of shims at the front of your PATH

というわけで、ansibleを実行するとシバンが参照されて必ずpyenvでインストールされたpythonのディレクトリが参照される。

## 対処

ansibleを実行できるようにするには、

* pyenvでインストールしたpythonでもansibleをpipインストール
* pyenvでglobal設定を一時的にsystemとする（ansibleをインストールしているpythonを使うようにする）

のどちらかだと考えた。

前者だとpyenvでインストールしたpythonでは常にansibleを入れるようにしないと
エラーが再発する可能性はある。しかも、不要であってもansibleを入れることになる。

後者だとansibleのplaybookを実行するときは都度`pyenv global system`と実行しないといけない。

~~悩んだがよく考えれば`/usr/bin/ansible`で実行すれば、今pyenvでどう設定しているか気にしなくてよいなと思ったため、
今後は`/usr/bin/ansible`で実行することにした。~~

2022-04-19追記
シバンが`#!/usr/bin/env python3`となっている限りpyenvで設定しているpythonのインタプリタが実行されるので、絶対パスで参照しようとダメですね。
同じことでハマって、以前解消したはずでは？と思って見直したら間違ったことを書いていることに気づきました。

## まとめ

* pyenvでpythonをglobalで使うpythonをインストールしてからansibleを実行すると、ModuleNotFoundError: No module named 'ansible'とでるようになった。
* できればplaybookでいい感じにしてコマンド実行方法は変えたくなかったが、
いい案が思いつかなかったので、~~絶対パスでansibleを実行することに。~~ `pyenv global system`を実行してからansibleを実行することに。

どなたかいい案あれば教えていただければ幸いです。
Stein使い方メモ

##はじめに
GoogleSpreadSheetをデータベースとして使用できるStein。

めちゃめちゃ便利なのですが
個人的に、使い方をよく忘れるのでここに残しておきます。

##使い方

https://qiita.com/masuraoProg/items/efaa6397d2d5409c968b

上記ののQiita記事を主に参考にしました。
まずはGoogle　SpreadSheetの準備が必要です。
その後Steinのサイトへ飛ぶのですが、Google検索しても以外と出てこないため下に残しておきます。

https://steinhq.com/

今回はNode.jsに実装したいため、ローカル環境設定を多少行います。

steinを使用したいフォルダ以上の階層で`npm i stein-js-client`を実行（親フォルダで実行してもいけました）。
＊**ここの記載をしているQiita記事が少なかった印象です**
（npmは[ここから](https://www.npmjs.com/package/stein-js-client)参照しました。）


あとはコード内に下記のようなコードを記載して使用します。
これは[公式ドキュメント](https://docs.steinhq.com/add-rows)の`Add rows to sheet`を参考にしてます。

```javascript

const SteinStore = require("stein-js-client");
const store = new SteinStore(
  "ここにSteinのAPIを記載"
);

store
  .append("Sheet1", [ //GoogleSpreadSheetのシート名と統一させる。日本語不可
    {
      title: "Awesome article",
      author: "Me!",
      content: "A brief summary",
      link: "blog.me.com/awesome-article"
    }
  ])
  .then(res => {
    console.log(res);
  });

```

##おわりに
公式ドキュメントは英語ですが
比較的易しい単語のためちょっと凝らして読めばなんとなく使いこなせるはずです。

##Tips
・Node.jsをインストールすると`npm`も使えるようになるみたいです（知らなかったあ）。

https://www.sejuku.net/blog/75691
Process 'Gradle worker Daemon 1' finished with non-zero exit value 1が出た

# 概要
Process 'Gradle worker Daemon 1' finished with non-zero exit value 1が出た場合の対処法

### 実行コマンド
```
$ ./gradlew --stop
```

### 原因
Gradleデーモンを複数起動していたことが原因
Kaggle APIでデータセットのダウンロードが403エラーになる時の解決法

`kaggle competitions download`コマンドでデータセットをダウンロードするには、そのコンペティションのルールに同意している必要があります。

```bash
# エラー
kaggle competitions download -c feedback-prize-2021
403 - Forbidden
```

コンペティションのデータセットのページにある「I understand and agree」をクリックするとダウンロードできるようになります。
![kaggle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10947/3c37360a-1c8c-4082-8617-24a60449d9fd.png)
seleniumを使用しているpythonファイルを実行ファイル化する

タイトルの通りで詰まったのでメモがわりに投稿します。

# 環境
Mac OS

## python環境
anacondaで構築
python3.10

# 詰まったこと
seleniumとchromedriverを使用していたので、chromedriverをどうするかと散々悩みました。
実行ファイル化したdistの中に含める、パスを通す…
配布予定なのでdistごとなのもなと思いました。

また、chromeのバージョンも変わっていくのでどうするかと…

# 解決策
このパッケージを見つけました。
[Github](https://github.com/SergeyPirogov/webdriver_manager/blob/master/README.md)

少し前の記事ですが使用方法は[Qiita](https://qiita.com/YoshikiIto/items/000f241f6d917178981c)に載っています。
**注意**
記事内でのpip install後の指定方法は下記にしてください

```　terminal
pip install webdriver-manager
```

使用方法も一応載せておきます。

```　python
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())
```

これでpyinstallerを使って実行ファイル化するとできました！

```
pyinstaller ファイル.py
```

##### これは自分用に

仮想環境で作成した時、インストールしているpythonを読み込んでいるところがあっているか確認すること
[テラテイル](https://teratail.com/questions/375961#reply-508267)で聞いちゃいました笑

以上！
python初心者ですので、おすすめの方法とかあれば教えてください！

[Twitter](https://twitter.com/pien_p_)も良ければ！
Firestoreでサブコレクション・サブドキュメントを削除したい

# どんな人向けか
Firestoreでデータベースを管理している場合に、サブコレクション・サブドキュメントも一緒に削除したい人

## 概要
公式にあるようにFirestoreでは親ドキュメントを削除しても子コレクション・子ドキュメントは削除されない
https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja

### だめな例
```dart
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;

static deleteAccount() async {
  await firebaseFirestore.collection('users').doc('mail').delete();
}
```

### いい例
```dart
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;

static deleteAccount() async {
  await firebaseFirestore
      .collection('users')
      .doc('mail')
      .collection('name')
      .get()
      .asStream()
      .forEach((element) {
    for (var element in element.docs) {
      element.reference.delete();
    }
  });
}
```

上記のように再帰的に削除しなければならない。
BPMに合わせて光るライト

任意のBPMに合わせてLightを発光させるスクリプトです。
光らせたいLightオブジェクトに直接アタッチして使ってください。

「Decay」は光の減衰スピードです。
1より大きい値にすれば徐々に強くなる光にできます。

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BPMLight : MonoBehaviour
{
    private Light light;

    private float currentTime;
    private float span;

    public int bpm = 120; //任意のBPM

    public float maxIntensity; //発光時の光の強さ
    public float minIntensity; //どこまで光が弱くなるか
    public float decay = 0.9f; //減衰率

    void Start()
    {
        span = 60.0f / bpm;

        light = GetComponent<Light>();
        light.intensity = maxIntensity;
    }

    void Update()
    {
        currentTime += Time.deltaTime;

        if(currentTime>span)
        {
            light.intensity = maxIntensity;
            currentTime = 0f;
        }

        light.intensity *= decay;
    }
}
WSL2のUbuntuでMySQLサーバーが起動しない

#症状
`sudo service mysql start`すると`[fail]`の文字が。何やと思って`/var/log/mysql/error.log`を見てみると

```
[ERROR] Could not create unix socket lock file /var/run/mysqld/mysqld.sock.lock.
[ERROR] Unable to setup unix socket lock file.
[ERROR] Aborting
```

調べてると、権限がないから`sock.lock`ファイルが作れないとのこと。
#解決法
以下のリンクと同じようにchownコマンドで解決。chownとか初めて使ったわ・・・

https://stackoverflow.com/questions/34954455/mysql-daemon-lock-issue
clocでgithub organizationの全てのリポジトリコード行をカウントする

**前準備**
- [cloc](https://github.com/AlDanial/cloc) をインストール
- read repositoryの権限を持ったaccess tokenを環境変数`GITHUB_TOKEN`に設定

以下のスクリプトの3行目の`''`にorganization idを追記して実行

```bash:count.sh
#!/bin/bash

organization=''

repositories=''
cursor='null'
has_next_page='true'
while [ $has_next_page = 'true' ]
do
  response=$(curl -H "Authorization: bearer $GITHUB_TOKEN" -X POST \
    -d '{ "query": "query { organization(login: \"'${organization}'\"){ repositories(first: 100, after: '${cursor}'){ nodes { name } pageInfo { hasNextPage endCursor }}}}"}' \
    https://api.github.com/graphql)
  echo $response
  repositories=$repositories' '$(echo $response | jq -r '.data.organization.repositories.nodes[].name')
  has_next_page=$(echo $response | jq '.data.organization.repositories.pageInfo.hasNextPage')
  cursor='\"'$(echo $response | jq -r '.data.organization.repositories.pageInfo.endCursor')'\"'
  echo $cursor
done

dir=$(mktemp -d)
echo $dir
for repository in $repositories
do
  git clone --depth 1 "https://github.com/acall-inc/${repository}.git" "${dir}/${repository}"
done
cloc --timeout 0 $dir
rm -rf $dir
```

```bash
bash count.sh
```
汎用JPドメインを更新したはずなのに whois の有効期限が更新されない

# 問題

掲題通り、所有している汎用JPドメイン (例: example.jp など)　の更新を行ったのだが、whois で見ると期限が更新されておらず、監視アラートに引っ掛かった。
この理由が知りたかったので調査した。

なお、今回は お名前.com で取得・更新を行ったものだが、それ以外で取得・更新した場合も同様の現象が発生する。

# 原因

**有効期限の延長は JP ドメインの管理元である JPRS が更新期限の翌日に行うという運用仕様** であるため。 つまり whois は汎用JPドメインの有効期限切れの監視に適さない (リマインダーとしては機能してくれるが...)。

これは汎用JPドメインの運用仕様として「期間満了がくるまで更新を行わない」という仕様によるものと考えられる。 この仕様は以下に引用する規則から読み取れる。

> 第11条（登録期間および登録期間更新）
  汎用JPドメイン名の登録期間は、第19条による汎用JPドメイン名登録原簿
（以下「登録原簿」という）の記載が完了した日の属する月の翌年対応月末日
までとする。
２ 当社は、**前項の登録期間満了の翌日に** 登録が継続している汎用JPドメイン
名の管理指定事業者に対して、当社所定の時期および方法により **登録期間更新
通知および登録更新料の請求書を送付する。**
３ 前項の規定にかかわらず、当社が登録更新を不相当と判断した場合には、
登録期間満了の30日前までにその汎用JPドメイン名の管理指定事業者に対して
登録終了通知を行い、登録期間満了日に登録は終了する。
４ 第２項に定める汎用JPドメイン名は、登録期間満了の日の翌日からさらに
汎用JPドメイン名の登録を１年間継続することができ、以後も同様とする。
５ 管理指定事業者は、登録者からの汎用JPドメイン名の登録更新方法および
登録更新料の支払い方法等を、取次規則に基づいて定める。
>
> 引用 - https://jprs.jp/doc/rule/rule-wideusejp.html (一部強調)

なお JP汎用ドメインのライフサイクルは以下のようになっている (JPRSウェブサイトから引用)。

![img1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502582/e58df9d0-94a6-9061-c936-87576a792634.gif)

https://jprs.jp/about/dom-rule/lifecycle/


ちなみに、この仕様に基づき、お名前.com などで複数年更新しても JPRS では1年分しか更新が反映されない。 複数年更新分のお金を先に預けている、という状態になる。


# 参考

https://faq.interlink.or.jp/faq2/View/wcDisplayContent.aspx?id=980

https://help.sakura.ad.jp/206057382/

https://help.onamae.com/answer/8453
STM32L010でソフトウェアシリアル1000bps(STM32L010F4P6)(USART)



目的
シリアルのテスト


![o_con180.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/93527faf-ba9d-adac-47c0-cee714dc4892.jpeg)



```c++


//S_SER_1000_010_1

#include "mbed.h"

DigitalOut TX(PA_2);

//仮想シリアルへの一文字出力 1000bps
int pc_putc(char ch)
{

    TX=1;
    TX=0;//Start
    wait_ms(1);

    for(int ii=0; ii<8; ii++) { //Data x 8
        TX=(ch>>ii)&1;
        wait_ms(1);
    }; //for

    TX=1;//Stop
    wait_ms(1);

    return(0);

} //pc_putc


//メインルーチン
int main()
{

    TX=1; //ポートの初期化

    //無限ループ
    while(1) {

        //一文字出力
        pc_putc('A');

        //1秒の待ち
        wait_ms(1000);

    }//while

}//main

//容量削減
void error(const char* format, ...) {}




```
ポートフォリオ作成のためにER図を書いてみた【Draw.io】

普段VSCodeをコーディングしているので、ER図作成のために`Draw.io`を利用してみました。

#まずはインストール！
![スクリーンショット 2021-12-29 14.54.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832042/cac16b42-290c-e849-e3c0-894a5457e7b0.png)

#次にファイル作成
拡張子を`.drawio`もしくは.`dio`にして作成してください。今回僕はポートフォリオとして作成しているので、画像ファイルとして送付も行ないたいと考えているため、`.drawio.png`として作成しました。

![スクリーンショット 2021-12-29 15.07.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832042/da0ad590-5862-5a57-c12e-6e4071603ee0.png)

#参考にさせて頂いた記事
[VSCodeでDraw.ioが使えるようになったらしい！](https://qiita.com/riku-shiru/items/5ab7c5aecdfea323ec4e)
[VSCode Draw.io Integrationがさらに便利になってた](https://tech.fusic.co.jp/posts/2021-06-15-vscode-draw-io-integration/)
モバイルサイトのデザイン・動きをお手軽に実機とかで確認したーい

##はじめに
モバイルサイトを作っててお手軽に動作確認するには、chromeとかsafariとかの開発機能を使いますよね。
でもアプリのwebViewでの表示をちゃんと確認したい。ならブラウザだけでは足りないよね。実機でちゃんとなるかは不明だし。

##こうする
#####iOSシミュレータで
自社アプリならソースがあるだろうから、iOSシミュレータ向けにビルドして、localhostでサイトを動かして、確認しよう。iOSシミュレータのアプリから、localhost指定でアクセスできるよ。
webサーバーはご自由に。MANPとか色々あるよ。
#####androidエミュレータで
androidエミュレータからはlocalhost指定ではアクセスできないようで、パソコンのIPアドレスを指定すればアクセスできるよ。
#####iOS/Android実機で
IPアドレスを指定すればiOS/androidの実機からでもアクセスできるよ。これで完璧だね。ポートを開けるのを忘れずに。
##最後に
iOSシミュレータでlocalhost指定以外は、まあ常識なんだけど、なかなか気づかないので、記事にしてみた。
もちろんアプリじゃなくてもブラウザを使ってアクセスできるよ。

でもDartでwebアプリを開発してるときは実機からはアクセスできなかった。なんか開発用の内蔵webサーバーの仕様らしかった。めんどくさかった:joy:
Ubuntu上のEmacsにrbenvを認識させる設定

情報が古かったり断片的だったりするので、簡易的にまとめる。

#前提
環境
Ubuntu 20.04.3 LTS
rbenv 1.1.1
ruby 3.0.0

rbenvとrubyのインストールについては省略

#PATHを通す
まず、PATHを通す。

~/.bash_profileに

```
export PATH="~/.rbenv/shims:/usr/bin:$PATH"
eval "$(rbenv init -)"
```

そして再起動か、即時反映させる場合

```
$ source ~/.bash_profile
```

#Emacsの設定
次にEmacsの設定ファイルである
~/init.elに

```init.el
(setenv "PATH" (concat (getenv "HOME") "/.rbenv/shims:"
                       (getenv "HOME") "/.rbenv/bin:" (getenv "PATH")))
(setq exec-path (cons (concat (getenv "HOME") "/.rbenv/shims")
                      (cons (concat (getenv "HOME") "/.rbenv/bin") exec-path)))
```

以上でEmacsにrbenvが認識されると思う。
apache2.4、ELB下でのアクセス元IPの処理

サイト中のあるエリアには、特定IP(例 000.000.000.000)からだけのアクセスを許可する場合、

# apache設定

```your-site.conf
<Directory "/var/www/secret">
    Require all denied
    Require ip 000.000.000.000
</Directory>
```

と書けばOKだけど、ELB(ElasticLoadBalancing)下では、アクセス元がELBのローカルIPになるため、上記設定では制限が正しく動作しない。


```
RemoteIPHeader X-Forwarded-For
```

を、記述することで、apache側が識別するIPが、本来のIPとなり、希望通りのアクセス制限が可能となる。

```your-site.conf
RemoteIPHeader X-Forwarded-For
<Directory "/var/www/secret">
    Require all denied
    Require ip 000.000.000.000
</Directory>
```
【参考】https://dev.classmethod.jp/articles/access-limit-behind-elb/

> RemoteIPHeaderは、LocationやDirectory等のディレクティブの中ではなく、グローバルコンテキストかVirtualHostの中に書く必要があります。送信元IPアドレスを自然に扱えるようになっているので、Apache2.4で送信元IPアドレスに対するアクセス制限を利用したい場合はこの書き方をするのが良さそうです。

## PHP側の処理

おなじく、PHP側で、アクセス元のIPアドレスを知りたい場合

```php:php
$_SERVER["REMOTE_ADDR"]
```

を用いるが、ELB化では、同じくELBのローカルIPになる。その場合、

```php:php
$_SERVER["HTTP_X_FORWARDED_FOR"]
```

を用いることで、元のIPを取得できるが、上記の"RemoteIPHeader X-Forwarded-For"を記述することで、従来の記述($_SERVER["REMOE_ADDR"])にて、アクセス元IPを取得することが可能。
【必見】django_restframworkでリレーションモデルをJSON形式で展開する方法

# 目的
DjangoRestframeworkでAPIを作成していて、

```
{
        "id": "9510f7c1-a364-4e44-96ae-2fdd7fbc957d",
        "gender": "M",
        "username": "Shun",
        "age": 25,
        "introduction": "よろしく",
        "job":1
}
```
このようなJSONをResponseとして返していたが、
このコードでは```job: 1```となっていてかなり扱いづらいJSONとなっているためなんとかしなければならないと思った。

# 解決方法
親モデルの利用するシリアライザの中に

```
外部キー名 = 外部キーのテーブルのシリアライザ名()
```
と記述するだけで外部キーのテーブルを展開できた。

# 具体例
django_restframeworkでModelViewSetを利用している。
Membersモデルの中にjobの外部キーがあり、Jobsモデルを参照している状態だ。
これに```外部キー名 = 外部キーのテーブルのシリアライザ名()```を記述して扱いやすいJSONとする。

```serializer.py
class JobSerializer(serializers.ModelSerializer):
    class Meta:
        # 対象のモデルを指定
        model = Jobs
        # 対象のフィールドを指定
        # created_atは対象外
        fields = ('id', 'average_salary', 'job_name','is_holiday_on_weekend','paid_holiday_count')


class MemberSerializer(serializers.ModelSerializer):
    # jobフィールドにjobのモデルを展開する
    job = JobSerializer()

    class Meta:
        # 対象のモデルを指定
        model = Members
        # 対象のフィールドを指定
        # created_atは対象外
        fields = ('id', 'gender', 'username','age','introduction', 'job')
```

### 注意!!!!
class Metaの下にmodelやfieldsは記述するが、この時のjobフィールドを記述するのはclass Metaの下ではない。
ここでかなり時間を費やしたバカがいるため気をつけること。

Postmanを使ってgetメソッドでAPIを叩いてみる。

```json
{
        "id": "f2e603b7-ae21-42c7-bada-a9eb93ad8a7a",
        "gender": "M",
        "username": "Yuto",
        "age": 24,
        "introduction": "Sup. I'm Yuto. All I can do for u is make you laugh and happy 24/7. It's fair enough, isn't it??",
        "job": {
            "id": 1,
            "average_salary": 1000000,
            "job_name": "marketing",
            "is_holiday_on_weekend": true,
            "paid_holiday_count": 100
        }
    }
```
最初のjsonとは違ってjobのモデルもしっかり表示することができている。

# 参考文献
[Django REST Frameworkを使って爆速でAPIを実装する](https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8)
[[DRF]結合テーブルの取得【N+1問題】](https://qiita.com/aja_min/items/9d6d6cf2ac9495836f5f)
[Swift]シミュレータ機のUserDefaultsをリセットしたい時

#概要
iPhone実機環境のUserDefaultsをコードからリセットする方法はググれば先人の方々の記事が見つかると思います。
ここではシミュレータ機でテストしている時にUserDefaultsをリセットしたい時の方法の一つを共有します。
#本文
シミュレータ機を選択（アクティブに）した状態で上のメニューから「Device」→「Erase All Content and Settings」を選びます。

![スクリーンショット 2021-12-29 6.58.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/27c8173a-caa1-60b2-eed8-c1c3f499d47d.png)

#補足
シミュレータ機の情報が初期化されます。消したくない情報まで消してしまわないか確認した上で行ってください。
また、シミュレータ機の再起動に少し時間がかかると思います。