OmniAICreator/Qiita-1.07M huggingface dataset:
【Django】Auth機能とカスタムテンプレートタグによってユーザーごとにアクセス可能なボタンを表示・非表示する方法

# 概要
* 以下の記事で、Auth機能とMessageフレームワークを使ってユーザーごとにアクセス権限を設定する手順を紹介しました。今回は、アクセス権限を設定し、なおかつ、ログインユーザーにアクセス権のあるボタンのみを表示する方法を紹介します。
* 前回の記事：
    * [Auth機能とMessageフレームワークを使ってユーザーごとにアクセス権限を設ける方法](https://qiita.com/Ryo-0131/items/1b1c3367e7727e2e9ce3)

# 前提
* 前回実施した続きなので、以下は実施済みの前提です。
    * Auth機能でGroup作成＆User追加
    * メッセージフレームワークを利用するための`views`設定やルーティング設定
   
# 実施方法
* カスタムテンプレートタグを使って「`group_id`に基づいてボタンの表示・非表示を制御する」ことを行います。
    * ①カスタムテンプレートタグの作成
    * ②HTMLテンプレートの編集

## ①カスタムテンプレートタグの作成
* カスタムテンプレートタグとは、`{% if ... %}`など元から使えるビルトイン・テンプレートタグと違って、自分で独自に定義して処理や関数を呼び出すことができるタグです。
    * 参考：[【Django】カスタムテンプレートフィルタ・テンプレートタグの作り方](https://djangobrothers.com/blogs/custom_template_tags_filters/)
* まずは、アプリ内に`templatetags`ディレクトリを作成します。
* `templatetags`ディレクトリ内に`__init__.py`ファイルを作成（これは空のまま）。
* `templatetags`ディレクトリ内に`group_tags.py`ファイルを作成。以下のように記載します。

```group_tags.py
from django import template

register = template.Library()

@register.filter
def has_group(user, group_id):
    return user.groups.filter(id=group_id).exists()

```

* `has_group`というフィルターを実装しました。このフィルターは、ユーザーが指定したグループに所属しているかどうかを判定し、結果を返します。
* `@register.filter`は、カスタムテンプレートフィルタを登録するデコレータです。

## ②HTMLテンプレートの編集
* ボタン制御を行いたいテンプレートを編集します。
* まず、`group_tags`モジュールをテンプレートで呼び出すため、先頭に以下を記載します。

```django:home.html
{% load group_tags %}
```

* 次に、例えば以下のアクセス制御をしたいとします。
    * `group_id = 1` の人にはボタン「権限レベル1のボタン」を表示し、それ以外は表示しない
    * `group_id = 2` の人にはボタン「権限レベル1のボタン」「権限レベル2のボタン」を表示し、それ以外は表示しない
* 上記の場合、以下のようにテンプレートに加えます。

```django:home.html
        {% if request.user|has_group:"1" or request.user|has_group:"2" %}
          <div class="card-wrapper">
            <div>
              <button class="button color">
                <a class = "button name" href="{% url 'level1' %}">権限レベル1のボタン</a>
              </button>
            </div>
          </div>
        {% endif %}


        {% if request.user|has_group:"2" %}
          <div class="card-wrapper">
            <div>
              <button class="button color">
                <a class = "button name" href="{% url 'level2' %}">権限レベル2のボタン</a>
              </button>
            </div>
          </div>
        {% endif %}
```


* これにより、`has_group`というカスタムフィルターを使用して、`group_id`に基づいたボタンの表示・非表示を制御することができました。

## `TemplateSyntaxError at...`エラーについて
* 以下のエラーが出た場合、正しいディレクトリにカスタムのテンプレートタグが登録されていない可能性があります。`templatetags`は通常アプリケーションのディレクトリ内に作成します。正しい場所にあるかチェックしましょう。

```
TemplateSyntaxError at /home/
'group_tags' is not a registered tag library. Must be one of:
```

## ホワイトリスト方式・ブラックリスト方式
* 以上、ボタンの表示・非表示を行うことができました。
    * `or`を使うことで複数のグループのアクセス制御ができますし、この方法だと割と簡潔に実装できます。
    * 仮に、アクセス権のないURLを直打ちで打つと、前回の記事で実装したメッセージが表示されます。
* カスタムテンプレートを使っているのは、Djangoのテンプレートエンジンでは、直接条件文を使用して表示・非表示を制御することができないためです。他にもっと良い方法がある、ということがあればぜひ教えてください。
* セキュリティ対策の考え方には、ホワイトリスト方式・ブラックリスト方式という考え方があります。どちらの方が好ましいかは、サイトのセキュリティ要件や運用方針に合わせて判断すると良いと思います。
    * ホワイトリスト方式：「安全な対象」を定義 = 承認するユーザー（グループ）を決める
    * ブラックリスト方式：「危険な対象」を定義 = 拒否するユーザー（グループ）を決める
    * 参考：[ホワイトリスト、ブラックリストって何ですか？](https://salt.iajapan.org/wpmu/anti_spam/universal/measure/whitelist-blacklist/)
RaspberryPiで構築したWebアプリ（Flask）を外部公開する

### 本記事の背景
Flaskは以前の記事で簡単に構築することは可能だが、外出先からアクセスできなかった。
[Flaskの構築](https://qiita.com/akeyi2018/items/0005cebf81c7909db84d)
本記事は、Flaskで構築したサイトを外部に公開することを試みる
<b>※本記事はルータを変更するため、設定を間違えるとネットワークが一時的に使えなくなる可能性があるため、
念のため、復旧する手順をご確認の上、行ってください。

### 外部公開
ローカルサイトを外部公開する方法はいろいろあるが、今回は最も簡単な方法でやってみる
NAT転送を設定する（外部のアクセスを内部アクセスへ転送する設定）
まずは、家庭内LANは以下のような構成と想定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/6fbef9e6-a32e-c9dd-2550-b23188468a65.png)
ルーターの種類によって若干呼び名が異なる
本設定はTP-Link
### NAT設定
まずは、ルータにアクセスする（192.168.0.1)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/8b721557-b7ae-0d70-ae4c-47af6b8ba672.png)

1.IPアドレスをメモする（xxx.xxx.xxx.xxx)
2.仮想サーバーをクリックし、追加ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/13dafad7-48de-d4a8-2483-5e8d64e0ca23.png)
3.以下の項目を入れる
サービス名：HTTP
外部ポート：8080など
内部IP：RaspberryPiのIPアドレスを入力する
内部ポート：5000
プロトコル：TCP
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/d1a3296e-90c0-371e-8f1d-ea9101601f57.png)
４．OKボタンを押す
### Flask起動
５．RaspberryPiにログインし、Flaskアプリを起動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/6911ed9c-bd54-bc39-8814-1eb630853374.png)
### サイト確認
6.スマホにWIFIを切断し、外部アクセスしてみる、以下の画面が表示されたら、アクセスが成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/48c742ea-8974-3ca9-f4f0-b3ffbb6691da.png)
k3dでkubectlコマンドを実行するとthe server is currently unable to handle the requestエラーが出る

# はじめに

k3dの環境を構築したところ私の環境ではエラーがでてしまい気になったのでまとめます

# 問題

k3dでクラスターを作成して`kubectl get po`をしたところエラーがでました

```
E0406 10:16:14.156000    1794 memcache.go:287] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E0406 10:16:14.231443    1794 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E0406 10:16:14.233014    1794 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E0406 10:16:14.234844    1794 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
```

# 解決方法

以下のコマンドで一度クラスターを削除して、再作成したところうまくいきました

```
$ k3d delete cluster
$ curl -sfL https://get.k3s.io |INSTALL_K3S_EXEC="--disable traefik --disable local-storage --node-name hkm.int.h.net --node-ip 192.168.151.10 server --node-taint CriticalAddonsOnly=true:NoExecute" sh -
$ k3d create cluster
```

# おわりに

うまくいったのですが、構築した瞬間は同じエラーが出ていました
なぜか時間がたつと消えていたのでターミナルを新しくしてみるとよいかもしれないです

# 参考

https://forums.rancher.com/t/solved-k3s-only-master-gives-the-error-couldnt-get-resource-list-for-metrics-k8s-io-v1beta1-the-server-is-currently-unable-to-handle-the-request/40416/2
minikubeをアンインストールしてk3dをインストールする

# はじめに

普段業務でKubernetesを利用しますが、社内にはk3dを使っている人と、minikubeを使っている人がそれぞれいます。
私はk3dを知らなかったので、当たり前のようにminikubeを入社当時いれましたが、最近k3dに変更したのでまとめていきます

k3dにすることで毎日最初に打っていた以下のコマンドが不要になりました

```bash
$ minikube start
```

# minikubeのアンインストール

以下でうまくいきました

```bash
minikube stop
docker stop (docker ps -aq)
rm -r ~/.kube ~/.minikube
sudo rm /usr/local/bin/localkube /usr/local/bin/minikube
systemctl stop '*kubelet*.mount'
sudo rm -rf /etc/kubernetes/
docker system prune -af --volumes
```

# k3dのインストール

以下を利用しました

```bash
$ curl -sfL https://get.k3s.io |INSTALL_K3S_EXEC="--disable traefik --disable local-storage --node-name hkm.int.h.net --node-ip 192.168.151.10 server --node-taint CriticalAddonsOnly=true:NoExecute" sh -
$ k3d cluster create
```

# おわりに

k3dに先にしておけばよかったと思いました
ただクラスターが動いていなければPCてきには快適なのかもしれないです

# 参考
https://github.com/kubernetes/minikube/issues/1043
Laravel phpUnit sqlite 'no such function : Field' エラー解決した時のメモ

# 前提
Laravel, phpunitで、sqliteのインメモリー機能を使ってテストを書いてる時に、以下sql構文エラーに遭遇した
```
SQLSTATE[HY000]: General error: 1 no such function: FIELD (SQL: select * from ... by FIELD(id, 1) limit 10000 offset 0)
```

運用、開発はmysqlを使っていて、テスト時のみsqliteに切り替えるよう実装していた。
試した範囲では、FIELD関数のみエラーが出ていた。

# 結論
FIELD関数はmysqlの機能のためsqliteではエラーになってしまうようだった。
そのため、使用するDBによってFIELDを使う部分を条件分岐させることでとりあえず解決した。
```php
if (env('DB_CONNECTION') === 'mysql') {
  $this->query->orderByRaw('FIELD(' ...')');
}
```


# 参考文献
- [List sort uses FIELD function not available in SQLite](https://www.drupal.org/project/views_list_sort/issues/2992877)
- [Laravel データベース接続の設定](https://qiita.com/te-k/items/1f2deddb6808afca2f2b)
Windowsサービスを監視するスクリプトはこちらです。

# 初めに
こんにちは、山田です。
今回はWindowsサービスを監視するスクリプトを作成したので記載していきます。

# スクリプト
早速ですが今回作成したスクリプトは以下になります。
```powershell
# 配列を定義
$arr = "サービス名","サービス名"…

# AWSインスタンスメタデータ取得
Write-Output "Fetching instance ID..."
$instanceid = Invoke-RestMethod -Uri http://169.254.169.254/latest/meta-data/instance-id
Write-Output "Instance ID: $instanceid"

# 配列の要素数だけループ
for ($i = 0; $i -lt $arr.Count; $i++){
    # サービス稼働確認
    Write-Output "Checking service status for: $($arr[$i])"
    $serviceStatus = Get-Service -Name $arr[$i] -ErrorAction SilentlyContinue
    if ($serviceStatus -ne $null -and $serviceStatus.Status -eq 'Running') {
        $Processes = 1
    } else {
        $Processes = 0
    }
    Write-Output "Processes=$Processes"

    #Putコマンドを利用し、CloudWatchに送信
    Write-Output "Sending metric to CloudWatch..."
    try {
        & "C:\Program Files\Amazon\AWSCLIV2\aws.exe" cloudwatch put-metric-data --metric-name $arr[$i] --namespace "CWAgent" --region ap-northeast-1 --value $Processes  --unit "Count" --dimensions "InstanceId=$instanceid"
        Write-Output "Metric sent successfully."
    } catch {
        Write-Output "Failed to send metric: $_"
    }
}
```

# 処理内容
今回作成したスクリプトの処理内容を以下に記載します。
このスクリプトは、特定のWindowsサービスが稼働しているかどうかを確認し、その結果をAWS CloudWatchにメトリクスとして送信するものです。以下に各部分の詳細な説明を記載します。

1. **配列の定義**：`$arr`という配列に、確認したいWindowsサービスの名前を列挙します。

2. **AWSインスタンスメタデータの取得**：`Invoke-RestMethod`を使用して、現在のEC2インスタンスのIDを取得します。このIDは後のステップでCloudWatchにメトリクスを送信する際に使用されます。

3. **配列の要素数だけループ**：配列`$arr`の各要素（サービス名）に対して以下の処理を行います。

   - **サービス稼働確認**：`Get-Service`コマンドを使用して、指定した名前のWindowsサービスのステータスを取得します。サービスが存在し、そのステータスが'Running'であれば、`$Processes`に1を設定します。それ以外の場合は、`$Processes`に0を設定します。

   - **CloudWatchにメトリクスを送信**：AWS CLIの`put-metric-data`コマンドを使用して、サービスの稼働状態（`$Processes`の値）をCloudWatchに送信します。メトリクスの名前はサービス名と同じにし、インスタンスIDを次元として指定します。

このスクリプトを実行すると、指定したWindowsサービスが稼働しているかどうかの情報がCloudWatchに送信されます。これにより、CloudWatchのダッシュボードやアラームを使用して、サービスの稼働状態を監視することが可能になります。

# 動作確認
CloudWatchメトリクスを確認し、対象のサービスが監視されていることが確認できればOkです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/de640c6b-bc5f-72ab-821c-2ec3e1a16f45.png)
logback-android を使う時に logback.xml を置く場所

メモ。
Androidアプリで logback-android を使う。

gradleの設定。
```gradle:app/build.gradle
dependencies {
  implementation 'org.slf4j:slf4j-api:2.0.7'
  implementation 'com.github.tony19:logback-android:3.0.0'
}
```

設定ファイル `logback.xml` を作成。
```xml:logback.xml
<configuration>
    <appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
        <encoder>
            <pattern>%msg</pattern>
        </encoder>
    </appender>

    <root>
        <appender-ref ref="logcat" />
    </root>
</configuration>
```


logback.xml を設置する場所について、logback-android 公式で `app/src/main/assets/logback.xml` と書かれているが、これは情報が古く、
いまのAndroidプロジェクトでは `app/assets/logback.xml` です。
 
https://github.com/tony19/logback-android
【Paiza問題集】標準入力メニュー/1行目で与えられるN個の実数の入力

# Paiza問題集
Pythonで記述

## 標準入力メニュー/1行目で与えられるN個の実数の入力

### STEP1　改行区切りでのN個の実数の入力
```Python
"""
改行区切りでのN個の実数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__real_number_step1
"""

# 整数を受け取る
count = int(input())

# 配列を作成する
number = []

# 
for i in range(count):
    number_i = float(input())
    number.append(number_i)

for i in range(count):
    print(number[i])
```

### STEP2 2行目で与えられるN個の実数の入力
```Python
"""
2行目で与えられるN個の実数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__real_number_step2
"""

# 整数を受け取る
count = int(input())

# 実数をスペース区切りで格納する
number = list(map(float, input().split(' ')))

# 実数を表示する
for i in range(count):
    print(number[i])
```

### STEP3 1行目で与えられるN個の実数の入力
```Python
"""
1行目で与えられるN個の実数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__real_number_step3
"""

#　文字列を受け取る
string = input().split(' ')

# 整数を受け取る
count = int(string[0])

# 文字列をスライスする
number = list(map(float, string[1:]))

# 実数を表示する
for i in range(count):
    print(number[i])
```

### STEP4 2行目で与えられるN個の実数の入力(large)
```Python
"""
2行目で与えられるN個の実数の入力(large)
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__real_number_step4
"""

# 整数を受け取る
count = int(input())

# 実数をスペース区切りで格納する
number = list(map(float, input().split(' ')))

# 実数を表示する
for i in range(count):
    print(number[i])
```

### FINAL問題 1行で与えられるN個の実数の入力(large)
```Python
"""
1行で与えられるN個の実数の入力(large)
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__real_number_boss
"""

# 文字列を取得する
string = input().split(' ')

# 1文字目の整数を取得する
count = int(string[0])

# 文字列をスライスする
number = list(map(float, string[1:]))

# 文字列を表示する
for i in range(count):
    print(number[i])
```
PhpStormでChatGPTを使ってみた

## 初めに
PhpStormでChatGPTが使えるらしいので使ってみる。

## 導入
1. PhpStormにChatGPTをインストール
設定 > プラグイン > MarketplaceでChatGPTをインストールする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/cfe2c986-a56b-1a6f-8641-83eabe6a3b53.png)

すると右側のメニューにChatGPTが出現する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/86c5464d-1b57-e439-b4c2-ee6449818c5d.png)

ただ、このままでは使えないのでOpenAIのAPI KEYを取得します。

## ChatGPTのAPI KEYを取得 ~ 設定

1. 下記にアクセス
https://platform.openai.com/account/api-keys

2. 「Create new secret key」を押下してAPI KEYを取得
![apikey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/52d7f68c-5922-8393-2615-5d6620f62d50.png)

3. 生成したAPI KEYをコピーする
![create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/2d791872-5ff8-a400-2ff7-94fefe4dc824.png)

4. PhpStormにAPI KEYを設定する
設定 > ツール > Open AI > GPT 3.5 TurboにAPI Keyを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/6dbfbf95-ef25-cf7f-b56b-f3db92aea4db.png)


## 使ってみた
ここから質問できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/93859b30-a926-3bb0-0674-3a403816d205.png)

例えば0除算をしているコードの時
```php
$a = 0;
$b = 10;

echo $a / $c;
```
右クリック> Find Bugで不具合を見つけてくれる。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/eab14a52-c3e6-a037-c8e3-a2298a2f1ae5.png)

ただ、英語で返信が来るので「日本語で返答して」みたいなことを言うと日本語で返答してくれます。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/748c3219-3220-fbfd-a775-4e87080f9901.png)

下記のような最適化の余地があるようなコードの時
```php
$array = [0,1,2,3,4,5];

if (count(array) > 0) {
    foreach($array as $value) {
        echo $value;
    }
}
```
右クリック> Optimize codeでコードを最適化するヒントをくれる。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/f077f683-eb8d-8add-d9a4-a6d56d92e740.png)


右クリック > Custom Promptでコードに補足して質問することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/cf26d155-7a2b-69a0-fae7-eecbae18f320.png)
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112426/e7f9badc-dfef-3f76-482b-3ba5eaa30462.png)
Error: EPERM: operation not permitted, uv_cwd

## 環境
Mac OS 12.5
node v16.13.0
Next.js v13.4.2

## 経緯
Next.jsの勉強をしていて、ビルドしようとしたら、下記エラーがでた。

```terminal
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
chdir: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
chdir: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
/hoge/versions/16.13.0/lib/node_modules/npm/lib/cli.js:35
    throw err
    ^

Error: EPERM: operation not permitted, uv_cwd
    at process.wrappedCwd [as cwd] (node:internal/bootstrap/switches/does_own_process_state:126:28)
    at Object.<anonymous> (/hoge/versions/16.13.0/lib/node_modules/npm/node_modules/depd/index.js:23:24)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/hoge/versions/16.13.0/lib/node_modules/npm/node_modules/agentkeepalive/lib/agent.js:6:19)
    at Module._compile (node:internal/modules/cjs/loader:1101:14) {
  errno: -1,
  code: 'EPERM',
  syscall: 'uv_cwd'
```

パーミッションエラー。

まずはこちらのページをみつけた。

[create-react-app で "Error: EPERM: operation not permitted, uv_cwd" とエラーが起きる原因と対処法](https://qiita.com/kyo_1111/items/5678b44509f505aee89d)

しかし、ターミナルの書類フォルダへのパーミッションは設定してあった。

`Error: EPERM: operation not permitted, uv_cwd` 

というキーワードではなかなか解決できるページがみつからない。

`Error: EPERM: operation not permitted, uv_cwd deped`

というキーワードで検索。

こちらのページを発見

[internal/bootstrap/switches/does_own_process_state.js:129 の対処法](http://tech.hi-works.com/webcreative/1084)

一度上の階層に移動してから、また今の場所にもどるだけで？

そんなばかなっ！！

やってみたら見事エラーがでず、ビルドができた。

魔法ですか？
[C/C++]初心者がやりがちなミスまとめ

# はじめに
こんにちは
自分の経験に基づいて、C/C++で初心者がやりがちなプログラムのミスをまとてみました。
・コード例
・対処法
・解説
に分けて説明します。
基本的には、ビルド時にエラーとならないものが中心です。
暇な時に随時追加していくかもしれません。（今は4つだけ）
## 注意点
自分自身まだまだ初心者ですので、改善方法について、よりよい方法があるかもしれませんのでご注意お願いします。
本記事の開発環境はVisual Studio 2017となっています。
環境によっては、コンパイル時に警告となるものもあります。
## 一覧
### 1. if文で同じ値か判定する時のミス
・コード例
num1とnum2が同じ値か調べたい場合など、以下の様にしてしまうと、違う値ですが”同じ値”が出力されます。
~~~C:main.cpp
#include <stdio.h>
int main(void)
{
	int num1 = 1;
	int num2 = 2;

	if(num1 = num2)
	{
		printf("同じ値\n");
	}
    return 0;
}
~~~
・対処法
==にする。
~~~C:main.cpp
if(num1 == num2)
~~~
・解説
if文は0か0でないかで判定されます。
num1 = num2 とした場合、num1の値(2)が最終的に評価されることになるので、結果は真となってしまします。

一度はミスした方も多いのではないでしょうか。
想定外の動作が発生した場合、最終的行き着くのはこのミスだった場合が多々あります。

### 2. if文で複数のORの条件を比較したい時のミス
・コード例
num変数が1か2か3であることを調べたい場合、以下の様にしてしまうと正しく評価されません。
~~~C:main.cpp
#include <stdio.h>
int main(void)
{
	int num = 0;
	if(num == 1 || 2 || 3)
	{
		printf("1か2か3");
	}
	return 0;
}
~~~
・対処法
以下の様にする
~~~C:main.cpp
	if(num == 1 || num == 2 || num == 3)
~~~
もしくは、コードを大幅に変更しないと駄目な可能性はあるが、ロジックを見直す。
比較対象が大量にある場合は、以下のような形が効果的。
~~~C:main.cpp
#include <stdio.h>
int main(void)
{
	int num = 0;
	int comp[] = { 1,2,3 };
	bool result = false;
	for(int i = 0; i < (int)(sizeof(comp) / sizeof(comp[0])); i++)
	{
		if(num == comp[i]) 
		{
			result = true;
			break;
		}
	}
	
	if(result)
	{
		printf("true");
	}

	return 0;
}
~~~
・解説
==の方が比較の優先順位が高いため、if(num == 1 || 2 || 3)の場合は、if((num == 1) || 2 || 3)
となります。さらに置き換えると if( 偽 || 真 || 真 )になってしまうので、この結果は真になります。

「num変数が、1か2か3」の日本語をそのままプログラムにすると、上記の様な形となるので、初心者は最初の1度だけミスるかもしれません。
### 3.if文の中括弧を省略した場合のミス
・コード例
結果が真の場合に、hoge1,hoge2を出力させたい場合、以下の様にしてしまうと、結果が偽の場合でもhoge2が出力されてしまいます。
~~~C:main.cpp
#include <stdio.h>
int main(void)
{
	int num = 0;
	if(num == 1)
		printf("hoge1\n");
		printf("hoge2\n");

	return 0;
}
~~~
・対処法
中括弧をつけましょう。
~~~C:main.cpp
	if(num == 1)
    {
		printf("hoge1\n");
		printf("hoge2\n");
    }
~~~
・解説
if文は中括弧を省略することができます。
ただし、省略した場合実行されるのは次の1行のみです。
上記の場合などは、hoge2はif文の外側となってしまう為、if文の結果に関わらず実行されることになります。

最初は中括弧を省略していて、後からもう1行のみ追加した場合などにたま～にあるので、if文では中括弧を必ず付けるのがおすすめです。
### 4. 二重ループでのミス
・コード例
3×3のループ、9回分出力したい場合に、以下の様にしてしまうと正しく出力できません。
（無限ループになります）
~~~C:main.cpp
#include <stdio.h>
int main(void)
{
	for(int i = 0; i < 3; i++)
	{
		for(int j = 0; j < 3; i++)
		{
			printf("出力\n");
		}
	}

	return 0;
}
~~~
・対処法
内側のfor文が間違っているので修正する。
~~~C:main.cpp
		for(int j = 0; j < 3; j++)
~~~
また、i、jなどの変数名でなく、目的にあった変数名を付けるのもおすすめです。
例：縦3行　横3行の何らかの処理をしたい場合
~~~C:main.cpp
#include <stdio.h>
int main(void)
{
	for(int tate = 0; tate < 3; tate++)
	{
		for(int yoko = 0; yoko < 3; yoko++)
		{
			printf("出力\n");
		}
	}

	return 0;
}
~~~
・解説
今でも偶にミスリます。
上記のコード例の場合、jに加算されていないので、 j < 3　の条件が偽なることはない為、無限ループになってしまいますね。

以上、他にも挙げだすとキリが無いですが、自分がハマったことのあるミスを紹介しました。
覆面算の穴埋め

覆面算を解くプログラムをPythonで作りました。
READ + WRITE + TALK = SKILL のアルファベットを数字に置き換えて、覆面算を解きます。
最上位に0は含みません。
違うアルファベットには違う数値が入ります。

```python
import copy

def main():

    l_r = [ii for ii in range(10)]

    for r in l_r:
        l_e = remove_list_method(l_r,r)
        for e in l_e:
            l_a = remove_list_method(l_e,e)
            for a in l_a:
                l_d = remove_list_method(l_a,a)
                for d in l_d:
                    l_w = remove_list_method(l_d,d)
                    for w in l_w:
                        l_i = remove_list_method(l_w,w)
                        for i in l_i:
                            l_t = remove_list_method(l_i,i)
                            for t in l_t:
                                l_l = remove_list_method(l_t,t)
                                for l in l_l:
                                    l_k = remove_list_method(l_l,l)
                                    for k in l_k:
                                        l_s = remove_list_method(l_k,k)
                                        for s in l_s:

                                            if r == 0 or w == 0 or t == 0 or s == 0:
                                                continue

                                            one = (r * 1000) + (e * 100) + (a * 10) + d
                                            two = (w * 10000) + (r * 1000) + (i * 100) + (t * 10) + e
                                            three = (t * 1000) + (a * 100) + (l * 10) + k
                                            ans = (s * 10000) + (k * 1000) + (i * 100) + (l * 10) + l

                                            if one + two + three == ans:
                                                print(one," + ",two," + ",three," = ",ans)

def remove_list_method(l_c,d):

    l = copy.copy(l_c)
    l.remove(d)

    return l

if __name__ == "__main__":
    main()
```

```python
l_r = [ii for ii in range(10)]
```

l_rリストに、[0,1,2,3,4,5,6,7,8,9]のリストを作って、r,e,a,d,w,i,t,l,k,sの必要なアルファベットのfor文を入れ子構造にして回していきます。
その際に、次のforループに入る前に、remove_list_methodで一つ前のループで使ってるリストから、一つ前のループの現在の数値を削除して、そのリストを次のループの探索リストにする事で、重複数値を回避します。
これで、違うアルファベットには違う数値が入ります。

```python
if r == 0 or w == 0 or t == 0 or s == 0:
    continue
```

ここで、READ、WRITE、TALK、SKILLのそれぞれの最上位、R、W、T、Sが0だった場合は、continue文で、ループ処理を1つ進めます。

```python
one = (r * 1000) + (e * 100) + (a * 10) + d
two = (w * 10000) + (r * 1000) + (i * 100) + (t * 10) + e
three = (t * 1000) + (a * 100) + (l * 10) + k
ans = (s * 10000) + (k * 1000) + (i * 100) + (l * 10) + l

if one + two + three == ans:
    print(one," + ",two," + ",three," = ",ans)
```

oneにREAD、twoにWRITE、threeにTALK、ansにSKILLのアルファベットに対応する数値を代入して覆面算が成り立つか、if文で判定します。
判定が真なら表示します。
結果は、

```
1632  +  41976  +  7380  =  50988
2543  +  72065  +  6491  =  81099
4905  +  24689  +  8017  =  37611
5094  +  75310  +  1962  =  82366
5096  +  35710  +  1982  =  42788
5180  +  65921  +  2843  =  73944
5270  +  85132  +  3764  =  94166
7092  +  37510  +  1986  =  46588
7092  +  47310  +  1986  =  56388
9728  +  19467  +  6205  =  35400
```

の10通りが答えです。
拡張子とは

## 拡張子 (extension) 

ファイルの名前の末尾に付けられる文字列のことでドット（.）の後に続く一連の文字で構成されている
EX)"example.txt"というファイル名では、".txt"が拡張子にあたる

主にコンピューターシステムでファイルの種類を示すために使用される
→オペレーティングシステムやアプリケーションがファイルを識別し、関連付けられた処理やアプリケーションを適用できる

## 一般的なファイルの拡張子とその意味

.txt: テキストファイル
.jpg, .png, .gif: 画像ファイル
.doc, .docx: Microsoft Word文書
.xls, .xlsx: Microsoft Excelスプレッドシート
.pdf: ポータブルドキュメントフォーマット (PDF)
.mp3, .wav: 音声ファイル
.mp4, .avi, .mov: 動画ファイル
.html, .css, .js: ウェブページ関連のファイル
.exe: 実行可能ファイル (Windows)
【便利ツール】クオーテーションなしの文字列をHTMLのタグにぶち込みたい人が参考にする記事はこちら！

## フツーに困った
あるWebアプリを作ろうとしたとき、API呼び出しに使える国略称をプルダウンするために**HTMLのoptionタグ**で囲みたかったのに、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958610/8a16c375-009e-9077-0a1a-e2c4ca705542.png)

[APIページ](https://hellosalut.stefanbohacek.dev/hello/)に載っている国略称一覧が、**クオーテーションすらないベタ打ち文字**だった:scream:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958610/fecf3bca-c14e-37e6-c15b-cf347dd6bd32.png)


## 自由に使ってね
ぱっと使えるコードがすぐには見つからなかったから、とりあえず**Python**で作ったよ。
```python:addTags.py
nations = 'ar, az, be, bg, bn, bs, cs, da, de, dz, el, en, en-gb, en-us, es, et, fa, fi, fil, fr, he, hi, hr, hu, hy, id, is, it, ja, ka, kk, km, ko, lb, lo, lt, lv, mk, mn, ms, my, ne, no, pl, pt, ro, ru, sk, sl, sq, sr, sv, sw, th, tk, uk, vi, zh'

nations_list = nations.split(', ')

for nation in nations_list:
    print("<option>" + nation + "</option>")

print(nations_list)
```

リストの中身をそのままprintしたから、ついでにクオーテーション付きの国略称をコピペすることもできるよ～

<details><summary>出力結果</summary>

```HTML:
<option>ar</option>
<option>az</option>
<option>be</option>
<option>bg</option>
<option>bn</option>
<option>bs</option>
<option>cs</option>
<option>da</option>
<option>de</option>
<option>dz</option>
<option>el</option>
<option>en</option>
<option>en-gb</option>
<option>en-us</option>
<option>es</option>
<option>et</option>
<option>fa</option>
<option>fi</option>
<option>fil</option>
<option>fr</option>
<option>he</option>
<option>hi</option>
<option>hr</option>
<option>hu</option>
<option>hy</option>
<option>id</option>
<option>is</option>
<option>it</option>
<option>ja</option>
<option>ka</option>
<option>kk</option>
<option>km</option>
<option>ko</option>
<option>lb</option>
<option>lo</option>
<option>lt</option>
<option>lv</option>
<option>mk</option>
<option>mn</option>
<option>ms</option>
<option>my</option>
<option>ne</option>
<option>no</option>
<option>pl</option>
<option>pt</option>
<option>ro</option>
<option>ru</option>
<option>sk</option>
<option>sl</option>
<option>sq</option>
<option>sr</option>
<option>sv</option>
<option>sw</option>
<option>th</option>
<option>tk</option>
<option>uk</option>
<option>vi</option>
<option>zh</option>
['ar', 'az', 'be', 'bg', 'bn', 'bs', 'cs', 'da', 'de', 'dz', 'el', 'en', 'en-gb', 'en-us', 'es', 'et', 'fa', 'fi', 'fil', 'fr', 'he', 'hi', 'hr', 'hu', 'hy', 'id', 'is', 'it', 'ja', 'ka', 'kk', 'km', 'ko', 'lb', 'lo', 'lt', 'lv', 'mk', 'mn', 'ms', 'my', 'ne', 'no', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sq', 'sr', 'sv', 'sw', 'th', 'tk', 'uk', 'vi', 'zh']
```
</details>
GitHubからレビューを抽出しよう

## 課題
弊社ではレビューコメントに対してフォーマットを指定する規則を設けている。
規則を設けた者として運用の評価を行いたいが、手動でのデータ集計に手間がかかる。

### 解決方法
GitHubではAPIが設けられているのでこれを利用する。
https://docs.github.com/ja/rest
https://docs.github.com/ja/graphql

#### RESTとGraphQL
APIが2種類提供されているが今回は「GraphQL」形式を選択した。

##### 理由
* GraphQLが実装されたAPIを触ってみたかったから
* APIの呼び出しが１つで、欲しいオブジェクト毎にエンドポイントが変わらない事
* Enterprise版とドキュメントが共通っぽい（REST APIはドキュメントが違って苦労した）

## Let's 開発
という訳で抽出するプログラムを作っていく。

### 抽出の仕様

* 団体"organization"を指定する
* リポジトリ"repository"を指定する
* 抽出期間（開始日～終了日）を指定する

#### 抽出１：対象のプルリクを抽出する
過去の評価が目的なのでクローズ済みかつマージされたプルリクのみ抽出します。
do whileで回しつつ`hasNextPage`がFALSEになるまで取得させるよ。

```php
$pr_query_string = implode(' ', [
    "repo:{$org}/{$repo}",
    'is:pr',
    'is:closed',
    'is:merged',
    'merged:2023-05-08..2023-05-12',
    'sort:updated-desc',
]);

$request_string = <<< __EOF
{
    search(type:ISSUE, query: "{$pr_query_string}", first: 100, after: null) {
        issueCount
        pageInfo {
            hasNextPage
            endCursor
        }
        nodes {
          ... on PullRequest {
            number
            title
          }
        }
    }
}
__EOF;
```

##### 参考

https://docs.github.com/ja/graphql/reference/queries#search

https://docs.github.com/ja/search-github/searching-on-github/searching-issues-and-pull-requests


### 抽出２：対象プルリクからレビューを抽出する
１で抽出したプルリク番号を基に指定プルリクのレビューコメントを抽出するクエリを逐次実行させます。弊社ではプルリクは小さく切る方針なので、レビュー個数や１レビューのスレッドが100を超えることは無い。無いよね？もし、溢れるような巨大なプルリクを作る方針なら、各コネクションのpageInfoからカーソルを取って適当にページネーションを実装しましょう。

```php
$request_string = <<< __EOF
{
    repository(owner: "{$org}", name: "{$repo}") {
        pullRequest(number: {$pr_number}) {
            title
            reviews(first: 100) {
                totalCount
                nodes {
                    commit {
                        author {
                            name
                        }
                    }
                    comments(first: 100) {
                        totalCount
                        nodes {
                            body
                            author {
                                login
                            }
                        }
                    }
                }
            }
        }
    }
}
__EOF;
```

また、GitHub APIでは一度のリクエストで取得できるオブジェクト数に上限があるので注意して設計してください。

https://docs.github.com/ja/graphql/overview/resource-limitations

#### 参考

https://docs.github.com/ja/graphql/reference/objects

## GraphQLを使ってみた所感

今回の規模なら1個のリクエストで全部取得できたかもしれないが、長期間の抽出を考慮するとオブジェクト上限に引っ掛かりそうな予感がしたのでリクエストを2段階に分けました。
[REST API](https://docs.github.com/en/enterprise-server@3.1/rest/pulls/comments#list-review-comments-in-a-repository)だとレビュワーのユーザーは取れるけど、レビューイ（レビュー受ける = コミットした人）のユーザー情報を取るには別途で[個別のコミット情報を取得するAPI](https://docs.github.com/ja/rest/commits/commits?apiVersion=2022-11-28#get-a-commit)をリクエストする必要がある。つまり、レビューコメントの数だけ追加リクエストする必要があった。しかし、GraphQLだと1回のクエリで取得できたのでGraphQLのメリットを享受できた感じはある。
【Paiza問題集】標準入力メニュー/N個の文字列の入力

# Paiza問題集
Pythonで回答

## 標準入力メニュー/N個の文字列の入力

### STEP1 改行区切りでのN個の文字列の入力
```Python
"""
改行区切りでのN個の文字列の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__string_number_step1
"""

# 整数を受け取る
count = int(input())

# 配列を作成する
string = []

# countの回数、文字列を受け取り配列に追加する
for i in range(count):
    string_i = input()
    string.append(string_i)

# 配列を表示する
for i in range(count):
    print(string[i])
```

### STEP2 2行で与えられるN個の文字列の入力
```Python
"""
2行で与えられるN個の文字列の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__string_number_step2
"""

# 整数を受け取る
count = int(input())

# スペース区切りで格納する
string = list(input().split(' '))

# 文字列を表示する
for i in range(count):
    print(string[i])
```

### STEP3 1行目で与えられるN個の文字列の入力
```Python
"""
1行目で与えられるN個の文字列の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__string_number_step3
"""

# 文字列をスペース区切りで取得する
string = list(input().split(' '))

# 1文字目の整数を受け取る
count = int(string[0])

# 1文字目をスライスする
string = string[1:]

# 文字を表示する
for i in range(count):
    print(string[i])
```

### STEP4 2行目で与えられるN個の文字列の入力
```Python
"""
2行目で与えられるN個の文字列の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__string_number_step4
"""

# 整数を受け取る
count = int(input())

# 文字目をスペース区切りで受け取る
string = input().split(' ')

# 文字列を表示する
for i in range(count):
    print(string[i])
```

### FINAL問題 N個の文字列の入力
```Python
"""
N個の文字列の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__string_number_boss
"""

# 文字列をスペース区切りで格納する
string = input().split(' ')

# 1文字目の整数を取得する
count = int(string[0])

# 文字列をスライスする
string = string[1:]

# 文字列を表示する
for i in range(count):
    print(string[i])
```
Power Automate で SharePoint リストの投稿内容を Teams に投稿する（添付ファイル付き）

# SharePoint リストに投稿された内容を添付ファイル付きで Teams に投稿する Power Automate フローの作成
SharePoint リストに投稿されたニュース等の情報を Teams にも投稿し読めるようにします。その際添付ファイルがあった場合に Teams の投稿にも添付ファイルをリンクで開けるように URL を添付できるよう工夫してみました。
## フローの全体図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/62fbc757-e23d-36bc-030c-35580c75fd89.png)
今回は検証用にフローを作成しているので最低限のフローとなっています。
## 実装
まずは SharePoint リストに項目が作成されたときをトリガーとして設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/57eab6d6-babd-5791-d898-d88a1342b839.png)
次に添付ファイルがある場合、リンクを作成して保存ておくための変数を用意しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/e598c071-916c-ca36-2bfe-b6db39d83926.png)
添付ファイルがない場合、リンクが不要となるので条件フローを利用して添付ファイルの有無を判定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/60ba969e-b586-e3fc-8ec3-fa7e2655d327.png)
「項目が作成されたとき」で取得した「添付ファイルあり」を条件として「次の値に等しい」で「true」としています。

まずは添付ファイルがない場合の「いいえ」側のフローを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/098b6e74-67b9-9d2a-f685-1c89a49a11ca.png)
「チャネル内のメッセージで応答します」フローを利用し、「Flow bot」で投稿していますが、メンションを行う場合には「User」で設定しましょう。
投稿する内容は「本文」と今回は「登録者 DisplayName」を設定し、SharePoint リストを登録したメンバーを表示するようにしてみました。

次に添付ファイルがある場合の「はい」側のフローを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/476275ac-b72e-a776-fecc-59cc3dff10cf.png)
まずは「添付ファイルの取得」フローを利用して添付ファイルの情報を取得します。複数のファイルが添付されている可能性もあるので、この情報を元に「Apply to each」フローを利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/62dc951e-5bb8-c81a-ca8c-d3c7f5717c9b.png)
「以前の手順から出力を選択」には直前で取得した「添付ファイルの取得」から「本文」を設定します。先に作っておいた「Link」変数を「文字列変数に追加」フローを利用し値には html のリンク形式で文字列として追加していきます。
```html
< href="[添付ファイルの取得から添付ファイルへのリンクを指定]">[添付ファイルの取得から名前を指定]</a><br>
```
最後に「チャネル内のメッセージで応答します」フローにて分岐の「いいえ」側の設定とほぼ同じですが、本文に「Link」変数を追加する形で登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/4bfacf30-81b7-5203-7bb8-1a3c264fa48d.png)
## 実際の投稿内容
実際に SharePoint リストに投稿すると以下のように Teams にも投稿されます。本文に`<hr>`を入れてみる等工夫をするとより見やすくなると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/cdfc27f9-0d2c-d21c-0b4e-95d8d7f7ac49.png)
※ 画像は`<br>`を入れる前のテストなのでファイル名が繋がっています。
## まとめ
SharePoint リストに投稿された内容をメールにて配信する方法を取っていましたが、メールは外部からの重要な情報に集約するため内部の連絡は Teams に集約することとしたので、Teams でも投稿内容が分かるようにするためのフローを検討しました。
添付ファイルを Teams 側にコピーするような手法も見られましたが、複数のファイルが点在するのはよろしくないためリンクを表示して SharePoint リストの添付ファイルを直接開く方法としています。
実際には Teams 上でリンクをクリックするとブラウザが開いて SharePoint のアイテムを表示しようとしますので、ブラウザでサインインしている必要があることを注意してください。
DDSP-SVCを用いた音声変換モデル（３）

これから学習に入ります。

\DDSP-SVC\configsの中のcombsub.yamlを修正します。num_workersとbatch_sizeは自分の環境に合わせて修正しても大丈夫です。

encoder: 'contentvec'
encoder_out_channels: 256
encoder_ckpt: pretrain/hubert/checkpoint_best_legacy_500.pt
cache_device: 'cuda'
num_workers: 2
batch_size: 8

修正が終わったらしたのコマンドを入れてください。

```
python train.py -c configs/combsub.yaml
```

\DDSP-SVC\exp\combsub-testの中に2000Stepごと保存されます。
IBMi駆け出し日記：iのファイルシステム(IFS)を理解する

# 統合ファイルシステム(IFS)って何？
統合ファイルシステム(Integrated File System)とはiのファイルシステムのことです、「IBM iって独特だから難しいんだよね〜」となる要因の一つだと思っています。
ACSにも目立つところにありますよね。
![スクリーンショット 2023-05-18 12.43.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/c1c2aca2-2884-4739-a04a-b2bd6b3665f1.png)

:::note warn
IBMi初心者向けにざっくり理解で書いていきます。
:::
もっと詳細なIFSについての参考記事
[i Magazine-IBM iとファイル・システム-](https://www.imagazine.co.jp/imagazine-7263/)

## IFSの構造
Open系(Linuxとか)のファイルシステムにIBMi固有のファイルシステムがくっついているイメージで持っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/9efff05c-e8d8-33ed-eb11-ca73f7a300bf.png)


QSYS.LIBとかhomeとかはサブディレクトリです。


5250画面では`WRKLNK /`でoption5で辿るとサブディレクトリがみられます。
![スクリーンショット 2023-05-18 15.06.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/42dd38ab-d099-39af-8bb2-c5a02853e44e.png)

homeやQIBMはOpen系と同様に多くの階層があるツリー構造です、
実際に`WRKLNK ('/QOPensys/bin/admin')`のような感じで下の階層に潜ることができます。

## ライブラリーシステムとコマンド操作

一方でQSYSLIBに該当するライブラリー・オブジェクトはこのような多重階層構造を持たず、2階建です。
ライブラリーの下にオブジェクト、DBテーブル（物理ファイル）とソースファイル（SRCPF）限定ですが、その下にメンバーがぶら下がっています。

AS400時代からのシステムオブジェクト(RPGIIIとか)が格納され、[EBCDIC](https://e-words.jp/w/EBCDIC.html)で記述されているために使い勝手が違うらしい。

`WRKLNK /`で辿ることもできますが、ライブラリとオブジェクトとメンバーが一気に表示されて非常に見にくいです、ので`DSPLIB`で見てみることをお勧めします。
ライブラリが表示され、option5で潜るとオブジェクトの詳細を見ることができます。
![スクリーンショット 2023-05-18 15.59.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/d4bfc1c5-7f2b-7ce3-3948-a68c0c1a7956.png)

ライブラリに入っているオブジェクトが表示されている
![スクリーンショット 2023-05-18 16.18.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/dcd44236-55ae-b2e0-9dd3-95c2fc919a6a.png)

5で詳細を見ることができる
![スクリーンショット 2023-05-18 16.18.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/044485d8-8534-f849-ebf2-d03d1124428a.png)

オブジェクトとメンバーの編集を行う場合は`STRPDM`で行います。
![スクリーンショット 2023-05-18 15.48.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/5d5b093e-51d6-1806-419e-302c18ef2f16.png)

例えば、2.work with objectsでQSYSライブラリーを表示すると、各オブジェクトに対して操作ができます。
![スクリーンショット 2023-05-18 16.24.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212743/e7572aed-d2f4-70a9-0afb-4695044bb116.png)
SSL certificate problem: certificate is not yet valid

非常にまれに起こる問題かなと思うけど、時間かかったので、メモする。

# 問題
WindowsのwslでのLinux環境で、会社のgitlabにアクセスしようとしたとき、下記のエラーが出た。
```
$ git pull origin main
fatal: unable to access 'http://gitlab.****/***.git/': SSL certificate problem: certificate is not yet valid
```

いつもの通りの操作だけど、今日突然エラーが出ている...

追記、
gitlabだけでなく、ほかのメンバーも似たようなエラーが出ており、下記の解決策で解決できた。

```
cause: Error: certificate is not yet valid
      at TLSSocket.onConnectSecure (node:_tls_wrap:1545:34)
      at TLSSocket.emit (node:events:513:28)
      at TLSSocket.emit (node:domain:489:12)
      at TLSSocket._finishInit (node:_tls_wrap:959:8)
      at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:743:12) {
    code: 'CERT_NOT_YET_VALID'
  }

```


# 解決策

いろいろ検索してたけど、解決できてなくて、最後にchatGBTに聞いたところ、解決した。

解決方法がすごいシンプルで、ちょっとわけわからないけど、念のため残しておく。

**システム時間を正確な時間にすること**

1. いまのシステム時間を確認する

    WSLでの時間が昨日の日付になっていることがわかった。

    ```
    $ date
    Wed May 17 12:10:09 JST 2023
    ```

2. システム時間を正確な時間に修正する

    ```
    sudo timedatectl  set-time 2023-05-18
    sudo timedatectl  set-time 14:17
    
    $ date
    Thu May 18 14:17:01 JST 2023
    ```
そうしたら、エラーが消えた。


chatGBTの回答によると、システム時間がずれていて、証明書の有効期限外になったことが原因。

しかし、証明書の有効期限を確認したら、問題なさそう。
有効期限が May 8, 2023, at 18:01:02 GMT ~ August 6, 2023, at 18:01:01 GMT　なので、
時間がずれていても、有効期限内になっているはず。

```
$ echo | openssl s_client -servername hostname -connect gitlab.lookingup.co.jp:443 2>/dev/null | openssl x509 -noout -dates
notBefore=May  8 18:01:02 2023 GMT
notAfter=Aug  6 18:01:01 2023 GMT
```

結論としては、システム時間を修正することで、問題解決したけど、原因はわかんない。謎。

## 追記

最近社内サービスサーバに接続する時も、似たようなcertificate is not yet validエラーが出ていて、
同じ解決方法でやってみたら、解決した。

今度は手動で時刻修正よりは、NTPサーバー設定をした。

参照：[AlmaLinux8：NTPサーバー設定（Chrony）
](https://centossrv.com/almalinux/chrony.shtml)

## その他の解決案

stackOverflow上では似たような質問が出ているけど、
[Unable to access gitlab: SSL certificate has expired](https://stackoverflow.com/questions/60024912/unable-to-access-gitlab-ssl-certificate-has-expired),

一番簡単な方法は、git のssl検証プロセスを禁止することだそう。
```
git config --global http.sslVerify "false"
```

すごい乱暴な解決方法だけど、すぐ効いた。

ただこれで一律に禁止するのはセキュリティ上で問題になるので、やめた方がよいだそう。

gitlabのhttps証明書を改めてダウンロードする方法も見かけたけど、うまくいってなくて、あきらめた。
Vue.jsのSFCでscript、template、styleを別ファイルにする

# 結論

1. ディレクトリ名をコンポーネント名にする（例：`SampleComponent`）
1. 1. のディレクトリ内に`index.vue`、`template.html`。`style.css`をそれぞれ配置する
1. `index.vue`の内容を以下の様にする

```vuejs:@/components/SampleComponent/index.vue
<script>
// ここにスクリプトコードを書いていく
import { defineComponent } from "vue";

export default defineComponent({
    name: "sample-component", //<- 必須
});
</script>

<template src="./template.html"></template> 

<style src="./style.css" scoped></style>
```

```vuejs:App.vue
<template>
    <SampleComponent />
</template>

<script>
import { defineComponent } from "vue";
import SampleComponent from "@/components/SampleComponent"

export default defineComponent({
    components: { SampleComponent },
});
</script>
```

# 参考

## ディレクトリ構造

* 📂src
    * :clipboard:App.vue
    * 📂components
        * 📂SampleComponent
            * :clipboard:index.vue
            * :clipboard:template.html
            * :clipboard:style.css

※SFCじゃなくなってるっつーツッコミは無しで。

了
Docker+PHPの開発でrailsのpryみたいにデバッグする

# はじめに
PHPのデバッグ方法をググると`var_dump`か`dd`、`Log`をコード内に仕込むという記事が見つかります。
しかし、Rubyの`binding.pry`を経験してからだとこれは効率悪いと感じるのではないでしょうか。
変数1つずつ確認するために追記して実行してログを見てまた修正して実行して..という苦行はしたくないです。

PHPだとPsySHを使えばpryのようなデバッグができるということで、この記事ではPsySHをDokerの開発で使うために試したことを記載します。

# Rubyのbinding.pryとは
binding.pryは、アプリケーションサーバの実行を中断してデバッグできる便利機能です。
ブレークポイントをしかけた場所で動作が止まり、そこのスコープでRubyのコードが対話的に書けます。

処理を止めたところで有効な変数やその中身の確認、関数なども実行できて結果もすぐわかります。
しかもこれがview、controller、modelのほぼどこでも記載すれば処理を一時的に止めることができるのでかなりデバッグしやすいです！

# PHPでデバッグ
やり方は、下の3つだけです。
 1. docker-compose.ymlにportsを追記する
 2. `$ docker-compose exec app php -S 0.0.0.0:8000 -t public`でサーバー起動
 3. デバッグしたいところに`eval(\Psy\sh());`を入れる

順番に設定からデバッグするところまでを記載します。
docker-composeを使用した例で、laradockなども同様に行えると思います。

まず、php用のコンテナにportsを追加します。

```docker-compose.yml
version: '3.7'
services:
  app:
    build: ./api-server
    container_name: php
    volumes:
      - ./api-server:/var/www/html
      - ./php/php.ini:/usr/local/etc/php/php.ini
    working_dir: /var/www/html
    # 追加
    ports:
        - "8001:8000"
  nginx:
    image: nginx:stable-alpine
    container_name: nginx
    ports:
      - 8000:80
    volumes:
     ...（省略）
  mysql:
    image: mysql:8.0
  ...（省略）
```

`docker-compose up -d`などした後にプロジェクトのルートディレクトリでサーバーを起動します。
```shell
$ docker-compose exec app php -S 0.0.0.0:8000 -t public
```

localhost:8001 に向けてリクエストを実行してサーバーにログが出ればOKだと思います。
例）`curl http://localhost:8001/health-check`
![スクリーンショット_2023-05-17_11_11_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921076/28e150ee-46e6-f2d2-7626-ab69ed99cf7f.png)


あとはお好きなところに`eval(\Psy\sh());`を記載してプログラムを動かすと処理が止まって対話的にデバッグができると思います！
終わる時は`exit`とすれば続きの処理が再開されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921076/e74d0ef7-042c-0653-cb6c-8928818922e2.png" width=65%>

今回の例ですと、`$user`や`$params`の値が確認できています。変数以外の関数も実行できたりするので良いと思っています。
少し設定を加えるだけで導入できるので、Rubyの開発からPHPに移行してきて間もない方、Docker+PHPでデバッグ方法に困っている方の参考になれば幸いです。
Re:Earthでクリックした位置の緯度経度を取得し表示する

## 結論
最終的なアウトプット
```
const html = `
    <style>
      body {
            margin: 0;
            padding: 10px;
            background-color: #fff;
        }
    </style>
    <div>
      <p>lat： <span id="lat">-</span></p>
      <p>lng： <span id="lng">-</span></p>
    </div>
    <script>
    // クリックした位置のx軸、y軸を取得
    var targetElement = parent.document.querySelector(".cesium-widget");
    targetElement.addEventListener("click", function(event) {
        var x = event.pageX;
        var y = event.pageY;
        // Re:Earth UI側にx、y軸データを送信
        parent.postMessage({ type: "clickEvent", x: x, y: y }, "*");
    });

    // reearth.ui.postMessageで送信されたデータを処理
    window.addEventListener("message", function (e) {
        if (e.source !== parent) return;
        document.getElementById("lat").textContent = data.lat;
        document.getElementById("lng").textContent = data.lng;
    });
`;
reearth.ui.show(html);

let latLngHeight = {};
reearth.on("message", (msg) => {
  // 受け取ったx,y軸データを元に緯度経度データを取得
  if (msg.type === "clickEvent") {
    latLngHeight = reearth.scene.getLocationFromScreen(msg.x, msg.y);
    reearth.ui.postMessage(latLngHeight);
  }
});
```

## 解説

### クリックした位置の緯度経度を取得する

- Re:Earth UIの画面がクリックされたら、画面の位置情報を取得する
    - Re:Earth UI画面の地図が表示されている範囲を設定
    `var targetElement = parent.document.querySelector(".cesium-widget");`
    - clickイベントでカーソルのx,y軸を取得
    `targetElement.addEventListener("click", function(event) {...});`
    - x,y軸の情報をpostMessageでRe:Earth UI側に送信
    `parent.postMessage({ type: "clickEvent", x: x, y: y }, "*");`


- 画面の座標から緯度経度を取得する
    - postMessageで送信されたデータを受け取る
    `reearth.on("message", (msg) => {...});`
    - 受け取ったx,y軸データを元に緯度経度データを取得
    `reearth.scene.getLocationFromScreen(msg.x, msg.y);`

### 緯度経度をHTML内に表示する
- `reearth.ui.postMessage` でHTMLにデータを送信
- データを受信して画面に表示
  `window.addEventListener("message", function (e) {表示処理}`


## 参考
[🎉Re:Earth v0.13.0 がリリースされました！](https://reearth.io/ja/blog/2022/12/7/release-v0130)
[プラグインの仕組み](https://docs.reearth.io/ja/plugin-guide/how-plugins-work/#webassembly)
ChatGPTにしれっとContinue generatingボタンが追加された

### Continue generating
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953179/68f704dd-c67f-2847-8aee-c203d59dd1da.png)

ChatGPTの出力が途中で止まった際にこのボタンを押すと、回答と回答の間にgo onだったり続き、と送ることなく、そのまま続きから出力が再開される。

プラグイン及びブラウジングのインパクトが大きすぎて気づかなかった。
特にPythonのコードを出力してもらう時に、回答が２回以上に分かれると、インデントがズレたり、続きのコードがエディタ形式ではなくなり、ただのテキストとして出力されてしまうことがあったが、しっかりと止まった部分からそのまま続きのコードが出力されるようになった。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953179/67ebc0b1-82a9-0ac3-69ee-a5500a44bb2b.png)
ディレクトリの統合や同期を行う時に便利なコマンドrsyncの使い方

gitを使うべきなのは百も承知なのですが、わけあって↓のような流れで作業する機会があったのでメモ
# 状況
`dirDev` ←開発用のデータが入ったディレクトリ（コピー元）
`dirProd` ←本番用のデータが入ったディレクトリ（コピー先）
があるとします。
dirDevを編集して開発→確認OK！となった場合、編集した分だけdirProdに反映したい、一部の開発用のファイルなどを除外して同期したい、みたいな状態。

# 基本：ディレクトリの統合と更新
コピー元`dirDev`で編集したファイルの変更をコピー先`dirProd`に反映（上書き保存）、新規追加したファイルをそのまま追加したい場合
```
$ rsync -av --update /path/to/dirDev/ /path/to/dirProd/
```

:::note warn
パスの最後のスラッシュをつけ忘れると違った挙動になってしまうので注意
:::

### 各オプションの説明
`-a` アーカイブモードで同期を行います。再帰的にディレクトリをコピーし、パーミッションや所有者などの属性情報を保持します。

`-v` 詳細モードで同期を行います。コピーされるファイルやディレクトリの名前を表示します。

`--update` 更新されたファイルのみをコピーします。コピー元とコピー先のファイルのタイムスタンプを比較し、コピー元のファイルの方が新しい場合にのみコピーが実行されます。


# 特定のファイルやディレクトリを除外して処理したい
コピー元`dirDev`とコピー先`dirProd`双方にあるけど更新（上書き）したくないファイル、処理を無視したいディレクトリなどを`--exclude`オプションで除外できます。

```
//test.txtとnode_modules内すべてのファイルを無視
$ rsync -av --update --exclude=test.txt --exclude='node_modules/*' /path/to/dirDev/ /path/to/dirProd/
```
# コピー元で削除されたファイルをコピー先でも削除したい
`--delete`オプションを使うことでコピー元`dirDev`に存在しないファイルをコピー先`dirProd`で削除することができます。（当然ながら消したファイルは元に戻らないのでバックアップ大事 :bulb: ）

```
//dirDevで削除したファイルをdirProdにも反映
$ rsync -av --update --delete /path/to/dirDev/ /path/to/dirProd/
```

<hr>

以上、rsyncコマンドの基本的な使い方のご紹介でした。
この他にも多数オプションがあり、本来はローカル↔リモートサーバーの同期やバックアップの作成などに使われるものらしいですね。
大量のファイルも高速に処理できて便利なコマンドなので、この機会に覚えておきたいと思います :pencil2: 

# 参考サイト

https://skume.net/entry/2021/08/09/015128

ありがとうございます :pray: :sparkles:
BootstrapのDropdownコンポーネントを使うと「Popper: CSS "margin" styles cannot be used...」と警告が表示される

# 概要

`bootstrap`の`dropdown`を使うと、以下の警告が`console`に表示される。

```console:console.log
Popper: CSS "margin" styles cannot be used to apply padding between the popper and its reference element or boundary. To replicate margin, use the `offset` modifier, as well as the `padding` option in the `preventOverflow` and `flip` modifiers.
```

:::note info
情報
* 「この警告は仕様」らしいので変更される可能性は低い。
:::

# 警告を表示されない様にするには

* `css`で`margin`の指定をやめる
* 新たに`dropdown-spacer`を作って`margin => height`に設定する

```diff_css:css
.dropdown-menu {
-  margin-top: var(--bs-dropdown-spacer); /* bs のデフォルト */
+  margin-top: 0;
}

+.dropdown-spacer{
+    height: var(--bs-dropdown-spacer);
+}
```

```diff_html:html
<div class="dropdown">
  <button
    class="btn dropdown-toggle"
    type="button"
    data-bs-toggle="dropdown"
    data-bs-display="static"
    aria-expanded="false"
  >
    <i class="bi bi-three-dots-vertical fs-4"></i>
  </button>

   <div class="dropdown-menu">

+   <div class="dropdown-spacer"></div>

    <button class="dropdwon-item">アイテム1</button>

    <a class="drapdown-item">アイテム2</a>
  </div>

</div>
```

# 参考

https://github.com/react-bootstrap/react-bootstrap/issues/5081

https://stackoverflow.com/questions/64141163/popper-css-margin-styles-cannot-be-used-to-apply-padding-between-the-popper-a

https://github.com/chakra-ui/chakra-ui/issues/3440

了