OmniAICreator/Qiita-1.07M huggingface dataset:
d3.jsを使用したmindmap作成

マインドマップ作ったことありますか？

あれば共感いただけると思うんですが、意外とノード同士の距離の取り方やレイアウトを実装するのが難しいです。

よく使われるアルゴリズムには以下のようなものがあります。

1. 力学モデル（Force-Directed Layout）
力学モデルは、ノードを質点、エッジをばねと見立て、物理法則に基づいてノードの配置を決定する方法です。このモデルはノード間の重なりを防ぐのに有効です。
引力と斥力: つながっているノード間には引力が働き、全てのノード間には斥力が働くようにします。
アルゴリズム: Fruchterman-Reingold アルゴリズムや Spring-Embedder アルゴリズムが代表的です。

2. ツリー構造の最適化
マインドマップはツリー構造に近いので、ツリー構造のレイアウトアルゴリズムを使うことが考えられます。
Reingold-Tilford Algorithm: これはバランスの取れたツリー構造を生成するためのアルゴリズムです。各ノードが適切な位置に配置されるよう調整します。
階層的レイアウト: ノードを階層ごとに整列させ、各レベルのノードを均等に配置する方法です。

とはいえです。一機能になるべく時間をかけたくないという方もいらっしゃると思います。

そんな方々には[D3.jsのtree機能](https://d3js.org/d3-hierarchy/tree)をお勧めします。

D3.jsこれ自体はあまり触ったことないという方もいらっしゃると思いますが、よくchartライブラリなどとして使われている、svg操作ライブラリです。

以下、綺麗に配置がされるという動作画面とreactで使えるhooksコードを参考程度に載せておきます。

![aaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295481/afc2d916-04a5-679b-5b79-e8fa0c344ce3.gif)

https://github.com/omitsuhashi/drill-web/blob/main/src/hooks/mind-map.tsx
ストーリーポイントの数字、素朴な疑問

## はじめに
アプリ制作の課題に入り、issueにたいしてストーリーポイントを設定しているところです。早速ですがストーリーポイントの数字についてなぜ1・2・3からの5になるのかが理解できなかったので調べたことをアウトプットしようと思います。

## そもそもストーリーポイントとは何か？
ストーリーポイントは主にアジャイル開発の一環として広まったもので、特定の誰かが決めたわけではなく、チームやコミュニティの間で自然に形成された考え方で、スクラムやXP（エクストリームプログラミング）などの手法で使われることが多い

ストーリーポイントという言葉自体は、アジャイル開発[^1]のストーリー（ユーザーや機能の要求）を評価するためのポイントという意味で、**タスクの大きさや複雑さを相対的に評価するための指標**として使われている

## ストーリーポイントの各数値について
| ストーリーポイント | 意味                                                                   | 具体例                                                       | 
| ------------------ | ---------------------------------------------------------------------- | ------------------------------------------------------------ | 
| 1                  | 非常に簡単なタスク。作業時間がほとんどかからない。                     | 文法チェック、軽微なバグ修正、テキストの変更                 | 
| 2                  | 簡単なタスク。少し時間がかかるが、問題なく終わる。                     | フォームの入力フィールド追加、CSSの微調整                    | 
| 3                  | 標準的なタスク。ある程度の労力と時間がかかるが、通常の範囲内           | 新しいページの作成、簡単なAPIコールの実装                    | 
| 5                  | やや複雑なタスク。複数の要素が絡み合い、多少の調査や試行錯誤が必要。   | ユーザー認証機能の追加、複数ページに渡るナビゲーションの改良 | 
| 8                  | 複雑なタスク。チーム内での協力や深い理解が必要。時間も多くかかる。     | 新しいデータベースの設計と実装、複雑なビジネスロジックの実装 | 
| 13                 | 非常に複雑なタスク。高い技術力と多くの時間が求められる。               | マイクロサービスの統合、大規模なシステムリファクタリング     | 
| 21                 | 大規模なタスク。全体のプロジェクトの進行に大きな影響を与える。         | プロジェクトの全面的な再設計、基幹システムの移行             | 
| 34                 | 極めて大規模で複雑なタスク。複数のスプリントを跨ぐ可能性が高い。       | 企業全体のシステム統合、大規模なデータ移行プロジェクト       | 
| 55                 | 非現実的なタスク。非常に大規模かつ複雑であり、さらに分割して扱うべき。 | 技術的負債の大規模清算、全社的なITインフラの再構築           | 

## これら数値は何に基づいているのか？
前置きが長くなりましたが、ストーリーポイントの数値が1・2・3・5・8・13になっている理由について。

**フィボナッチ数列に基づいているから**

フィボナッチ数列は、前の2つの数を足したものが次の数になる特性があり、これがタスクの不確実性を表現するのに適しているとされています。

評価の際に曖昧さを減らすため、ストーリーポイントを評価する時、具体的な数値よりも相対的な比較が重要だから、フィボナッチ数列のように数を飛ばすことで、より明確な判断ができるようになる

もう少しかみ砕いて説明すると、タスクの不確実性や複雑さをより明確に表現できるから
具体的には、タスクが大きくなるほど見積もりの精度が下がるため、数値が飛ぶことでその不確実性を反映できることとなる

## 実際にはどの数字まで使用するのか？
13または21までのストーリーポイントを使用することが一般的なようです。21を超える場合は、タスクが大きすぎるため、細かく分割して扱うことが推奨されています。


## 参考

[^1]: システムやソフトウェア開発におけるプロジェクト開発手法の1つで、大きな単位でシステムを区切ることなく、小単位で実装とテストを行う。「アジャイル」には“素早い”という意味がある

https://www.fujitsu.com/jp/services/agile/featurestories/about-agile-01.html

https://lychee-redmine.jp/blogs/project/tps-story-point/
[プロジェクト進行]なぜグダグダになってしまうのか？

# 進捗どうですか(ﾆｯｺﾘ
大手とかだとプロパーの元に、複数のBPがぶら下がり、プロジェクトが進んでいくかと思いますが、みんな上手く進んでる？

ここ最近、 ~~自分がアサインしてるところを含め、~~ なんか順調に回ってないプロジェクトが多いなぁということで、そんなプロジェクトたちの共通点を洗い出してみようかなと。

# そもそもなんで回らなくなるのか？
なぁぜなぁぜ。
## そもそも無理なスケジュール
見積もり上で３人月だったから、３人入れて１ヶ月で終わらせろよ的な、設計～開発・テストとかで必ずかかる時間がきちんと考慮されていないという残念な思想のせいで回らなくなるやつ。
特に分業できないようなものの場合、どんだけ人を入れても暇な人が出来るだけという状況になるだけだからな。

## 決定力のないPM/PL
「こうしよう」「こうあるべき」「スグにお客様に確認しますね！」という決定がなかなか出来ないPM/PLがいることで、質問・課題が先延ばしになって全体の遅延に繋がるアレ。
鶴の一声で仕様をとっとと決めて先に進めてほしいと言うのが、仕様決定権のない下々の者たちの総意となりますので、頑張って決めてください。

## 無駄な打ち合わせが多い
何も決まらない、一人一人に何か発言させる、関係ない人にもとりあえずで参加してもらうといった、時間だけがジャブジャブ浪費される打ち合わせが多い。
最初に打ち合わせのゴールを決める、発言じゃなくて複数人同時にチャットに書いてもらう、その人が必要になった時にちょっと呼び出すとかするだけでも、だいぶ時間が効率化出来るんじゃないかという思い。
チームに8人いたとして、1時間の打ち合わせで1人日分取っちゃうんだよ？15分で終わらせて0.25人日分で終わらせたくね？

進捗報告なんて事前に何してる・どれぐらい進んでるかをチャットとかで書いてもらって、ソレをPM/PLが纏めて全体に報告するとかで十分じゃね？とか思うんですが、世の中の偉い人たちはみんな集めて一人ひとり発言させて、なんで遅れてるのかの説明させて、自分のターンじゃない時はそのクソみたいなやり取りを永遠と聞かされるというクソみたいな時間の使い方を好むみたいでホントにうんざりしちゃうよネ！

## 属人化してしまうタスク
プロパーもBPも ~~出来る人・出来ない人~~ スキルとかの差があると思うので、全員が全員同じ作業量をこなせないというのは承知の上だけど、この作業もあの作業もAさんにやってもらうしかないという属人化してしまうのはなんとか回避したいよね。
例えばその人が全体スケジュールに関わる重要なタスクこなしてる時、横槍で別タスクきた際に作業止まったりすると全体に影響が出ちゃうし、そもそもその人が稼働あげないと回らないというクソみたいな流れになっちゃうもんね。
きっとそういう人って「自分がやりますよ！」って表面上では優しくしてくれるけど、裏で「お前らでやれやクソが！」みたいなこと言ってるかもしれないよ（ﾆｯｺﾘ


# まっとめ
もっとなんかありそうだけど、特に大きな共通点としてはこんな感じなのかなって。
回ってない中でもなんかやりがい的なのが見つかれば仕事として面白いんだろうけど、コレといった改善点もなくただひたすらに辛いだけのプロジェクトってやる気全然起きないし、早く終わってくれ（早く退場させてくれ）ってなっちゃうよね～
Workato：Pythonコネクタで任意のモジュールをインストールして利用する

# はじめに

WorkatoのPythonコネクタは、基本的には用意されたモジュールのみの利用が可能ですが、自分が使いたいモジュールが用意されていない場合もあると思います。そのような場合は、pipモジュールを利用することで、任意のモジュールをインストールして利用することが可能です。

なお、Pythonコネクタは /tmp 以下のみ書き込み可能なため、モジュールのインストール先も /tmp とする必要があります。また、モジュールのインストールはコード上で行い、インストールしたモジュールをコード上で動的にインポートして利用する形となります。

# コード

以下は、boto3(AWS SDK for Python)モジュールをインストールする例になります。boto3をインストールすることで、Pythonコネクタ上から簡単にAWSのリソースがAPI操作できるようになります。

なお、Workatoのレシピの作成手順および設定方法については、ここでは割愛します。
（Pythonコネクタについてある程度習熟していることを前提とします）

```python
import pip
import site
import importlib

def main(input):  
  # インストールするパッケージ
  package_name = 'boto3'

  # インストール先ディレクトリ (/tmpであること)
  target_dir = '/tmp'

  # モジュールをインストールする
  pip.main(['install', '--target', target_dir, package_name])

  # インストールディレクトリをsys.pathに追加
  site.addsitedir(target_dir)

  # sys.pathをリフレッシュ
  importlib.reload(site)

  # モジュールをimportする
  boto3 = importlib.import_module(package_name)
  
  s3 = boto3.resource('s3')

  #
  # 必要な処理を記述する
  #
  
  return {"result": "success"}
```
kintone設定管理ツールginueメモ

# ginueについて
ginueはkintoneのアプリの設定情報を管理するためのツールです。いつも使わせていただいております。ありがとうございます。

https://github.com/goqoo-on-kintone/ginue

詳しくは👆を見てください。

この記事は自分用メモです。

# ginueの導入
npmから。
```bash
npm i -D ginue
```

# ginueの設定
いろいろ書き方があって迷うので、決定版をここに。
ginueの設定は.ginuerc.jsが書きやすい。これをプロジェクトホームに置く。

.ginuerc.js
```javascript
module.exports = {
    //ディレクトリの設定
    location: 'kintone',

    //環境は名前をいくつでも設定できる
    env: {
        dev: {
            domain: 'example.cybozu.com',
            username: 'login_name',
            password: 'login_password',
            //basic認証は:でIDとパスワードを連結（kintoneの仕様といっしょ）
            basic: "Administrator:myBasicAuthPassword",
            //アプリはアプリIDの配列で指定可能だが、
            //名前を付けたオブジェクトほうが、出力後の視認性がよい
            app: {
                "customer-master": 2597,
                "support-history": 2598
            }
        },
        stage : {
            domain: 'example.cybozu.com',
            username: 'login_name',
            password: 'login_password',
            basic: "Administrator:myBasicAuthPassword",
            app: {
                "customer-master": 3597,
                "support-history": 3598
            }
        },
        prod : {
            domain: 'example.cybozu.com',
            username: 'login_name',
            password: 'login_password',
            basic: "Administrator:myBasicAuthPassword",
            //ゲストスペースを指定できる
            guest : 5,
            app: {
                "customer-master": 7,
                "support-history": 8
            }
        }
    },
}
```

この設定での出力結果はこのようになる。
```bash
│  
└─kintone
    ├─dev
    │  ├─customer-master
    │  │      アプリ設定
    │  │      
    │  └─support-history
    │          アプリ設定
    │          
    ├─prod
    │  ├─customer-master
    │  │      アプリ設定
    │  │      
    │  └─support-history
    │          アプリ設定
    │          
    └─stage
        ├─customer-master
        │      アプリ設定
        │      
        └─support-history
                アプリ設定
```
これをdiffツールやGitなどで管理する。

# コマンド
データの取得、反映。
```bash
# 環境からデータを取得
npx ginue pull 環境名：省略するとすべて

# 環境にデータを反映（リリースはしない）
npx ginue push 環境名：省略するとすべて
```

よく忘れるコマンド
```bash
# 環境の状態をリリースにする（kintoneのアプリを更新ボタン）
npx ginue deploy 環境名：省略するとすべて
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/ef98a105-4eda-4693-1517-24a6ca17497d.png)

# まとめ
素晴らしいツールです。ginue pushしない限り安全に利用できます。
設定を取得した後、ぼくは[WinMerge](https://winmerge.org/?lang=ja)で開発と本番の環境の違いを調べています。

この記事は以上です。

---
kintoneのカスタマイズやプラグイン開発・コンサルティングを行っています。

https://www.pulsar-works.jp/
【ChatGPT＋Code Interpreter】で文字の回転をさせるアニメを作る。


　どうも、カーブミラーです。

　今回は、文字の回転をさせるアニメを作ります。ようするに文字を傾かせたり逆さにしたりを繰り返してアニメGIFにします。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::

　ニュースがないので、
　　さっそく、本題です。

　今回は、
　　文字の回転をさせる
　　　アニメGIFを作ります。

　なぜ、これをするのか、ですが
　　単なる興味です😅

　まずは、
　　出来上がりを
　　　どうぞ。
![resized_512x512.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/9065254c-84b4-3d19-17f7-46084844a630.gif)

　回転だけでなく
　　移動もさせました。

　単なる回転だけだと
　　面白くないので😸

　では
　　経緯のやり取りをどうぞ。
　　　Pythonコードが出てきますが
　　　　割愛します（長いので😅）
***
***user***
CodeInterpreterで描画した文字を回転させるなんてできますか？　横倒しにするとか。

***ChatGPT***
はい、CodeInterpreterで文字を回転させることは可能です。Pythonの`matplotlib`ライブラリを使用して、文字を回転させて描画することができます。以下はその一例です。
（コード）

このコードでは、文字「回転した文字」を90度回転させて描画します。他の角度に変更したい場合は、`rotation`パラメータの値を調整してください。たとえば、45度回転させたい場合は、`rotation=45`とします。
（ダウンロードリンク）

***user***
CodeInterpreterで、“A”を45度ずつ左回転させて、360度回転させるアニメGIFを作成してください。

***ChatGPT***
（“A”の反時計回りの回転アニメGIF）

***user***
背景を512×512にして

***ChatGPT***
（画素数が512×512の回転アニメGIF）

***user***
文字を回転させながら、移動させることは可能？

***ChatGPT***
文字を回転させながら移動させることも可能です。`matplotlib.animation`を使用して、文字の位置をフレームごとに更新することで、回転と移動を同時に行うことができます。以下はその例です。
（コード）

このコードでは、文字「A」を回転させながら左から右へ移動させるアニメーションを作成します。実行してみます。
（ダウンロードリンク）

***user***
右から左にお願いします

***ChatGPT***
（ダウンロードリンク）

***user***（最後まで回転してないよ）
最後に文字の傾きをなくしてください。つまり、360度回転して欲しいです

***ChatGPT***
（ダウンロードリンク）
***

　これで下記の内容で作成されました。
　・画素数を512×512
　・“A”を反時計回りに回転（最後まで）
　・右から左に移動
　・アニメGIF化
***
　新たなセッションで
　　これを再現するには
　　　最終的なコードをコピーして、
　　　　行なおうとします。

　コードは
　　ダウンロードリンクの右側に
　　　“[>_]”をタップすれば見れます。

　ところが
　　コードを新しいセッションに
　　　コピペしても動きません。

　理由は
　　ライブラリの読み込みの記述が
　　　書かれていないことが原因です。

　ではどうしたら？
　　ChatGPTさんに依頼しました😅

　同じセッションの続きです。
***
***user***
新たなセッションで指示して、このアニメGIFを作成するための指示Promptを作成してください。

***ChatGPT***
以下は、アニメGIFを作成するためのPythonコードを含む指示プロンプトです。新しいセッションでこのプロンプトを使用してください。

```Text:Prompt
以下のPythonコードを使用して、文字「A」を45度ずつ回転させながら右から左に移動し、最終的に元の角度に戻るアニメーションGIFを作成してください。背景サイズは512x512です。

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

# 文字の設定
text = "A"
angles = np.concatenate((np.arange(0, 360, 45), [0]))  # 最後に角度0を追加
positions = np.linspace(0.9, 0.1, len(angles))

# 背景サイズを512x512に設定
fig, ax = plt.subplots(figsize=(5.12, 5.12))
ax.axis('off')
text_obj = ax.text(0.9, 0.5, text, fontsize=50, ha='center', va='center')

# アニメーションの更新関数
def update(i):
    angle = angles[i % len(angles)]
    pos = positions[i % len(positions)]
    text_obj.set_rotation(angle)
    text_obj.set_position((pos, 0.5))
    return text_obj,

# アニメーションの作成
ani = animation.FuncAnimation(fig, update, frames=len(angles), interval=500, blit=True)

# GIFとして保存
ani.save('/mnt/data/rotating_moving_A_full_rotation.gif', writer='imagemagick')

plt.close(fig)
```

この指示プロンプトを新しいセッションで実行することで、同じアニメーションGIFを作成することができます。
***
　また、
　　Code Interpreterを使うことを
　　　明示しないと、Pythonを
　　　　処理してくれません。

　そこで、
　　上記Promptの先頭に
　　　“CodeInterpreterで、”を
　　　　追記して送信します。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
Ubuntu24.04 OpenARCインストール

参考サイト：https://www.therewill.be/2024/03/security/openarc-on-ubuntu/#toc2
OpenDKIMの設定が終わってる前提  

`git clone 'https://github.com/trusteddomainproject/OpenARC.git'`  
`cd OpenARC`  
`autoconf -fvi`  
`make`
`make install`  
`make install systemd`  

`vi /etc/openarc.conf`
```
AuthservID ホスト名
Domain ドメイン名
KeyFile /etc/dkimkeys/ドメイン名/セレクタ名.private
Selector セレクタ名
Mode sv
Socket  inet:8892@localhost
Canonicalization relaxed/relaxed
SignHeaders to,subject,message-id,date,from,mime-version,dkim-signature
SoftwareHeader no
Syslog Yes
UserID opendkim
AutoRestart yes
PidFile /var/run/opendkim/openarc.pid
```

`cp /usr/local/share/doc/openarc/openarc.service /usr/lib/systemd/system/`
`vi /usr/lib/systemd/system/openarc.service`
```diff
--- /usr/local/share/doc/openarc/openarc.service
+++ /usr/lib/systemd/system/openarc.service
@@ -7,12 +7,11 @@

 [Service]
 Type=forking
-PIDFile=${prefix}/var/run/openarc/openarc.pid
-EnvironmentFile=-${prefix}/etc/sysconfig/openarc
-ExecStart=${exec_prefix}/sbin/openarc $OPTIONS
+PIDFile=/var/run/opendkim/openarc.pid
+ExecStart=/usr/local/sbin/openarc -c /etc/openarc.conf
 ExecReload=/bin/kill -USR1 $MAINPID
-User=openarc
-Group=openarc
+User=opendkim
+Group=opendkim

 [Install]
 WantedBy=multi-user.target
```

`systemctl daemon-reload`
`systemctl enable openarc`
`systemctl start openarc`

`vi /etc/postfix/main.cf`
```
smtpd_milters = inet:127.0.0.1:8891,inet:127.0.0.1:8893,inet:127.0.0.1:8892
```
※,inet:127.0.0.1:8892を最後に追加
`systemctl reload postfix`

gmailにメール送信してヘッダーを確認
i18nでAmplify-UIの認証画面の日本語化を試しました

# やりたいこと
・前回Amplify-UIで作った認証画面は、デフォルトで英語表示になっていますので、日本語化対応を行いたい

※Amplify-UIの認証画面の作り方は以下をご参照ください

https://qiita.com/curlneko/items/99acf9d6c09482f6acb1

# やり方

前回のフォルダ配下に、i18n.jsのファイルを作り、日本語翻訳のdictを作ります～
（i18nは事前にモジュールのnpm installが要らずAmplify-UIでもともとついた機能となります）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/78cfc2a9-1e8d-bb61-ea13-2a16144c7f7b.png)

中にはこんな感じ～
（日本語翻訳は自分でやらないといけない）

```ruby:i18n.js
// i18n.js
import { I18n } from 'aws-amplify/utils';

const dict = {
  ja: {
    // サインイン画面
    'Username': 'ユーザー名',
    'Password': 'パスワード',
    'Email Address *': 'メールアドレス',
    'Enter your Username': 'ユーザー名を入力してください',
    'Enter your Password': 'パスワードを入力してください',
    'Confirm Password': 'パスワードを確認',
    'Please confirm your Password': 'パスワードを再入力してください',
    'Reset Password': 'パスワードのリセット',
    'Enter your username': '名前（ID）を入力してください',
    'Sign In': 'サインイン',
    'Sign in': 'サインイン',
    'Sign Up': 'サインアップ',
    'Forgot your password?': 'パスワードをお忘れの方',
    'Reset password': 'パスワードをリセット',
    'No account?': 'アカウントを持っていない方',
    'Create account': 'アカウントを作成',
    'Create Account': 'アカウントを作成',
    'Have an account?': 'アカウントお持ちの方',
    'Confirm Sign up': 'サインアップの確認',
    'Back to Sign In': 'サインインに戻る',
    'Send code': 'コードを送信'
    // 必要に応じて他のラベルも追加
  },
};

I18n.putVocabularies(dict);
I18n.setLanguage('ja');

```

次に、index.jsにi18n.jsをimportします

```ruby:index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import Test from './Test';
import reportWebVitals from './reportWebVitals';

// ここを追加
import './i18n';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Test />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

すると、もう一度画面を起動
http://localhost:3000/

前回英字だった画面が日本語になりました～

**Before**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/cf395706-210d-677f-2171-255e20fd9ae1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/3e303589-6aae-0f28-c37b-38d32720c592.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/318720b2-8d0f-53aa-1bbe-fceead699833.png)


**After**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/2c341b3c-9d40-b08c-4e39-46bfc27dd3ac.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/c8a05009-6ba2-5fd2-21f1-5822ace2ab7c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/6b4d9d0f-d10e-1b1f-c67f-4cb23abf558e.png)






# 参照サイト

https://docs.amplify.aws/gen1/javascript/build-a-backend/utilities/i18n/
謎のUncaught SyntaxError: Unexpected token '<' エラーについて

# Uncaught SyntaxError: Unexpected token '<' エラー

Laravelで開発をしていたら突如コンソールに

```

Uncaught SyntaxError: Unexpected token '<'
    at Function (<anonymous>)
    at template.js:259:12
    at t.exports (_apply.js:13:25)
    at attempt.js:29:12
    at t.exports (_apply.js:15:25)
    at _overRest.js:32:12
    at t.exports (template.js:258:16)
    at t.value (Template.js:14:21)
    at station-list.js:11:4
    at station-list.js:1:20573

```

というエラーが起き、データがうまく出力されないといった現象に遭いました。

これがまた厄介でローカル環境では表示されるのに開発環境では表示されないのです。

色々試した結果

`<% //コメント文 %>`
↓に変更
`<% /* コメント文 */ %>`

すればうまく動作しました。

Underscore.jsやLodashなどのJavaScriptのテンプレートエンジンを使っている環境では
環境の差分によってこのようなエラーが起きるといった現象があるようです。

詳しい原因は追及する時間がなかったので省略...

私はこれを突き止めるまで1時間くらいかけてしまったので誰かのお役に立てれば幸いです...
Docker学習メモ #2

## **1. ボリュームとは？**

ボリュームとは

コンテナーにはファイルの変更、削除などを行うスクラッチスペースがある。しかし、コンテナーを削除するとそういった変更は全て記憶されていないので、新たにコンテナーを起動しても反映されない。

> [ボリューム](https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/) とは、コンテナー内に特別なファイルシステムがホストシステムに向けて生成され、そこにアクセスする機能を提供するものです。 コンテナー内のあるディレクトリがマウントされていると、そのディレクトリ内で行われた変更がホストマシンからも見ることができます。 仮にコンテナーの再起動の前後で 1 つのディレクトリをマウントしておけば、同一のファイルを維持できることになります。
> 

ここでのホストシステムとは、自分のパソコンである。

つまり、ボリュームとは、**コンテナーと自分のパソコンでファイルを共有する機能**のことである。

STEP1　ボリュームの作成

```docker
docker volume create ボリューム名
```

## 2. ネットワークとは？

アプリケーションは通常、１つのコンテナだけでは作らない。アプリケーションのコンテナ以外にも、データベースのコンテナ、ミドルウェア(ここではリバースプロキシ)のコンテナなどを用いる。

ネットワークとは、このようなコンテナ同士が通信をしたいときに用いられる**仮想的なネットワークのこと**である。

ネットワークを作成
Nuxtにおける四つのライフサイクルフックの比較

Nuxtには、アプリケーションの異なる段階で実行されるライフサイクルフックがいくつかあります。今回は、ライフサイクルの違いと使い方を理解の限りで説明してみます。あくまでも備忘録ですね。

## 1. App Hooks (ランタイム)

アプリケーションの状態管理に適している。プラグインで使用可能。

### 種類
https://nuxt.com/docs/api/advanced/hooks#app-hooks-runtime

### 例

```typescript
// plugins/test.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('page:start', () => {
    /* your code goes here */
  })
})
```

## 2. Nuxt Hooks (ビルド時)

Nuxtの設定や拡張に使用されます。Nuxtモジュールやnuxt.config.jsで使用可能。
アプリケーションの構造やビルドプロセスのカスタマイズに適している。

### 種類
https://nuxt.com/docs/api/advanced/hooks#nuxt-hooks-build-time


### 例

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    close: () => { }
  }
})
```

```ts
// Within Nuxt Modules
import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.hook('close', async () => { })
  }
})
```

## 3. Nitro App Hooks (ランタイム、サーバーサイド)

NitroはNuxtのサーバーサイドフレームワークです。このフックはサーバー起動時に1回だけ実行されます。requestとresponseのライフサイクルに介入可能、サーバーサイドのエラーハンドリングにも適している。

### 種類
https://nuxt.com/docs/api/advanced/hooks#nitro-app-hooks-runtime-server-side

### 例

```ts
// ~/server/plugins/test.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('render:html', (html, { event }) => {
    console.log('render:html', html)
    html.bodyAppend.push('<hr>Appended by custom plugin')
  })

  nitroApp.hooks.hook('render:response', (response, { event }) => {
    console.log('render:response', response)
  })
})
```

## ４. Vue Lifecycle Hooks (クライアントサイド)
Vueコンポーネントに関連するフックです。Vueインスタンスの生成、更新、破棄の各段階で実行されます。

### 種類
https://vuejs.org/guide/essentials/lifecycle.html
### 例
```vue
<script setup>
import { onMounted, onUnmounted } from 'vue'

let intervalId
onMounted(() => {
  intervalId = setInterval(() => {
    // ...
  })
})

onUnmounted(() => clearInterval(intervalId))
</script>
```
# まとめ


### build時コンテキスト
- Nuxt Hooks
  - 使用場所: Nuxt Config, Nuxt Modules
  - 特徴: Nuxtアプリの起動時に1回、順番に呼び出される

### runtimeコンテキスト
-  Nitro Hooks
   - 使用場所: Nitro Plugins
   - 特徴: サーバー起動時に1回実行される

-  (Nuxt) App Hooks
   - 使用場所: Nuxt Plugins, Vue Composable
   - 特徴: Vueアプリの作成時にサーバーとクライアントの両方で呼び出される

-  Vue Lifecycle Hooks
   - 使用場所: Vue Components, Vue Composables
   - 特徴: クライアントサイドでのみ呼び出される



| コンテキスト         | フック                | 使用場所                           | 特徴                                             |
|----------------------|-----------------------|-----------------------------------|--------------------------------------------------|
| **build時** | **Nuxt Hooks**        | Nuxt Config,<br> Nuxt Modules         | Nuxtアプリの起動時に1回、<br>順番に呼び出される       |
| **runtime**　| **Nitro Hooks**       | Nitro Plugins                     | サーバー起動時に1回実行される                    |
| **runtime** | **(Nuxt)<br> App Hooks**  | Nuxt Plugins,<br> Vue Composable      | Vueアプリの作成時に<br>サーバーとクライアントの<br>両方で呼び出される |
| **runtime** | **Vue Lifecycle Hooks**| Vue Components, Vue Composables   | クライアントサイドでのみ呼び出される             |


# 参照リンク
https://nuxt.com/docs/guide/going-further/hooks
https://blog.nuxtdojo.com/p/2-understanding-lifecycle-hooks-in
https://qiita.com/Yuto_Tatsumi/items/177e41b2de15869b8952
GraspNET 物体把持のためのデータセットの１例


pdf [GraspNet-1Billion: A Large-Scale Benchmark for General Object Grasping](https://openaccess.thecvf.com/content_CVPR_2020/papers/Fang_GraspNet-1Billion_A_Large-Scale_Benchmark_for_General_Object_Grasping_CVPR_2020_paper.pdf)

物体の把持は多くのアプリケーションにとって重要であり、コンピュータビジョンの課題でもある。しかし、乱雑なシーンに対する把持ポーズ検出は、学習データの不足と評価ベンチマークの不足という問題を抱えている。本研究では、統一的な評価システムを備えた大規模な把持ポーズ検出データセットを提供する。このデータセットには、10億以上の把持ポーズを持つ97,280枚のRGB-D画像が含まれています。一方、我々の評価システムは、解析的な計算によって把持が成功したかどうかを直接報告するため、グラウンドトゥルースを網羅的にラベリングすることなく、あらゆる種類の把持ポーズを評価することができる。   さらに、点群入力が与えられた場合、接近方向と操作パラメータを分離して学習するエンドツーエンドの把持ポーズ予測ネットワークを提案する。また、把持のロバスト性を向上させるために、新しい把持親和性フィールドを設計する。我々は、データセットと評価システムが実世界の実験とよく一致することを示すために広範な実験を行い、我々の提案するネットワークが最先端の性能を達成することを示す。   我々のデータセット、ソースコード、モデルは、www.graspnet.net で公開されている。

DeepL.com（無料版）で翻訳しました。

dataset https://graspnet.net/datasets.html

![Screenshot from 2024-07-29 10-48-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/3afff89f-a472-8111-1af3-ac900018fb90.png)


License:
All data, labels, code and models belong to the graspnet team, MVIG, SJTU and are licensed under a Creative Commons Attribution 4.0 Non Commercial License (BY-NC-SA). They are freely available for free non-commercial use, and may be redistributed under these conditions. For commercial queries, please drop an email at fhaoshu at gmail.com and cc lucewu at sjtu.edu.cn .

テストデータでさえ、６０GB以上もある。
このような種類のデータセットは、質も量も必要になってきているからだろう。

![Screenshot from 2024-07-29 10-53-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/7438c929-7c27-a311-1ad3-39a39ae89e4a.png)

データセットの中にはDense Annottaion も含まれている。

上記の論文は、単にデータセットを構築するだけではなく、把持姿勢(Grasp pose)の推定をも実施している。

![Screenshot from 2024-07-29 10-58-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/1f4bae62-7b2f-acf3-ec54-d7a0c05ba751.png)


![Screenshot from 2024-07-30 13-51-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/103fd693-3723-61b5-2411-d0d5c0cbae96.png)
![Screenshot from 2024-07-30 13-51-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/66d9dcc7-d93d-1e5c-a2b6-91d9a07ae021.png)
表1. 公開されている把持データセットの特性のまとめ。

![Screenshot from 2024-07-30 13-50-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/d5a0bf1a-87f1-1368-ef97-06729e387101.png)

図5. End-to-end ネットワークの概要。(a)N個の点座標を入力とするシーン点群に対して、点エンコーダ・デコーダが点群の特徴を抽出し、C-dim特徴でM個の点をサンプリングする。(b)接近ベクトルはApproachNetによって予測され、(c)円柱領域内の点をグループ化するために用いられる。(d) OperationNetは操作パラメータを予測し、ToleranceNetは把持のロバスト性を予測する。   詳細は本文を参照。
初心者向けのデバッグ術


## はじめに

この記事を書くきっかけは、あるページのsvg図のアニメーションに不具合があり、修正したいと思ったことです。不具合の内容として、SVG図が読み込み終わっていない場合、10回に1回は空白で表示されることがありました。

この問題を解決するための考え方を共有したいと思います。

## デバッグのステップ

### 1. 問題を明確にする

まず、問題を把握することが重要です。今回の場合：

- サイトを再読み込むと、世界地図のSVGが正常に表示されない
- 画像読み込み前にDOM要素は空白で表示される
- 10回くらいに1回程度の頻度で発生

### 2. 問題を分解する

大きな問題を小さな部分に分けて考えましょう。今回の例では、以下のように分解して考えました：

1. 画像の読み込み
2. アニメーションの実行

### 3. 仮説を立てる

問題の原因について、ブレインストーミングでいくつかの仮説を立てます。

- SVG画像の読み込みの実装方法
- アニメーション開始のタイミングが早すぎる？
- キャッシュの問題？
- 非同期処理？
- ...

### 4. 一つずつ検証する

#### SVG画像の読み込み改善

```html
<!-- Before -->
<object id="world-map" type="image/svg+xml" data="/path/to/map.svg"></object>

<!-- After -->
<img id="world-map" src="/path/to/map.svg" @load="onSvgLoaded" />
```

`<object>`タグを`<img>`タグに変更することで、読み込みを解決できるようになりました。

#### アニメーション開始タイミングの調整


キャッシュされた画像の場合、`@load`イベントが発火しない可能性があります。そこで：

```typescript
onMounted(() => {
  onSvgLoaded();
})
```

これにより、キャッシュされた画像でもアニメーションが正しく開始されるようになりました。

## まとめ

具体的な例の紹介よりも、向上すべきなのは根本的な問題解決能力です。では、デバッグとエラーを解消するための基本的な考え方をいくつか紹介します：

- **ロジック**のどこかに問題があるか
- 系統的に**問題を小さく分割**し、一つずつ検証
  - ドキュメントを読む
  - stackoverflowなどの技術コミュニティに記事を検索する
  - genAIに聞く
- 問題が発生している箇所を**特定**し
  - 開発者ツール
  - console.log 
- **条件分岐**が正しく設定されているか、**変数の値**や**関数の実行**かどうかを確認
- **エラーメッセージを徹底的に理解する**: エラーメッセージは大切な情報源です

## 好きな言葉

computer is never wrong :)
重大インシデント管理(MIM)の概要

## 概要
重大インシデント管理(MIM)の概要を、通常のインシデント管理との違いとMIMの解決プロセスに着目して説明いたします。


## サービス運用ワークスペースでの重大インシデント管理の概要

重要な問題を解決し、ダウンタイムを最小限に抑え、ビジネス継続性を維持するには、効果的な重大インシデント管理が不可欠です。重大インシデントは、ビジネス運営に重大な影響を与える優先度の高いインシデントであり、多くのユーザーまたは重要なサービスに影響を及ぼし、直ちに対応する必要があります。

広範なサービス停止が発生した場合、事前に定義された役割とビジネス要件を使用して、迅速な特定と復旧を促進します。関係者間の効果的なコミュニケーション調整と、明確なエスカレーションパスを定義する構造化された解決アプローチを促進します。追跡が重要であり、サービス運用ワークスペースはすべてのインシデントの管理を積極的に支援します。

インシデントの管理には、通常のインシデントと重大なインシデントの区別が含まれます。重大なインシデントは、重要なビジネス機能とより大きなユーザーベースに影響を及ぼし、より高い優先順位が付けられます。また、より構造化された緊急対応と、緊急時対応計画のための機能横断的な調整が必要です。

### 通常のインシデントと重大インシデントの比較：

1. 通常のインシデント：
   - 1人または少数のユーザーに影響を与える可能性のあるIT サービスへの計画外の中断
   - 優先順位とSLAに従って解決可能
   - 割り当てられたすべてのITユーザーが管理可能

2. 重大なインシデント：
   - ビジネスや組織に重大な混乱を引き起こし、多数のユーザーに影響を与えるITサービスの計画外の中断
   - できるだけ早く解決する必要があり、迅速な解決プロセスが必要
   - 重大インシデントマネージャーによって管理される必要がある

サービス運用ワークスペースでのIT運用チームが使用する重大インシデントプロセスには、以下の5つのフェーズがあります：

#### フェーズ1：特定
- 影響力と緊急性に基づいてインシデントを重大インシデントとして分類
- 重大インシデントマネージャーが候補を重大インシデントに昇格

#### フェーズ2：コミュニケーションとコラボレーション
- 重大インシデントマネージャーが電子メールやメッセージングなどのコミュニケーションツールを使用
- 利害関係者に情報を提供し、解決の取り組みを調整

#### フェーズ3：解決
- 重大インシデントマネージャーが構造化されたアプローチに従って解決
- 解決コードとメモを更新し、インシデントを終了
- 目標は、業務運営への悪影響を最小限に抑えながら、できるだけ早く通常のサービス運用を回復すること

#### フェーズ4：問題記録の作成
- 重大インシデントの根本原因分析のための問題記録を作成
- 重大インシデントマネージャーが自動的に問題記録を作成し、情報をコピー

#### フェーズ5：インシデント後のレビュー
- 重大インシデントマネージャーが関係者のための分析レポートを作成
- レポートを確認し、根本原因を特定し、今後のインシデント管理の実践を強化

重大インシデントのハンドブックは、各フェーズの実行をサポートします
- 状況の確認とインシデントの影響の理解
- 重大インシデントの基準を満たす場合のインシデントの推進
- コミュニケーションツールを使用した関係者への情報提供とコラボレーション支援
- 解決プロセスのガイドとすべてのステップの文書化
- インシデント後レポートの作成と教訓の記録

## まとめ
サービス運用ワークスペースとプレイブックワークフローは、重大インシデント発生時の運用中断を効果的に最小限に抑えることを目的としています。

### 参照
[Major Incident Management](https://docs.servicenow.com/ja-JP/bundle/tokyo-it-service-management/page/product/incident-management/concept/major-incident-management.html)
[Major Incident Management | Overview - YouTube](https://www.youtube.com/watch?v=47iyD-GDPU0)
[CDGC] APIによるCatalog SourceのJob実行: 参考資料編

# はじめに


本記事では、データカタログ(CDGC)における、APIによるCatalog SourceのJob実行について、参考資料を紹介させていただきます。


# 資料群

<strong>CDGCのPublic REST API - Postman コレクションサンプル</strong>
- CDGCのAPI全般のナレッジベースです。Postman を使ったサンプルも記載されています。
- 「Catalog Source Management API」が、Catalog SourceのJob実行APIとなります。

https://knowledge.informatica.com/s/article/CDGC-Public-API-Postman-Collection?language=ja

<BR>

<strong>API Reference - Run a catalog source job</strong>
-  API Referenceマニュアルによる、Catalog SourceのJob実行の解説です。※ログインが必要 for Informatica Community


https://docs.informatica.com/data-governance-and-quality-cloud/data-governance-and-catalog/current-version/api-reference/run_a_catalog_source_job.html

<BR>

<strong>開発者向け API Reference - Run a catalog source job</strong>
-  開発者向けのガイドのサイトです。


https://developer.informatica.com/tpn/v5/reference/run-a-catalog-source-job
山折り谷折り (paizaランク A 相当) を考察する

https://paiza.jp/works/mondai/real_event/origami

解き方は 幾つもあると思いますが、自分が実際に考察した内容を書きます。

# ・ 問題

（横長の）紙を、一方方向に$N$回折ったときに、紙に付いた折り目（谷・山）を答える問題。

<img width="500" alt="" src="http://paiza.s3.amazonaws.com/problem/images/108/img1.png" />

問題ページから引用した下の図は、$2$回折ったときの『折り目』を示していて、左から『谷折り → 谷折り → 山折り』になっていることが分かります。

<img width="150" alt="" src="http://paiza.s3.amazonaws.com/problem/images/108/img2.png" />

山折りを `1`、谷折りを `0` として、答えとなる折り目を左から順に `0` と `1` からなる文字列として一行に出力するため、上の例では`001`が答えになります。

### 制約

$1 \leq N \leq 20$

# ・ 考察

実際の紙を、$1$回 → $2$回 → $3$回 と折ってみて、折り目の増え方（増える位置と山・谷）を観察しました。


- $0$回 → $1$回

紙の中央に谷折りができます。これは自明ですね。

- $1$回 → $2$回

中央の折り目の左右に新しい折り目が（左側に谷折りが、右側に山折りが）増えました。

![origami.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/3caf7084-30c1-13a2-69ec-c0b8a49145d3.png)

- $2$回 → $3$回

左側の折り目の左右と、右側の折り目の左右に新しい折り目が増えます。
増える折り目は 先ほどと同じで、左側に谷折りが、右側に山折りが増えます。

- $3$回 → $4$回

左から偶数番目の折り目をそのままとすると、
左から奇数番目の折り目の左右に新しい折り目が増えました。
増える折り目は これまでと同じで、左側に谷折りが、右側に山折りです。

$1$回 → $2$回と、$2$回 → $3$回も同じこの規則性で説明できますので、この規則をコードに表すことにします。シンプルなコードで書けると思います。


# ・ コード

再帰ではなく、素直にループ処理で表現できます。

配列は`0-Indexed`のため、考察時とは折り目の偶奇が逆になります。
偶数番目の折り目の左右に新しい折り目を増やし、奇数番目の折り目はそのまま引き継ぎます。

計算量は$O(2^{N}N)$だと思いますが、$N$が十分に小さいので、Paizaに提出しても数ミリ秒で処理が終わりました（Swift / Python とも）。

```swift:Swift
let N = Int(readLine()!)!
var ans = [0]
for _ in 0 ..< N - 1 {
    var arr = [Int]()
    for m in 0 ..< ans.count {
        if m % 2 == 0 {
            arr.append(0)
            arr.append(ans[m])
            arr.append(1)
        } else {
            arr.append(ans[m])
        }
    }
    ans = arr
}
print(ans.map { String($0) }.joined(separator: ""))
```

Swift版を[Paiza](
https://paiza.io/projects/e/8bgpNMxvkE3Eo7QVOuaMKw?theme=twilight)で見る<br>　


```python:Python
N = int(input())
ans = [0]
for _ in range(N - 1):
    arr = []
    for m in range(len(ans)):
        if m % 2 == 0:
            arr.append(0)
            arr.append(ans[m])
            arr.append(1)
        else:
            arr.append(ans[m])
    ans = arr

print(''.join([str(x) for x in ans]))
```

Python版を[Paiza](
https://paiza.io/projects/e/PnZoPypeRYDTbbHkWUb_AQ?theme=twilight)で見る
windowsにPHP+Imagickを入れてみた

簡単に画像処理プログラミングを行いたくてImagick付きのPHPをインストールしてみた。

## Imagickのモジュール
Imagickのdllは、PECL DLLs for PHPにあった。以下のファイル
https://windows.php.net/downloads/pecl/releases/imagick/3.7.0/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/c63a2bc4-549b-4ead-2cb8-ea1769585514.png)

## Windows版のPHP
ダウンロードしたimagick.dllはビルド＝vs16、PHPバージョン＝8.1、ts(Thread Safe)、64ビットになるのでそれに合うPHPをダウンロード
https://windows.php.net/download/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/6cdb424a-026c-4584-2923-fd2079ec087d.png)

フォルダc:\phpを作ってその下にphp-8.1.29-Win32-vs16-x64.zipを解凍
フォルダc:\php\imagickを作ってその下にphp_imagick-3.7.0-8.1-ts-vs16-x64.zipを解凍

## php.iniの設定
c:\php\php.ini-productionをコピーしてphp.iniにリネーム
最後に以下を追加
```
[ImageMagick]
extension=c:\php\imagick\php_imagick.dll
```

## 動作確認
環境変数PATHに追加する前にコマンドプロンプトで確認
PATHに以下の２フォルダを追加
```
set PATH=%PATH%;C:\php;C:\php\imagick
```
phpinfoでimagickが有効になったか確認
```
php -i | more
```
```
imagick

imagick module => enabled
imagick module version => 3.7.0
imagick classes => Imagick, ImagickDraw, ImagickPixel, ImagickPixelIterator, ImagickKernel
Imagick compiled with ImageMagick version => ImageMagick 7.1.0-18 Q16 x64 2021-12-14 https://imagemagick.org
Imagick using ImageMagick library version => ImageMagick 7.1.0-18 Q16 x64 2021-12-14 https://imagemagick.org
...
```
## 環境変数PATHに追加
コントロールパネル＞システム＞システムの詳細設定＞詳細設定＞環境変数でPATHを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/9992ec10-e79f-1e40-42be-c41784afb341.png)
【Unity】移動モーション設定

移動させるキャラは、KyleRobotを使用させてもらいました。
以前作成したPlayerControllerに以下のAnimatorにパラメータを入れるコードを追加。

```
void ApplyAnimatorParameter()
{
    m_Animator.SetFloat( "Speed", m_RigidBody.velocity.magnitude, 0.1f, Time.deltaTime );
}
```
```
void Update()
{
    UpdateIsGrounded();
    if( !m_IsGrounded ) return;
    Jump();

    ApplyAnimatorParameter();
}
```

Animator(Speedの数値によってモーションが切り替わるようになっている)
![speed.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666230/1cf062b6-e225-dd27-57b4-f96d9d9064fa.jpeg)

実行結果
![bandicam-2024-07-29-09-55-22-123.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666230/29460bf8-f8cb-dfcb-09e2-6b9ebbae34ea.gif)


参考にさせていただいたサイト
https://www.youtube.com/watch?v=k-X4bqcc4Mg
GASで変更した点をスプレッドシートに即時反映させる

# GASで変更した点をスプレッドシートに即時反映させる

## 背景
GASを用いてスプレッドシートにデータをセットしてPDFを発行する際に正しく出力されていないことに気づいた

### 本記事の対象
- スプレッドシートでシートを変更したときに、最新状態に反映させる方法を学ぶ
- PDFを出力するときに正しく出力させる


## 既存のコード
claspを使用してGASの開発を行っているため、TypeScriptのコードになりますが、GASでも同様の問題に直面するはずです。

#### シートの更新をするコード
```updateSheet.ts
const getSheet = (sheetName: string) => {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  if (!sheet) throw new Error("Sheet not found");
  return sheet;
};

const updateSheet = () => {
  const sheet = getSheet("your sheet name");
  sheet.getRange("A1").setValue("hoge");
};

```

#### PDFを保存するコード
(細かい処理は省略しています)
```savePdf.ts
const getPdfUrl = (): string => {
  return "https://pdf_service_url";
};

//シートをバイナリ形式に変換
const getPdfBlob = (url: string): GoogleAppsScript.Base.Blob => {
  const token = ScriptApp.getOAuthToken();
  const options = {
    headers: { Authorization: "Bearer " + token },
  };
  return UrlFetchApp.fetch(url, options).getBlob();
};

//バイナリ形式をPDF形式に変換後保存
export const savePdf = () => {
  const pdfUrl = getPdfUrl();
  try {
    const folder = DriveApp.getFolderById("folderId");
    const blob = getPdfBlob(pdfUrl).setName("fileName");
    folder.createFile(blob.setName("fileName"));
  } catch (error) {
    console.error("saveAsPdf error", error);
    throw new Error("PDFの保存に失敗しました");
  }
};

```

上記の`updateSheet`関数を使用したあとに、`savePdf`関数を使用すると、A1のセルに"hoge"が反映されずに前の状態(なにも記載されていなかったら白紙)のPDFが出力されてしまう。


## 原因
- GASは処理が反映されるのにタイムラグがある
- プログラムを`データ更新→PDF出力`のフローを行っても、スプレッドシート上には反映されずに、`PDF出力→データ更新`というフローになってしまっている

### 解決策
- 変更点をスプレッドシートに即時反映させる`flush()`を使用

変更点
```savePdf.ts

// 修正前
export const savePdf = () => {
  const pdfUrl = getPdfUrl();
  try {
    const folder = DriveApp.getFolderById("folderId");
    const blob = getPdfBlob(pdfUrl).setName("fileName");
    folder.createFile(blob.setName("fileName"));
  } catch (error) {
    console.error("saveAsPdf error", error);
    throw new Error("PDFの保存に失敗しました");
  }
};


//修正後
export const savePdf = () => {
  const pdfUrl = getPdfUrl();
  try {
    //追記
    SpreadsheetApp.flush()
    const folder = DriveApp.getFolderById("folderId");
    const blob = getPdfBlob(pdfUrl).setName("fileName");
    folder.createFile(blob.setName("fileName"));
  } catch (error) {
    console.error("saveAsPdf error", error);
    throw new Error("PDFの保存に失敗しました");
  }
};

```

上記のように`SpreadSheetApp.flush()`を使用すると解決しました


## おわりに
GASでPDFの出力をする際に、正しく反映されないことに気づき、原因を探りました。
今回のようにエラーが出ずに、出力結果を見ないと気づけないようなバグは非常に怖いです。タイムラグがあり、正しく出力されてしまうこともあり、原因特定に時間がかかるというのも非常に厄介でした。
このようなことを避けるためにも、新しく使用する技術については、ドキュメントをしっかり読み込み開発をするべきだと思い勉強になりました。
【TypeScript/JavaScript】Knipで不要なコードを簡単に削除する方法

# はじめに
TypeScript/JavaScriptのプロジェクトで不要なコードを検出し、削除するツール「Knip」について紹介します。
# Knipとは？
`Knip`は、TypeScriptやJavaScriptのコードベースから不要なコードを検出するためのCLIツールです。

以下のような不要なコードを検出することができます。

+ package.json の dependencies / devDependencies に含まれているが、実際には使われていないパッケージ
+ exportされているが、どこからもimportされていない変数、関数、型
+ 使用されていないファイル

これらの不要なコードを検出し、整理することでプロジェクトのメンテナンス性を向上させることができます。
# Knipの使い方
`Knip`の使い方は非常にシンプルです。
以下のコマンドを実行することで、プロジェクト内の不要なコードを検出できます。
```sh
# インストール
npm install -D knip typescript @types/node

# 実行
npx knip
```
### 実行例
以下は、`Knip`を実行した際のサンプル出力です。
```sh
Unused files (2)
  src/oldFile.ts
  src/unusedComponent.tsx

Unused dependencies (2)
  lodash
  moment

Unused exports (3)
  functionA in src/utils.ts
  constantB in src/constants.ts
  typeC in src/types.ts
```
# Knipの機能
`Knip`は"zero config"を目指しているツールで、追加の設定なしに多くのプロジェクトで利用可能です。
特に以下のような場合でも、簡単に導入することができます。

+ 各種linterやtest runner、ビルドツールの設定でimport文を使わず暗黙的に読み込むパッケージがある場合
+ monorepoで複数の package.json が存在する場合

# Knipの仕組み
`Knip`が不要なコードを検出する仕組みを理解するためには、エントリーファイルとプラグインという概念が重要です。
### エントリーファイル
エントリーファイルは、不要なコードを検出する際の起点となるファイルです。デフォルトでは index.ts や main.tsx などがエントリーファイルとなります。

`Knip`はエントリーファイルから順番にimportされているファイルを解析し、使用しているパッケージやexportされている変数、関数、型などを検出します。
```typescript:index.ts
import { functionA } from './utils'
import { componentX } from './components'

// 使用しているコードのみ
functionA()
componentX()
```
```typescript:utils.ts
export const functionA = () => {
  console.log('Function A')
};

export const functionB = () => {
  console.log('Function B')
};
```

```typescript:components.tsx
export const componentX = () => {
  return <div>Component X</div>
}

export const componentY = () => {
  return <div>Component Y</div>
}
```
上記の例では、functionBとcomponentYが未使用として検出されます
### プラグイン
プラグインは、各ライブラリ（例えばJestやESLint、Next.jsなど）で使用しているファイルから不要なコードを検出する機能です。

プラグインを有効化することで、特定のライブラリやフレームワークに依存するファイルも解析対象に含めることができます。

例えば、Jestのテストファイルに対しても解析を行う設定が自動で適用されます。
```javascript:jest.config.js
module.exports = {
  testMatch: ['**/__tests__/**/*.js?(x)', '**/?(*.)+(spec|test).js?(x)'],
}
```
```typescript:__tests__/example.test.ts
import { functionA } from '../utils'

test('functionA test', () => {
  expect(functionA()).toBe(undefined)
})
```
この例では、__tests__/example.test.tsファイルも`Knip`の解析対象になります。
# Knipの導入事例
KnipはTypeScriptやJavaScriptのプロジェクトで広く利用されており、特にベースマキナのプロジェクトでは不要なコードの整理に大いに役立っています。

また、Knipは設定がシンプルであり、導入後のエラー対処も容易であるため、多くのエンジニアにとって使いやすいツールとなっています。
# プラグインが正しく機能しない場合の対処法
Knipはzero configとはいえ、追加設定が必要な場合もあります。

例えば、プラグインに関連したパッケージが正しく検出されない場合、以下のように設定を追加することで解決できます。
```typescript:knip.config.ts
export default {
  jest: {
    entry: ["**/__custom_tests__/**/*.ts"],
    config: ["jest.config.ts"],
  },
  ignoreDependencies: ["jest-watch-select-projects"],
}
```
# おわりに
今回は、TypeScript/JavaScriptの不要なコードを検出するツール「Knip」について紹介しました。

Knipはzero configを目指しているツールであり、簡単に導入できるため、ぜひ皆さんのプロジェクトでも試してみてください。

Knipを利用することで、プロジェクトのコードベースをよりクリーンに保つことができます。

# 参考文献

https://tech.basemachina.jp/entry/introduction-knip
discord.js v14での権限設定、確認

りょうです。
今回はdjs v14の権限の設定、確認とうについての記事です。
それではれっつごー👍

## PermissionsBitField
discord.js v13で使われていた`Permissions`がv14で**PermissionsBitField**に変更されました。

```diff_javascript
- const { Permissions } = require('discord.js');
+ const { PermissionsBitField } = require('discord.js');
```

内容的には特に変更はありません。

よく使われる奴ら置いときます。
この形で使うようにしてください。↓
```
Permissions.BitField.Flages.権限名
```
|権限名|内容|
|:-:|:-:|
|Administrator|管理者|
|KickMembers|メンバーのキック|
|BanMembers|メンバーのBAN|
|ViewChannels|チャンネルの閲覧|
|SendMessages|メッセージの送信|
|ManageMessages|メッセージ管理(削除等)|
|ManageChannels|チャンネル管理(作成、削除)|
|ManageRoles|ロールの管理(作成、削除)|
|ManageWebhooks|ウェブフックの管理(作成、削除)|
|ReadMessageHistory|メッセージ履歴の閲覧|
|Connect|VCへの接続|
|Speak|VCでの発言|
|MuteMembers|VCでのメンバーのミュート|

## 権限を持っているかの確認
権限の確認には`member.permissions.has`を使用します。

メンバー(実行者)が権限を持っているか確認(今回は管理者権限)
**テキストコマンドの場合↓**
```js
   	if (!message.member.permissions.has(PermissionsBitField.Flags.Administrator)) {
   	return 
   	}
```

**スラッシュコマンドの場合↓**
```js
    if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) {
    return 
    }
```

bot自身が権限を持っているか確認
**テキストコマンドの場合↓**
```js
   	if (!message.guild.members.me.permissions.has(PermissionsBitField.Flags.Administrator)) {
   	return 
   	}
```

**スラッシュコマンドの場合↓**
```js
    if (!interaction.guild.members.me.permissions.has(PermissionsBitField.Flags.Administrator)) {
    return 
    }
```

`!ping`などのようなテキストコマンドであれば`message.member.permissions.has`です。
スラッシュコマンドの場合は`message`のかわりに`interactions`を使うので間違えないように注意。
これを使用することで特定の権限を持つユーザーのみが実行できるコマンドの実装が可能になります。

## チャンネルの権限の変更
チャンネルの権限をいじるのは`permissionOverwrite`を使用します。
ユーザーID、ロールIDなどで指定します。
**allow**で許可する権限、**deny**で禁止する権限を設定します。
また、everyoneロールに関しては`guild.roles.everyone`で指定できます。

チャンネルの閲覧を許可し、メッセージの送信を禁止している例↓
```js
 message.channel.permissionOverwrites.set([
   {
     id: 'ロールID または メンバーID', 
     allow: [PermissionsBitField.Flags.ViewChannel], 
     deny: [PermissionsBitField.Flags.SendMessages], 
     type: 'role または member' 
   }
 ], '理由');
 ```
 `type`の部分はロールIDを入力した場合はroleに、メンバーIDを入力した場合はmemberにしてください。

## まとめ
権限の設定、確認方法を知っておくとbot開発に幅が出ます。
チケットの作成や特定権限持ちにだけ実行できるコマンドなどの実装もできるようになるのでさっさと覚えておきましょう。
こんなのがほしいとかあればコメントしてもらえれば書くかもです。

**Discordに湧く荒らしの情報や対策方法の共有をしている界隈最大規模の自鯖↓**
https://discord.gg/ESRGwGQhxc
LLMのハルシネーション軽減プロンプト

## 具体的なプロンプト例

『CoVe（Chain-of-Verification）』を実行するためにユーザーが行うことは、初期の質問プロンプトにて、以下のようにLLMへの指示を追加することです。
```
ユーザー：
[質問]
1. まずは上記の問いに対して、回答の初稿を作成してください。
2. 回答を細かく分解して複数の小さな問い（検証質問）を生成してください。
3. それぞれの小さな問いに対して細かく回答してください。
```
上記のように自発的な検証を促すプロンプトによって、回答の質が上がります。
なお。ChatGPTのようなインタフェースでは上記で実行できますが、システムにあらかじめ組み込む場合も考えられます。

## 実験結果
本フレームワークによって回答の質が向上する（ハルシネーションが減る）ことが以下のように示されています。
① Wikidataタスクにおいて、Llama 65Bのfew-shotベースライン（0.17）から大幅に精度を向上させ、0.36に達した
② MultiSpanQAにおいて、F1スコアがfew-shotベースライン（0.39）から23%向上し、0.48になった
③ ネガティブな回答（ハルシネーション）が2.95から0.68に減少した
④ 長文生成においても、FACT SCOREが28%向上した

## 引用元
https://x.com/ai_database/status/1705071910885941683
[ワンライナー]特定のタグが無いVPCのインスタンスを全て停止する

# はじめに
以前、下記の記事を公開したのですが、こちらは特定のVPCのインスタンスを定期的に停止、起動する方法でした。

https://qiita.com/katahiro/items/0043b25b0b1090c04054

要望「むしろ止めちゃいけないもの以外全部止めたいです」

なるほど、では止め方を考えてみましょう

# 前提条件
- Shell Script実行環境
- IBM CloudのCLIを利用
- `jq`コマンドを利用
- 全てのリージョン、全てのVPCに対するアクセス権限がある

権限があればIBM Cloud Shellで実行も可能ですね。

# ワンライナー
IBM Cloudに既にCLIでログインした状態からになります。
停止状態ではないインスタンスに `dont-stop-me-now` タグが付いていない場合は、インスタンスを停止するように指示しています。実は怖くて実行はしていません。
```shell
for region in us-south us-east br-sao ca-tor eu-gb eu-de eu-es jp-tok jp-osa au-syd ; do ibmcloud target -r $region 1>/dev/null 2>&1 ; ibmcloud is ins --json | jq '.[] | select(.status != "stopped")' | jq -cr '.id' | while read line ; do if [ -z `ibmcloud resource search $line --json | jq -cr '.items[].tags[]' | grep -x "dont-stop-me-now"` ];then ibmcloud is in-stop -f $line ; fi ; done ; done
```
同じだけど、ちゃんと書くと次になります
```shell
for region in us-south us-east br-sao ca-tor eu-gb eu-de eu-es jp-tok jp-osa au-syd
do 
  ibmcloud target -r $region 1>/dev/null 2>&1
  ibmcloud is ins --json | 
  jq '.[] | select(.status != "stopped")' | 
  jq -cr '.id' | 
  while read line
  do 
    if [ -z `ibmcloud resource search $line --json | jq -cr '.items[].tags[]' | grep -x "dont-stop-me-now"` ];
    then 
      ibmcloud is in-stop -f $line
    fi
  done
done
```

# 汎用操作ツールとの連携
先に紹介した記事では、環境変数に `INSTANCE_ID` を指定して、`COMMAND02` でそのインスタンスIDのインスタンスを停止するようにしていましたが、こちらの `INSTNACE_ID`は指定せず、`COMMAND02`に 先ほど紹介したワンライナーのコマンドを指定すれば動くと思います。

https://qiita.com/katahiro/items/0043b25b0b1090c04054

# さいごに
あまり多くないと思いますが、複数の利用者がいて、検証用環境だけどサーバー立ち上げっぱなしになっていて、費用発生してるけど、止めて良いの？他の人からすると思うかもしれません。
止めちゃいけないもの以外は止めちゃう、という方法も1つのCloud節約手段なのかなと思い、こちらの記事を書かせて頂きました。
RSpecでよく遭遇するエラーとその解決法

RSpecを使ってRubyのテストを行う際、特定のエラーに遭遇することがよくあります。この記事では、よく直面するエラーとその解決方法について簡単に解説します。

# 1. NoMethodError: undefined method
#### エラーの原因
メソッドが定義されていないオブジェクトに対して呼び出された。
スペルミスや、メソッドが期待するコンテキストで利用されていない。
#### 解決方法
メソッド名を確認し、スペルミスがないかチェックします。
オブジェクトが正しく初期化されているか確認します。
メソッドのスコープや継承の関係を確認し、メソッドが呼び出せる状態にあるかを確認します。

# 2. NameError: uninitialized constant
#### エラーの原因
定数やクラス名が正しく定義されていない。

#### 解決方法
定数やクラス名を確認し、正しく定義されているかチェックします。
ファイルの読み込み
必要なファイルを読み込んでいるか確認します。
```
require_relative 'your_file'
```
# 3. RSpec::Expectations::ExpectationNotMetError
#### エラーの原因
期待した結果と実際の結果が一致しない。
#### 解決方法
expectとactualの値を再確認し、テストの意図が正しく表現されているかを確認します。
期待される結果が現実的かを検討し、テストケースを見直します。
```
expect(actual).to eq(expected)
```

# 4. ArgumentError: wrong number of arguments
#### エラーの原因
メソッドが想定する引数の数と、実際に渡された引数の数が異なる。
#### 解決方法
メソッドの定義を確認し、引数の数やデフォルト値が正しく設定されているかチェックします。
テストケースで渡している引数の数を確認し、適切な数を渡しているか確認します。

# 5. ActiveRecord::RecordInvalid
#### エラーの原因
データベースに保存しようとしたレコードが、バリデーションに失敗した。
#### 解決方法
モデルのバリデーションルールを確認し、テストデータがそれに従っているかを確認します。
バリデーションに失敗した具体的な原因をerrors.full_messagesなどで確認して、データを修正します。
#
今回紹介したエラーは、RSpecのテストを行う際によく見られるものですが、解決方法を理解しておくことで、スムーズにテストを進めることができます。エラーが発生した際には、まずエラーメッセージをよく読み、どの部分で問題が発生しているのかを特定することが大切です。
すげぇエンジニアってどういう人？

なんのまとまりもない独り言。

# エンジニアから見たすげぇエンジニア
- あの人開発めっちゃはやいな
- 他の人のコードもめっちゃ指摘するし
- 設計ん時も全然俺らが考慮できてないことめっちゃ考えてる
- エラーあっても聞いたら絶対解決するもんな
- ちょっと見てもらったらささっと調べて「これちゃう？」って
- 触ったことない言語でもすぐ既存メンバー以上の生産性出すし
- **あいつに任せれば、なんとかしてくれんねんなぁ**

そう、「なんとかしてくれる」。
これがすごく、すげぇし頼れる。
開発者からしてもそうだし、マネジメント側からしてもそうだし。
初めてやることでも、なんとかしてくれる。
安心して任せられる。

# 顧客から見たすげぇエンジニア
- あの人、こっちが要望伝えたら、絶対最適なもん提案してくれる
- 他の人に聞いたら結構な見積額になったり、今の資産を活用する前提の提案やけど、あの人は現行システムも既存サービスもローコード・ノーコードも視野に、将来のこととかも見越して提案してくれるし、実際やってくれる。
- 他の会社やと、ローコードは扱ってませんとか担当変えますとかあるけど、あの人はなんでもやってくれる

エンジニアっつーか、開発会社？ITコンサル？
まぁ客からしたら手段なんてどうでもいいって話。
やりたいこと、解決したいこと、良くしたいことがあって、それが安く早く品質良く実現できるなら、スクラッチだろうがローコードだろうが既存サービス導入だろうがどうでもいい。（もちろん自社で保守する前提で自社のスキルに合わせたもんで作って、ってこともあるけど）
それを叶えてくれるならなんでもいいんだよ。
別にハイコード開発専門のプログラマーでもいいけど、言語なんてマジでどうでもいいんだよ。
プロの目で最適な技術選定して提案してくれ。
お前が得意とか苦手とかはどうでもいい。
やれるとこに依頼すっからよぉ。

---
まぁそんな単純な話ではないんだが。
各ディレクトリにアクセス可能なユーザーのリストを再帰SQLで求める

# 問題設定

ディレクトリのツリーがある。
各ディレクトリごとに、そのディレクトリへの**アクセスを許可するユーザーのリスト**が定義されており、このリストに入っていないユーザーはそのディレクトリにアクセスできない。
さらに、あるディレクトリにアクセスできないユーザーは、その**子孫のディレクトリにもアクセスできない**。
このとき、各ディレクトリにアクセスできるユーザーのリストを求めたい。

# 準備

今回は、例としてこのようなディレクトリのツリーを考える。

![今回考えるツリー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/3e57a9dc-ad27-d4b7-d286-e4bb54623bab.png)

ユーザー Caroline はディレクトリ subsub にアクセス可能なユーザーのリストに含まれているが、その親ディレクトリの sub1 にアクセスできないため、ディレクトリ subsub にもアクセスできない。

これをSQLで表現する。
今回は、SQLite3を使用する。

`dirs` テーブルには、ディレクトリの名前 `name` とその親ディレクトリの名前 `parent` を格納する。
親ディレクトリが存在しない場合、`parent` は `NULL` である。

`accessors` テーブルには、ディレクトリの名前 `dir` とそのディレクトリにアクセス可能なユーザーの名前 `name` を格納する。

```sql
CREATE TABLE dirs (
	name TEXT NOT NULL,
	parent TEXT
);

CREATE TABLE accessors (
	dir TEXT NOT NULL,
	name TEXT NOT NULL
);

INSERT INTO dirs (name, parent) VALUES
	('top', NULL),
	('sub1', 'top'),
	('sub2', 'top'),
	('subsub', 'sub1');

INSERT INTO accessors (dir, name) VALUES
	('top', 'Alice'),
	('top', 'Bob'),
	('top', 'Caroline'),
	('top', 'David'),
	('sub1', 'Bob'),
	('sub1', 'David'),
	('sub2', 'Alice'),
	('sub2', 'David'),
	('subsub', 'Bob'),
	('subsub', 'Caroline');
```

:::note info
実際のデータベースでは、

* 主キーを設定する
* 外部キー制約を設定する
* ディレクトリやユーザーの名前を直接格納せずにIDで管理する

などを行ったほうがいい可能性があるが、今回は簡単のため省略する。
:::

# 再帰SQLとは

再帰SQLでは、SELECT文の実行結果として得られたテーブルを次の入力として用いることで、繰り返しデータを処理して結果を求めることができる。
(SQLite3における) 再帰SQLは、以下の形式で表せる。

```sql
WITH RECURSIVE withテーブルの形式 AS (
	非再帰項
	UNION ALL
	再帰項
)
メインクエリ;
```

これは、以下のように実行される。

1. 空の結果テーブルを用意する
2. 「非再帰項」を実行し、結果をwithテーブルに格納・結果テーブルに追加する
3. 「再帰項」を実行する。このとき、withテーブルの内容を参照できる
4. 「再帰項」を実行した結果が1行以上あれば、実行した結果をwithテーブルに格納・結果テーブルに追加し、3に戻る  
   結果が0行の場合は、メインクエリを実行する。このとき、結果テーブルの内容をwithテーブルとして参照できる

詳しくは、以下のページを参照するとよい。

[再帰SQL -図解- #Database - Qiita](https://qiita.com/Shoyu_N/items/f1786f99545fa5053b75)

# 各ディレクトリにアクセス可能なユーザーを求める

以下のSQLクエリにより、今回の問題において各ディレクトリにアクセス可能なユーザーを求めることができる。

```sql
WITH RECURSIVE allowedUsers(dirName, nextDirName, accessor) AS (
	SELECT dirs.name, dirs.parent, accessors.name
	FROM dirs
	INNER JOIN accessors ON dirs.name = accessors.dir
	UNION ALL
	SELECT allowedUsers.dirName, dirs.parent, allowedUsers.accessor
	FROM dirs
	INNER JOIN accessors ON dirs.name = accessors.dir
	INNER JOIN allowedUsers ON dirs.name = allowedUsers.nextDirName
	WHERE allowedUsers.accessor = accessors.name
)
SELECT dirName as dir, accessor
FROM allowedUsers
WHERE nextDirName IS NULL;
```

まず、非再帰項で以下の組を求める。

* ディレクトリ名
* 次にチェックを行うディレクトリ (親) 名
* そのディレクトリにアクセスできるユーザー名

あるユーザーがあるディレクトリにアクセスできる必要条件の一つは、そのディレクトリのアクセス許可リストにそのユーザーが載っていることである。
この非再帰項は、この条件のチェックに相当する。

次に、再帰項でディレクトリツリーを登り、親のアクセス許可リストのチェックを行う。
あるユーザーが親のアクセス許可リストにも入っていれば、さらにその親のチェックに進むことができる。
一方、親のアクセス許可リストに入っていなければ、登れずにチェックは終了する。

最後に、メインクエリで最後 (親が `NULL`) まで登れたディレクトリとユーザーの組のリストを取得する。

以下の実行結果が得られた。

|dir|accessor|
|---|---|
|top|Alice|
|top|Bob|
|top|Caroline|
|top|David|
|sub1|Bob|
|sub1|David|
|sub2|Alice|
|sub2|David|
|subsub|Bob|

前述のディレクトリツリーの各ディレクトリにアクセス可能なユーザーのリストがきちんと求まっているようである。