OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者向け】リアルタイム通信を実現するための手段をまとめる

## はじめに
フロントエンドとバックエンドでリアルタイム通信をする必要があったので、どんな選択肢があるのか調べてみました

この記事を読めばリアルタイム通信を実現するWebの技術にどのような種類があるのか、そしてそれらがどういったものなのかをイメージできるようになるかと思います

**注意事項：**
こちらの記事はあくまでHTTP/HTTPS上のプッシュ技術ということで、MQTTやWebRTCについては言及しないこととします

## リアルタイム通信を実現するための手段

### Polling
Polling　（ポーリング）とはクライアンド側からサーバー側に対して、一定間隔でHTTPリクエストを行う方式のことです。

この方式はデータが更新されているかどうかは関係ありません。シンプルにデータが更新されていれば、更新されている旨のレスポンスを返し、更新されていない場合は更新されていない旨を返します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270253/b96c75b7-7b4c-7e9d-4e74-67e119c4eb77.png)
Polingのメリットとデメリットは以下の通りです
#### デメリット
- 最大でポーリング間隔分だけ遅延する（リアルタイム性が低くなる）
- データの更新が全くない場合でも一定間隔でリクエストを投げるので、サーバーに負荷がかかる



### Long polling（Comet）
Pollingの遅延を解決するために考え出された方式です。また、Long polling（ロングポーリング）はComet（コメット）とも呼ばれ、Pollingを応用したものです。こちらも同様にHTTP通信でやり取りを行います

下記の画像からも分かるように、クライアントからサーバーに対してHTTPリクエストを投げるところはPollingと同じですが、Long Pollingはサーバー側でデータの更新が行われるまでHTTPレスポンスを保留します。データの更新が行われてから初めてHTTPレスポンスを返すのです

また、もしもネットワークエラーなどで接続が失われた場合は、ブラウザはすぐに新しいリクエストを送信します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270253/8cd711d8-fa28-db11-63e4-1502a3b94e93.png)
Long Pollingのデメリットは以下の通りです
- 長時間接続を維持するため、サーバーのリソースを大量に使用する
    - 特に大量のクライアントから頻繁にリクエストを受け付けるようなアプリケーションの場合は、このデメリットが顕著に出る
- それぞれが個別のリクエスト・レスポンスであるため、オーバーヘッドが大きくなる

### Server-Sent Events（SSE）
SSEはレスポンスをデータの更新があるまで保留にするところはLong Pollingと同じですが、データの更新が起こる度にレスポンスを完結させるのではなく、HTTPのチャンク転送エンコーディングという技術を使って、レスポンスの本文データを、複数のチャンクに分割し、データの更新が行われる度に、クライアントに対してイベントを返します

また、チャンク転送エンコーディングを用いているためSSEは、サーバーからのデータのみを受け取り、クライアントからデータを送信しません。これにより、Long Pllingで問題となっていたサーバーのリソース使用量を減らすことが可能になります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270253/dc1fea37-3b4f-3524-ecfd-8f324d7f5a9f.png)
SSEのデメリットは以下の通りです
- サーバーからのイベント通知のみサポートしているため、クライアントからサーバーにリクエストを送信できない
- クライアント側は待機状態になるため、新たなHTTP Requestを投げるには別のコネクションが必要になる（ブラウザが同一ドメインに対して同時に保持できるコネクション数は数個しかない）

### Websocket
これまでに紹介した中で、最もリアルタイム性が高いのがこのWebsocketです。そのため、チャットアプリやオンラインゲームなどリアルタイム性が必要かつ重要なシーンで使われます

このプロトコルはTCP層に近いためヘッダが軽量です。また、HTTPに比べてサーバーが使用するリソース・通信負荷が少なく、リアルタイム性も高いです。バイナリの送受信も可能です

多数のユーザ接続に対してもサーバへの負荷が少なくスケールがしやすいです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270253/cc3a4e78-ace7-ddd0-5d42-0ab68b698e1f.png)
Websocketのデメリットは以下の通りです
- 通信機器やproxyによっては遮断される場合がある
- 学習コストが高いこと。WebSocketを用いた経験がない場合、実装方法や認証方法、セキュリティなどを学習する必要がある

## 終わりに
最後までお読みくださりありがとうございました。何かご指摘等あればコメントしていただけると嬉しいです

業務でMQTTも使っているので、またそちらもまとめていきます！
type aliasをinterfaceに変える

<h2>typeをinterfaceに変えてみる</h2>
変数のタイプを決めるにあたって、type alias方法とinterface方法がある。<br>
interfaceとtype aliasの違いとしては<br>
①interfaceは"="を使わない。<br>
②タイプを結合させたり組み合わせたりする方式の違い
<br>

<h4>①interfaceは"="を使わない。</h4>
下の二つは同じ定義です。
二つの違いはtype aliasは"="を使っていますが、interfaceは"="を使いません。

```react
// Type Alias
type NewsFeed = {
  readonly points: number;
  readonly comments_count: number;
  read?: boolean; // ? はoptional
} 

// interface
interface NewsFeed {
  readonly points: number;
  readonly comments_count: number;
  read?: boolean;  // ? はoptional
}
```

<h4>②タイプを結合させたり組み合わせたりする方式の違い</h4>
interfaceは2つのタイプを合わせたり、union type やintersection typeをサポートをしていません。<br>
interfaceは 「&」の代わりに「extends」を使用します。しかし「|」を代替するものはありません！<br>
なので、ORの条件を表したい時はtype aliasを使うしかありません。

```typescript
// Type Alias
type NewsFeed = News & {
  readonly points: number;
  readonly comments_count: number;
  read?: boolean;  // ? はoptional
} 

// interface
interface NewsFeed extends News {
  readonly points: number;
  readonly comments_count: number;
  read?: boolean;  // ? はoptional
}
```

<h2>interfaceの長所</h2>
interfaceは名前からも分かるように, より明確かつ明示的にできるという印象を与えます。<br>
例えば、上記の例の場合にはnewsを拡張してnewsfeedを作ると直感的です。<br>
「&」のように何か結合して数学演算をするような表現法よりは文字で表現するので、<br>
コードを読む観点からだとtype aliasよりはinterfaceの方が好まれると言えます。


<h2>追加説明、readonlyとは？</h2>
readonly読み取り専用であることを表します。<br>
なので、readonlyにした属性を変えようとするとエラーが出てしまいます。<br>
このようにタイプの説明を豊富にしておけばおくほど、ミスを未然に防ぐことができるので、<br>
安全なコードを作成することができます。<br>
<b>タイプを作成するときに時間を投資して作成しておけば、以降の実際のコードを作成するにあたりむしろ時間をたくさん稼ぐことができます。これは修正してもいいかだめか悩みをしなくても良い！になります。</b><br>
これらの長所がTypeScriptの最高の長所のでは？！
[WIP] PHP でデータベースに接続する PDO

:::note note
初学者の独り言メモです
PDO について DB への接続・切断、SQL を発行する部分を分けたり、例外処理、プレペアードステートメント、DAO などぼんやり理解したものの本や記事によって異なる関数が使われているのを多く見かけました。プレースホルダの書き方の違いや関数の記述の違い、関数をどう使い分けるのかを知ろうというのが目的です。書き起こしながら理解を深めようと随時加筆・修正していきます。ここで使用するデータベースは MySQL です。 JDBC ドライバ接続についても理解しないと。
:::

データベースに接続するための抽象化レイヤーが PHP に用意されています。「PHP Data Objects（PDO）」が用意されています。今回「**PDO クラス**」を使います。
参考：[PDO:PHP - Manual](https://www.php.net/manual/ja/book.pdo.php)

:::note warn
抽象レイヤーとは何かは後回し
:::

**PDO クラス** のインスタンスを生成してデータベースに接続しますが、データベース接続に必要な情報は以下です。

1. データベースサーバーの名前（ホスト名）
2. データベースの名前（スキーマ名）
3. データベースのユーザー名
4. データベースのパスワード

```php:PDO 基本構文
$変数 = new PDO(
	DB設定(データベースの種類;ホスト名;文字コード),
	ユーザー名,
	パスワード
);
```

以下、$pdo オブジェクトを使ってデータベースとデータをやり取りします。
```php:PDO Sample
<?php
    $dsn = "mysql:dbname=xxx;host=xxx;charset=xxx";
    $user = "root";
    $password = "xxx";

    $pdo = new PDO($dsn, $user, $password);
```
:::note warn
データベースへの接続
WordPress でのデータベース接続に似ているなぁ。データベースへの接続には決められたルールがあるんだね。データベースサーバーをホテルの一室と考えると、どのホテル（ホスト名）のどの部屋（スキーマ名）でなんて名前（ユーザー名）で予約して指定の鍵（パスワード）で入室できる感じかな。
:::

## データ取得関連の関数
他にもありますが、見かけた関数だけを抜き出しました。
- [prepare()](https://www.php.net/manual/ja/pdo.prepare.php)　　…SQLを準備する **`PDO::prepare`**
- [setAttribute()](https://www.php.net/manual/ja/pdo.setattribute.php)　…属性を設定する **`PDO::setAttribute`**
- [query()](https://www.php.net/manual/ja/pdo.query.php)　　　…SQLを実行する **`PDO::query`**
- [execute()](https://www.php.net/manual/ja/pdostatement.execute.php)　　…SQLを実行する **`PDOStatement::execute`**
- [fetch()](https://www.php.net/manual/ja/pdostatement.fetch.php)　　　 …結果を取得する **`PDOStatement::fetchAll`**
- [fetchAll()](https://www.php.net/manual/ja/pdostatement.fetchall.php)　　 …結果をすべて取得する **`PDOStatement::fetch`**

今回はここまで
C#でグローバル変数(仮)を宣言する

# C#にグローバル変数は無い

**C#にはグローバル変数がありません．**
Microsoftの公式サイトにも「C# にはグローバル変数やグローバル メソッドはありません」と明記されています．
[C# のクラス、構造体、レコードの概要(microsoft.com)](https://learn.microsoft.com/ja-jp/dotnet/csharp/fundamentals/object-oriented/)

しかしながら、グローバル変数を使用したい場面は少なからずあります．
　ex：Form1のLoadイベントで取得したユーザー情報を、Form2でも使用したい．

# グローバル変数のように扱う方法

以下のように記述します．
"USER"の部分が変数名となります．

```C#
public static class Global
    {
        public static string USER;
    }
```

他のフォームで使用するときは、以下のように記述します．
"Sample_Project"の部分がアセンブリ名となります．
```C#
    label1.Text = Sample_Project.Form1.Global.USER;
```

変数の呼び出しが少し長くなりますが、上記の方法でグローバル変数的に使うことができます．

以上です．
S3のバケットポリシーで特定のユーザーのみ許可する方法

あまり記事を見かけなかったので、メモ程度に残しておこうと思います
## ①ブロックパブリックアクセスをオフにする
ブロックパブリックアクセスがオンになっていると、バケットポリシーが無視されます
## ②バケットポリシーを定義
以下を読み替えながらコピペしてみてください
##### ※ここでバケットポリシーを間違えると、権限エラーでバケットポリシーを編集できなくなるので注意が必要です！!!
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowUser",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::BUCKET_NAME/*",
            "Condition": {
                "ArnNotEquals": {
                    "aws:PrincipalArn": [
                        "arn:aws:iam::123456789012:root",
                        "arn:aws:iam::123456789012:user/USER_NAME"
                    ]
                }
            }
        }
    ]
}
```

- Sid: 適当な名前
- Effect： 拒否 or 許可を定義。今回は拒否の記述を行うためDeny
- Principal: 対象。今回は全員
- Resource: 対象のバケット名を指定。適宜置き換えてください
- Condition： 条件を設定。今回は、ルートユーザーと特定のIAMユーザーを指定しています。適宜読み替えてください。123456789012はアカウントIDです

これで設定は完了です！簡単でしたね！
【FastAPI】Failed to execute 'fetch' on 'Window' / String contains non ISO-8859-1 code point. エラーの原因と解決方法

# エラー内容
* FastAPIを使ってAPIのリクエスト・レスポンスのテストをしていたら、以下のエラーメッセージが返ってきた。

```
TypeError: Failed to execute 'fetch' on 'Window': Failed to read the 'headers' property from 'RequestInit': String contains non ISO-8859-1 code point.
```

* FastAPIとは：PythonでRESTful APIを開発するためのWebフレームワーク

# 原因
* リクエストヘッダーの中に`non ISO-8859-1 code point`、つまり日本語が入っていた。
* ISO 8859-1とは、ラテンアルファベットの文字コード標準。西欧系の言語なので、日本語には対応していない。
    *ISO 8859-1の詳細についてはこちら： [ISO/IEC 8859【ISO 8859】ISO 8859-1
](https://e-words.jp/w/ISO-IEC_8859.html)

# 解決方法
* リクエストヘッダーから日本語をなくしたら、このエラーはなくなりました！
【Next.js】Error: Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavior>.が表示されたときの対処法

Next.ｊｓで'next/link'の機能を使いページ間のLinkを設定しようとした時
このようなエラーがでてきました。

```
Unhandled Runtime Error
Error: Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavior>.
Learn more: https://nextjs.org/docs/messages/invalid-new-link-with-extra-anchor
```

設定したソースはこちらです。
```nav.js
import Link from "next/link";

export default function Nav() {
  return (
    <nav>
      <ul>
        <li>
          <Link href="/">
            <a>HOME</a>
          </Link>
        </li>
        <li>
          <Link href="/about">
            <a>ABOUT</a>
          </Link>
        </li>
        <li>
          <Link href="/blog">
            <a>BLOG</a>
          </Link>
        </li>
      </ul>
    </nav>
  );
}
```

エラー内容を読んでみると、```a```タグを削除するか<Link>に```legacyBehavior```の値をつけたらよいようです。

特に```a```タグが必要ないなら削除します。

```nav.js
import Link from "next/link";

export default function Nav() {
  return (
    <nav>
      <ul>
        <li>
          <Link href="/">
            HOME
          </Link>
        </li>
        <li>
          <Link href="/about">
            ABOUT
          </Link>
        </li>
        <li>
          <Link href="/blog">
            BLOG
          </Link>
        </li>
      </ul>
    </nav>
  );
}
```


classをつけたりするため必要な場合は```Link```に```legacyBehavior```を設定します。
```nav.js
import Link from "next/link";

export default function Nav() {
  return (
    <nav>
      <ul>
        <li>
          <Link href="/" legacyBehavior>
            <a className="home">HOME</a>
          </Link>
        </li>
        <li>
          <Link href="/about" legacyBehavior>
            <a className="about">ABOUT</a>
          </Link>
        </li>
        <li>
          <Link href="/blog" legacyBehavior>
            <a className="blog">BLOG</a>
          </Link>
        </li>
      </ul>
    </nav>
  );
}
```

これでエラーが無くなりました。
草莽Erlang ── 31. lists:flatten


口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:flatten/1

入れ子になったリストを平坦化した新しいリストを返します。

https://www.erlang.org/doc/man/lists.html#flatten-1

```erlang
> lists:flatten([1, [[2], 3]]).
[1,2,3]

> lists:flatten([[], [[], []]]).
[]
```

## lists:flatten/2

入れ子になったリスト（第一引数）を平坦化したリストに別のリスト（第二引数）を末尾に追加することができます。追加されるリストは平坦化されません。平坦化されるのは第一引数のリストだけです。

https://www.erlang.org/doc/man/lists.html#flatten-2

```erlang
> lists:flatten([1, [[2], 3]], [4, 5]).
[1,2,3,4,5]

> lists:flatten([1, [], 2], [3, [], 4]).
[1,2,3,[],4]
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
Rails7で外部URLのリダイレクトは例外が発生するようになった

Rails7でリダイレクトの処理が少し変わったので見ていきます。

## Rails のリダイレクト

Railsでは以下のように書くとリダイレクトすることができます。

```ruby
# 内部URL
redirect_to root_path
# 外部URL
redirect_to 'https://example.com'
```

## Rails7 のリダイレクト

Rails7からは Open Redirect protection がデフォルトとなり、外部のURLにリダイレクトすると`UnsafeRedirectError`発生するようになりました（内部のURLにリダイレクトするときは今まで通りです）

例外を発生させないようにするために、`allow_other_host: true`を設定する必要があります。

```ruby
redirect_to 'https://example.com', allow_other_host: true
```

## URLが内部URLかチェックする

パラメータでURLを渡す場合は、外部のURLになる可能性もあります。`UnsafeRedirectError`をキャッチしても良いですが、内部URLかチェックするために`url_from`を使うことができます。もし外部URLの場合はnilが変えるので、フォールバックするURLを書いておきましょう。

```ruby
redirect_to url_from(params[:redirect_url]) || root_url
```


## References

https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to

https://github.com/rails/rails/pull/41134/commits/ff8c01a0885a6f154114f9b4485463c91b4f1e43
pip uninstall 失敗した時（scikit-learn）


・パッケージのインストール先を確認(Location)

```
$ pip show scikit-learn
Name: scikit-learn
Version: 1.1.0
Summary: A set of python modules for machine learning and data mining
Home-page: http://scikit-learn.org
Author: 
Author-email: 
License: new BSD
Location: /Users/hoge/opt/anaconda3/lib/python3.8/site-packages
Requires: joblib, numpy, scipy, threadpoolctl
Required-by: 
```

・パッケージ確認（scikit-learn）
※.dist-infoディレクトリはパッケージメタデータの格納先

```
$ ls -apl /Users/sou/opt/anaconda3/lib/python3.8/site-packages | grep learn
drwxr-xr-x    9 sou  staff      288 Jan 19 20:43 scikit_learn-1.1.0.dist-info/
drwxr-xr-x   55 sou  staff     1760 Jan 19 20:43 sklearn/
```

・パッケージ消去
```
$ sudo rm -rf sklearn scikit_learn-0.23.2.dist-info
```

・もう一度インストール
【Rails7】 Simple Form でdata属性をつける

# 初めに
Rails7
simple_form
haml
を使っています。

調べても出てこなくて45分潰れました。
hamlで書いてます。

# 結論
こうじゃなくて
```haml
= f.input :name, data: { hoge: 'hoge' }
```

こう
```haml
= f.input :name, input_html: { data: { hoge:  'hoge' } }
```


### 参考
https://developer.mozilla.org/ja/docs/Learn/HTML/Howto/Use_data_attributes
Java Timeで月末日を取得する

# TL; DR

`java.time.temporal.TemporalAdjusters.lastDayOfMonth()` を使う。

# 実証コード 

```java
// Java
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;

public class Test {
    public static void main(String[] args) {
        LocalDate date1 = LocalDate.of(2023, 2, 15);
        LocalDate date2 = LocalDate.of(2024, 2, 15);

        System.out.println(date1.with(lastDayOfMonth()).format(DateTimeFormatter.ISO_LOCAL_DATE));
        System.out.println(date2.with(lastDayOfMonth()).format(DateTimeFormatter.ISO_LOCAL_DATE));
    }
}
```

```kotlin
// Kotlin
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAdjusters.lastDayOfMonth

object Test {
    @JvmStatic
    fun main(args: Array<String>) {
        val date1 = LocalDate.of(2023, 2, 15)
        val date2 = LocalDate.of(2024, 2, 15)

        println(date1.with(lastDayOfMonth()).format(DateTimeFormatter.ISO_LOCAL_DATE))
        println(date2.with(lastDayOfMonth()).format(DateTimeFormatter.ISO_LOCAL_DATE))
    }
}
```

出力結果

```
2023-02-28
2024-02-29  // うるう年も自動で計算してくれます
```

## 他にも

- `firstDayOfMonth()`: 月初日の取得
- `firstDayOfNextMonth()`: 翌月の初日を取得
- `firstDayOfYear()`: その年の1月1日を取得
- `lastDayOfYear()`: その年の12月31日を取得
- `firstDayOfNextYear()`: 翌年の1月1日を取得
- `firstInMonth(DayOfWeek dayOfWeek)`: その月の最初の `dayOfWeek` にあたる日を取得
- `lastInMonth(DayOfWeek dayOfWeek)`: その月の最後の `dayOfWeek` にあたる日を取得
- `dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)`: その月の `ordinal` 週目の `dayOfWeek` にあたる日を取得
- `next(DayOfWeek dayOfWeek)`: その日の次の `dayOfWeek` にあたる日を取得
- `nextOrSame(DayOfWeek dayOfWeek)`: その日と同じか、次の `dayOfWeek` にあたる日を取得
- `previous(DayOfWeek dayOfWeek)`: その日の前の `dayOfWeek` にあたる日を取得
- `previousOrSame(DayOfWeek dayOfWeek)`: その日と同じか、前の `dayOfWeek` にあたる日を取得
マイクラチュートリアル7-3 パスワード認証


```lua
os.loadAPI("h2touchpanel")

local password = 0


function input(num)
  print("before:",password)
  password = password * 10 + num
  print("after:",password)
end

function clear()
  password = 0
end

function enter()
  if password == 1234 then
    print("OK! Open the door.")
    rs.setOutput("right", true)
    sleep(5.0)
    rs.setOutput("right", false)
  else
    print("NG! Please retry!")
  end
  password = 0
end


local buttons = {}
buttons[1] = {name = "1", cmd = function() input(1) end}
buttons[2] = {name = "2", cmd = function() input(2) end}
buttons[3] = {name = "3", cmd = function() input(3) end}
buttons[4] = {name = "4", cmd = function() input(4) end}
buttons[5] = {name = "5", cmd = function() input(5) end}
buttons[6] = {name = "6", cmd = function() input(6) end}
buttons[7] = {name = "7", cmd = function() input(7) end}
buttons[8] = {name = "8", cmd = function() input(8) end}
buttons[9] = {name = "9", cmd = function() input(9) end}
buttons[10] = {name = "0", cmd = function() input(0) end}
buttons[11] = {name = "clear", cmd = function() clear() end}
buttons[12] = {name = "enter", cmd = function() enter() end}

local monitor = peripheral.wrap("top")
local option = {topPos = 2, bottomPos = 9}
local panel = h2touchpanel.makePanel(buttons, 3, 4, monitor, option)
panel:draw()


while true do
  local event, btn = panel:pullButtonPushEvent()
  btn:run()
  panel:drawPushedButtonEffect(btn, 0.5)
end

```
ClusterをLinuxで動かす方法 (2023年版)

## 環境
```
$ uname -a
Linux deb11-v4 6.0.0-6-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.0.12-1 (2022-12-09) x86_64 GNU/Linux
```

## 手順
1. ClusterのインストーラーをWindowsへダウンロードします
1. Windowsでインストールします。この時の場所はUSBメモリにしておきます
1. LinuxにSteamを入れておきます
1. Steam経由でProtonをインストールしておきます
1. LinuxにUSBメモリを刺します
1. `mkdir hoge && cd hoge`します。このときのディレクトリ名と親ディレクトリの場所はなんでもいいです。これがwineのprefixの場所になるのでよく覚えておいてください。
1. `STEAM_COMPAT_DATA_PATH=/path/to/hoge ~/.steam/steam/steamapps/common/Proton\ Experimental/proton run /path/to/cluster/cluster_win.exe`します
    * 注: `~/.steam`が`~/.local/share/Steam`だったりします。適宜読み替えてください
    * 注: Protonのバージョンが違うかもしれません。適宜読み替えてください
1. 起動したclusterのランチャーを一度[x]で閉じます
1. wineが入っていなければ、`sudo apt install wine`
1. `WINE_PREFIX=/path/to/hoge/pfx ~/.steam/steam/steamapps/common/Proton\ Experimental/dist/bin/wine start winecfg`して、設定がWindows 10として認識されるような設定になっていることを確認します
1. 9でwineをインストールしたのであればディスクの節約のために`sudo apt remove wine`します。
1. `STEAM_COMPAT_DATA_PATH=/path/to/hoge ~/.steam/steam/steamapps/common/Proton\ Experimental/proton run /path/to/cluster/cluster_win.exe`でもう一度clusterのランチャーを開きます
1. アカウントを持っていなければ作ります。連携ログインがやりやすくておすすめです
1. ログインします
1. ワールドに入ります
1. Enjoy.

## 参考文献
* [clusterをLinuxで動かす - tosuke](https://scrapbox.io/tosuke/cluster%E3%82%92Linux%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99) - 「チート検出みたいなのが強化されてて、ちゃんとWin10互換にしていても「サポートされていないOSです」と出る」と書いてあるが、筆者は確認できませんでした。
【Debian】libtoolizeのインストール

## 困ったこと
[Apache Thrift](https://thrift.apache.org/)をビルドしようとしたとき`libtoolize`を`./configure`で要求してきたので、`apt`でインストールしようととする。しかし
```sh
apt search libtoolize
```

で調べてもパッケージがない。

## 打つべきコマンド
```sh
sudo apt install libtool
```

で入った。

## 参考文献
https://rougeref.hatenablog.com/entry/20170907/1504829580
Windows 11の付箋アプリのデータ保存場所とバックアップ方法

　Officeを使うことになった社員にMicrosoft Apps for Businessライセンスを付与したアカウントでPCにサインインさせたところ、アプリ内でサインインしていなかった（というか未だにサインインできない）はずのMicrosoft謹製付箋アプリのメモ内容が消滅してしまいました。
　幸い、失って困る重要な情報はなかったので損害は出ず。まあ現実でも大事な情報を付箋に書いて貼ったまま利用するというのは常識的にどうかと思うのですが。
　でも常識という言葉があるのは非常識なことが現実にあるからです。実際、画面中が付箋で覆いつくされるほどのヘビースティッカーな従業員はいるわけです。もう付箋の意味ないだろうそれ.......
 その方のパソコン入れ替え時などにひとつひとつ付箋の内容を.txtやらに移すのはその方自身が作業するとしても時間がかかり面倒です。
そこで、付箋の内容を付箋の形を維持したままバックアップや移動はできないかと大Go〇gle先生の力を借りることに。

　大体のサイトでは、
C:\Users\ユーザ名\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe/LocalState

の中にある
・plum.sqlite
・plum.sqlite-shm
・plum.sqlite-wal

　この３つのファイルをバックアップし、復元するにはこの3つを上書きして再起動すればよいとしているところが多くありました。
この情報をもとに、適当に付箋を作って該当ファイルをデスクトップにコピー→アプリリセット後にコピーしたファイルを元のディレクトリに上書きペーストしてみるものの、


あれ？

全く

メモが

復活しない？？？？


　日本語サイトのみならず英語圏のサイトやMicrosoft公式フォーラムでも同様の内容が書かれていますが、何回トライしてもそこに現れるのは初回起動時に作られる0文字のメモのみ。
君たち本当に付箋アプリ使ったことあるのかい？

　ウェブの海には情報の屍しかないと見切りをつけ、なんとかバックアップできないかと試行錯誤したところなんとできてしまいました。

先ほど記した階層の1つ上である
C:\Users\ユーザ名\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe

この階層にある
・AC
・LocalState

　この２つのフォルダをバックアップし、アプリリセット→初回起動後に元の保存場所に上書きペーストして再起動。
そして再ログイン後に付箋アプリを起動してみると、なんと神頼みを書き連ねたメモたちがカムバックしているではありませんか。

　画面上の付箋の位置や大きさなどは初期化され中央に重ねて表示されてはしまいますが、それでもメモの形態を保ったままバックアップ/復元をすることに成功しました。
　
　ちなみにWindows10の途中のアップデートから付箋アプリの保存場所が変わっているそうなので、W10ユーザーの方はこの通りにいけるかは知りません。自分の環境以外のWindows11ですらうまくいく保証はできませんけど。


　正直付箋アプリ自体の需要が不明なのでこの記事がどれほど役立つかはわかりませんが、誰かの役にたてたら幸いです。
稚拙な文章で読みづらかったかと思いますが、最後までお付き合いいただきありがとうございました。
　これからは、そもそも付箋のバックアップをしなくてもいいようにヘビースティッカー達は矯正させていきたいと思います......
データ活用の進め方 ～稟議決裁編～

「データ活用」をキーワードにネットで検索すると、導入したツールの成功事例の記事を
よく見かけますが、「これからデータ活用を進めようとしている方」にとっては、
「どうやって導入するまでに至ったのか？」も気になるのではないでしょうか？

そんな「これからデータ活用を進めようとしている方」に向けて
弊社におけるデータ活用を進めるまでの道のりを
　* [目的設定編](https://qiita.com/C0nnectW1thData/items/1d461615b84b7f773aa6 "目的設定編")
　* 稟議決裁編
　* [導入編](https://qiita.com/C0nnectW1thData/items/4324ff3564c0baef3e28 "導入編")
　* [運用体制構築編](https://qiita.com/C0nnectW1thData/items/acfbc6c71ac9af77a427 "運用体制構築編")
の全4回に分けてご紹介します。

「上手くいったこと」もあれば、「上手くいかなかったこと」もあるので、
ざっくばらんに書きたいと思います。

全4回のうち、本記事は「稟議決裁編」として、プロジェクトの目的を設定した後に
Salesforceのライセンス追加+Tableauの新規購入の稟議を決裁してもらうまでの
経緯をご紹介したいと思います。

# 要約
稟議決裁という会社にとっての投資の許可を得るためには、
**データ活用をすることで「会社の成長」につながるロジックを作ること**
が重要だと感じました。
特にツールを新規に購入する場合は、投資に見合ったリターンを得られるのか？という
問いに対する答えをしっかり用意しておく必要があると思います。

# いざ、稟議書作成
「目的設定編」でご紹介したように、このプロジェクトの目的は、お客様からの声を
踏まえて、

> 過去経緯を踏まえて、お客様の状況にあわせた回答・提案をできるようにして、
> お客様の満足度の向上を図ること

としました。
この目的を軸に、
　* 検討の背景
　* As-Is
　* 現状の課題
　* SalesforceおよびTableauを使ったTo-Be
　* マスタスケジュール
　* プロジェクト体制
　* 費用対効果
を資料にまとめ、上司にレビューを求めに行きました。
当時の私は今よりももっと未熟だったため、それなりに自信をもって臨んだのですが、
結果はボロボロでした。
その時のやり取りはこんな感じだったと思います。

私　：今までスプレッドシートとかを使って必死にいろいろ加工してましたが、
　　　Salesforceにデータを集めてTableauで可視化することで、お客様のInsightを
　　　素早く得られるようになります！
上司：で？
私　：ちゃんと構築ができれば、お客様の満足度の向上につながります！
上司：で？
私　：今までのスプレッドシートとの格闘がなくなるので、生産性が上がります！
上司：で？
私　：で！？

# 重要なのは、会社の成長
データ活用に関するプロジェクトは「お客様の満足度向上」や「従業員の生産性向上」が
キーワードになることが多いと思います。
この2つのキーワードだけを切り取って、いろいろ端折って言い換えてみると、
「今までよりは人手をかけずに、お客様の離反を防ぐことができる」
になると思います。

前述の上司の「で？」には、以下の3つの意味が込められていました。
　1\. お客様の離反を防ぐことも重要だが、それだけでは現状維持にしかならない。
　2\. 生産性の向上も重要だが、その将来は極端に言うと人員削減が待っている。
　3\. 上記2点を踏まえて、継続的な投資に見合った会社の持続可能な成長は見込めるのか？

「会社の成長」にはいろんな解釈があると思いますが、一番わかりやすいのは
「売上UP」です。

SalesforceとTableauを使ってデータ活用をすることで売上UPにつながるのでしょうか？
このロジックを考えることが承認してもらえる稟議書を作成する上で最も難しかったことで、
最も重要なことだったと思います。

# アウトプットイメージは有ったほうが良い
「稟議書」は会社によっていろんなフォーマットがあると思いますが、
一般的なのは文字がずらっと並んでいる味気ない文書ではないでしょうか。

文字だけを使って、Tableauの良さを伝えることは難しいです。
また、稟議書を読む人たちにとっても、文字だけではTableauの良さを理解することは、
難しいと思います。

なので、補足資料が付けられるのであればデータ活用のアウトプットイメージを
添付することにしました。
Tableauの場合、[Tableau Public](https://public.tableau.com/app/discover "Tableau Public")というTableauで作ったダッシュボードが
無料で公開されているサイトがあるので、私はここからヒントを得て、
アウトプットイメージを作りました。

ただ、このアウトプットイメージも使い方を間違えると逆効果になることがあります。
本来ダッシュボードには「伝えたいストーリー」に沿って作られているので、
ストーリーのないアウトプットイメージを載せてしまうと、また「で？」と言われます。
私は言われました。

# まとめ
なんやかんやで無事に稟議書も作り上げることができ、承認ルートもなんとか走り切って、
決裁を得ることができました。

稟議決裁のことを振り返ってもそうですし、運用を始めている今も感じていることですが、
**データ活用をすることで会社の成長につながるロジックを作ること**
は難しいのですが、とても重要です。
「業務効率化」や「生産性向上」の先にある世界をイメージすることで、
データ活用の幅も広がると思います。

# 最後に
本編で、ようやくSalesforceをベースとしたTableauによるデータ活用をすることについて
会社の許可を得ることができました。
ここまで来るのに一苦労で燃え尽きそうになるのですが、スタートラインに立っただけです。
次回の「導入編」では、導入プロジェクトを進めるまでに準備しておいて良かったことや、
苦労したこととその対応方法について触れたいと思います。
データ活用の進め方 ～目的設定編～

「データ活用」をキーワードにネットで検索すると、導入したツールの成功事例の記事を
よく見かけますが、「これからデータ活用を進めようとしている方」にとっては、
「どうやって導入するまでに至ったのか？」も気になるのではないでしょうか？

そんな「これからデータ活用を進めようとしている方」に向けて
弊社におけるデータ活用を進めるまでの道のりを
　* 目的設定編
　* [稟議決裁編](https://qiita.com/C0nnectW1thData/items/7a7ff5effb5ec4180e13 "稟議決裁編")
　* [導入編](https://qiita.com/C0nnectW1thData/items/4324ff3564c0baef3e28 "導入編")
　* [運用体制構築編](https://qiita.com/C0nnectW1thData/items/acfbc6c71ac9af77a427 "運用体制構築編")
の全4回に分けてご紹介します。

「上手くいったこと」もあれば、「上手くいかなかったこと」もあるので、
ざっくばらんに書きたいと思います。

全4回のうち、本記事は「目的設定編」として、データ活用を進めるに至った背景から
データ活用プロジェクトの目的設定までの経緯、そして、データ活用を進めるツールとして
SalesforceとTableauの利用に舵を切った経緯をご紹介します。

# 要約
**データを活用して実現したい目的を定めること**が重要だと感じました。
データ活用に向けて検討を進めていくうちに、ついつい「データを活用する手段」に
気を取られてしまいがちです。
本当の目的を見失うことなく検討を進めるための取り組みとして、
検討の経緯をドキュメントに残すことを徹底しました。
ドキュメント化することで、関係者とのコミュニケーションロスを減らすことができ、
過去の考えを振り返ることができたので、同じ議論を繰り返すことを避けられました。

# データ活用を進めるに至った背景
弊社では年に1回、お客様満足度調査を実施しています。
選択式の回答もあれば、自由記述の回答もあり、お客様の声を直接伺える貴重な機会です。
その調査結果にて「もう少し担当者間の情報連携を強化してもらいたい」というコメントを
頂いたことがデータ活用を全社的に進めるに至ったキッカケです。
このキッカケからお客様情報を一元化・最新化して、データを活用できる環境を整えるために
部門横断のプロジェクトがトップダウンで発足しました。

# まずは、現状把握
弊社はお客様と直接の接点を持つ部門が営業・導入・保守の3つに分かれており、
情報の管理はそれぞれの部門がやりやすい方法で管理されているため、
結果として、いわゆる「データのサイロ化」が発生していました。
また、このサイロ化の状態をスプレッドシートを駆使して、必要に応じて、
気合と根性で対応していたため、「データ管理方法の属人化」も発生していました。

# 次に、プロジェクトの目的を設定
「データのサイロ化」や「データ管理方法の属人化」を解決して、
「お客様情報を一元化・最新化して、データを活用できる環境を整えること」は
手段であり、目的ではありません。
私にとって「データ活用」は漠然とした問いだったため、情報収集のために
ネットで検索していたのですが、手段に関する記事をよく見かけるため、
記事を読んでいるうちに、ついつい思考が「手段の検討」に移行してしまい、
課題の本質を掴むまでに時間がかかってしまいました。

冒頭にも書きましたが、重要なのは
**「データを活用して実現したい目的を定めること」**
です。

弊社の場合はお客様満足度調査のコメントとしていただいた
「もう少し担当者間の情報連携を強化してもらいたい」
がキッカケで「データ活用」の話が始まりました。

このキッカケからお客様が本当に求めていることは何か？を考えました。
この時のポイントは「お客様」を主語にして考えることだったと思います。

お客様は我々が「担当者間の情報連携」をすることで、我々にどのようなアクションを
期待してくれているのか？

この問いから私はこのプロジェクトの目的を

「過去経緯を踏まえて、お客様の状況にあわせた回答・提案をできるようにして、
　お客様の満足度の向上を図ること」

としました。

# そして、ツールの検討
目的を達成するためには、お客様の情報を一元化・最新化できるようにするだけではなく、
その情報から素早く気付きを得て、素早くアクションに移せるツールが必要だと考えました。
情報を一元化しても、クロス集計表しかアウトプットすることができないツールでは、
アウトプットの解釈に時間がかかり、素早くアクションを取れないからです。
そして、このプロジェクトに必要なツールとして、CRMとBIツールの検討を進めました。

ツールは、既に社内で活用が進んでいるものがあり、それが外部開発なく、
設定の変更だけで様々な要求に耐えられそうなのであれば、新しいツールを選ばず、
既存のツールを拡張することが良いと思います。

弊社の場合、営業がSalesforceを活用していましたので、Salesforceのライセンスを
追加して、利用できる人数を増やし、機能を拡張する方向に舵を切りました。
そしてBIツールですが、SalesforceがTableauを買収したこともあり、
Salesforceとの親和性と今後の拡張に期待して、Tableauを採用する方針としました。

# まとめ
ネットの検索は便利なのですが、場合によっては検索結果がノイズになることもあります。
私はこのノイズに惑わされ、課題の本質を見失うところでした。

改めてにはなりますが、データ活用を進める上で重要なことは
**データを活用して実現したい目的を定めること**
です。

# 最後に
本編では、使いたいツールを決めただけで、「ツールを買う」には至っていません。
次回の「稟議決裁編」では、社内稟議を通した方法について触れたいと思います。
マイクラチュートリアル7-2 モニター ドアの開閉

```lua
os.loadAPI("h2touchpanel")

function door(isOpen)
  rs.setOutput("right", isOpen)
end

local buttons = {}
buttons[1] = {name = "OPEN", cmd = function() door(true) end}
buttons[2] = {name = "CLOSE", cmd = function() door(false) end}

local monitor = peripheral.wrap("top")
local option = {topPos = 1,bottomPos = 10}

local panel = h2touchpanel.makePanel(buttons, 1, 2, monitor, option)
panel:draw()


while true do
  local event, btn = panel:pullButtonPushEvent()
  btn:run()
  panel:drawPushedButtonEffect(btn, 0.5)
end
```
[備忘録] macのターミナルからGoogleドライブにアクセス

# 手順
1. [Googleドライブのデスクトップ版](https://www.google.com/intl/ja_jp/drive/download/)をインストール
1.  インストール後, 指示に従ってブラウザでGoogleアカウントの認証
1.  ホームディレクトリにリンクが作成される
    - `$HOME/Google Drive`
    - リンク先 : `/Users/$USER/Library/CloudStorage/GoogleDrive-hogepiyo@gmail.com`
        - `hogepiyo`の部分は認証したGoogleのアカウント名
VSCodeでお絵かきDraw.ioが激アツ

# 概要
エンジニアでも企画でもコンサルでもセールスでも、図をキレイ〜に整理して管理したいというユースケースは度々ありますよね。  
この記事では、エディタとして広く使われているVSCodeでお絵かきする方法を紹介します。

# Draw.io Integrationのセットアップ
そんな時は、Draw.io Integrationのプラグインを使うことがおすすめです。  
セットアップは簡単です。  
以下の図に示すように`拡張機能：マーケットプレース`より`draw.io`で検索して、  
Draw.io Integrationをインストールしてください。  
![スクリーンショット 2023-01-19 16.11.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121442/bd9bf58d-9f32-fee3-f7f1-cda36b06c0fd.png)

# 使い方
インストールが完了したら、`エクスプローラー`でファイルを新規に作成します。  
その際、拡張子を`drawio.svg`とするようにしてください。  
すると、以下の図に示すようにDraw.ioのインタフェースが現れて、D&Dで図を作成、加工できるようになります。
![スクリーンショット 2023-01-19 16.17.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121442/3710e863-f550-7320-b018-6f0e66e473c3.png)

# サンプル
サンプルとして、人材特性マップなるもの（仮想）を描いてみました。  
![スクリーンショット 2023-01-19 23.38.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121442/054f1b3f-7365-face-2e78-9fb70b2fd708.png)


この図は、当該企業の中の人材について「攻めと守りの思考タイプ」と「構成人数（マジョリティ/マイノリティ）」の２軸で分類しています。  

中程にある`Actor`の人材は、ある企業では「攻め＋マイノリティ」な人材でしたが、他方の企業では「守り＋マイノリティ」な人材にマッピングされる、ラベリングされ得るという様を示しています。  
`Actor`のスキルや性格などは不変（変わらない）ですが、環境や置かれた状況によって、また解釈する人によって評価が変わる可能性があることを示しています。  
ご本人の使命感やモチベーションの根源と企業からのラベリングが一致すればよいのですが、そうでない場合はお互いのすり合わせが必要になってくるでしょう。  
また、そのギャップに本人の成長のヒントや、成し遂げたいことの真意が隠されているかもしれません。
> 例えば、攻め＋マジョリティの領域には、ある企業ではセールスがマップされる可能性があります。また、攻め＋マイノリティは事業開発がマップされることもあるでしょう。攻めにも守りにも、大衆的な業務と少数派の業務領域とがあるはずです。

話を戻して、  
このようにテキストもスクエアのブロック図も半透明なカラーリングも自由自在に扱えるため、Draw.io Integrationのプラグインはとてもおすすめです。
【doctrine】Specを使用してデフォルトで条件の入ったdoctrineのオブジェクトを出力したい

## 環境
php7
Symfony3

## そもそもSpecとはなんぞや
[Doctrine-Specification/0-usage.md at 2.x · Happyr/Doctrine-Specification](https://github.com/Happyr/Doctrine-Specification/blob/2.x/docs/0-usage.md)

doctrineのクエリよりも簡素に書けるよ―というライブラリらしい。
~~全然慣れない~~

## 首題について

```php
$spec = Spec::andX(
    Spec::isNotNull('hoge'),
);
```

これだけで済んだ、、、
まあ慣れなんですかね、、、
ジョインして間もないので解決しても腑に落ちないところはある。
フォロー、フォロワー機能の実装

# モデルの作成を行う
- Userモデルの中間テーブルとなるRelationshipモデルを作成する

- カラムは、以下となります
follower_id : フォローしたユーザー
followed_id : フォローされたユーザー

```
$ rails g model Relationship follower:references followed:references
```

- 上記コマンド作成されたファイルに下記を追記
`foreign_key: { to_table: :users }`
```:(作成日時)_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.references :follower, foreign_key: { to_table: :users } #追記
      t.references :followed, foreign_key: { to_table: :users } #追記

      t.timestamps
    end
  end
end
```
- 修正後データベースへ反映
```
$ rails db:migrate
```

# モデルの修正
- 先程作成したrelationshipモデルの修正を行っていきます

```:app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower
  belongs_to :followed
end
```
- モデル作成時に、カラムをreferences型にしていたので自動で外部キーが設定されている
- だが、上記の記述のままだと作成していない`followerテーブル`と`followedテーブル`を参照しようとするので`class_name: "User"`でuserテーブルからデータをとってくるように指定します。
```:models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User" #追記
  belongs_to :followed, class_name: "User" #追記
end 
```

- 続いてuserモデルを修正します
- `class_name: "Relationship"`でRelationshipテーブルを参照するよう記述します
```:models/user.rb
has_many :follower, class_name: "Relationship"
has_many :followed, class_name: "Relationship"
```
- `foreign_key`(外部キー)で参照するカラムを指定します
```:models/user.rb
class Relationship < ApplicationRecord
  has_many :follower, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
  has_many :followed, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
end
```
下記の
- フォローされる側、フォローしてくる側を取得しないといけないためthroughでスルーするテーブル、sourceで参照するカラムを指定。

```:models/user.rb
 has_many :following_user, through: :follower, source: :followed # 自分がフォローしている人
  has_many :follower_user, through: :followed, source: :follower # 自分をフォローしている人
```
- 最後に後ほど使用する定義を記述
```:models/user.rb
  # フォローする
  def follow(user_id)
    follower.create(followed_id: user_id)
  end

  # フォローを外す
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end

  # フォローしているか判定
  def following?(user)
    following_user.include?(user)
  end
```

# コントローラーの作成
```
$ rails g controller relationships
```
- 先程モデルに定義したメソッドを使用してコントローラーへ記述を行う
```:controllers/relationships_controller.rb
def create
  current_user.follow(params[:user_id])
  redirect_to request.referer
end

def destroy
  current_user.unfollow(params[:user_id])
  redirect_to request.referer
end
```

# ルーティング
- 今回、userのidが必要なためrelationshipsをネストさせます
- memberを使って、別のルーティングを追加します
```:config/routes.rb
resources :users, only:[:index, :show, :edit, :update] do
  member do
    get :follows, :followers
  end
  resource :relationships, only: [:create, :destroy]
end
```

# ビュー
ボタンを作成したい箇所に下記を記述
```
<% if current_user.following?(@user) %>
    <%= link_to 'フォロー外す', user_relationships_path(@user.id), method: :delete, class: "btn-sm btn-danger" %>
    <% else %>
    <%= link_to 'フォローする', user_relationships_path(@user.id), method: :POST, class:"btn-sm btn-success" %>
<% end %>
```

- 以上で機能は完成です
python .globの使い方

# ディレクトリ構成
dirname
┣1.txt
┣2.txt
┗3.dat
# とりあえず使ってみる
```python
import glob
import os
file = glob.glob('dirname/*.txt')
print(file)
#['dirname\\1.txt', 'dirname\\2.txt']
```
# フォルダ名とファイル名を分けて取得
```python
print(os.path.split(file[0]))
#('dirname', '1.txt')

print(os.path.split(file[0])[1])
#1.txt

print(os.path.split(file[1]))
#('dirname', '2.txt')
```
# for inで特定の拡張子のファイル名だけ出力
```python
for n in glob.glob('dirname/*.txt'):
    print(os.path.split(n)[1])
#1.txt
#2.txt
for n in glob.glob('dirname/*.dat'):
    print(os.path.split(n)[1])
#3.dat
```
【Mac】ターミナルでスペースがはいったファイルを扱う

# はじめに
名前にスペースがはいってるフォルダを扱ってる時にパスがうまく指定できませんでした。
対策を知ったので記録しておきます。

以下のようなスペースのはいったフォルダを作成して例にしてみます。
![スクリーンショット 2023-01-19 19.45.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/70874dc5-a316-2101-6444-f52180c2277d.png)

# 対策
スペースの前に`\`を挿入します
### 良い例
```
/Users/miyamototaishin/Desktop/sample folder
```
### 悪い例
```
/Users/miyamototaishin/Desktop/sample\ folder
```

# おわり
意外と見落としがちで原因探しに時間がかかっちゃうことがあります。
時間がもったいないので覚えておきましょう。
【備忘録】torch.Tensorが入ったlistを二次元のTensorに変換

```python
import torch

tensor_list = []
for i in range(3):
    tensor_list.append(torch.rand(3))
print(tensor_list)
# [tensor([0.4824, 0.2966, 0.3177]), tensor([0.5601, 0.0189, 0.4304]), tensor([0.9667, 0.4388, 0.2032])]

tensor_list = torch.stack(tensor_list, dim=0) # これ

print(tensor_list)
# tensor([[0.4824, 0.2966, 0.3177],
#       [0.5601, 0.0189, 0.4304],
#       [0.9667, 0.4388, 0.2032]])
```
VMware PowerCLI で証明書エラーになった場合の対処法

vCenter Server を PowerCLI で操作しているとき、証明書関連のエラーが出力されることがある。
`Connect-VIServer` などの一部コマンドレットでは Insecure 相当のオプション（この場合は `-Force`）で回避ができるが、 これに該当するオプションが見当たらない場合が.... 例えば：
```bash
PS /root> get-vm -name test-vm | Export-VApp -Destination /root -Format ova -Name test-vm.ova
Export-VApp: 2023/01/13 14:04:43        Export-VApp             The SSL connection could not be established, see inner exception.
```

このような場合は、`InvalidCertificateAction` へ `Ignore` をセットしてやれば良いようだ。
```bash
PS /root> Set-PowerCLIConfiguration -InvalidCertificateAction:Ignore

Perform operation?
Performing operation 'Update VMware.PowerCLI configuration.'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y

Scope    ProxyPolicy     DefaultVIServerMode InvalidCertificateAction  DisplayDeprecationWarnings WebOperationTimeout
                                                                                                  Seconds
-----    -----------     ------------------- ------------------------  -------------------------- -------------------
Session  UseSystemProxy  Multiple            Ignore                    True                       300
User                                         Ignore
AllUsers
```
【備忘録】 日本語の文章を事前学習済Bertで特徴量にembeddingする (Colab環境2022/01/19)

Colab環境
```
!pip install transformers
!pip install fugashi
!pip install ipadic
!pip install tqdm
```
```python
import torch
from transformers import AutoModel, AutoTokenizer
import tqdm

bertjapanese = AutoModel.from_pretrained("cl-tohoku/bert-base-japanese")
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")
device = "cuda" if torch.cuda.is_available() else "cpu"

bertjapanese.to(device)
features = []

for i, text in enumerate(tqdm(texts)):
    input_ids = tokenizer.encode(text, return_tensors="pt", max_length=512, truncation=True) # 事前学習bertモデルのinputの長さは最大で512
    outputs = bertjapanese(input_ids.to(device))
    last_hidden_states = outputs[0]
    feature = last_hidden_states[0, 0, :] # bertjapaneseは複数の文章を同時に処理できるが，一つずつ変換しているので0番目を指定，二つ目の0はclsトークン部分を表す
    path = "path_to_save_dir" + str(i) + ".pt" 
    torch.save(feature, path)
```
一度に複数の文章を処理しようとするとメモリが足りずにクラッシュする．
今の画質でまずまずの満足(youtube動画のアップロードで)

# 概要
今年に入ってyoutube動画を初めてアップロードしました。いざ、動画の作成に取り掛かると、いろいろな問題が起こってきました。作成のための各種デバイスの用意がありますが、まずは録音のマイク準備です。リモート会話用のマイクがあったので、とりあえずはそれで代用しました。その次は、録画用のアプリの選択ですが、最初は前に使用していた無料のFilmora 9ソフトを使いました。無料のため、透かしが入ってしまいます。とりあえず、これで動画の作成環境は整いました。パソコンはDellのInspiron 620Sでメモリーは増設しています(8GB)。OSはWindows 10 64bit CPUです。
# 接続
(1)マイク
マイクは、パソコン本体の裏側にあるピンク色の3.5mmジャックへ差し込みました。
(2)スピーカー
スピーカー接続は有線、無線の環境があります。CDコンポのスピーカがありましたので、それをNobSoundデバイスに接続して、音源はパソコンの緑色の3.5mmジャックとNobSoundデバイスのAUXジャックを3.5mmジャック(オス)のケーブルで接続しました。NobSoundデバイスは他にブルートゥース、USBでも接続できます。

# 録画ソフト
録画ソフトはいろいろ試した結果、Screen Recoder 4 Deluxe版を選びました。PC画面の録画を行いたかったためと、価格が安かったことが選択の理由です。
# マイクロフォン
録音用には、ピンマイクを探しました。これもいろいろ探しました。その結果、Pop Voiceというコンデンサーマイクにたどり着きました。全指向性で周辺のかすかな音も拾ってくれます。これは、スピーカーで流している音声とマイクの音声を録音したいためです。youtubeの音楽をバックで流しながら、マイクでナレーションを入れるためです。
# 動作テスト
この実行環境でyoutube動画を作成してみました。その時のScreen Recorderの解像度は1080pを指定しています。ビデオフレームレートは30fpsです。出力ファイルの形式はmp4形式です。システム音声はオフに設定しています。マイクの音量、入力デバイスの音量はともに100%です。作成したyoutube動画は「yyプラグインデモx.265」です。
約16分の動画です。
作成した動画をyoutubeへアップロードして、再生して見たところ、解像度がよくなく、テキスト表示が多少ぼやけていました。見栄えが良くないので、これを何とかしたいと思い、ネットで対策を探しましたところ、AviUtlという無料ソフトがあり、これを使用してぼやけをシャープにしてみようと試みました。しかし、mp4ファイルを出力するにはさらにプラグインが必要とわかり、それらのプラグインを探しました。今回は、入力プラグインにL-SMASH Works File Reader、出力プラグインに拡張x265出力(GUI)ExをAviUtlのPluginフォルダーにインストールしました。 これで、Screen Recorderで生成したmp4ファイルを元に、AviUtlでx265エンコードしたmp4ファイルを作成しました。それをyoutubeへ再アップロードして確認したところ、今度はかなりテキスト表示がシャープになり、ぼやけもなくなりました。
以下の動画で比較できます。

## デモ動画
対策前　[yyプラグインデモ(x.265版).mp4](https://youtu.be/6lndlvY3MUQ)
対策後　[yyプラグインデモx.265.mp4](https://youtu.be/zCczDNii_xM)


# あとがき
youtubeを見ていると高解像度の動画もあり、低解像度の動画もあります。アップロードする側にとっては出来れば高解像度でアップしたいと思います。しかし、高解像度の動画を作成することかなりハードルが高いと実感しています。普通のパソコンでグラフィックボードも特別なボードは搭載していません。今の2Kや4Kの動画は無理です。せいぜい1080Pクラスの解像度と思い、Screen Recorderではその設定をしていますが、なぜか、アップロードした動画では720pになっています。この辺のことは今後の課題です。
【Laravel】デプロイ時の公開フォルダの設定（さくらのレンタルサーバー使用）

## 困った事
- 久しぶりにLaravelアプリをさくらのレンタルサーバーにデプロイしようと思い、2年ほど前の自分の記事[「さくらのレンタルサーバでLaravelアプリをデプロイしてみた(Qiita)」](https://qiita.com/kohboh/items/ff09e051977e5d7e9f5c)を参考に作業していたら、以下のようにハマった。
- アプリの公開のために、サーバー上のLaravelプロジェクトのpublicを参照するシンボリックリンクを公開フォルダに置いたが、ルートURLが`http://www.初期ドメイン/public/public`と、publicはつくし、なぜか2回繰り返されてしまった。前回はそんなことなかったのに。
- ルートURLが不適切なことから、プロジェクト内のルーティングもおかしなことになって正常に動作しなかった。
- 前回はそんなことなかったので、色々なサイトを見ながら、色々試した結果、丸1日かけて解決できた。

## 結論
- 公開フォルダの設定を、シンボリックリンクを含めたところまで適切に設定する必要があった。
- さくらのレンタルサーバーでは、初期ドメインの公開フォルダは`www`ディレクトリに固定されているため、シンボリックリンクを含めることができない。
- 同サーバーでは、追加でドメインを作成すれば公開フォルダをwww以下で自由に設定できる。新規ドメインでシンボリックリンクまでを含めるようにしたところ、正常にルートURLを設定できるようになった。

## 実例
- アプリ名：`my-app`
- アプリのパス：`~/laravel-projects/my-app`
- さくらのレンタルサーバーでは、追加料金無しでさくらインターネットのサブドメインを2個まで登録できる。
- 手順
    1. 任意のドメインを登録する。今回は`pink-green-yellow.skr.jp`というドメインを追加登録する。
     ~~サーバーのコントロールパネルから、Web公開フォルダを`~/www/pink-green-yellow/public`に設定する。
     `www`ディレクトリ下に`pink-green-yellow`ディレクトリを作成し、シンボリックリンクを貼る。~~
    2. さくらサーバーのコントロールパネルから、追加したドメインのWeb公開フォルダを`~/www/my-app`と設定する。
    3. 2で設定した公開フォルダにあうように、シンボリックリンクをwwwフォルダ下に作る。
        ```bash:サーバー上でのコマンド
        % ln -s ~/laravel-projects/my-app/public ~/www/my-app
        ```
    4. `https://www.pink-green-yellow.skr.jp`にアクセスして、ルート画面が表示されれば成功。
## その他
- `.htaccess`を編集している記事があり、少し試そうとしたがしっかり理解できているわけではないので、あまりいじりたくはなかった。結果、`.htaccess`はいじらずに解決できたので良かった。
確定申告をスマホ一つで 令和4年分

# はじめに
行政的な手続きを面倒くさがるタイプの人に、確定申告を少しでもやる気になってもらうために書きました。

# 確定申告
人は皆、収入とそのために出費した支出の差に応じて所得税を払う必要があります。サラリーマンは年末調整さえしておけば会社がややこしい計算を肩代わりして翌年度の税額を決めてくれます。**ただし**、下記のような特定の場合において自分自身で**確定申告**して翌年度の税額を確定します。

https://www.nta.go.jp/taxes/shiraberu/shinkoku/tokushu/index.htm

### 確定申告したほうが良い場合
例えば下記のような場合は確定申告することにより払いすぎた税金が戻ってくるので、したほうが良い場合です。
* 高額な医療費を支払ってその分を税額計算から控除してもらいたい場合
* 住宅を購入してその支払額の一部を税額計算から控除してもらいたい場合
:::note warn
しないと損します（数万円）。
:::

### 確定申告をしないといけない場合
例えば給与以外の所得があった場合などは本来払うべき所得税額が源泉徴収で会社が計算したものに比べて増えるので、正しい税額を確定申告する必要があります。
* 副業などで25万円以上稼いだ場合
* 12月に転職して源泉徴収ができなかった場合

:::note alert
しないと脱税になります。
:::

# やるとなったら
確定申告はとても**面倒**ですが、年に1回しかやらなくていいタスク。時期は毎年1月から3月の期間しかできません。しかし、やると決まったらあらかじめ準備しておくことができます。申請方法はトータルで楽になれる国税庁（=確定申告書作成コーナー）とデジタル庁（=マイナポータル）を連携させて一気に必要な情報を集める方法を選択します。

```mermaid
graph TD;
    確定申告書作成コーナー-->マイナポータル;
    マイナポータル-->e-私書箱;
    マイナポータル-->ねんきんネット;
    ねんきんネット-->社保や国保;
    マイナポータル-->e-tax;
    e-tax-->住宅ローンなど;
    e-私書箱-->保険会社;
    e-私書箱-->ふるさと納税事業者;
```

## マイナポータルの事前準備
確定申告の時期に備えてマイナポータルを中心とした自分の必要情報を自動収集するネットワークシステムである「マイ・マイナポータル」を構築しておくことが大切です。
### マイナンバーカードを作る
マイナポータルはその名の通りマイナンバーカードによるMFAを前提としたIDプロバイダです。発行に手間と時間がかかるものの、これがないと始まりません。扶養家族が居る場合、その**扶養家族の氏名・生年月日・マイナンバー**の情報が必要になります（カードは不要）。
### マイナポータルに入る
マイナンバーカードができたらスマホにアプリを入れてログインしましょう。カード作成時に作った暗証番号を入れてカードをスマホにタッチすることでログインできます。

https://myna.go.jp/

### マイナポータルにe-私書箱を連携する
個人的にここが一番の難関でした。
e-私書箱は多くの保険会社やふるさと納税事業者と連携して、マイナポータルに提供してくれます（直接マイナポータルに連携してくれたほうが助かりますが・・・）。
e-私書箱のIDを新たに作って連携したら、今度はe-私書箱に保険会社から生命保険の情報を連携してもらったり、ふるさと納税事業者からふるさと納税の情報を連携してもらったりします。

:::note warn
ふるさと納税のワンストップ特例を利用していたとしても、確定申告でリセットされるので、改めて登録しておく必要があります。
:::
### ねんきんネットやe-TAXを連携する
他にもいろいろ連携できるので、なるべく自動でデータを集めたいところです。

https://www.nta.go.jp/taxes/tetsuzuki/mynumberinfo/mnp_junbi/kakutei.htm

## 源泉徴収票の準備
サラリーマンなら会社から発行される源泉徴収票が必要になります。金額や記載されているデータが必要になるだけなので、PDF等で入手できればOKです。

:::note
転職等した場合は「退職所得の源泉徴収票・特別徴収票」も追加で必要になります。
:::

# 確定申告
人は皆、収入とそのために出費した支出の差に応じて所得税を払う必要があります。
しかし、ここまで準備ができていればスマホとマイナンバーカードで1時間もあれば確定申告ができるでしょう。

https://news.yahoo.co.jp/articles/ddfe3ca4a91b18edf89325756ef292f659e331ef

# おわりに
はじめてスマホで確定申告をやって、なんとなくシステム構築の試行錯誤に似ている気がしたのでQiitaに投稿しました。マイナポータルにうまくデータが連携されたときは感動！
実際には試行錯誤と2週間くらいの準備期間が掛ったことをここに告白します。
CNN（畳み込みニューラルネットワーク）とは？

こんにちは、すきにーです。

今日はCNNについて書こうと思います。

①CNNとは
CNNとは「convolutional nearal network」の略であり、
日本語にすると「畳み込みニューラルネットワーク」と訳されます。
画像認識の分野でよく使われるニューラルネットワークです。

畳み込みニューラルネットワークときいて、
「畳み込みとは何ぞや？」と思いますよね。

もうちょっとで説明しますね。
先にCNNの構造を説明します。

②ＣＮＮの構造
ＣＮＮは主に３つの層構造で構成されています。

・畳み込み層
・プーリング層
・全結合層

です。
これらが合わさることで、画像を認識できるようになるんです。
すごいですよね。

③畳み込み層の役割
畳み込み層の役割は、一言でいえば「畳み込む対象の特徴を抽出すること」です。
フィルター（カーネル）を使って、画像とフィルターの値を掛け合わせます。
そうすることで特徴が抽出されます。
（特徴が抽出される仕組みまで書きたいんですけど、うまく言葉にかけないですね。
アウトプットって難しい）

④プーリング層の役割
プーリング層の役割は「重要な情報を残しながら情報を縮小すること」になります。
![スクリーンショット-52-768x327.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/2c93763a-ac75-e4f8-b607-f1da9f93a6a0.png)

この画像だと最大値を残して他をなくしていますね。

こうすることで、画像内で対象物の位置がずれたり、角度が変わっても対応できるようになります（ロバスト性が向上するとも言います）。

⑤全結合層の役割
全結合層では、最終的な識別を行うために、情報を一次元にします。
これは猫だ！とか、これは海が写った風景画だ！とかを判断できるようにする前準備って感じです。

⑥出力層
出力層で最終的な識別を行います。
これは猫だ！とか、これは海が写った風景画だ！とかを判断します。


畳み込み層、プーリング層でやってきたことを全結合が一次元にまとめて、
出力層が結果を発表するという流れですね。

⑥活性化関数
畳み込み層でReLu関数
全結合層でもReLu関数
出力層でsoftmax関数
を使うことが多いです。


⑦終わりに
これで畳み込み層に関する説明は終わりです。

コンピューターは画像を視ることはできないけど、認識することはできるというのはすごいですね。
たとえば猫がどういう姿をしているのか、視覚的には分からないけど、
画像の特徴を把握することで猫と認識できているというのは想像がつかないですね。

次回はtensorflowを使ったCNNの実装をやっていこうか、RNNの説明をしようかで迷ってます。

以上です。
Qiita初記事でした。
読んでいただきありがとうござました。
setTimeoutで実行する関数に引数を渡す

第一引数の関数を第二引数に渡したミリ秒後に実行する`setTimeout`メソッド。
下記のように関数に引数を取ると即実行されて意図どおりになりません。

```js
function sayHello(name = 'Tom'){
    console.log(`hello ${name}`)
}

setTimeout(sayHello('John'), 3000) // 間髪入れず「hello John」が出力
```

setTimeoutに渡さなければならないのは関数オブジェクトであり、関数の実行結果ではないからです。
そのため、引数を取らない場合でも即実行されてしまいます。

```js
setTimeout(sayHello(), 3000) // 間髪入れず「hello Tom」が出力
setTimeout(sayHello, 3000) // これならOK。正しい渡し方
```

どうすれば、引数を渡しつつ指定ミリ秒後に関数を実行できるのか。

## 無名関数をわたす

実行したい関数を包含した無名関数をsetTimeoutの引数とすることで、nameを指定することが可能です。

```js
function sayHello(name = 'Tom'){
    console.log(`hello ${name}`)
}

setTimeout(function(){
    sayHello('John')
}, 3000)
```

## bindメソッドを使う

```js
function sayHello(name = 'Tom'){
    console.log(`hello ${name}`)
}

setTimeout(sayHello.bind(null, 'John'), 3000)
```
bind()は、下記の性質を持つ新たな関数オブジェクトを作成するメソッドです。
- 第一引数にとるオブジェクトを呼び出し元の関数内でthisとして参照する
- 第二引数にとる値を呼び出し元の関数内で引数として参照する

今回はthisを使用しないため、第二引数のみ指定しています。

趣旨から少し外れますが、第一引数にオブジェクトをわたすことで下記のような書き方も可能です。

```js
const obj = {
    name: 'John'
}

function sayHello(name = 'Tom'){
    console.log(`hello ${this.name}`)
}

setTimeout(sayHello.bind(obj), 3000) //　3秒後に「hello John」が出力
```

## setTimeoutの第三引数以降に指定する

コメントにて言及いただきました。
setTimeoutの第三引数以降に渡す値は、実行する関数の引数として参照されます。

```js
function sayHello(name1, name2){
    console.log(`hello ${name1} and ${name2}`)
}

setTimeout(sayHello, 3000, 'John', 'Tom') // 3秒後に「hello John and Tom」が出力
```
Power Query ヘルパークエリ詳説 (2) CSVファイルの読み込み　その１

# フォルダー指定後の動作を選択

　フォルダーパスを指定した後、ダイアログの右下には、5つの選択肢があります。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/66e5f46e-b311-4810-35c7-045e8b711f3b.png"/>


### 1. キャンセル
　読み込みを中止します。
### 2. データの変換
　フォルダー内のデータをテーブル形式にしてPower Queryエディタを開きます。ファイルはまだ結合・変換がされておらず、Binaryとなっています。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/72700266-5fb3-7f38-5c18-7bfc20118c8d.png"/>

### 3. 読み込み
　2の状態でPower Queryエディタを開かず読み込みを行います。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/579408ec-c8f6-4cb8-79d3-8456c45a19d8.png"/>


### 4. データの結合と変換
 ファイルの結合・変換のためのダイアログが表示されます。
　
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/c7d98205-d1e7-93fb-5fcb-b15f9ca26f83.png"/>

　「OK」を押すと、結合・変換のためのヘルパークエリが作成され、Power Queryエディタが開かれます。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/98ec79bc-5114-fcad-5d37-15176a200958.png"/>

### 5. 結合および読み込み
　4と同様に、ファイルの結合・返還のためのダイアログが表示され、「OK」を押すと、Power Queryエディタは開かれず読み込みを行います。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/f6f1f8ef-99f9-0fc4-1ee1-6605ee1ebeca.png"/>

### どれを選べばよいのか
　フォルダーを指定してCSVファイルを読み込む場合、4番目の **「データの結合と変換」** を選択するようにします。CSVファイルが特に変換が必要ない場合は5番目の **「結合および読み込み」** を選択してもいいのですが、通常は **「データの結合と変換」** を選択するようにしましょう。

# 変換内容の補正
　正しいCSVファイルであれば、きちんとデータが読み込まれていると思いますが、エクセルをCSV形式で出力したようなファイルの場合、データを整形してやる必要があります。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/f36468cc-3097-6823-8158-30b0d2f76a92.png"/>

　変更するクエリは、 **「サンプルファイルの変換」** です。このクエリを選択して、必要なステップを追加していきます。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/38d873fb-d023-1801-6fde-ad4cfd647ffc.gif"/>

　この変更は、自動的に **「ファイルの変換」** に反映してくれます。

　ところが、この変更によって結合を行っている「気象データ」のクエリでエラーが発生してしまいました。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/0696827e-a730-4287-11d5-5a65a9c283bf.png"/>


　最期の「変更された型」でエラーが発生しています。原因は、型の変換に項目名を使っているのですが、先程の「サンプルファイルの変換」を修正した際の項目名の変更が反映されていないためです。こちらは自動では変更されないので手動で直す必要があります。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/e27a447b-b382-2970-d21c-4d5378bdfa1d.png"/>

　ステップを1つづつ選択して、エラーとなった「変更された型」を削除し、改めて型の変換を行って完成です。。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/9b3ed42e-78d5-cebb-c027-aaf86ed0212d.gif"/>
sudoなしの環境にTimes New Romanを入れてmapltotlibをいい感じにする

sudoがないのでいつも憤死しそうになる。あればaptなりyumなりで`msttcore-fonts`を入れるだけなんですけどね。。
まあ頑張りましょう。


# フォントのインストール

フォントですがあまり知られていませんが`$HOME`配下にインストールすることが可能です。
あとTimes New Romanは`msttcore-fonts`なるパッケージに入っておりRPMが入手可能ですので、ここからフォントファイルを取り出してインストールします。具体的には以下：

```bash
# RPM取り出したら`etc`と`usr`なるディレクトリが作られて後で鬱陶しいのでtmpの下で作業する
mkdir fonts_downloads
cd fonts_downloads
# `msttcore fonts RPM`とかでググるとRPM配布ページが見つかる。以下は例
wget https://rpmfind.net/linux/sourceforge/m/ms/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm
# `rpm2cpio`と`cpio`が無かったら泣きましょう。こいつらのインストール方法は知らん
rpm2cpio msttcore-fonts-installer-2.6-1.noarch.rpm | cpio -id
# うまくいけば`usr/share/fonts`の下にフォントが展開される。これを`$HOME`配下の適切なディレクトリにコピーする
# フォントインストール用のディレクトリは環境によって違うかもしれない（以下はRHEL7.8の場合）
font_install_dir=$HOME/.fonts
rsync -auv usr/share/fonts/ $HOME/.fonts/
```

# matplotlibの設定更新

キャッシュを消さないと新しいフォントを見つけてくれないらしいので消しましょう。@`matplotlib/3.6.2`
```
rm -rv .cache/matplotlib
```

フォントの設定は、`plt.rcParams`でやるのが常套だけどめんどくさい、と思っていたら`matplotlibrc`なるものがあるそうですね[^matplotlibrc]。
これ使えばスクリプトごとにrcParamsを書き直す必要がないので良いですね。

まずは自分の環境におけるmatplotlibrcの置き場所を調べましょう。
```
python3 -c 'import matplotlib as mpl; print(mpl.get_configdir())'
# 手元の（というかssh先だが）環境では`$HOME/.config/matplotlib`と出てきた
```

で、出てきたディレクトリの下にファイルを作成します。なおフォント以外の項目は趣味です。

```$HOME/.confg/matplotlibrc
font.family       : serif
font.serif        : Times New Roman
mathtext.fontset  : stix

axes.linewidth    : 0.5
xtick.major.width : 0.5
ytick.major.width : 0.5
figure.figsize    : 5.8, 4.1
font.size         : 12
```

以上です。あとは適当にプロットしたらデフォルトでTimes New Romanが有効になっています。

# テスト

```python
from matplotlib import pyplot as plt
import numpy as np

x = np.arange(0, 1, 0.01)
plt.plot(x, np.sin(2*np.pi*x), label=r'sin $2\pi x$')
plt.xlabel(r'$x$')
plt.ylabel(r'$y$')
plt.legend()
```

![hogehoge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450648/6db60b4f-4149-9579-08e9-4be5ee18d052.png)

よかったですね。


[^matplotlibrc]: https://hogelog.com/python/about-matplotlibrc.html
プリザンターのサーバースクリプトで、編集画面を開いたときのユーザーによってボタンの表示・非表示を自動で切り替える

 # はじめに

編集画面を開いた際、ログインしているユーザーが「新規作成者」、もしくは「管理者」であれば画面下部に「参照コピー」ボタンを表示し、そうでなければ「参照コピー」ボタンを非表示にする

 # ソースコード
```javascript

//ログインしているユーザーIDを取得
const loginUserId = context.UserId;
//レコードの新規作成者IDを取得
const createUserId = model.Creator;
//レコードの管理者IDを取得
const managerUserId = model.Manager;
//ログインしているユーザーIDと新規作成者ID、もしくはログインしているユーザーIDと管理者IDが同じであれば処理続行
if (loginUserId == createUserId | loginUserId == managerUserId) {
    //参照コピーボタンを表示
    elements.DisplayType('ReferenceCopyCommand', 0);
//そうでなければ処理続行
} else {
    //参照コピーを非表示
    elements.DisplayType('ReferenceCopyCommand', 3);
}

```

 # 工夫
特に工夫はない。しかし、JavaScriptには(==)と(===)で違う意味があることに今回気が付きました。詳細はほかの記事に投稿しています。