OmniAICreator/Qiita-1.07M huggingface dataset:
BibTeX 使用時に，本文中で引用文献を任意の文字列で出力する方法

# はじめに

BibTeX や biblatex を使用している際に，引用文献を任意の文字列で出力したくなったことはありませんか？
例えば，ある文献を本文中で Paper I のように呼ぶ場合などを想定しています．
他にも，日本語論文を書いている際に，本文中で英語を使用しなければいけない箇所（図表のキャプション中）では日本語文献であっても英語で出力したい場合があると思います（私はこの問題にぶつかったので解決方法を模索しました）．
ハイパーリンクを使用していない場合はベタ打ちでもいいと思いますが，ハイパーリンクを埋め込みたい場合は一工夫必要です．
やり方自体は [natbib のマニュアル](https://ftp.kddilabs.jp/CTAN/macros/latex/contrib/natbib/natbib.pdf) にも書いてありますが，意外と知られていない気がしているので困っている人に届いてくれたら嬉しいです（「そんなこと知っているよ当然じゃない？」って人はごめんなさい）．

# やり方

## `\citet` を使った通常の出力方法

`natbib` パッケージを使用するのでプリアンブルで忘れずに宣言してください．

```tex:main.tex
\usepackage{natbib}
```

例えば `bib` ファイルに以下のように記載したとします．

```bibtex:japanese.bib
@inbook{奥村:技評2023,
    author      = {奥村, 晴彦 and 黒木, 裕介},
    yomi        = {Okumura, Haruhiko and Kuroki, Yusuke},
    title       = {［改訂第9版］\LaTeX 美文書作成入門},
    publisher   = {技術評論社},
    pages       = {172--188},
    year        = {2023}
}
```

このとき，論文末尾の文献一覧には以下のように出力されます（これは使用する `bst` ファイルに依存します）．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643071/f984ac52-a039-873e-93e4-0b7c23cad4a2.png)

今書いている論文が日本語であった場合，本文中では以下のように使用します．

```tex:main.tex
今回のケースは\citet{奥村:技評2023}の統計と一致している．
```

そうすると PDF には次のように出力されますよね（これも使用する `bst` ファイルに依存します）．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643071/a82d591d-769a-b4dd-1695-5fade344dfd3.png)

ここまではこの記事を読んでいる方には問題無いかと思います．
しかし，今書いている論文が日本語であっても図表のキャプションに限っては英語で書かなければいけない場合があります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643071/c00207b8-4da6-ecd2-8d5f-772373e73f08.png)

上図の 1. のような出力だと気持ち悪いですよね（日本語文献を引用する場合は問題無いという流派もありますか？私はよくわかりません）．
上図の 2. のような出力がここでの目標です．

## 任意の文字列での出力方法

引用文献を任意の文字列で出力するコマンドとして `\citetalias` と `\citepalias` が用意されています．
ただし，どのような文字列で出力するのか宣言する必要があるので `\defcitealias` コマンドを事前に読み込む必要があります．
キャプションの中には書けないようですが，`\citetalias` よりも前の文章中で書いてあれば大丈夫です．

```tex:main.tex
\defcitealias{奥村:技評2023}{Okumura and Kuroki (2023)}
The present case is in agreement with the statistics by \citetalias{奥村:技評2023}.
```

これだけで簡単に出力できます．

`\citepalias` は括弧つきで出力してくれるコマンドです．
`\citetalias` の `\citep` バージョンだと思えばいいでしょう．
使い方は同じです．

```tex:main.tex
\defcitealias{奥村:技評2023}{Okumura and Kuroki, 2023}
The present case is in agreement with the previous study \citepalias{奥村:技評2023}.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643071/b0304a24-ec55-6777-2991-4857f859e9e0.png)


# 参考文献

[CTAN: Package natbib](https://ftp.kddilabs.jp/CTAN/macros/latex/contrib/natbib/natbib.pdf)（ターミナルで `texdoc natbib` と打っても出てきます）
自分にとって既知の内容でも、誰かにとっては新たな学びかもしれないので発信していく

## はじめに

◆この記事は何？
発信のマインドを紹介する記事です。

◆対象は？
アウトプットができていないと感じる方

◆この記事のねらい
アウトプットのハードルを下げる

## 先に結論
- あなたの当たり前は、誰かの新しい発見になるかもしれない
- 発信方法を工夫することでアウトプットのハードルが下がる

## アウトプットできないときの悩み

多くの人が「この情報は当たり前すぎて価値がないのでは？」と考え、アウトプットをためらっています。
これは機会損失につながります。

そのような悩みがあるときは、「自分にとって既知の内容でも、誰かにとっては新たな学びかもしれない」というマインドが有効です。

これにより発信のハードルが下がります。

## 発信しやすい場所

自信が持てない情報でも、適切な発信場所を選ぶことで価値ある共有になります。

例えば、私は内容に応じてQiitaや社内チャットツールなど発信場所を使い分けています。

発信内容によって場所を変えることで「誰かにとっては新たな学び」という機会を掴み取りやすくなります。


## 発信の工夫

発信の方法を工夫することで、「誰かにとっては新たな学び」を創出しやすくします。

例えば「参考文献と一緒に紹介する」です。

先日の記事は、私には当たり前の内容でしたが、参考文献をいくつか参照しながら発信しました。
その結果、多くの反響をいただきました。

https://qiita.com/mkt_hanada/items/d6c8c6ec2e11f1ad9666

## おわりに

この記事では、アウトプットのマインドについて紹介しました。

私は「自分にとって既知の内容でも、誰かにとっては新たな学びかもしれない」ので、アウトプットを継続していきたいと思います。

それでは。
【PHP】mt_randの精度を調べてみた

# はじめに

ABテストのために組んだスクリプトの精度を計算してみた。

# 問題

本当に50%で結果が出るのか文献が見つからなかったので。
（というか探すより自分で調べたほうが早い）

# 解決方法

下記を実行するのみ。

```test.php
<?php

function testRandomness($arr, $trials = 1000) {
    $results = [
        'count0' => 0,
        'count1' => 0
    ];

    for ($i = 0; $i < $trials; $i++) {
        $result = mt_rand(...$arr);
        if ($result < $arr[1]/2) {
            $results['count0']++;
        } else {
            $results['count1']++;
        }
    }

    return $results;
}

// 試行回数を指定して関数を実行
$trials = 1000000; // ここで試行回数を指定
$results = testRandomness([0,1],$trials);

echo "試行回数: $trials\n";
echo "0の割合: " . ($results['count0'] / $trials * 100) . "%\n";
echo "1の割合: " . ($results['count1'] / $trials * 100) . "%\n";


$results = testRandomness([0,1000],$trials);

echo "試行回数: $trials\n";
echo "0の割合: " . ($results['count0'] / $trials * 100) . "%\n";
echo "1の割合: " . ($results['count1'] / $trials * 100) . "%\n";

$results = testRandomness([0,100000],$trials);

echo "試行回数: $trials\n";
echo "0の割合: " . ($results['count0'] / $trials * 100) . "%\n";
echo "1の割合: " . ($results['count1'] / $trials * 100) . "%\n";
```

# 結果

50%といって良さそうな気がします。

|   | 0,1                        | 0,1000                     | 0,100000                   | 
| - | -------------------------- | -------------------------- | -------------------------- | 
|n1| 0の割合: 49.945%<br>1の割合: 50.055% | 0の割合: 49.9088%<br>1の割合: 50.0912% | 0の割合: 50.0147%<br>1の割合: 49.9853% |  
|n2| 0の割合: 49.9824%<br>1の割合: 50.0176% | 0の割合: 49.9858%<br>1の割合: 50.0142% | 0の割合: 49.9405%<br>1の割合: 50.0595% | 
|n3| 0の割合: 50.0394%<br>1の割合: 49.9606% | 0の割合: 49.9034%<br>1の割合: 50.0966% | 0の割合: 49.9573%<br>1の割合: 50.0427% | 


# 参考

https://www.php.net/manual/ja/function.mt-rand.php
エラーの見方：Failure/Error…

## はじめに
今回は課題の中で起きたエラーメッセージについて調べたことをアウトプットします。エラー一つにしても発生場所、原因は様々で、エラー表記の部分だけを直しても改善しなかったり😢
どんなエラーでも対応できるようになりたい

## 環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3


## エラー内容
```
     Failure/Error:
       <% if @yesterday_articles.any? %>


     ActionView::Template::Error:
       undefined method any?' for nil:NilClass
```
私はこのエラー文を見た時「any?メソッドが定義されていないエラー」だと勘違いしていました。こんな誤った見方をしない為にも、少しずつかみ砕いていきたいと思います

### 1. エラーの発生場所
```
<% if @yesterday_articles.any? %>
```
- `@yesterday_articles`という変数に対して`any?`メソッドを呼び出そうとしている

### 2. エラーの内容
```
undefined method `any?' for nil:NilClass
```
- `undefined method 'any?'`という部分は`any?`メソッドが存在しないオブジェクトに対して呼び出されていることを示している
- `for nil:NilClass`という部分は、`nil`クラス（NilClass）に対して `any?`メソッドを呼び出そうとしたことを示している
- つまり、**変数`@yesterday_articles`が`nil`であるために、`any?`メソッドを呼び出そうとしてエラーが発生している**ことを示している

### nilが原因と判断できる理由
- `undefined method 'any?' for nil:NilClass`から、`@yesterday_articles`が`nil`であることがわかり、`nil`でなければ、`nil:NilClass`という部分が表示されることはないから
- `any?`メソッドは通常、配列やActiveRecordのリレーションなどのコレクションに対して使われるメソッドです。`@yesterday_articles`が`nil`でない場合、`any?`メソッドが呼び出せるはず
- 

## 解決方法
### 1. インスタンス変数の初期化を確認
ArticleMailer#report_summary メソッド内で `@articles_published_yesterday`を正しく初期化しているか確認
```
class ArticleMailer < ApplicationMailer
  def report_summary
    @total_published_articles = Article.published.count
    @articles_published_yesterday = Article.published_yesterday

    mail(to: 'admin@example.com', subject: '公開済記事の集計結果')
  end
end
```

### 2. ビューでのエラーハンドリングを追加
ビュー内で`@articles_published_yesterday`が`nil`でないことを確認するコードを追加する（app/views/article_mailer/report_summary.text.erb）
`present?`メソッドを使うことで、変数が`nil`かどうかをチェックする

```
公開済の記事数: <%= @total_published_articles %>件

<% if @articles_published_yesterday.present? %>
  <% if @articles_published_yesterday.any? %>
    昨日公開された記事数: <%= @articles_published_yesterday.count %>件

    <% @articles_published_yesterday.each do |article| %>
      タイトル: <%= article.title %>
    <% end %>
  <% else %>
    昨日公開された記事はありません
  <% end %>
<% else %>
  昨日公開された記事はありません
<% end %>
```

## さいごに
今回のエラーについては解決方法2を行うことで解決しました。よかった。英語の翻訳と少し違ってみえるエラーの文章。毎回ChatGPTが欠かせません。一昔前はこんな便利な機能がない中エラー解決していたなんて…すごすぎますね
初登壇で得た教訓と感想

# 前置き

「AWS CDK Conference Japan 2024」で人生初登壇しました。
詳しくはこのあたり。

https://qiita.com/hkusaba/items/274bcfb4fbeaeed47cf2

そこで得た教訓と感想を記載します。
教訓は、割と初心者あるあるになっている気がします。

# 教訓

## もっと発表の場数を踏んだ方がいい

発表時、登壇資料の投影どうしよっかなー、画面複製じゃなくて画面拡張でもっていったろ！という、何もわからないながらのノリでやりました。
結果として、スピーカーノート映ってへんけどやるかー。になりました。
ただ、発表練習（後述）をしていたおかげで、スライドを見ながらなんとか発表できました。

結果として、大きめのカンファレンスにいきなり登壇するより、LT会などを通じて、どういう風に画面を表示すると発表しやすいかを試行錯誤する機会をいくつか設けた方がいいです。
さらに、会場によって、登壇者から見た時に、投影されているスライドが見やすい見にくいなどの差異があるので、その差分を吸収できる形がベターです。

## モニターチェックには時間をかけた方がいい

起きた現象としては同上。
焦らず、自分が納得できるまで、ある程度の時間を取った方がいい。

## オーディエンス有りの発表練習は直前に組んだ方がいい

当日の10日前くらいに、社内で人を集めて、オーディエンスありきの発表練習の機会を設けました。
結果、喋り方・発表のファインチューニングや、レイアウト・構成などの資料の微修正・微調整を行うことができました。
ここまではよかった。
ただ、10日前の早い段階で実施してしまったため、「なんだ、いけるじゃん。」という安心が勝ち、これでいいやという風に資料を大きく見直さないようになってしまいました。

結果として、発表後に、資料の流れとか自分の話したかった事がそもそも抜けていたことに気付きました。
なので、ある程度資料も固まって、日付も近いタイミングでやることをオススメします。
例えば3日前とかがいいんじゃないですかね。

## 短めの枠で応募する

そこまでコアな話・込み入った話をしないのであれば、基本的に10分で足りる。
応募時に悩んで、15分枠があったら嬉しいけれど無いので20分でいこう！と思ったのですが、これは結果的に失敗だったと思ってます。
手短に話を簡潔にまとめること・時間を巻きで発表することよりも、トピックを広げることの方が難しいです。

シンプルなトピックであれば、短い枠で応募しましょう。

## 自分の意見や体験を盛り込むこと

概要だけを話してしまうと、どう思ったの？結局どうなの？という感じで、発表内容が薄っぺらくフワッとしちゃいます。
（詳細は、ページ上部のQiitaの記事を参照

発表内容の軸の実際のユースケースや、結論として何を言いたいのか、ということを書いておきましょう。
プロポーザル時点で盛り込めるとベターです。

これを行うことで、懇親会でいろんな人との会話も膨らみ、更にイベントを楽しめ、より多くのコミュニティとの対話が生まれると思います。

## プロポーザルに忠実に

当たり前で簡単に聞こえますが、大事です。

プロポーザルを出してから本番まで、時間の変遷とともに、プロポーザルを出した時の意図や想いは薄れていきます。
それらを忘れないようにすること、もっというと、それらをプロポーザル上で明文化しておくことが大事です。


# やっていて良かった点

発表練習をオーディエンス有でやっておくと、人のリアクションを見ながら話す練習ができます。
すると、本番の緊張よりも発表することに集中でき、余裕が生まれます。

# 登壇はいいぞ

発表面白かったですと言ってくださる人がいて、私は嬉しかったです。
普段コミュニティから情報をもらってばかりだった私が、一時的に何かを与えることができたので、少しだけコミュニティに恩返しできたと思っています。

また、自分ではそんなことと思っている内容も、他者から見ると新たな視点になるんだなと感じました。
話してみたい！でプロポーザルを出して、話してみるって大事です。
より多くの人が知見を分け合うことで、コミュニティは維持でき、更に成長することが出来ると考えてます。


また、懇親会での議論も、他の方の視点で出た質問に対して話すことができ、楽しかったです。

---

初登壇だったので、多少の失敗はあれど楽しかったし、学ぶことが多かったです。

ぜひ若手の人も、登壇にチャレンジしてみたいなと思いました。
（LTからがオススメ
そして、毎週のように登壇している人は本当に凄いなと思います。

ありがとうございました。
2件目も楽しかったです。
Tabcmdを利用して、Tableau CloudまたはServerからビューをダウンロードしてみた

## 前提
・Tabcmd実行マシンは、Windows OSを前提にしております。
## 参考サイト
https://help.tableau.com/current/online/ja-jp/tabcmd.htm

https://github.com/tableau/tabcmd/releases

https://help.tableau.com/current/online/ja-jp/security_personal_access_tokens.htm

## 手順
### 1.Tabcmdのインストール
#### ①以下のサイトから、Tabcmdをダウンロード
・Windows OSの場合：tabcmd.exe
・mac OSの場合：tabcmd-mac.zip

https://github.com/tableau/tabcmd/releases

#### ②Tabcmdをインストール
ダウンロードしたtabcmd.exeをダブルクリックして、インストール
インストール先など変更の場合は、以下のヘルプをご参照ください。

https://help.tableau.com/current/online/ja-jp/tabcmd.htm
### 2.Tableau CloudのPATを作成
https://help.tableau.com/current/online/ja-jp/security_personal_access_tokens.htm
#### ①Tableau Cloudの右上のプロファイルアイコンをクリックし、「マイアカウントの設定」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/1d883033-f63d-8c00-90e2-a28c0c19a9a8.png)
#### ②個人用アクセストークンのトークン名を入力し、「トークンを作成する」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/c0941854-f678-ca14-e9a2-39ec24b1af05.png)
※表示されるシークレットは２度と表示されないため、メモしておく
### 3.Tabcmdより、Tableau Cloudへログイン
#### ①コマンドプロンプトを起動し、tabcmd.exeをインストールしたフォルダに移動
例：
```
C:\Users\testuser>cd Downloads
```
#### ②手順2で作成したPATを利用して、Tableau Cloudへログイン
例：(日本のPodではない場合は、-sのURLを変更してください。)
```
tabcmd login -s https://prod-apnortheast-a.online.tableau.com -t サイト名 --token-name トークン名 --token-value トークンシークレット
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/f998e57c-0c95-fd2d-f631-0522242ac646.png)
### 4.Tableau Cloudからビューをダウンロードするバッチを作成
```
@echo off
cd "C:\Users\testuser\Downloads"
tabcmd export "_PL_01/sheet4?カテゴリ=家具&サブカテゴリ=テーブル" --pdf -f "C:\Users\testuser\Downloads" --filename "test.pdf"
```
補足：
・export後ろの""の中には、＜workbook＞/＜view＞を入力。ビューのURLの.../views/後ろの部分から切り抜く
・フィルターは、?の後ろにフィルター名と値を入力。複数の場合は、&で区切りをする
・パラメータ指定の場合は、頭にParameters.を追加
例：
```
@echo off
cd "C:\Users\testuser\Downloads"
tabcmd export "_PL_01/sheet4?事業部=事業部B&Parameters.費目切り替え=固定費" --pdf -f "C:\Users\testuser\Downloads" --filename "test.pdf"
```
https://help.tableau.com/current/server/ja-jp/tabcmd_cmd.htm#iddf805b62-18ff-4497-9245-adc6905b2084
### 5.バッチを実行
#### ①バッチをダブルクリックして、実行
#### ②Windowsのスケジュールに登録して、自動化する場合は、以下のブログをご参考。
https://qiita.com/Richard_Roe/items/44e16841f16ee40c6113
## トラブルシューティング
#### ①プロキシ
プロキシーが途中経路上に存在する場合は、—proxy もしくは -x オプションが利用可能。
プロキシーで認証が必要な場合は、あいにく対応するオプションが実装されてないため、
プロキシーを回避してインターネット経由でTableau Cloudへ接続頂く必要がある。

https://tableau.github.io/tabcmd/docs/tabcmd_cmd.html

　（抜粋）
　-x, —proxy
　Use to specify the HTTP proxy server and port (Host:Port) for the tabcmd request.
#### ②tabcmd loginユーザ
tabcmd loginコマンドを使用する場合は、サーバーがSAMLを使用するよう構成されている場合でも SAMLシングルサインオン(SSO)を使用できない。
ログインするには、サーバー上で作成されているユーザー名とパスワードを渡す必要がある。
ユーザ名とパスワードを渡せない場合は、手順2を参考にPATをご利用ください。
Goroutineを理解したい！

## Goroutineとは？Go言語の並行処理を理解しよう
Go言語（Golang）は、Googleによって開発されたオープンソースのプログラミング言語で、シンプルで効率的な並行処理をサポートしています。その中でも特に注目すべき機能が「Goroutine」です。この記事では、Goroutineの基本概念、使い方、そしてその利点について詳しく解説します。
## Goroutineとは
Goroutineは、Go言語における軽量なスレッドのようなものです。Goroutineを使うことで、プログラムの複数の部分を同時に実行することができます。Goroutineは非常に軽量で、数千から数百万のGoroutineを同時に実行することが可能です。

#### Goroutineの特徴
1. メモリ消費:
Goroutineはカーネルスレッドに比べて非常に少ないメモリしか消費しません。カーネルスレッドは1MB程度のスタックを必要としますが、Goroutineは2KBのスタックだけが必要です。
2. 生成・破壊コスト:
GoroutineはGoランタイムから生成と破壊が行われるため、コストが低いです。
3. コンテキストスイッチ:
GoroutineはM:Nモデルを採用しており、マルチタスキングによるコンテキストスイッチが抑えられ、マルチコアが活用できます。
## Goroutineの基本的な使い方
Goroutineを使うのは非常に簡単です。関数呼び出しの前にgoキーワードを付けるだけで、その関数が新しいGoroutineとして実行されます。
基本的な例
```go:例
package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello, World!")
}

func main() {
    go sayHello() // Goroutineとして関数を実行
    time.Sleep(1 * time.Second) // メイン関数が終了しないように待機
}
```
このプログラムでは、sayHello関数がGoroutineとして実行されます。time.Sleepを使ってメイン関数が終了しないようにしている点に注意してください。
#### 複数のGoroutine
複数のGoroutineを同時に実行することも簡単です。
```go:例
package main

import (
    "fmt"
    "time"
)

func printNumbers() {
    for i := 1; i <= 5; i++ {
        fmt.Println(i)
        time.Sleep(100 * time.Millisecond)
    }
}

func printLetters() {
    for i := 'A'; i <= 'E'; i++ {
        fmt.Printf("%c\n", i)
        time.Sleep(150 * time.Millisecond)
    }
}

func main() {
    go printNumbers()
    go printLetters()
    time.Sleep(1 * time.Second)
}
```
このプログラムでは、printNumbersとprintLettersの2つの関数がそれぞれGoroutineとして実行され、数字と文字が並行して出力されます。
### Goroutineの利点
1. 軽量性
Goroutineは非常に軽量で、少量のメモリしか消費しません。これは、GoランタイムがGoroutineのスケジューリングを効率的に行うためです。数千から数百万のGoroutineを同時に実行することが可能です。
2. シンプルな並行処理
Goroutineを使うことで、複雑なスレッド管理を行うことなく、簡単に並行処理を実現できます。goキーワードを使うだけで、新しいGoroutineを作成できます。
3. チャネルによる通信
Go言語には、Goroutine間での通信を簡単に行うための「チャネル」という機能があります。チャネルを使うことで、Goroutine間でデータを安全にやり取りすることができます。
チャネルの基本的な使い方
以下は、チャネルを使った基本的な例です。
```go:例
package main

import (
    "fmt"
)

func sum(a []int, c chan int) {
    total := 0
    for _, v := range a {
        total += v
    }
    c <- total // チャネルに結果を送信
}

func main() {
    a := []int{1, 2, 3, 4, 5}
    c := make(chan int)
    go sum(a, c)
    result := <-c // チャネルから結果を受信
    fmt.Println(result)
}
```
このプログラムでは、sum関数がGoroutineとして実行され、計算結果がチャネルを通じてメイン関数に送信されます。
### Goroutineのスケジューリング
GoroutineのスケジューリングはGoランタイムによって管理されます。Goランタイムは、利用可能なリソース（CPUコアやスレッド）を最大限に活用し、全てのGoroutineが均等に処理されるようにします。
### M:Nスケジューリング
Goランタイムでは、M:Nスケジューリングモデルが採用されています。これは、M個のGoroutineをN個のカーネルスレッドにマッピングすることを意味し、1つのカーネルスレッドが複数のGoroutineを切り替えながら実行することができます。
### スケジューリングの透過性
Goを使用する開発者は、スケジューリングの詳細を気にする必要がありません。プログラマは単にgoキーワードを使ってGoroutineを起動するだけで、後はランタイムが適切にスケジューリングを行います。
## まとめ
Goroutineは、Go言語の強力な並行処理機能の一つです。軽量でシンプルなGoroutineを使うことで、効率的な並行処理を実現できます。さらに、チャネルを使うことで、Goroutine間の通信も簡単に行うことができます。

#### 参考文献:
- https://www.ariseanalytics.com/activities/report/20221005/ 
- https://zenn.dev/farstep/articles/f712e05bd6ff9d
- https://zenn.dev/nobonobo/articles/53b1539ae1dd09 
- https://hiramekun.hatenablog.com/entry/2023/12/29/002550
Popover

```tsx
import React, { useState } from 'react';
import CommentIcon from '@mui/icons-material/Comment';
import Popover from '@mui/material/Popover';
import Typography from '@mui/material/Typography';
import { Button, Box } from '@mui/material';

const CommentIconWithPopover: React.FC = () => {
  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

  const handlePopoverOpen = (event: React.MouseEvent<HTMLElement>) => {
    setAnchorEl(event.currentTarget);
  };

  const handlePopoverClose = () => {
    setAnchorEl(null);
  };

  const open = Boolean(anchorEl);

  return (
    <Box
      display="flex"
      justifyContent="center"
      alignItems="center"
      height="100vh"
    >
      <Button
        onMouseEnter={handlePopoverOpen}
        onMouseLeave={handlePopoverClose}
      >
        <CommentIcon />
      </Button>
      <Popover
        id="mouse-over-popover"
        sx={{
          pointerEvents: 'none',
        }}
        open={open}
        anchorEl={anchorEl}
        anchorOrigin={{
          vertical: 'top',
          horizontal: 'left',
        }}
        transformOrigin={{
          vertical: 'bottom',
          horizontal: 'right',
        }}
        onClose={handlePopoverClose}
        disableRestoreFocus
      >
        <Typography sx={{ p: 1 }}>テキストを表示します</Typography>
      </Popover>
    </Box>
  );
};

export default CommentIconWithPopover;
```

* id: id="mouse-over-popover"

このidプロパティは、このPopoverコンポーネントの一意の識別子です。他の要素と区別するために使用されます。

* sx: sx={{ pointerEvents: 'none' }}

sxプロパティは、MUIコンポーネントにスタイルを追加するためのプロパティです。ここでは、pointerEvents: 'none'が設定されており、これによりPopoverがマウスイベント（クリック、ホバーなど）を受け付けないようにしています。

* open: open={open}

openプロパティは、Popoverが表示されるかどうかを制御します。trueの場合、Popoverは表示され、falseの場合は非表示になります。

* anchorEl: anchorEl={anchorEl}

anchorElプロパティは、Popoverのアンカー要素（基準となる要素）を指定します。Popoverはこの要素に基づいて位置が決まります。ここでは、CommentIconにカーソルがホバーされたときに設定される要素です。

* anchorOrigin: anchorOrigin={{ vertical: 'top', horizontal: 'left' }}

anchorOriginプロパティは、アンカー要素のどの部分を基準にしてPopoverを表示するかを指定します。ここでは、アンカー要素の上部(vertical: 'top')の左側(horizontal: 'left')を基準にPopoverが表示されます。

* transformOrigin: transformOrigin={{ vertical: 'bottom', horizontal: 'right' }}

transformOriginプロパティは、Popoverのどの部分を基準にして位置を調整するかを指定します。ここでは、Popoverの底部(vertical: 'bottom')の右側(horizontal: 'right')が基準となります。

* onClose: onClose={handlePopoverClose}

onCloseプロパティは、Popoverが閉じられるときに呼び出される関数を指定します。ここでは、handlePopoverClose関数が呼び出され、Popoverが閉じられます。

* disableRestoreFocus: disableRestoreFocus

disableRestoreFocusプロパティは、Popoverが閉じられたときにフォーカスを元の要素に戻さないようにします。通常、Popoverが閉じられると、フォーカスが元のアンカー要素に戻りますが、このプロパティを設定するとそれを無効にします。
ev3devとDUALSHOCK 4の融合

この記事では、Pythonを使ってPS4コントローラーをEV3に接続していろいろ取得します。

DUALSHOCK 4を前提にコードを書いていますが、別のコントローラーにも応用が利くと思います。

## コード

PS4コントローラーを検出し、コントローラーの入力に基づいてEV3ロボットのモーターを制御します。

```python
#!/usr/bin/env python3
import evdev
import ev3dev.auto as ev3
import threading

def scale_stick(value):
    return (value / 255) * 2000 - 1000

def dc_clamp(value):
    return max(min(1000, value), -1000)

# PS4コントローラーの検出
print("Finding PS4 controller...")
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
ps4dev = devices[0].fn
gamepad = evdev.InputDevice(ps4dev)

# モータースレッドクラス
class MotorThread(threading.Thread):
    def __init__(self):
        self.left_motor = ev3.LargeMotor(ev3.OUTPUT_B)
        self.right_motor = ev3.LargeMotor(ev3.OUTPUT_C)
        threading.Thread.__init__(self)

    def run(self):
        while True:
            self.left_motor.run_forever(speed_sp=dc_clamp(forward_speed - turn_speed))
            self.right_motor.run_forever(speed_sp=dc_clamp(-forward_speed - turn_speed))

motor_thread = MotorThread()
motor_thread.setDaemon(True)
motor_thread.start()

# コントローラー入力の処理
forward_speed = 0
turn_speed = 0
for event in gamepad.read_loop():
    if event.type == 3:  # スティックの移動
        if event.code == 1:  # 左スティックのY軸
            forward_speed = scale_stick(event.value)
        if event.code == 3:  # 右スティックのX軸
            turn_speed = scale_stick(event.value)
```

## 解説
```python
import evdev
```
`evdev`はあまり聞き覚えがないですがコントローラーからの入力を処理するために使っています。

```python
print("Finding PS4 controller...")
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
ps4dev = devices[0].fn
gamepad = evdev.InputDevice(ps4dev)
```
接続されたデバイスからコントローラーを見つけています。

```python
for event in gamepad.read_loop():
    if event.type == 3:  # スティックの移動
        if event.code == 1:  # 左スティックのY軸
            forward_speed = scale_stick(event.value)
        if event.code == 3:  # 右スティックのX軸
            turn_speed = scale_stick(event.value)
```
スティックの入力値は-1000から1000の範囲で提供されます。ちょうどモーターの速度も-1000から1000なのでちょうどいいですね。

## `event.type`と`event.code`

それぞれイベントの値は以下のサイトを参考にするといいと思います。
https://github.com/codeadamca/ev3-python-ps4
ただサイトによって書いてある値がまちまちだったり、間違っていたりするので実際にコードを組んて動かしてみるのが安全です。
私の方で検証できたら、まとめます。

## 参考文献

https://www.ev3dev.org/projects/2018/09/02/PS4Explor3r/

https://python-evdev.readthedocs.io/en/latest/apidoc.html
【Nginx】POSTで受けたリクエストをGETでリダイレクトする

Nginxでリバースプロキシサーバーを構築している際に、POSTで受けてGETでリダイレクトするような必要がありました。
その際にあまり情報がなく詰まったので記録として残します。

## 前提
以下のような設定イメージで、リクエストをhttpsで受けた後内部IPを使って別のサーバーにhttpでリダイレクトを行なっています。
```nginx.conf
server {
    listen       443 ssl;
    server_name  example.com;

    proxy_set_header Host               $host;
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host   $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP          $remote_addr;

    ssl_certificate /etc/nginx/example.com.crt;
    ssl_certificate_key /etc/nginx/example.com.key;

    # GET : https://example.com/sample/hoge?param1=123&param2=abc
    location ~^/sample/hoge$ {
          # GET : http://192.168.0.0.8080/sample/hoge?param1=123&param2=abc
          proxy_pass http://192.168.0.0:8080;
    }
}
```

## 解決策
以下のようにリダイレクトする際のmethodをGETに指定しつつパラメータを引き渡すことで実現できました。
```nginx.conf
server {
    listen       443 ssl;
    server_name  example.com;

    proxy_set_header Host               $host;
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host   $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP          $remote_addr;

    ssl_certificate /etc/nginx/example.com.crt;
    ssl_certificate_key /etc/nginx/example.com.key;

    # GET : https://example.com/sample/hoge?param1=123&param2=abc
    location ~^/sample/hoge$ {
          # GET : http://192.168.0.0.8080/sample/hoge?param1=123&param2=abc
          proxy_pass http://192.168.0.0:8080;
    }

    # POST : https://example.com/sample/fuga?param1=123&param2=abc
    location ~^/sample/fuga$ {
          # GET : http://192.168.0.0.8080/sample/fuga?param1=123&param2=abc
          proxy_method GET;
          proxy_pass http://192.168.0.0:8080$request_uri;
    }
}
```
レジストリってどんな情報が入ってるんだろうね？

# 免責事項
自分の管理してるマシンについてのみ行ってくださいね。
当たり前だけど、ここに書いた話勝手に試してトラブル起きても何ら責任負わんので。

# はじめに
なんとなくレジストリを眺めてみたくなった。
とはいえ、ただ漠然と眺めるだけじゃなくて、ツール使って見る観点を絞りながら見ていこうと思う。

[Registory Explorer](https://ericzimmerman.github.io/#!index.md)を使って、どんな情報が入っているのかをまず見てみる

とりあえずユーザ関係で色々出てきそうなSAM（セキュリティアカウントマネージャ）あたりから見てみようと思う

# ユーザの一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/b7da766b-8e28-a397-ce99-c78dd15e9b26.png)

もはや言うまでもなくアカウント一覧が出てきたよね。

秘密の質問が書いてあったので見てみる。
これを入力するとパスワード再設定ができてログインができるわけですな。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/0d1acdd7-c967-feb6-bee3-403c1052aa3a.png)

この秘密の質問を設定したところのスクショ。
![スクリーンショット 2024-07-10 091108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/fa335b0f-b98d-9d1d-a8c3-dee2b969ec2f.png)

しかもこのローカルアカウント、Adminグループなので悪い人がこの技術使ったらPCに直接触れる人であれば、パスワードの変更なんかも容易なんですよね。
まぁそんな感じです。

# レジストリファイル等のシステムファイルの収集方法
適当なLinuxを[rufus](https://rufus.ie/ja/)でUSBメモリに焼いて、Linuxでブートしたあと
ファイルシステムを読み込み専用でマウントしてアーティファクト収集をしてみた。
これ以外にも手当たり次第、プリフェッチファイルとかAmCacheとかWindowsイベントログを収集してみた。

# この技術の応用
もし、秘密の質問機能を使っているなら、パスワード忘れても安心だね！
適当にLinuxでブートして、SAM拾ってきて秘密の質問の回答を見ればパスワード変更できるよ

おわり。
divタグの高さは中の子要素に高さによって、高さが決まる

divタグは特に指定をしない限り、中の子要素の高さによって、高さが決まります。
知ってはいたのですが、色々組み合わせていると少しハマったので記事にしてみました。

### ハマったポイント
要素同士を親のdiv要素の上端、下端にそれぞれ配置しようとしたのですが、要素同士がくっついたままでした。
```html
<div class='container'>
  <div class='child-1'></div>
  <div class='child-1'></div>
</div>
```

```css
.container {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
```

↑のコードだと子要素同士がくっついたままになっていて、2番目の子要素の下に大きなスペースがありました。
検証ツールを使って確認してみたところ、親要素も2つの子要素の大きさの幅しかなく、開いていたスペースは更にその親の要素のものでした。

### 修正

なので、親要素に高さを指定し、子要素を上下端に配置させました。
```css
.container {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 300px; /* これ */
}
```
社内SEのエンジニアライフプラン

個人的「質はともかく継続する」33日目です。

## 社内SEの難しさ

私はいま社内SEとして勤務していますが、エンジニアとしてのプランが難しいなぁと感じることが多くなりました。
もともとはSESとして働いていたのですが、年齢を重ねるにつれてプライベートで融通が利きやすいほうが都合よくなったので、社内SEへと転身することにしました。
当初の問題は解決したのですが、社内SEにはそれはそれで難しいところがありました。

## 市場価値を上げづらい

社内SEにも色々あると思いますが、私は主に社内システムの内製化に関わった仕事をしています。
ある社内の業務アプリを製造し、運用し、保守し、また製造し...という感じです。
内製システムの開発・保守となると、決まった技術を使い続けることになります。
そうすると、どうしても社内独自のフレームワークやシステムの扱いにばかり長けることになり、一般的に普及しているフレームワークや言語、クラウドサービス等を使う機会がほとんどありません。
研修や研究という名目で使うことはありますが、やはり勉強レベルで、実務レベルでの利用はありません。
そうなると、どうしても今の会社特化エンジニアになってしまい、市場で求められているスキルを身につけるのが困難になります。

## 温度差を感じることがある

個人的には新しいフレームワークや言語、アプリ等は大好きです。
ワクワクして、好奇心を満たしてくれるので、すぐに使って見たくなります。
AIのような新しい技術から、デザインにいたるまで色々と興味があります。
ですが、周りを見渡すと内製システム以外にはあまり興味のない人が多いようで、新しい技術について意見を交換する機会があまりなく、技術に関する温度差を感じることがあります。
これは社内SEに限った話ではないですが、ちょっと寂しく感じます。

## エンジニアというより会社員になる

良し悪しは別にして、社内SEをやっていくとどうしても「エンジニア」というよりも「会社員」というほうがしっくりくるようになってきました。
開発することよりも調整ごとのほうが多く、時には２ヶ月全く開発をしない、なんていうこともあります。
自分がやりたいなぁと思っている仕事を協力会社の方に渡さざるを得ない場面もあり、悔しい思いをすることもあります。
かといってマネジャーなのかと言えばそうでもなく、どっちつかずで不安になることがあります。
また、給与アップするには如何に社内に関わるか、ということが大事になってきたりするため、技術力を上げても、プロジェクトマネージャになっても、給与とは関連がなく、やるせない気持ちになることがあります。

## それでも社内SEは悪くない

と、ここまでネガティブなことばかり書いてきましたが、それでも社内SEには強いメリットがあります。
初めにも書きましたが、やはりプライベートの調整が利きやすいのは最大のメリットです。
育休や産休、親の介護等で中・長期間の休暇をとりやすく、周りの理解やリカバリーもあり、復帰もサポートがあるため心強い。
やはり周りに自分の状況を知ってくれている人がいる、というのは本当に心強いです。

## ライフプランに応じて変えていく

エンジニアの多くの方が、「ずっと一線でバリバリ活躍していきたい」と思っているのではないでしょうか。
私もそう思っていた時期がありましたし、いまも心の中に残っています。
ですが、年齢を重ねるごとに自分の事だけではなく、家族のことを考えないといけない場面が増えてきました。
エンジニアライフプランは、まずライフプランがあってのものなのかな、と思います。
例えば、若いときは時間と体力を使って色々な経験をつみ、バリバリと開発していく。
年齢を重ねたり、プライベートの状況が変わってきたら、融通が効く会社に転職をする。
また時間ができたら、バリバリと開発の一線に戻る、あるいはフリーランスでやっていくのもよい。
もちろん、AIの登場もあり、年齢を重ねるごとに転職のハードルは上がっていきますが、そうやって、ライフプランに合わせて、エンジニアライフプランを考えるのが良いかなと改めて考えました。

また、私自身は、最近「育成」に興味があります。「エンジニア」を特別なものとして考えすぎず、でも「エンジニア」という部分を土台にして、他のことにもチャレンジして見たいなぁ。
React Router v6で<Route>をネストした際に子要素のelementにたどり着かない

# はじめに

React初心者です。
React Router v6でRouteのネストを使用した際に子コンポーネントの要素が表示されない問題で詰まったので解決法を記載します。

# 問題

問題のコードは以下の通り。

``` JSX
<Routes>
    <Route path="page1" element={<Page1 />}>
        <Route path="detailA" element={<Page1DetailsA />} />
        <Route path="detailB" element={<Page1DetailsB />} />
    </Route>
</Routes>
```

### やりたかった事

* `/page1`なら`<Page1 />`のelementを呼び出す。
* `/page1/〇〇`なら`<Page1〇〇 />`のelementを呼び出す。

### 実際の挙動

/page1/〇〇でも`<Page1 />`のelementが呼び出される。

# 解決

Routeはヒットした時点で子は無視されるらしいです。以下の記述で思っていた通りに動作しました。


``` JSX
<Routes>
    <Route path="page1">
        <Route path="detailA" element={<Page1DetailsA />} />
        <Route path="detailB" element={<Page1DetailsB />} />
        <Route path="" element{<Page1 />} />
    </Route>
</Routes>
```

これでも行けました。こちらの方が分かりやすくて良いのかな？

``` JSX
<Routes>
    <Route path="page1">
        <Route index={true} element{<Page1 />} />
        <Route path="detailA" element={<Page1DetailsA />} />
        <Route path="detailB" element={<Page1DetailsB />} />
    </Route>
</Routes>
```

# 最後に

古いバージョンの情報が混在していて調べるのに苦労しました。こういった基本レベルの仕様などは頭に入れておきたいです。

# 参考にした記事

以下記事を参考にしました。

https://zenn.dev/everyday_newbie/scraps/37e2ac522ea6c6
Yii2フレームワークのエントリスクリプトを理解する。

[前回記事](https://qiita.com/KoheiOgura/items/d16f95a8ea5007f79edf)の`/var/www/html/humhub/index.php`の中身を理解する。

``` index.php
<?php

/**
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

// comment out the following two lines when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/protected/vendor/autoload.php');
require(__DIR__ . '/protected/vendor/yiisoft/yii2/Yii.php');


$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/protected/humhub/config/common.php'),
    require(__DIR__ . '/protected/humhub/config/web.php'),
    (is_readable(__DIR__ . '/protected/config/dynamic.php')) ? require(__DIR__ . '/protected/config/dynamic.php') : [],
    require(__DIR__ . '/protected/config/common.php'),
    require(__DIR__ . '/protected/config/web.php')
);

(new humhub\components\Application($config))->run();
```
---
これ↓は
``` index.php
defined('YII_DEBUG') or define('YII_DEBUG', true);
```
これ↓と同じ意味。
```
if (!defined('YII_DEBUG')) {
    define('YII_DEBUG', true);
}
```
---

``` index.php
require(__DIR__ . '/protected/vendor/autoload.php');
```

- `require()`でファイルを読み込む。

---

``` index.php
$config = yii\helpers\ArrayHelper::merge(
```

- `::`はスコープ演算子。`クラス::定数やメソッド`でクラスの定数やメソッドにアクセスする。
- merge()メソッドの戻り値を変数`config`に格納する。

参考：merge()の呼び出し先
``` /var/www/html/humhub/protected/vendor/yiisoft/yii2/helpers/BaseArrayHelper.php
static function BaseArrayHelper::merge(
    array $a,
    array $b
): array
```

functionの末尾の`:`は戻り値の型を定義している。

``` index.php
(new humhub\components\Application($config))->run();
```

- Applicationクラスのコンストラクタに引数に変数configを渡して、インスタンスをnewする。
- Applicationクラスのrun()メソッドを実行する。

参考：Applicationクラスの呼び出し先コンストラクタ
``` /var/www/html/humhub/protected/humhub/components/Application.php
    public function __construct($config = [])
    {
        // Remove obsolete config params:
        unset($config['components']['formatterApp']);

        parent::__construct($config);
    }
```

- `__`が頭についているメソッドはマジックメソッドと呼ばれるPHPで予約済みのメソッド。
- PHPでコンストラクタを定義するときは`__construct()`と定義する。
- `関数( 引数 = 設定したいデフォルト値 )`で引数のデフォルト値を定義する。

```/var/www/html/humhub/protected/humhub/components/Application.php
unset($config['components']['formatterApp']);
```

- `unset()`で配列の要素を削除する。
- `$array['key1']['key2']`は、多次元連想配列の要素を1次元目と2次元目のキーを指定して削除する。

```/var/www/html/humhub/protected/humhub/components/Application.php
parent::__construct($config);
```

- 親クラスのコンストラクタを呼び出すお作法。
Linuxでよく使用するコマンドのまとめ

### 目次
-  [はじめに](#はじめに)
-  [前提条件](#前提条件)
-  [ファイルシステム操作](#ファイルシステム操作)
-  [テキスト処理](#テキスト処理)
-  [プロセス管理](#プロセス管理)
-  [ネットワーク管理](#ネットワーク管理)
-  [システム情報の取得](#システム情報の取得)
-  [パッケージ管理](#パッケージ管理)
-  [ユーザーとパーミッション管理](#ユーザーとパーミッション管理)
-  [まとめ](#まとめ)

### はじめに
こんにちは、TechoesのCです。この記事では、Linuxを少し使ったことがある方向けに、基本的なコマンドの使い方を紹介します。これらのコマンドを使いこなせるようになると、システム管理や開発作業がもっとスムーズに行えるようになります。

### 前提条件
この記事で紹介するコマンドを使うための前提条件です。

- Linuxの基本的な操作方法に少し慣れていること
- 一部のコマンドを実行するためにsudo（管理者）権限が必要な場合もあります
- 適切なパッケージマネージャがインストールされていること（例：apt-get、yum）

### ファイルシステム操作

#### ls コマンド
現在のディレクトリの内容を表示します。
```rb
ls
```
追加説明として、**`ls -l`** を使うと詳細な情報を表示でき、**`ls -a`** を使うと隠しファイルも表示することができます。

#### cd コマンド
ディレクトリを移動します。
```rb
cd path/to/directory
```
 **`cd ..`** を使うと一つ上のディレクトリに移動し、**`cd ~`** を使うとホームディレクトリに移動できます。

#### mkdir コマンド
新しいディレクトリを作成します。
```rb
mkdir new_directory_name
```
**`mkdir -p path/to/directory`** を使うと、親ディレクトリも含めて作成できます。

#### cp コマンド
ファイルやディレクトリをコピーします。
```rb
cp source_file_or_directory target_directory
```
**`cp -r`** を使うと、ディレクトリを再帰的にコピーすることができます。

#### mv コマンド
ファイルやディレクトリを移動または名前変更します。
```rb
mv source_file_or_directory target_directory_or_new_name
```
ファイルの名前を変更する際にもこのコマンドを使用できます。

### テキスト処理
#### cat コマンド
ファイルの内容を表示します。
```rb
cat filename
```
**`cat file1 file2`**  を使うと、複数のファイルを連結して表示することができます。

#### grep コマンド
指定したパターンに一致する行を検索します。
```rb
grep 'pattern' filename
```
**`grep -r 'pattern' directory`**   を使うと、ディレクトリ内の全ファイルを検索することができます。

#### sed コマンド
テキストを操作して置換や編集を行います。
```rb
sed 's/old_text/new_text/g' filename
```
**`sed -i 's/old_text/new_text/g' filename`**  を使うと、ファイルを直接編集することができます。

### プロセス管理
#### ps コマンド
実行中のプロセスを表示します。
```rb
ps aux
```
**`ps -ef`**   を使うと、全てのプロセスを詳細に表示することができます。

#### kill コマンド
プロセスを終了させます。
```rb
kill process_id
```
**`kill -9 process_id`** を使うと、プロセスを強制終了させることができます。

### ネットワーク管理
#### ping コマンド
ネットワーク接続のテストを行います。
```rb
ping hostname_or_ip_address
```
**`ping -c 4 hostname_or_ip_address`** を使うと、4回だけpingを実行します。

#### ifconfig コマンド
ネットワークインターフェースの設定を表示します。
```rb
ifconfig
```
ネットワークインターフェースを設定する場合は、**`ifconfig interface_name up/down`** を使用します。

### システム情報の取得
#### top コマンド
システムのリソース使用状況をリアルタイムで表示します。
```rb
top
```
**`htop`** コマンドも同様に使用できますが、よりユーザーフレンドリーなインターフェースを提供します（インストールが必要です）。

#### df コマンド
ディスク使用量を表示します。
```rb
df -h
```
**`du -sh`** を使うと、ディレクトリのサイズを表示することができます。

### パッケージ管理
#### apt-get コマンド
パッケージの管理とインストールを行います（Debian系）。
```rb
sudo apt-get update
sudo apt-get install package_name
```
**`sudo apt-get remove package_name`** を使うと、パッケージを削除することができます。

#### yum コマンド
パッケージの管理とインストールを行います（Red Hat系）。
```rb
sudo yum update
sudo yum install package_name
```
**`sudo yum remove package_name`** を使うと、パッケージを削除することができます。

### ユーザーとパーミッション管理
#### useradd コマンド
新しいユーザーを追加します。
```rb
sudo useradd new_username
```
**`sudo passwd new_username`** を使うと、パスワードを設定することができます。

#### chmod コマンド
ファイルのパーミッションを変更します。
```rb
chmod permissions filename
```
**`hmod u+rwx,g+rx,o-rwx filenam`** で、ファイルの所有者（u）に読み取り、書き込み、実行権限を与え、グループ（g）には読み取りと実行権限を与え、その他のユーザー（o）からはすべての権限を取り除きます。


#### まとめ
以上が、Linuxでよく使用されるコマンドの基本的な使い方です。これらのコマンドを使いこなすことで、システム管理や開発作業を効率的に行うことができます。

各コマンドには多くのオプションがあります。詳細な使い方を学ぶために、各コマンドのマニュアルページ（man コマンド名）を参照して、深掘りしてみてください。
iOSのSafariでWindow.openできなかった話



# はじめに

RustとWebAssemblyを使って入力文字が流れる電光掲示板ツール的なのを作った際に

手持ちのiPhoneのChromeブラウザではWindow.openできたので確認を怠っていたが、

SafariだとWindow.openができず、遷移できていないことを発見した。

電光掲示板ツールについて

https://qiita.com/shisojuice/items/0bd4663aed0a3152d1f6


# 原因

調べてみたら結構あるあるらしく、下記の記事で原因と解決方法をまとめられていた。

https://www.chaordic.co.jp/memorandum/chaordicdesign/12/

https://qiita.com/chelcat3/items/b46061d90b6675c34a67

どうやらポップアップがブロックされているらしい。

# 解決方法

上記の記事と同じように修正する

```javascript:script.js

 if (!window.open("./flow.html?" + speedparam)){
    location.href = "./flow.html?" + speedparam; // ios/safari対応
 } else {
    window.open("./flow.html?" + speedparam);
}

```

下記iPhone上でのデモサイト画像

![iOSのSafariでWindow.openできなかった話_001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3777149/50f7cecb-ac86-d3dd-f889-915ca085a3c7.jpeg)

![iOSのSafariでWindow.openできなかった話_002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3777149/9596ec86-4747-a107-c36f-4d9c38179a94.jpeg)


# まとめ

同じWebkitベースのiOSのChromeで動いたからといって

Safariでも同じように動くわけではないと改めて実感しました。😔

学習用デモサイトだからといって調査を怠ってしまったので今後はこのようなことが無いように

注意していきたい。💪
RustとWebAssemblyでCanvasタグ使わずにお絵描きしてみた



# はじめに

前回RustとWebAssemblyで拡大鏡ツール作った際に、mouse操作中でもそれなりのパフォーマンスで画像を加工できたので、

Canvasタグ使わなくてもImgタグに直接お絵描きできそうだと思ったので実際にやってみる。🖌️

前回作った拡大鏡ツールについて

https://qiita.com/shisojuice/items/7f640c13cc040e341ac0


# プロジェクトの作成

まず、load時にCanvas代わりとなるImageを表示する。

(今回は白紙の320pxベース)

```rust:lib.rs
// 省略

#[wasm_bindgen]
pub fn set_canvas() -> String {
    let canvas = DynamicImage::new_rgba8(320, 320);
    let mut buffer = Cursor::new(Vec::new());
    canvas.write_to(&mut buffer, ImageFormat::Png).unwrap();
    let base64_string = general_purpose::STANDARD.encode(buffer.get_ref());
    // データURL形式で返す
    format!("data:image/png;base64,{}", base64_string)
}

// 省略

```

次にパフォーマンスを考慮してmouseupのタイミングで

Imgタグの画像とmousemoveで通過した座標を受け取り、

受け取った座標をつなげて線にして画像に描画するような処理を実装する。

```rust:lib.rs
// 省略

#[derive(Serialize, Deserialize)]
struct Point {
    x: f64,
    y: f64,
}

#[wasm_bindgen]
pub fn draw_canvas(str_url: String,json_str :String) -> String {
    let points: Vec<Point> = serde_json::from_str(&*json_str).unwrap();
    let comma_pos = str_url.find(',').unwrap();
    let str_base64 :String  =Some(&str_url[comma_pos + 1..]).unwrap().to_string();
    let image_data = general_purpose::STANDARD.decode(str_base64).unwrap();
    let mut img =  image::load_from_memory_with_format(&image_data, ImageFormat::Png).unwrap();
    let color = Rgba([0, 0, 0,255]);
    // 座標をつなげて線を描画
    for i in 0..(points.len() - 1) {
        let start = &points[i];
        let end = &points[i + 1];
        draw_line_segment_mut(
            &mut img,
            (start.x as f32, start.y as f32),
            (end.x as f32, end.y as f32),
            color,
        );
    }
    let mut buffer = Cursor::new(Vec::new());
    img.write_to(&mut buffer, ImageFormat::Png).unwrap();
    let base64_string = general_purpose::STANDARD.encode(buffer.get_ref());
    // データURL形式で返す
    format!("data:image/png;base64,{}", base64_string)
}

// 省略

```

この上記関数をJavascript側でmouseupのeventで呼び出す。

```Javascript:index.js
// 省略

mainImg.addEventListener("mouseup", (event) => {
        document.getElementById("mainImg").src  = draw_canvas(mainImg.src, JSON.stringify(myXY));
        pressed = false;
        myXY.length = 0;
    });

// 省略

```

メインの処理は実装したので、

残りのmouseやtouchのevent処理を実装すれば完成！💪


# 今回の成果物

デモURL

https://shisojuice.github.io/Rust_WithoutCanvas/


デモ画像

![RustとWebAssemblyでCanvasタグ使わずにお絵描きしてみた_001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3777149/ce5b4c1d-ad3a-12ae-1f22-0dc9e350e360.jpeg)


ソース

https://github.com/shisojuice/Rust_WithoutCanvas


# まとめ

今回はRustとWasmでImgタグをCanvasタグの代わりにしてみました。🎨

正直、なんの役にも立ちそうにないですが、、、

気になったので記事にしてみました。📝

※間違い等ありましたら、ご指摘いただけると助かります。
AWSとRaspberry Piを組み合わせてハイブリッドクラウド環境を構築する方法


# AWSとRaspberry Piを組み合わせてハイブリッドクラウド環境を構築する方法

自宅のRaspberry PiとAWSを連携させて、柔軟でスケーラブルなハイブリッドクラウド環境を構築する方法をご紹介します。今回は、Raspberry Pi上のデータをAWSのS3にバックアップする手順を説明します。

## 手順概要

1. **AWS S3バケットの作成**
2. **Raspberry PiでのAWS CLIインストールと設定**
3. **ローカルディレクトリとS3バケットの同期**
4. **S3バケットの内容確認**

## 1. AWS S3バケットの作成

### 1.1 AWS管理コンソールにログイン
[AWS管理コンソール](https://aws.amazon.com/jp/console/)にアクセスし、ログインします。

### 1.2 S3サービスに移動
管理コンソールの検索バーで`S3`と入力し、S3サービスを選択します。

### 1.3 バケットの作成
「Create bucket」をクリックし、バケット名とリージョンを入力してバケットを作成します。

- **Bucket name**: unique-bucket-name
- **Region**: 適切なリージョンを選択

他の設定はデフォルトのままで、「Create bucket」をクリックしてバケットを作成します。

## 2. Raspberry PiでのAWS CLIインストールと設定

### 2.1 Raspberry Piのアップデート
まず、Raspberry Piを最新の状態にアップデートします。

```bash
sudo apt update
sudo apt upgrade -y
```

### 2.2 AWS CLIのインストール
次に、AWS CLIをインストールします。

```bash
sudo apt install awscli -y
```

### 2.3 AWS CLIの設定
AWSのアクセスキーとシークレットアクセスキーを使用して、AWS CLIを設定します。

```bash
aws configure
```

設定時に以下の情報を入力します。

- **AWSアクセスキーID**
- **シークレットアクセスキー**
- **デフォルトリージョン名**
- **出力フォーマット**（例：json）

### AWSアクセスキーIDとシークレットアクセスキーの取得方法

1. **AWS管理コンソールにログイン**:
   [AWS管理コンソール](https://aws.amazon.com/jp/console/)にアクセスし、ログインします。

2. **IAMサービスに移動**:
   管理コンソールの検索バーで「IAM」と入力し、IAMサービスを選択します。

3. **ユーザーの選択**:
   左側のメニューから「ユーザー」をクリックし、アクセスキーを生成したいユーザーを選択します。まだユーザーを作成していない場合は、「ユーザーを追加」をクリックして新しいユーザーを作成します。

4. **セキュリティ認証情報のタブに移動**:
   選択したユーザーの詳細ページで、「セキュリティ認証情報」のタブをクリックします。

5. **アクセスキーの作成**:
   「アクセスキーの作成」をクリックし、表示されるアクセスキーIDとシークレットアクセスキーをメモします。シークレットアクセスキーはこの時点でしか表示されないため、必ず保存してください。

### IAMユーザーに適切なポリシーをアタッチ

1. **IAMサービスに移動**:
   管理コンソールの検索バーで「IAM」と入力し、IAMサービスを選択します。

2. **ユーザーの選択**:
   左側のメニューから「ユーザー」をクリックし、エラーが発生しているアクセスキーに関連付けられたユーザー（MOKO1221）を選択します。

3. **ポリシーの追加**:
   - **AmazonS3FullAccess** ポリシーをアタッチする方法
     - 「許可を追加」をクリックし、「ポリシーのアタッチ」を選択します。
     - ポリシー名の検索バーに `AmazonS3FullAccess` と入力して検索します。
     - 検索結果から `AmazonS3FullAccess` ポリシーを選択し、「ポリシーのアタッチ」をクリックします。

## 3. ローカルディレクトリとS3バケットの同期

### 3.1 ローカルディレクトリの作成
まず、アップロードするファイルを保存するためのローカルディレクトリを作成します。

```bash
mkdir -p /home/moko1221/myfiles
```

### 3.2 テスト用ファイルの作成
同期の動作を確認するために、テスト用のファイルを作成します。

```bash
echo "This is a test file" > /home/moko1221/myfiles/testfile.txt
```

### 3.3 ローカルディレクトリからS3バケットへ同期
以下のコマンドを使用して、ローカルディレクトリをS3バケットに同期します。

```bash
aws s3 sync /home/moko1221/myfiles/ s3://unique-bucket-name1111/myfiles
```

## 4. S3バケットの内容確認

### S3バケットの内容を確認
以下のコマンドを実行して、S3バケット内のファイルを表示します。

```bash
aws s3 ls s3://unique-bucket-name1111/myfiles/
```

### 期待される出力

このコマンドの出力として、先ほど作成したファイル `testfile.txt` が表示されれば成功です。

```bash
2024-07-10 13:23:42         20 testfile.txt
```

### まとめ

これで、AWSとRaspberry Piを組み合わせてハイブリッドクラウド環境を構築するための基本的なステップを完了しました。以下は、今回行った手順のまとめです：

1. **AWS S3バケットの作成**:
   - S3バケットをAWS管理コンソールで作成しました。

2. **AWS CLIのインストールと設定**:
   - Raspberry PiにAWS CLIをインストールし、アクセスキーとシークレットアクセスキーを設定しました。

3. **必要なIAMポリシーの追加**:
   - AWS IAMでユーザーに `AmazonS3FullAccess` ポリシーを付与しました。

4. **ローカルディレクトリとS3バケットの同期**:
   - ローカルのディレクトリをS3バケットに同期し、ファイルをアップロードしました。

今後も、AWSとRaspberry Piを活用してさまざまなプロジェクトを進めることができます。例えば、データのバックアップ、自動化スクリプトの実行、IoTデバイスの管理などです。

何か他にサポートが必要な場合や新しいプロジェクトのアイデアがあれば、遠慮なくお知らせください。
OpsRamp - Agentベースカスタムスクリプトモニターについて

本記事では、OpsRamp Agentにおけるカスタムスクリプトモニター(G2)について説明します。

# 概要
OpsRampでは、Bash / PowerShel / Pythonを用いて独自のモニターを作成し、OpsRamp Agentから実行することが可能です。

# 設定方法
OpsRamp Agentのカスタムスクリプトモニターは、Setup > Monitoring > Monitorsから設定することが可能です。
Adapter TypeにApplication、Application TypeにRemote Script Executorを選択します。
Scriptに任意のスクリプトを入力します。特定のJSONフォーマットでメトリクス名・値を標準出力することでアラートおよびグラフに表示することができます。JSONフォーマットの詳細は設定画面のShow Moreからご確認ください。

:::note warn
メトリクス名は、Metrics項で選択したメトリクスと合わせる必要があります。
:::

Metricsで任意のメトリクスを設定します。このメトリクスに従い、アラートを発報することが可能です。
Configuration Parametersで任意のOSおよびスクリプトタイプを選択します。
![AgentG2Base_custom-monitor1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/0c887499-8477-a054-5611-525deec78066.png)
![AgentG2Base_custom-monitor2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/561f4ac8-3a5a-660d-7aee-dec08343f92d.png)

作成したモニターをデバイスに割り当てることで適用できます。

---------------------------------------
[<img width = 250 height = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/111de30a-4d33-aa33-5c7d-83d9015093e6.png">](https://www.vistanet.jp/knowledge-base/)
VScodeのデバッグ時に出力が文字化けした際の対処

## はじめに
VScodeにて単体テストを作成し、テストのデバッグを行った際に出力が下記のように文字化けした状態で表示されました。
とりあえず、テスト実行してみるも失敗する状態…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/b4a53a50-8d45-6bed-d794-0fb09dfd5a53.png)

デバッグでもテスト走行後も結果は日本語で出力されていたので、エラーが起こっていることや成功・失敗は判別できたのですがこの文字化けのせいで何か見逃しているかもしれない…と不安であるのと、単純に気持ち悪いのでいろいろ試してみました。

::: note info 

- 環境：Windows10

:::

## 試したこと

まずは単純な方法から試しました。
大抵再起動でどうにかなると思っている界隈です。

- VScodeを閉じて再起動　⇒　ダメ
- Windowsの最新化 　⇒　ダメ
- PC自体を再起動 　⇒　ダメ

ダメか～…と「**助けてGoogle先生！！**」と素直に調べてみました。

## 対処法

**1. コントロールパネルより「時計と地域」押下**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/270d4174-c625-5c79-2698-31f513238199.png)


**2.「地域」押下**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/ab9afa9a-3bc4-9594-5e4b-3998bf60e2ab.png)

**3.開いた「地域」より「管理」タブに切り替えて「<font color = "red">システムロケールの変更</font>」押下**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/1397ef02-45fb-1487-48af-0ba1be18a153.png)

**4.開いた「地域の設定」より「現在のシステムロケール(C:)」が「日本語(日本)」となっていることを確認し、「ベータ：ワールドワイド言語サポートで Unicode UTF-8を使用(U)」にチェックを入れて、「OK」押下**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/43a2288e-9a1b-702c-f82f-18e254de2b23.png)
※私の場合は、最初から「現在のシステムロケール(C:)」が「日本語(日本)」なっていました。
しかし、違う言語が設定されている場合はプルダウンより「日本語(日本)」を選択する必要があると思います。

**5.再起動を求められるので再起動を実施**

「あのエラーなんだろうな～」と考えながら天を仰ぎながら待ちましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/5d8ae1a4-84d2-c4c2-06c4-19b1da777125.png)

#### 無事に解消されました！！
黒塗り部分は自分のローカル環境のディレクトリが表示されているので隠しております。

ちなみに単体テストが失敗していたのは単純にテストコード内ですっ飛ばしていた処理があっただけでした。
ですが、もやもやが解消されたのと失敗の原因がこの中にあるかもという可能性を潰せたのでスッキリしました！

## おわりに

私の場合は数日置いてからVScodeを開いたら出力が文字化けしていて、冒頭でも記載の通り結果は表示されるからいいかな～と放置していたのですがやっぱり気持ち悪いので解消できてよかったです。

本当に細かい部分でもおかしいことがあると動かないものですので、こういったもやもや感は今度も大事にしていきたいです。
暗号資産Ukkey Coinのフルノードを構築する方法

## 要　旨
暗号資産Ukkey Coin(UKY)のフルノードを構築する方法(CLI)について記述します。
## 実行環境等
VPS:KAGOYA VPS
OS:Ubuntu22.04LTS
CPU/メモリ:2コア/2GB
ストレージ:200GB SSD
料金　32円/日、880円/月(2024.7.9時点)
同期開始:2024.7.9(火)18:00
同期完了:2024.7.10(水)18:00
同期に要した時間:24時間
使用ストレージ容量:14GB
## 実施要領
アップデート
```linux
apt update
```
ウォレットのインストール
```linux
wget https://github.com/ukkeyHG/UkkeyCoin/releases/download/0.13.2.0/ukkeycoin-0.13.2.0-linux.tar.gz
```
展開する。
```linux
tar -xvf ukkeycoin-0.13.2.0-linux.tar.gz
```
不要になったファイルの削除
```linux
rm ukkeycoin-0.13.2.0-linux.tar.gz
```
ディレクトリの移動
```linux
cd ukkeycoin-0.13.2.0-linux
```
コマンドをインストールする
```linux
install -m 0755 -o root -g root -t /usr/local/bin *
```
ukkeydの起動
```linux
ukkeyd
```
起動を確認したら(1分経過したら)、一旦停止させる。(起動時に動作内容は表示されない)
ctr + C
~/.ukkeycore/ukkey.confを新規作成する。
```linux
vi ~/.ukkeycore/ukkey.conf
```
以下を記述して、保存する。
```linux
mainnet=1
daemon=1
server=1
rpcuser=rpcuser
rpcpassword=rpcpassword
rpcport=9998
gen=1
genproclimit=-1
```
再度ukkeydを起動させて、同期させる。
```linux
ukkeyd
```
同期状態の確認。
```linux
tail -f ~/.ukkeycore/debug.log
```
同期が終了したら、次いでVPSを再起動した際に自動でukkeydが起動されるようにする。
start.shシェルスクリプトの作成。
ディレクトリの移動
```
cd /root
```
```
vi /root/start.sh
```
以下をstart.shに記述する。
```linux:start.sh
#! /bin/sh

/root/ukkeycoin-0.13.2.0-linux/ukkeyd
```
作成したstart.shファイルに実行権限を付与する。
```
chmod 755 start.sh
```
crontabの設定
```
crontab -e
```
以下をcrontabに記述する。
```
@reboot /root/start.sh
```
これでVPSを再起動した際に、自動でukkeydが起動されるように設定された。
最後に毎時00分と30分にマイニングが自動で実行されるように設定する。
mining.shシェルスクリプトの作成
```linux
vi mining.sh
```
以下を記述する。
```linux:mining.sh
#! /bin/sh

/root/ukkeycoin-0.13.2.0-linux/ukkey-cli generate 1
```
毎時00分と30分にmining.shが実行されるようにcrontabに設定する。
```linux
crontab -e
```
以下を記述する。
```linux
0,30 * * * * /root/mining.sh
```
これで毎時00分と30分にマイニングが自動で実行される。
## 結　言
今回は、暗号資産Ukkey Coin(UKY)のフルノードを構築する方法(CLI)について記述しました。
最後までご覧くださり、ありがとうございました。
開発工数と運用工数の割合を一年間計測したお話

# はじめに
システムリリース後に運用面も担当しているのですが、開発にしっかり手が回るように運用工数にどれくらい時間がかかっているのかを計測することにしました。


# 結果

月毎の開発工数と運用工数を算出し、合計工数に対する運用工数の割合をグラフにしました。
月平均約20%でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/6dba9f51-f081-cb46-fc0d-941a87246bbf.png)

<font color="Red">赤</font>：
リリース前の準備や、お客さんからの依頼対応などをメインにしていました。

<font color="Gold">黄</font>：
こちらもお客さんからの依頼対応がメインでしたが、手順書を作成したので工数は減っています。

<font color="Blue">青</font>：
開発メインで作業できていました。定期的な運用対応はあるのですが、こちらに関しても手順書を作成したので工数はかからないもののお客さん毎の対応となるため、一定数の工数はかかっていました。



# おわりに
開発速度に支障が出ないレベルはどのラインなのか、
そして約20%の運用工数に対して削減できる点はあるのか、探りを入れて改善行動していきたいと思います。
【PowerBI】秒数データから時間、分、秒を取り出す【DAX関数】

### TRUNC関数で、時間、分数の整数部分を取り出す

PowerBIでは（PowerBIだけでなく一般にも？）時間の量的データは「HH:MM:dd」の形式では表せないようです。
例えば、0:00:00（0時） から1:23:45 (1時間23分45秒)の時間の量的データは、開始から終了までの【時間】ではなく、1時間23分45秒という時の中のある一点【時刻】として扱われてしまいます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322371/35400214-3f24-9f95-c075-f10b87573d1a.png)
そのため、カテゴリAは3794秒、カテゴリBは5466秒というように、秒数で格納されている数量データで棒グラフや円グラフを表現することはできますが、いくら棒グラフで数量の比較ができても、秒数の時間的数量を人間の目から想像するのは難しいです。

ヒント表示やテーブルの列で、人間が時間の量的データを感じやすい「HH:MM:dd」の形式に変換した表示をするため ` Major(Convert) ` という名前でメジャーを作ってみました。
```rb 
Major(Convert) = 
VAR i = 
    CALCULATE(
        SUM('TableToConvert'[Seconds]),
        'TableToConvert'[Category]==SELECTEDVALUE('TableToConvert'[Category])
    )
    
VAR HOUR_VALUE = TRUNC(i / 3600) -- 時間単位の部分を取得

VAR MINUTES_VALUE = TRUNC((i - HOUR_VALUE * 3600 ) / 60)-- 秒単位の部分を取得

VAR SECOND =  i - (HOUR_VALUE * 3600 ) - (MINUTES_VALUE * 60)

Return HOUR_VALUE&":"&FORMAT(MINUTES_VALUE, "00")&":"&FORMAT(SECOND, "00")
```

※分や秒は一桁の数値が取れる場合、0パディングを足して2桁で表現したいので、FORMAT([数値], "00")で調整しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322371/d7792747-b167-37ea-5f16-99d47e586749.png)


以上、どこで使うか分かりませんが、秒数を「HH:MM:dd」に変換する式をまとめてみました。
Top Forex Brokers Review 2024

![Forex-Regulations.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835259/1d78bcea-8afd-18bd-af11-179c355ff538.jpeg)

"Top Forex Brokers Review" is the ultimate platform for any trader who want to enter in the forex market and find out the perfect broker for forex trading. Since 2007, TopFXBrokersReview.com has been guiding the traders to select the best broker through providing in-depth reviews on Recommended Forex Brokers, Best Forex Brokers, Forex Reviews, Free Forex Education, Trading Resources, Forex Brokers Comparison, Forex Brokers by Country, Forex Account Types, Forex Trading Platforms, Scam Brokers List, Forex Bonus & Forex Signals. We offer authentic forex broker reviews based on industry-leading criteria. Top Forex Brokers Review is one of the leading best forex broker review platforms in the industry.

Nevertheless, the forex market is one of the most dynamically traded and biggest financial market in the world. Hence, our Forex reviews and recommendation will come in handy as we have a dedicated team to pick the reliable forex brokers out of the hundreds of Forex brokerage firms.

Explore TopFXBrokersReview.com to choose the right broker for you, along with access to the free forex education resources.
https://www.topfxbrokersreview.com/