OmniAICreator/Qiita-1.07M huggingface dataset:
Oracle Analytics Cloud Classic：ダッシュボードのダッシュボード・プロンプトに編集リンクを表示する

はじめに
---
Oracle Analytics Cloud Classic：Dashboardをつくっているとき、ダッシュボードプロンプトやAnswersの分析に編集リンクを表示しておくと、1ステップで編集画面にいくことができ便利です。
編集リンクを表示しておく手順について記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/77a6f63c-7426-929f-8d3b-751f142f048f.png)


前提
---
OAC、ADWサービスをプロビジョニングし、作成している
サブジェクト領域を作成、保存、デプロイしている
ダッシュボードプロンプト、Answersで分析を作成し、ダッシュボード、

本記事では[「Oracle Analytics Cloud インデックスページを作成してみました。」](https://qiita.com/tni38/items/534a39c1231b23c617f4])の以下を実施しています。
Oracle Analytics Cloud のサービス作成
お試し用にADWでSHスキーマをもとにSHJPスキーマを作成する。
セマンティックモデラー(Semantic Modeler)を試す。
Oracle Analytics Cloud Classic：分析をはじめる。Dashboard、Answersで分析をはじめる。

ダッシュボードページの編集画面を開く
---
OAC Classicで、上部メニューのダッシュボードをクリックし、作成済のダッシュボードをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/076f8caf-9f63-3042-9a8b-dd51e7508ae3.png)

右上部の歯車アイコンをクリックし、メニューから"ダッシュボードの編集"をクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/4e47e2f3-366d-8f2a-c122-92a1e5afb89b.png)



ダッシュボードプロンプトの編集リンクの表示の設定をする
---
ダッシュボードプロンプトの編集リンクの表示の設定をします
ダッシュボードに配置しているダッシュボードプロンプトの枠の右上にマウスカーソルを移動すると、プロパティアイコンが表示されますのでクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/568aa5e6-5852-88a0-0e30-dc9a7c300854.png)

メニューから、"プロパティ・リンク"をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/ecf47b9d-c40e-5e64-f0f4-bcceca14d9a0.png)

プロンプト・リンクのダイアログで、"編集"をクリックしてチェックを入れ、OKをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/96ad71ad-4792-c963-bef2-a85facc4ec41.png)

保存アイコンをクリックして保存後に、実行アイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/65d9f483-8b07-4511-b817-cc609f169042.png)

ダッシュボードプロンプトの下部に編集リンクが表示されます。クリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/3baf4cd0-8998-769d-5afb-1573daf22def.png)

ダッシュボードプロンプトの編集画面にダッシュボードから１クリックで遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/9ed97cbf-0229-602b-644f-ceb04b02003e.png)

このようにダッシュボードページをつくっている間は、編集リンクを表示させておくと1ステップで編集画面にとぶので便利です。

以上
for文

```py.qiita.py
#  5 制御構文for
#  同じ処理の繰り返しを行うときに、for文を用いて処理を繰り返す

# 　5-1 range関数について
j = range(5)
print('range関数の型は、',type(j))
#  range型をrange → list型にキャスト
j_list = list(j)
print(j_list)

# range関数は正数のリストを作成して返す関数
# 　range(1, 5)とすると最初の数を指定できる
#  range(1,10, 2)こうすると、1個飛びで整数のリストを作成できる。
#  range(1, 10, 2) →  [1, 3, 5, 7, 9]
k = list(range(1, 10, 2))
print(k)

```
```py.qiita.py
# 　5-2 forを使う
#  0~4までの数字を出力
for i in range(5):
    print(i) 

#  1~9までの数字を1個とびで出力
for i in range(1, 10, 2):
    print(i)

#  5-3 for文を用いて遊ぶ
#  len()関数は文字数をカウントする
word = 'Python'
print(len(word))

for i in range(len(word)):
    print(word[i])
    
#  rangeを使わずにfor文を回す
for s in word:
    print(s)

#  5-4 リスト
l = ['Python', 'GoLang', 'Java']

# 値を取り出す *インデックスを使用しないこっちの方がおすすめ
for t in l:
    print(t)
    
# インデックスの指定で値をとりだす
for t in range(len(l)):
    print(f'インデックス{t}の要素は', l[t])
    
```
福岡 Rubyist会議 03 に参加して

初めてオフラインでのプログラマーの集まりに参加した感想をまとめたいと思います。
私自身はRubyに関わり出した時期がちょうどコロナが流行し出した時期で、オンラインではイベントなどに参加していましたがオフラインでの参加は初めてでした。

# 結論
最初に全体を通して感じたことですが、「生でしか感じられない空気感を感じることができた」の一言につきます。
発表者の話を受けての会場のどよめきだったりそういった反応はオンラインのイベントのチャット欄からでは窺い知れないものだと今回のイベントを通じて感じました。
地方に住んでいる身としては、オンラインでイベントに参加出来るのは楽でいいですが、現地に行って実際に参加することには敵わないと思い知り、今後は出来るだけ参加してみたいと思いました。

# 各発表者の発表を受けて
短いですが各発表を受けて私が感じたことを書きたいと思います。

## yasulabさん　RubyistによるRubyistのための簡単動画制作
タイトルの通り発表で聞いたことをそのまま行えば動画配信できそうな内容でした。
動画撮影などしたことなかったこともあり、音を重要視するべきと言う内容はとてもためになりました。
今回聞いた内容を使って社内勉強会などの動画を作成すべきかとも感じました。

## hsbtさん　Rubyのリリースを爆速にするための方法
調べたことがなかったので他言語とのリリースに関する比較については興味深かったです。
また、リリースの大変さを知りありがたいと思いながら使わせて頂こうと感じました。

## そらはさん
配信システムを内製していることに驚きました。
また、そらはさんが担当している会場のWi-Fi設定では、部屋間配線が大変らしいのでケーブルは踏まないようにしたいと思います。

## 岡嵜雄平さん mruby on Iot devices
ここでも使用環境のバージョンアップの影響で動かなくなった話を聞き、どこでも起きるのだなと感じました。
また、マイコンとか以前触っていたこともあり興味があるのでmrubyで色々作ってみるのも面白そうだと感じました。

## hachiさん Factorybot改善ツール作成失敗と学び
私もrspecの際にcreateで毎回作っているのでそこを修正すれば改良できるかなとは思いましたが、テストごとに細かい設定を変えて作っている場合もあるので見極めが難しそうだと感じました。
特に、現時点では共通で一回も更新していなくても、後からの修正で変更や細かい設定が追加された場合に潜在的なバグを生みそうなので導入するには注意が必要とも感じました。

## Pockeさん　外部コマンド実行入門
外部コマンドのセキュリティの話もあり、話を聞いてまず思ったのが以前の案件で外部コマンドを導入したけど大丈夫だったかの心配でした。（rakeタスクでの固定のコードだったので問題ないはず。。）
使用するメソッドを判断するツリーは力作で使わせて欲しいとも思いましたが、最後は結局Open3に行き着くという話でまずOpen3の仕様を読もうと感じました。

## 西山和広さん　Rubyist Magazine Reboot
発表の終わりに質問というより意見が多数出ていたのがオフラインならではと感じました。
その中で面白かったのが、過去の記事を見ることでそのときの情報を見られる歴史的価値があるという話で、私も一読者から初めてみようと思いました。

## ぺんさん メンテできないコードをメンテする技術
会場で一番反応(どよめき)が大きかったのがこの発表でした。
ぺんさんといえばRubyKaigi 2022でTRICKで1,2,4位を受賞した方で今回はTRICKのコードをいかにメンテするかという話でした。
話の中で複数の名言があり、そのタイミングが会場の反応が一番大きいものだった気がします。
以下はその一部です。
- RubyはQuineを書きやすい
- Rubyはアスキーアート化しやすい

説明を聞いて理解はできても納得できないなと思いつつ面白いと感じました。
いつか私もTRICKに応募してみたいと思いつつ、すぐにはできそうにないので過去の作品を見直しつつ写経から始めようかと思っています。

# おわりに
最後になりますが、このような面白い会議を開催してくださったスタッフ様、スポンサー様、並び発表者の皆様に感謝したいと思います。
ファイルアップロードとセキュリティ

## はじめに
花粉にうんざりをしているキティちゃんです。おはこんばんにちは。今回はファイルアップロードとセキュリティについてお話をしていこうと思います。

## きっかけ
ファイルをアップロードする機能を見かけたからです。見つけちゃうとテーマとして面白そうだなと思ってつい書いちゃいます。

## ファイルアップロードとは
画像であったり、PDFなどをフォルダから選択してアップロードをするなんて経験をしたことがある方もいらっしゃるかと思いますが、まさにこのアップロードする行為、機能がファイルアップロードです。最近だとライブチケットの顔写真登録でこの機能を見かけました。自分の顔写真を撮って、アップロードして登録するものです。よく、入力した内容に誤りがないか、個人情報に偽りがないかを確認する目的でアップロードさせたりしますね。

## どんなセキュリティの問題があるのか
以下のことが挙げられます。
1.アップロード機能に対するDoS攻撃
2.アップロードしたファイルをサーバー上のスクリプトとして実行する攻撃
3.仕掛けを含むファイルを利用者にダウンロードさせる攻撃
4.閲覧権限のないファイルのダウンロード

## アップロード機能に対するDoS攻撃
この内容を触れるにあたって、DoS攻撃についても説明します。DoS攻撃とは、大量なリクエストを送るとことで、サーバーに負荷をかけ、レスポンスを低速にしたり、サービスを落としたりする攻撃のことです。この攻撃をファイルアップロード時に利用します。アップロードをする際に、大量のデータを送信、データ容量の大きいものを送信し、Webアプリケーションに対して、大きな負荷を与えます。

【対策】例えば、Apacheの設定ではリクエストボディサイズを絞ることができます。それ以外の設定方法は各言語のマニュアルだったりを参照してください。
Apacheでは、[LimitRequestBody]が該当する設定となります。

## アップロードしたファイルをサーバー上のスクリプトとして実行する攻撃
アップロードしたファイルがWebサーバーの公開ディレクトリに保存される場合、アップロードしたスクリプトファイルがWebサーバー上で実行できてしまう可能性があります。例えば、PHPなどのスクリプト言語がアップロードでき、外部からスクリプトを実行されてしまうと、他サーバーへの攻撃をしたり、ファイルの改ざん、情報漏洩に繋がります。

【対策】1つは、利用者にアップロードされたファイルは公開ディレクトリに置かず、アプリケーション経由で閲覧させることで、直接ユーザーがアクセスしてファイルが実行することを防げます。2つ目はファイルの拡張子を制限することです。よくある実装としては、クライアント側でJavaScriptで拡張子チェックがありますが、これだけでは、すり抜ける方法がいくつかありますので、サーバーサイド側で拡張子をチェックする仕組みを実装する必要があります。

## 仕掛けを含むファイルを利用者にダウンロードさせる攻撃
文字通り、仕掛けをしたファイルのアップロードができてしまう場合に起きうる攻撃です。利用者などがアップロードされたファイルを閲覧したり、ダウンロードして実行してしまったりすることで不正なJavaScriptが実行されてしまったり、マルウェアに感染してしまう恐れがあります。

【対策】JavaScritpが実行できるということは、XSS攻撃が成立します。ファイルのダウンロードによるXSS攻撃の対策としては、以下が挙げられます。特にContent-Typeは正しい設定がされていない場合、古いブラウザなどは異なる解釈をしてしまうことがあります。少し話がずれてしますが、例えば、「Content-Type: text/html; charset=UTF-8」が正しい設定だとした場合、「Content-Type: text/html」とcharsetの文字コードが設定されていないと、古いブラウザではUTF-7と解釈してしまい、XSSの攻撃に繋がるといった話もあります。

1.ファイルContent-Typeを正しく設定する
2.レスポンスヘッダのX-Content-Type-Options: nosniffを指定する
3.ダウンロードを想定したファイルには、レスポンスヘッダとしてContent-Disposition: attachmentを指定する
4.PDFを扱う場合はPDFファイルはブラウザ内で開かず、ダウンロードすることを強制する
5.PDFをobject要素やembed要素では開けない仕組みを実装する

マルウェアなどの実行ファイルがアップロードされないようにするためには、拡張子のチェックをクライアント/サーバーサイドにて実施するのは勿論ですが、マジックナンバーと言われるファイルの種類を識別する数値をチェックすることも有効な方法です。

## 閲覧権限のないファイルのダウンロード
アップロードしたファイルをダウンロードする際の問題として、限られた権限者のみがダウンロードできるはずにも関わらず、権限のない者がダウンロードできてしまう場合があります。これは、アクセス制御の実装がされていないために、起きてしまいます。

【対策】機能を実行してよいユーザであるのか、リソースに対する操作の権限があるのかをチェックする必要があります。よくあるのは、セッション変数に格納したユーザIDを基準に権限をチェックするといった実装があります。

## 終わりに
特にどのように実装をするのかといった話には触れていませんが、今回の内容を書く上で、徳丸浩さんの本などを参考にさせていただきました。『体系的に学ぶ安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践』では実装についてのお話もあるため、興味を持った方は是非読んでみてください。また、この話はWebアプリの診断でも役立つとは思うので少しでもお役に立てればなと思います。

## 参考
『体系的に学ぶ安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践』著 徳丸浩様

『Apache コア機能 LimitRequestBody ディレクティブ』APACHE
・https://httpd.apache.org/docs/2.4/ja/mod/core.html#limitrequestbody

『Webサービスにおけるファイルアップロード機能の仕様パターンとセキュリティ観点』株式会社Flatt Security様
・https://blog.flatt.tech/entry/file_upload_security

『マジックナンバー (フォーマット識別子)』Wikipedia
・https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B8%E3%83%83%E3%82%AF%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC_(%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E8%AD%98%E5%88%A5%E5%AD%90)
GitLFSで100MB以上のファイルをGitHubにコミットする方法

```
brew install git-lfs
```
Git LFsをインストールしていない人はインストールを。
<a href="https://git-lfs.github.com/">Windowsの人はこちら</a>
Windowsの人は、公式ホームページからexe版でインストールを。


コミットしたいフォルダーまで移動して
```
$ git init
```
をする。
```
$ git branch
```
で成功できているか確認をする。

もし、このように表示されたら
```
fatal: unsafe repository ('E:FilePath/a/b/c' is owned by someone else)
To add an exception for this directory, call:

        git config --global --add safe.directory E:/document/a/b
```
エラー通りに以下のコマンドを実行する。パスは環境に応じて変更する。
ちなみに、外部ストレージを使用しているとセキュリティ上よくないけどGitの環境構築していいの？みたいな感じのエラーだと思ってくれて大丈夫。
```
// もし上のようなエラーが出たら以下のコマンドを実行しよう。
git config --global --add safe.directory
```

続いて、
```
$ git lfs install
```
をしてlfsを導入する。

```
$  find . -size +100M -ls
942425235235248834232  42245 -rw-r--r--   1 UserName    46234   67108864 Feb 23 13:19 
./Library/ArtifactDB //100MB越えのファイルパス(環境によってそれぞれ違う)

```
で100MB超えているファイルを一覧で表示させる。

```
$  git lfs track '/path'
```
続いて、LFSに100MB越えのファイルを登録するコマンドを実行する。/path/には、先ほどfindコマンドを実行して表示された100MB越えのファイルのパスをそのまま入力する。./となっているが.は消していいと思う。

また、他にも特定の拡張子だけを対象にすることもできる。詳しくは、以下のサイトを参考にしてください。
https://support-ja.backlog.com/hc/ja/articles/360038329474-Git-LFS%E3%81%AE%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95

例
```
$  git lfs track '/Library/ArtifactDB'
```
続いて、以下のコマンドを実行する。
```
$ cat .gitattributes
```

ちなみに、なにを追加していいかわからない人はGoogleで
「[使用ツール] .gitattributes」と「[使用ツール] .gitignore」と検索するとお手本になるテンプレートが出てくるので、VScodeなどで開いてコピペしてもいいかもしれません。.gitignoreはGitによる追跡(登録)を除外するファイルを登録するためのファイルです。


Githubのホームページからリポジトリを作成して、
```
git add .

git remote add origin https://github.com/ユーザ/[作成したリポジトリ].git

git@github.com:ユーザ/[作成したリポジトリ].git
```

~~githubUserName/RepositoryNameの部分は、リポジトリのサイトに書かれている、git@github.com:githubUserName/RepositoryName.gitと置き換える形で使用してください。~~

そして、コミットして、
```
git commit -m 'First commit'
```

最後にプッシュしましょう！
```
git push
```
Let's Encrypt + Wowza + WebRTCでICEサーバーとのネゴシエーションに失敗する

# はじめに

前述の

https://qiita.com/SECUAL_masa/items/1682ff1a08edb084935d

でキーストア生成もできたことだし、WowzaでWebRTCを試すかーと思って試してみたら映像視聴が行えない。
原因とその調査過程を以下にまとめる。

# 原因

Let's Encryptで生成した証明書の暗号方式がECDSAになっている。(WowzaがECDSAには対応していない？？？)

# 調査

## chrome://webrtc-internals/

Chromeの場合は「chrome://webrtc-internals/」でWebRTCの稼働状況を確認できる。
すると"iceconnectionstatechange"が"failed"になっている。

## パケットキャプチャ

Wowza側でパケットキャプチャしてみる。(iceconnectionstatechangeがfailedになるタイミングのパケット)
以下は別の環境で視聴が行えている時のパケットと今回視聴が行えない環境でのパケットを比較した結果である。

### 動作確認できる環境(成功)

![パケットキャプチャ_成功する場合.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1236186/a14135b0-e515-aae5-ea4b-d60524325588.png)

### 今回試した環境(失敗)

![パケットキャプチャ_失敗する場合.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1236186/592e2171-4409-c0c9-97ad-ef816d058cc5.png)

Wowza側が"Certificate Unknown"と言っているので、従来の証明書と形式が違う？？？と推測。

## 証明書を比較

そこで証明書を見比べてみる。(以下に抜粋したものを貼り付け)

### 動作確認できる環境

```
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
```

RSA。

### 今回試した環境

```
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
```

ECDSA！。

# 何故このような差が生まれたか

これまでLet's Encryptの証明書を生成するためのcertbotはUbuntuに標準で入っているものを利用していたが、今回はcertbot公式サイトの手順を参照しsnapを利用して生成した。

https://certbot.eff.org/

そこでapt install certbotで標準パッケージを入れなおして生成しなおすと、証明書もRSAになり、WebRTCでの視聴確認が無事行えた。

今回はここまで。以下も気になるところだが、それはまた時間ができた時にでも。

・Wowzaが本当にECDSAに非対応なのか？
・snapで入れたcertbotで暗号アルゴリズムをRSAにする方法は？
upcast

入力値チェックのためにbyte→longのように大きな器に移し替えることを
upcastと呼ぶ
```java
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;

/**
 *
 * @author java
 */
public class SampleProject {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        byte b = 100;
        long l = b;    //up cast
        System.out.println(l);
        if (l>Byte.MAX_VALUE || l<Byte.MIN_VALUE) {
            System.out.println("max erro or min error");
        }
    }
}
```
BigDecimal

```java
public class SampleProject {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        BigInteger bi = BigInteger.valueOf(1);
        System.out.println(bi);
        BigDecimal bd = BigDecimal.valueOf(100);
        BigDecimal bd2 = bd.multiply(BigDecimal.valueOf(3));
        System.out.println(bd2.longValue());
        bd2 = bd.divide(BigDecimal.valueOf(5));
        System.out.println(bd2.longValue());
        bd2 = BigDecimal.valueOf(100);
        bd2 = bd2.divide(BigDecimal.valueOf(3),3,RoundingMode.HALF_UP);
        System.out.println(bd2.doubleValue());
        bd2 = BigDecimal.valueOf(100);
        bd2 = bd2.divide(BigDecimal.valueOf(3));   //循環小数でエラーになる
    }
```
```
1
300
20
33.333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
	at java.base/java.math.BigDecimal.divide(BigDecimal.java:1736)
	at sampleproject.SampleProject.main(SampleProject.java:32)
C:\Users\java\AppData\Local\NetBeans\Cache\15\executor-snippets\run.xml:111: The following error occurred while executing this line:
C:\Users\java\AppData\Local\NetBeans\Cache\15\executor-snippets\run.xml:68: Java returned: 1
BUILD FAILED (total time: 0 seconds)
```
VoltMX Version 9.5 をダウンロードする方法

## 目次
1. はじめに
1. ダウンロード方法
1. 最後に

## はじめに

2022年12月5日に、VoltMX 9.5がリリースされ、
さまざまな機能が追加されました。

https://opensource.hcltechsw.com/volt-mx-docs/95/docs/documentation/VMX_release_notes.html#v9-servicepack-5-fixpack-5

今回は、Ver9.5をダウンロードする方法について紹介します！

## ダウンロード方法

まずは現在使用しているバージョンを確認してください。
もし使用しているバージョンが 9.2.55以下の場合、Ver9.5をダウンロードすることができません。

https://opensource.hcltechsw.com/volt-mx-docs/docs/documentation/VMX_release_notes.html#v9-servicepack-2-fixpack-56

まずV9 Servicepack 2 Fixpack 56にアップデートしましょう！

対象のバージョンをダウンロードしたい場合、
上メニューのVolt MX Iris->Available Fix Packをクリックするとアクセスできます。

ダウンロード可能なバージョンが表示されるため、
まずV9 Servicepack 2 Fixpack 56をダウンロードしましょう。
![スクリーンショット 0005-02-24 11.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/1d0ccfcf-0125-8203-4a3c-df550365ef54.png)

詳しいダウンロード方法は以下をご参考ください。

https://qiita.com/Kony_Team/items/9623c054c3f3b122621f#version9%E3%81%AE%E5%A0%B4%E5%90%88-1

V9.2.56が開いたら、
右上のアカウント情報の左側に最新バージョンが表示されます、
Version9.5が表示されますので、いつも通りDownloadボタンを押したら完了です！


![スクリーンショット 0005-02-24 11.25.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/957cdbbe-fb7e-7cdd-8c37-d2f08a0d48bb.png)


## 最後に
今回は、V9.5をダウンロードする方法について紹介しました！  
V9.5では新しい機能がたくさん追加されていますので、是非この機会にダウンロードしてみてくださいね👋
【バッチ処理】Catサーバー バックアップファイルを、Landiscの共有フォルダへコピーしたメモ

### 定期bat
#### ■用途
・Catサーバーにバックアップされたファイルを、Lanで繋がっている、Landisc（IP:192.168.1.4）の共有フォルダへコピーする定期実行処理。
#### ■コード

```.bat
@echo off

rem ---　定義 ---

rem CATサーバーパス
set SOURCE_PATH=D:\Cat
rem データベースバックアップ フォルダ名
set DMPDIR=BackupData\LongSearchData
rem CSVバックアップ　フォルダ
set CSVDIR=CSVLog

rem === 保存先 === パス
set SERVER_PATH=\\192.168.1.4\JIMBak\CAT

set USERNAME=???
set PASSWORD=zzz

rem --- フォルダ ---
set NEWDIR=NewCatBackup
set OLDDIR=OldCatBackup


rem ======= 処理開始 =======

rem --- 共有フォルダ　サーバーへアクセス
net use %SERVER_PATH% /user:%USERNAME% %PASSWORD%

rem --- バックアップ処理 01
robocopy %SOURCE_PATH%\%CSVDIR% %SERVER_PATH%\%CSVDIR%\%NEWDIR% /e /zb /dcopy:T /COPYALL /r:0 /log:D:\Cat\Backup_log\csv_backup.log
robocopy %SOURCE_PATH%\%DMPDIR% %SERVER_PATH%\%DMPDIR%\%NEWDIR% /e /zb /dcopy:T /COPYALL /r:0 /log:D:\Cat\Backup_log\db_backup.log

rem --- 削除処理
rmdir /S /Q %SERVER_PATH%\%CSVDIR%\%OLDDIR%
rmdir /S /Q %SERVER_PATH%\%DMPDIR%\%OLDDIR%

robocopy %SERVER_PATH%\%CSVDIR%\%NEWDIR% %SERVER_PATH%\%CSVDIR%\%OLDDIR% /e /zb /dcopy:T /COPYALL /r:0 /log:\\192.168.1.4\Cat\Backup_log\csv_backup.log
robocopy %SERVER_PATH%\%DMPDIR%\%NEWDIR% %SERVER_PATH%\%DMPDIR%\%OLDDIR% /e /zb /dcopy:T /COPYALL /r:0 /log:\\192.168.1.4\Cat\Backup_log\db_backup.log

rem --- バックアップ処理 02

rem 3. 切断
net use %SERVER_PATH% /delete
```

#### ■コマンドや、オプションなど
##### ・robocopy 
robocopy [ソース] [宛先] /e /zb /dcopy:T /COPYALL /r:0 /log:[ログファイル名] /tee

各オプション。

[ソース]: バックアップ元のディレクトリのパス
[宛先]: バックアップ先のディレクトリのパス
**/e:** サブディレクトリを含めて再帰的にコピーする
**/zb:** セキュリティ設定が適用されたファイルをコピーするためにバックアップ操作を行う
**/dcopy:T:** ディレクトリのタイムスタンプをコピーする
**/COPYALL:** ファイルの属性、タイムスタンプ、許可、オーナー、ACLをすべてコピーする
**/r:0:** エラーが発生した場合、最大で0回まで再試行する（リトライしない）
**/log:**[ログファイル名]: ログファイルを出力するファイルパスを指定する
**/tee:** ログファイルとコンソール出力の両方に出力する

**・コード記述例**
robocopy C:\Data D:\Backup /e /zb /dcopy:T /COPYALL /r:0 /log:C:\BackupLogs\backup.log /tee

このコマンドを実行すると、C:\Dataディレクトリ以下のすべてのファイルとサブディレクトリが、D:\Backupディレクトリ以下にコピーされます。また、/logオプションで指定したパスに、バックアップのログファイルが出力される。

##### ・rmdir

rmdir /S /Q は、Windows コマンドラインで使用されるディレクトリの削除コマンド。

※以下は rmdir /S /Q の使い方。

rmdir コマンドを実行し、削除するディレクトリの名前を指定。

**/S** オプションを使用すると、指定されたディレクトリ内のすべてのファイルやサブディレクトリを再帰的に削除。
**/Q** オプションを使用すると、ユーザーに確認のプロンプトが表示されず、削除が自動的に実行

※以下は例。

**■コード記述例**
**rmdir /S /Q C:\example_directory**

上記例では、example_directory という名前のディレクトリとその中に含まれるすべてのファイルやサブディレクトリを削除します。注意してください。このコマンドは削除するディレクトリを確認せず、すぐに削除を実行するため、削除対象のディレクトリを誤って指定すると重要なデータが失われる可能性がある。

##### ・net use
**net use \\(サーバー名) /user:(ユーザー名) (パスワード)**

**コマンド例**
下記のコマンド例はユーザー名"???" パスワード"zzz"でファイル共有サーバー"\\192.168.1.4\JIMBak\CAT"にアクセスする例

**net use \\192.168.1.4\JIMBak\CAT /user:??? zzz**
【React】カスタムフックとは

## この記事の目的
- Reactの理解とアウトプット、振り返り用
- Reactでよく使われている基本的な技術を言語化できるようする

## カスタムフックとは
>複数のコンポーネントの中に存在する共通の処理を取り出して作成した関数のこと。汎用的なカスタムフックを作成することで作成したアプリ>ケーション内だけでなく別のアプリケーションでも再利用することが可能になります。

簡単に言うと、同じ処理書くのは無駄だし読みずらいし、どっかでまとめちゃおうって話。まとめたら必要なときに呼び出せばいいじゃんってこと。
カスタムフックって言葉を使っているけど、要はただの関数のこと
### メリット
- 使いまわしがきく
- テストが簡単
- コードが読みやすくなる
- hooksの各機能を使用できる（useState,useEffect,useMemoなど）

## カスタムフックのルール
- フックを含む関数であること（useState,useEffect,useMemoなど）
- 命名はuse〇〇とする
- hooksというディレクトリを切って管理していくのが一般的


## カスタムフック使用例
例として「全ユーザー一覧を取得するカスタムフック」(./hooks/useAllUsers.ts)を作成して、作成したカスタムフックを呼び出し取得したユーザ情報を表示する(./App.tsx)といったことをしていきます。

### ユーザ情報を表示するファイル（カスタムフックを呼び出し）
```./App.tsx
import "./styles.css";
import { UserCard } from "./components/UserCard";
import { useAllUsers } from "./hooks/useAllUsers";

export default function App() {
  // カスタムフックを呼び出し、返却値を受け取る
  const { getUsers, userProfiles, loading, error } = useAllUsers();
  const onClickFetchUser = () => getUsers();

  return (
    <div className="App">
      <button onClick={onClickFetchUser}>データ取得</button>
      <br />
      {error ? (
        <p style={{ color: "red" }}>データの取得に失敗しました</p>
      ) : loading ? (
        <p>Loading...</p>
      ) : (
        <>
          {userProfiles.map((user) => (
            <UserCard key={user.id} user={user} />
          ))}
        </>
      )}
    </div>
  );
}
```
### 全ユーザー一覧を取得するカスタムフック
```./hooks/useAllUsers.ts
import axios from "axios";
import { useState } from "react";
import { UserProfile } from "../types/userProfile";
import { User } from "../types/api/user";

// 全ユーザー一覧を取得するカスタムフック
export const useAllUsers = () => {
  const [userProfiles, setUserProfiles] = useState<Array<UserProfile>>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);

  const getUsers = () => {
    setLoading(true);
    setError(false);

    axios
      .get<Array<User>>("https://jsonplaceholder.typicode.com/users")
      .then((res) => {
        const data = res.data.map((user) => ({
          id: user.id,
          name: `${user.name}(${user.username})`,
          email: user.email,
          address: `${user.address.city}${user.address.suite}${user.address.street}`
        }));
        setUserProfiles(data);
      })
      .catch((err) => {
        setError(true);
      })
      .finally(() => {
        setLoading(false);
      });
  };

  // 他のコンポーネントでカスタムフックで定義したStateや関数が使用できるように、returnで返却する
  return { getUsers, userProfiles, loading, error };
};
```
## カスタムフックまとめ
- ルールは「フックを含む関数」「命名はuse〇〇」「hooksディレクトリ内で管理」
- メリット：「再利用」「テスト容易」「コード読みやすい」「hooksの各機能を使用可能」
- カスタムフックで定義したStateや関数が使用できるように、returnで返却する
カラム作りに！データ型まとめ（rails）

# はじめに

今回はカラムを作るときに欠かせない、データ型を解説します！
データ型？はぇ～ってなっている人。ご安心ください。
一つずつ解説していきます！

## データ型について解説


データ型はカラムに条件をつける事ができます。

例えると、
ECサイトで、金額入力の場所に
「ほげほげ」と入力できるのっておかしくないですか？
普通なら数字だけを制限したいのに、値段ではなく「ほげほげ」が表示されて
値段が分からなかったら店側が困っちゃいます。。
それに、金額を出したいのに文字が入れれると、
迷惑客も現れるかもしれません。
自由に使える醤油を舐めるかのような迷惑客みたいな輩ならあり得る話です。

用は、使える文字、数字を制限することができるのです！便利！


## 代表的なデータ型

| データ型 | 制限される内容 |
|:-:|:-:|
| integer    | 数値（整数）  |
| decimal    | 数値（精度の高い小数）  |
| float      | 数値（浮動小数）  |
| string     | 文字（~255字までの短い文字列）  |
| text       | 文字（長い文字列） |
| date       | 日付  |
| datetime   | 日時  |
| time       | 時刻  |
| timestamp  | タイムスタンプ  |
| binary     | バイナリ  |
| boolean    | 真偽  |


## データ型以外にもカラムに設定できるもの

### AUTOINCREMENT

自動的に番号を連番で割り振る機能です。
IDによく使われますね
アカウントや投稿の作成順に1から順に割り振られます。

### NOT NULL

空欄を禁止する機能。
保存する時にカラムの中身が空ではダメなものにはこれをつけると良いです！
アカウント作成のpasswordなしは厳禁！だとか、
ブログでタイトルは必須！と考えるのでしたらタイトルのカラムにNOT NULLをつけるといいです。

### DEFAULT

初期値を設定する機能ですね。
レコードが登録された時に自動でカラムの値をいれて登録します。

### UNIQUE

重複を禁止する機能ですね。
同じメールアドレスでの登録は禁止にしたい時やpasswordの重複などで使います。



## 最後に

カラムに制限をかけると、事前にエラーを防げるようになります。
エラー撲滅にこの記事を参考にしていただければ幸いです。
【Rails】gem draperを使用した時 rails g controller で decoratorのファイルを生成させない方法

# draperとは
draperはdecoratorを導入するためのgemとなります。
decoratorの役割やdraperの使い方などはここでは解説しないのでdraper知らないよって人は↓の記事などを見てみるといいかもです。

https://qiita.com/jonson29/items/00077b54bb91ed74fdb8

# rails g controllerでdecoratorファイルが生成される
draperを導入した後に新しくコントローラーを追加するとdecoratorのファイルも自動で生成されると思います。

```
$ rails g controller tasks
      create  app/controllers/tasks_controller.rb
      invoke  erb
      create    app/views/tasks
      invoke  rspec
      create    spec/requests/tasks_spec.rb
      invoke  helper
      create    app/helpers/tasks_helper.rb
      invoke    rspec
      invoke  decorator
      create    app/decorators/task_decorator.rb
      invoke    rspec
      create      spec/decorators/task_decorator_spec.rb
```
ただ、このコントローラーのdecoratorは使う予定がないなどdecoratorを自動で生成したくない場合もあると思います。
そういった場合はgeneratorsの設定を変更することで自動生成させなくすることができます。

# decoratorファイルを生成しない方法
`config/application.rb`に`g.decorator false`を追記します。
```ruby:config/application.rb
    config.generators do |g|
      g.test_framework :rspec,
                       fixtures: false,
                       view_specs: false,
                       helper_specs: false,
                       routing_specs: false
      g.factory_bot false
      g.decorator false # 追加
    end
```

設定変更後にコントローラを生成してみると今度はdecoratorファイルが生成されなくなっていることが分かると思います。
```
$ rails g controller posts
      create  app/controllers/posts_controller.rb
      invoke  erb
      create    app/views/posts
      invoke  rspec
      create    spec/requests/posts_spec.rb
      invoke  helper
      create    app/helpers/posts_helper.rb
      invoke    rspec
```

設定変更後ももちろん`rails g decorator`コマンドではdecoratorファイルを生成することができます。
```
$ rails g decorator post
      create  app/decorators/post_decorator.rb
      invoke  rspec
      create    spec/decorators/post_decorator_spec.rb
```

# さらに詳しい説明
draperのソースコードを見てみると`ControllerGenerator`に`hook_for :decorator`という記載があります。
これは`rails g controller`した時に`DecoratorGenerator`を呼び出すということを意味するので
generatorsの設定に`g.decorator false`を設定することでdecoratorファイルの生成を止めることができるのでした。
```ruby:lib/generators/controller_override.rb

require "rails/generators"
require "rails/generators/rails/controller/controller_generator"
require "rails/generators/rails/scaffold_controller/scaffold_controller_generator"

module Rails
  module Generators
    class ControllerGenerator
      hook_for :decorator, type: :boolean, default: true do |generator|
        invoke generator, [name.singularize]
      end
    end

    class ScaffoldControllerGenerator
      hook_for :decorator, type: :boolean, default: true
    end
  end
end
```

draper以外でももし他のgemを導入した時に自動で生成されるファイルがあってそれを無効にしたいときは
generatorsの設定にそのgemでフックしている名前を書くことで設定を変更できると思います。
ジェネレーターについてもっと詳しく知りたいって人はRailsガイドをみるといいかもです。

https://railsguides.jp/generators.html
vagrant起動エラー

# 概要
vagrant起動時のエラーメッセージについての対応メモ
なお、自身の環境はMac OS12.6を想定している。


# エラーメッセージ
vagrant upで仮想ホストを起動しようとしましたが下記エラーが表示される。
```
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'ubuntu/bionic64' version '20230222.0.0' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["startvm", "45b862f3-823a-45f8-a6fe-59244e78dfa5", "--type", "headless"]

Stderr: VBoxManage: error: The virtual machine 'xxxx_default_1677201045807_72286' has terminated unexpectedly during startup with exit code 1 (0x1)
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component MachineWrap, interface IMachine
```

# 対処法
色々と解決を試みていましたが、vagrant周りの知識が不足していたために再インストールで解決しました(一番ダメなやつ。。。)
```
$ brew uninstall --cask virtualbox vagrant
$ brew install --cask virtualbox vagrant
```
TortoiseGitプルできない解決方法

# 発生した問題
GitBashを使って、pull、pushできますが、TortoiseGitを使ったとき、以下のエラーが発生しました。
`No supported authentication methods available`

# 解決方法
TortoiseGitのSSH　ClientをGitBashと同じものに設定すれば、うまくpullできます。

# 手順
1. TortoiseGitの設定画面を開いて、左側のネットワークを選ぶ
   ![Snipaste_2023-02-24_10-31-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/852963fa-8d52-d2bd-399a-aae58058b09e.png)
2. SSHクライアントのパスを修正する
   参照ボタンを押して、Gitフォルダのssh.exeを選ぶ
   ![Snipaste_2023-02-24_10-32-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/ba10511f-b1bb-5147-caa3-2b52cb401306.png)
3. 設定した後、適用して、OKボタンを押す
   ![Snipaste_2023-02-24_10-33-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/a0b49ce9-8989-c2c9-9d59-96fc4feb3937.png)
Ubuntu 22 + OpenSSL 3.0 環境下でキーストアの生成に失敗する

# 事象

Ubuntu 22.04.1 LTSにWowzaをインストール後、Let's Encryptで証明書を生成し、キーストアに変換しようとすると以下のエラーが出た。

```
# openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out output.p12
Enter Export Password:
Verifying - Enter Export Password:
# /usr/local/WowzaStreamingEngine/jre/bin/keytool -import -alias cacert -keystore output.p12 -file chain.pem
Enter keystore password:  
keytool error: java.io.IOException: keystore password was incorrect
```

エラーメッセージの内容と"keytool"で検索しても原因になかなか辿り着けず、時間を要したので備忘録として残しておく。

# 解決方法

.p12ファイル生成時のopensslの引数に"-legacy"を付与すればよい。

```Text:対応前
openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out output.p12
```

```Text:対応後
openssl -legacy pkcs12 -export -in cert.pem -inkey privkey.pem -out output.p12
```

# バージョン

ディストリビューションや各種ライブラリのバージョンは以下の通り。

| バージョン |
|:-|
| Ubuntu 22.04.1 LTS |
| OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022) |
| Wowza 4.8.21+6 |
| openjdk version "11.0.2" 2019-01-15 |

### UbuntuとOpenSSLの関係

Ubuntu 20まではOpenSSL 1.1系だが、Ubuntu 22からOpenSSL 3.0系に変わっていた模様。

| UbuntuとOpenSSLの関係 | |
|:-|:-:|
| Ubuntu 20 | OpenSSL 1.1系 |
| Ubuntu 22 | OpenSSL 3.0系 |

### OpenJDK

今回はWowza同梱のOpenJDKを利用している。

```
# /usr/local/WowzaStreamingEngine/jre/bin/java -version
openjdk version "11.0.2" 2019-01-15
```
phpチートシート


# 最初にやること

phpはときどき何かの拍子に使うことがあるのですが、いろいろなことを忘れていて毎回調べるのもうっとおしいのでチートシートとしてアップします。
phpのビルドインサーバーを使う前提です。

![IMG_0001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/4772e876-b7a8-4d80-5f2c-d3e7ae7720e7.jpeg)

そもそもphpサーバーがどう動いているかというと
![IMG_0002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/ab00c0e3-2f37-d9a3-ece1-f3c3e6530541.jpeg)

phpではスーパーグローバル変数というのがよく出てきますが、これも忘れがちなのでついでにアップしておきます

![IMG_0005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/a7806799-a071-259c-d245-67b6022fb6ab.jpeg)

| 1 | 2 | 3 |
|:-:|:-:|:-:|
| 1  | $GLOBALS  |  すべてのグローバル変数を格納 |
| 2  | $_SERVER  |  サーバー情報を格納 |
| 3  | $_GET  |  GET メソッドで送信されたパラメータ |
| 4  |  $_POST | POST メソッドで送信されたパラメータ  |
| 5  |  $_FILES |  アップロードされたファイルの情報 |
| 6  |  $_COOKIE |  クッキーによって送信されたパラメータ |
| 7  | $_SESSION  | セッション変数  |
| 8  | $_REQUEST  |  HTTP リクエストのパラメータ |
| 9  |  $_ENV | 環境変数  |



もうひとつセッションのイメージも忘れがちなのでアップします

![IMG_0006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/1996c650-0cec-4583-8216-59e1ed33fb95.jpeg)

ログイン時のざっくりしたイメージはこんな感じです。
![IMG_0004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/bf3a764e-0494-9f3d-067d-e3db1530b387.jpeg)

本当はクライアントとサーバー間でもう少し細かいやり取りがあるのですが、ざっくりということで

# 忘れがちなこと
foreach文も忘れがちなので共有しておきます

![IMG_0003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/42ccafb9-4485-168b-9341-db6b5814e77d.jpeg)

 # データベースに繋いで取得するまで（mysqlの場合）
```php
$conn = new PDO("mysql:host=$host;dbname=$dbname", $user, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT * FROM tables"); 
$stmt->execute();
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC); 
$rows = $stmt->fetchAll();
```
# if文
Pythonとちがって条件のところに()をつける、elifはelseif
```php
      <?php if ($b==1): ?>
        aaaa<br>
      <?php elseif ($b==2): ?>
        bbbb<br>
      <?php else:?>
        cccc<br>
      <?php endif; ?>
```
最終的にクライアントにレスポンとして送られるのは条件が成立した部分のhtmlのみ。上の例で、たとえば$b=1だったらaaaaだけがクライアントに送られてくる


# 配列まわり
本質は連想配列、キーがないと普通の配列としてindexが割り振られる

```php
     $ar=["1"=>"aaa","zzz"=>"bbb","ccc"];     
     print_r($ar);
```
結果：
Array ( [1] => aaa [zzz] => bbb [2] => ccc )

replitで確認できます
https://replit.com/@bkh4149/phpnoPei-Lie#index.php

![php_repl.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411052/99e2d8ee-6d3d-f72e-6a42-49c27408b7c7.jpeg)
Pythonでgoogletrans使用時の「AttributeError: 'NoneType' object has no attribute 'group'」解決方法

# 1. やりたいこと
```python
#visionをインポート
from google.cloud import vision
from googletrans import Translator

translator = Translator()

#image.jpgを開いて読み込む
with open('./image/image.jpg', 'rb') as image_file:
    content = image_file.read()

#visionAPIが扱える画像データにする
image = vision.Image(content=content)

#ImageAnnotatorClientのインスタンスを生成
annotator_client = vision.ImageAnnotatorClient()

response_data = annotator_client.label_detection(image=image)
labels = response_data.label_annotations

for label in labels:
    des = Translator().translate(label.description, src='en', dest='ja')
    print(des.text, ':', round(label.score * 100, 2), '%')
```
取得した画像をvisionAPIで画像認識し、出力されたラベルを自動で日本語に変換したい。
英語を日本語に変換するためにgoogleが提供しているgoogletransを使って実装していきたい。（googletransはGoogle Translate API を実装したPythonライブラリです）

# 2．問題点
```python
AttributeError: 'NoneType' object has no attribute 'group'
```
Pythonでgoogletransを使って英語を日本語に変換したいのだが、__「AttributeError: 'NoneType' object has no attribute 'group'」__ が起きてしまった。
誤字脱字も確認したが、そのような形跡もないようだ。
開発したい機能ができないのでなんとか解決したい
# 3．解決方法
googletransのバージョンが問題だったようだ。
googletransをインストール済みだったので、まず下記のコマンドをターミナルに入力してアンインストールした。（筆者はWindows環境です）

```python
pip uninstall googletrans
```
次に下記のコマンドで「googletrans==3.1.0a0」をインストールした。
```python
pip install googletrans==3.1.0a0
```

# 4．結果
```python
額 : 98.47 %
笑顔 : 97.43 %
顎 : 96.62 %
表情 : 93.29 %
人間 : 89.59 %
ギターアクセサリー : 88.6 %
あご : 87.69 %
ハッピー : 87.13 %
ジェスチャー : 85.26 %
タータン : 84.28 %
```

問題なく出力できたようだ。

# まとめ
今回はgoogletransのバージョンが問題でした。
コードみてもリファレンスみてもわからないときは、バージョンを疑うべきですね。
今後の教訓です。
Docker + laravel-dompdfで日本語が文字化けする

# はじめに
Laravelではdompdfライブラリを使って、簡単にPDFの出力ができます。

https://github.com/barryvdh/laravel-dompdf

今回はLaravelでPDF出力時に、日本語が文字化けした時の対策を簡略にまとめてみました。

# 実装
### Controller
```php
$pdf = PDF::loadView(
    // bladeファイル名
    'pdf',
    // PDFの中身
    ['title' => 'こんにちは', 'content' => '内容が入ります']
);

// A4サイズ、横向き
$pdf->setPaper('A4', 'landscape');

// PDFファイルをダウンロード
return $pdf->download('download.pdf');
```

### View
```php
<x-pdf-layout>
    @section('css') 
    <style type="text/css">
        body {
            page-break-inside: avoid;
            text-align: center;
            font-size: 3rem;
        }
    </style>
    @endsection
    <x-slot name="header">title: {{ $title }}</x-slot>
    <div>
        content: {{ $content }}
    </div>
</x-pdf-layout>
```

### PDF
※下の空白を切り取りました。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/6b4cc6a2-30b9-154a-1c27-8c2f4087e9a5.png)

### PHP Dockerfile
#### install Font
migmixを使用
https://mix-mplus-ipa.osdn.jp/migmix/
```dockerfile
RUN cd  /tmp && \
    wget --trust-server-names 'https://osdn.net/projects/mix-mplus-ipa/downloads/72510/migmix-1p-20200307.zip' && \
    unzip migmix-1p-20200307.zip && \
    mkdir -p /var/www/app/public/fonts && \
    cp /tmp/migmix-1p-20200307/*.ttf \
    /var/www/app/public/fonts/ && \
    chmod 777 /var/www/app/public/fonts
```

### View
```php
<x-pdf-layout>
    @section('css') 
    <style type="text/css">
        /* 追加 */
        @font-face{
            font-family: migmix;
            font-style: normal;
            font-weight: normal;
            src: url("fonts/migmix-1p-regular.ttf") format('truetype');
        }
        body {
            /* 追加 */
            font-family: migmix;
            page-break-inside: avoid;
            text-align: center;
            font-size: 3rem;
        }
    </style>
    @endsection
    <x-slot name="header">title: {{ $title }}</x-slot>
    <div>
        content: {{ $content }}
    </div>
</x-pdf-layout>
```
### PDF
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/be0f46c0-2dc1-a144-8386-f644b30a3ab6.png)

# さいごに
dompdfのバージョン次第、サポートしないフォントフォーマットもあるので、ご注意ください。
<strike>それが原因でフォント変更の時にだいぶ時間使いました</strike>

https://github.com/dompdf/dompdf/issues/932

# 参考
https://zakkuri.life/laravel-pdf-ja/

https://qiita.com/kurosuke1117/items/1b32e2e7944f1200a7cc
【JavaScript】window.onloadが複数回使えない時の対処法

JavaScriptの`window.onload`が走らない状況に陥ったので
同じことが起きても忘れないよう備忘録として。。

# 状況
Vue.jsで実装していた内容をJavaScriptで書き直そうとした際に、`window.onload`の処理が走らない。

**Vue.js（書き直し前）**

```javascript:main.js
const app = createApp({
  mounted() {
    console.log('[Vuejs]ページが読み込まれました');
  }
});
```
**JavaScript（書き直し後）**

```javascript:main.js
window.onload = function () {
  console.log('[JavaScript]ページが読み込まれました');
};
```
上記のように書き直したら`console.log('[JavaScript]ページが読み込まれました')`が走らない。

# 原因
window(ブラウザ)に渡したコールバックは上書きされてしまうため
window.onloadは複数回使えない。
（他に読み込んでいたjsで`window.onload`が実装されていた。）

# 対処法
`window.addEventListener`で実装するように変更。
```javascript:main.js
window.addEventListener('load', function () {
  console.log('[JavaScript]ページが読み込まれました');
};
```

# 参考

https://developer.mozilla.org/ja/docs/Web/API/Window/load_event

https://webstyle.work/windowonload/
【解決法】MAMPでlocalhostにアクセスするとhttpsにリダイレクトされてしまう

ちょこちょこ使用しているMAMP
過去何度かhttpsにリダイレクトされ、「このサイトは安全に接続できません」と出て長時間悩んだので、備忘録作成します。
（全然解決できなくて何度か諦めてた笑）

## 前提
### 環境
- MAMP使用
- chrome環境

### 困ってたこと
MAMPは無事に立ち上がり「MAMP Website」をクリックすると下記が表示され、ウェブサイトが表示されない
![スクリーンショット 2023-02-24 9.43.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2940151/16bc8c99-68b4-c934-5dbf-9b8804342c0f.png)


## 解決手順
1. chrome://net-internals/#hsts にアクセス
1. Delete domain security policiesのDomainに「localhost8888（リダイレクトされるドメイン）」を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2940151/48c53e0f-3f55-6a17-b24a-6b7e585754a6.png)
1. すぐ隣のDeleteキーを押す

最後に記載する参考記事によると、基本的には？これでできるぽいです。たぶん。
ただわたしは解決しなかったので、

### それでも解決しない場合
**キャッシュの削除を実行**
24時間のキャッシュを削除しました。

これで解決！
すぐ終わったので、今まで諦めてたのがばからしい〜

## 参考
本当に助かりました。ありがとうございました。
- [localhostにアクセスすると勝手にhttpsにリダイレクトされてしまって接続が拒否される時に見る記事](https://note.com/alphace_t/n/n868673e0307d)
Power BI サービスでExcelデータをインポートする(失敗談)

`Power BI Desktop`と`Power BIサービス`って微妙に仕様が違いますよね。
前回ご紹介しました記事の中でもEXCELが正しく取り込めなかったらエラーになりますよとお伝えしました。

https://qiita.com/fsd-kozue/items/7cc98cc44a5e3585b40b

今回EXCELデータを取り込むときにどんなことで失敗したか事例をご紹介したいと思います。


# 準備するもの
元データはこれ(ただのEXCELで作った一覧表)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/b04dc2c0-aebe-307a-110e-d1d634c61ce6.png)

# Power BI DesktopにEXCELデータを取り込む場合
Power BI Desktopに取り込む⇒問題なし
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/f4b827da-2f1f-b9cb-90e5-2c082981d082.png)


# Power BI サービスにEXCELデータを取り込む場合
ワークスペースに取り込む⇒エラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/c5629c78-92cd-3002-1f88-ed6662996f92.png)



原因を調べてみると、エラーの内容は↓の説明にありました！

https://learn.microsoft.com/ja-jp/power-bi/connect-data/service-admin-troubleshoot-excel-workbook-data

つまり、Power BIサービスにデータを取り込みたかったら、単なる表ではなくて、データ形式に変換しなさいよ！ってことですね。
これはPower BIの仕様をよく理解してなかったら失敗あるあるになりそうです。

そして、この後EXCELファイルを修正。
表形式からテーブル型に変換するときは、「挿入」⇒「テーブル」で修正できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/7c0c9e1f-c349-40a2-4cba-57cd8e1d9ca3.png)

EXCELを保存しなおして、再度ワークスペースに取り込み直すと・・・ちゃんとデータとして認識されました！
※EXCELファイルは取り込むときに別名に変更しております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/baeabbfa-5972-788c-aa58-67ae664c93ae.png)

# 考察
- Power BI Desktop：データ読み込み時に、データを変換してくれる機能があるのでエラーにならない
- Power BI サービス：データ読み込み時に、テーブル型と認識して取り込もうとするのでエラーになる
ある意味Power BI Desktopのほうが仕様的にも使い勝手がいいなとは思いますが、レポートを共有したい場合は、Power BIサービスを使わざるを得ないので、今後レポートを作成する際には注意したいですね。

# まとめ
どんなツールでも初めて使ってみて、うまくいかなかったり、エラーが出たりすると結構あわててしまうものですよね。
意外とこういう失敗ってあるのではないかと思い、ご紹介させていただきました。
Power BIは、テーブルを意識した行列の組み合わせにしておかないと上記以外にも取り込めないパターンがありますので、エラーを出しながらナレッジを蓄積したいと思います。
【Flutter】アプリ名やバンドルIDを一元管理できる神パッケージがやばい！Pub.dev flutter_rename_app_plus

flutterの、アプリ名、バンドルID、アプリケーションIDをpubspec 上で一元管理＆簡単に変更できる神パッケージが見つかったのでご紹介。

pubspec 内で値を変更すると、info.plist や androidmanifest.xml も含めて、書き換えてくれます！

これを応用すれば、既存のフラッタープロジェクトをクローンしつつ、別プロジェクトに簡単に変更することが可能に！🦄

変更できる項目は
```
flutter_rename_app_plus:
  application_name: Bank App
  dart_package_name: bank_app
  application_id: com.android.bank
  bundle_id: com.ios.bank
  android_package_name: com.bank.app
```

になります。


https://pub.dev/packages/flutter_rename_app_plus
【Python】pipenv + PyinstallerでPythonコードを.exe化


今回は、pipenvによるPythonの仮想環境の立ち上げと、Pyinstallerによるpythonコードのexe化を紹介する

## .exe化

1. pipenvとpyinstallerをインストール
    ```
    pip install pipenv
    pip install pyinstaller
    ```
2. 適当なフォルダを作成&移動
    ```
    mkdir make_exe  
    cd make_exe  
    ```
3. pipenv環境を作成。PipfileとPipfile.lockがカレントディレクトリに作成される。
    ```
    pipenv --python 3.11
    ```
4. 正常に環境が立ち上がっているか確認
    ```
    pipenv --venv
    ```
5. 仮想環境に入る
    ```
    pipenv shell  
    ```
6. 必要なライブラリをインストール
    ```
    pipenv install pandas
    pipenv install polars
    pipenv install pyarrow
    pipenv install webdriver_manager
    pipenv install beautifulsoup4
    pipenv install requests
    ```
7. ライブラリが正常にインストールされているか確認
    ```
    pipenv run pip freeze
    ```
8. requirements.txtの作成
    ```
    pipenv requirements > requirements.txt

    ちなみにインストールは、
    pipenv install -r ./requirements.txt
    ```
9. pipenv環境で実行可能な確認
    ```
    pipenv run python  .\sample.py
    ```
10. 実行可能か確認できたらpyinstallerでexe化する
    ```
    pipenv run pyinstaller .\sample.py --onefile --hidden-import="pyarrow.vendored.version"      
    ```
11. 仮想環境を閉じる
    ```
    pipenv --rm
    ```

## その他
1. Pipfileの内容からPipfile.lockファイルの依存関係を更新する
    ```
    pipenv lock
    ```
2. Pipfile.loackの内容を仮想環境へ適用する
    ```
    pipenv sync
    ```
2. "Your dependencies could not be resolved"のエラーが出たら、以下のコマンドで依存関係をクリアする
    ```
    pipenv lock --clear   
    ```
3. 古いバージョンのライブラリがないか確認する
    ```
    pipenv update --dry-run
    ```
4. 仮想環境内でコマンドを実行する
    ```
    pipenv run ***
    ```

## 特定のファイルを含める
```
pipenv run pyinstaller .\sample.py --onefile --hidden-import="pyarrow.vendored.version" --add-data "C:\Users\11235\.virtualenvs\Arieku_Scraping-RTlt89YW\Lib\site-packages\selenium_stealth\js;selenium_stealth/js"
```

### まとめ
今回は、pipenvによるPythonの仮想環境の立ち上げと、Pyinstallerによるpythonコードのexe化を紹介した。
Ruby: MariaDB のデータを削除 (Delete)

## プログラム

フォルダー構造

```text
$ tree -a
.
├── .env
├── config_mariadb.rb
└── maria_delete.rb
```

.env
config_mariadb.rb
はこちら
[Ruby: MariaDB のバージョンを表示](https://qiita.com/ekzemplaro/items/3ad75619d32e92ccc866)

```rb:maria_delete.rb
#! /usr/bin/ruby
#
#	maria_delete.rb
#
#					Feb/24/2023
#
require 'mysql2'
#
load 'config_mariadb.rb'
# ------------------------------------------------------------
def	delete_proc (client,id)
	sql_str="DELETE from cities where ID = '#{id}'"
	client.query(sql_str)
end
# ------------------------------------------------------------
STDERR.puts "*** 開始 ***"
#
id_in = ARGV[0]
#
puts id_in
#
host,user,password,data_base = config_mariadb_proc()
client = Mysql2::Client.new(host: host, username: user, password: password, database: data_base)
#
delete_proc(client,id_in)
#
client.close
#
STDERR.puts "*** 終了 ***"
# ------------------------------------------------------------
```

## 実行結果

```text
$ ./maria_delete.rb t3328
*** 開始 ***
t3328
*** 終了 ***
```
Ruby: MariaDB のデータを更新 (Update)

## プログラム

フォルダー構造

```text
$ tree -a
.
├── .env
├── config_mariadb.rb
└── maria_update.rb
```

.env
config_mariadb.rb
はこちら
[Ruby: MariaDB のバージョンを表示](https://qiita.com/ekzemplaro/items/3ad75619d32e92ccc866)

```rb:maria_update.rb
#! /usr/bin/ruby
#
#	maria_update.rb
#
#					Feb/24/2023
#
require 'mysql2'
require 'date'
#
load 'config_mariadb.rb'
# ------------------------------------------------------------
def	update_proc (client,id,population)
	date_mod=Date.today
	sql_str="UPDATE cities SET population='#{population}', DATE_MOD='#{date_mod}' where ID = '#{id}'"
	client.query(sql_str)
end
# ------------------------------------------------------------
STDERR.puts "*** 開始 ***"
#
id_in = ARGV[0]
population_in = ARGV[1].to_i
#
puts id_in,population_in
#
host,user,password,data_base = config_mariadb_proc()
client = Mysql2::Client.new(host: host, username: user, password: password, database: data_base)
#
update_proc(client,id_in,population_in)
#
client.close
#
STDERR.puts "*** 終了 ***"
# ------------------------------------------------------------
```

## 実行結果

```text
$ ./maria_update.rb t3324 91762800
*** 開始 ***
t3324
91762800
*** 終了 ***
```
Raspberry Pi OS 2023-02-21 Release-note 翻訳

(追記: 2023/5/4にRaspbian OS 2023-05-03がリリースされています)
https://qiita.com/utaani/items/0c639dc8395a82c19ffd

https://downloads.raspberrypi.org/raspios_full_armhf/release_notes.txt

2023-02-21:
- レガシービデオドライバを使用するRaspberry Pi 4以外のすべてのプラットフォームで、glamor (訳注: X Window System用の2Dアクセラレータ) が無効化されました。
- msdri3 ビデオ ドライバー のサポートが追加されました
- 推奨ソフトウェアにKiCadが追加されました
- 画面解像度変更ツールに新しいタッチスクリーンドライバのサポートが追加され、細かいUIの微調整が実施されました
- GTKメッセージダイアログで右揃えのボタンが表示されるようになりました
- バグ修正 - メニューのアップデータ プラグインは、更新が失敗したときにアイコンをクリアしなくなりました
- バグ修正 - GTK スイッチ コントロールにキーボード ハイライトが表示されるようになりました
- 韓国語とブラジル語の翻訳を一部追加
- rpi-imagerで「ステルスSSID」時の設定の問題を修正
- kms++-utils をインストール
- Raspberry Pi ファームウェア 78852e166b4cf3ebb31d051e996d54792f0994b0
- Linux カーネル 5.15.84
Ruby: MariaDB のデータを読む (Read)

## プログラム

フォルダー構造

```text
$ tree -a
.
├── .env
├── config_mariadb.rb
└── maria_read.rb
```

.env
config_mariadb.rb
はこちら
[Ruby: MariaDB のバージョンを表示](https://qiita.com/ekzemplaro/items/3ad75619d32e92ccc866)

```rb:maria_read.rb
#! /usr/bin/ruby
#
#	maria_read.rb
#
#					Feb/24/2023
#
# ------------------------------------------------------------------
require 'mysql2'
#
load 'config_mariadb.rb'
# ------------------------------------------------------------------
STDERR.puts "*** 開始 ***"
#
host,user,password,data_base = config_mariadb_proc()
client = Mysql2::Client.new(host: host, username: user, password: password, database: data_base)

sql_str = "SELECT id,name,population,date_mod FROM cities order by ID"
begin
	result = client.query(sql_str)
	result.each do |row|
		print "#{row['id']}\t#{row['name']}\t#{row['population']}\t#{row['date_mod']}\n"
	end
end
#
client.close
#
STDERR.puts "*** 終了 ***"
# ------------------------------------------------------------------
```

## 実行結果

```text
$ ./maria_read.rb 
*** 開始 ***
t3321	岡山	729638	2006-9-18
t3322	倉敷	318472	2006-2-25
t3323	津山	182564	2006-8-8
t3324	玉野	572948	2006-11-15
t3325	笠岡	893257	2006-7-21
t3326	井原	167589	2006-9-7
t3327	総社	241637	2006-4-8
t3328	高梁	438129	2006-10-12
t3329	新見	519472	2006-6-9
*** 終了 ***
```
Python で IPv4 アドレスの CIDR 表記を相互変換するやつ

Python で IPv4 アドレスの CIDR 表記文字列を数値表現と相互変換する関数を書いた。IPv4 アドレスを数値として扱いたいとき (？) にご活用ください。

``` python
def cidr2int(cidr: str) -> tuple[int, int]:
    cidr = cidr.split("/", 1)
    cidr[0] = cidr[0].split(".")
    assert len(cidr[0]) == 4
    addr = 0
    for i, octet in enumerate(cidr[0]):
        assert 0 <= int(octet) <= 0xFF
        addr += int(octet) * 0x100 ** (3 - i)
    prefix = int(cidr[1])
    assert 0 <= prefix <= 32
    mask = 0xFFFFFFFF >> (32 - prefix) << (32 - prefix)
    return addr, mask


def int2cidr(addr: int, mask: int) -> str:
    assert 0 <= addr <= 0xFFFFFFFF
    assert 0 <= mask <= 0xFFFFFFFF
    octets = reversed([(addr & (0xFF * 0x100**i)) >> (i * 8) for i in range(4)])
    return f"{'.'.join([str(octet) for octet in octets])}/{bin(mask).count('1')}"
```

``` python
cidr2int('192.168.1.0/24')  #=> (3232235776, 4294967040)
int2cidr(3232235776, 4294967040)  #=> '192.168.1.0/24'
```
Ruby: MariaDB のデータを作成 (Create)

## プログラム

フォルダー構造

```text
$ tree -a
.
├── .env
├── config_mariadb.rb
└── maria_create.rb
```

.env
config_mariadb.rb
はこちら
[Ruby: MariaDB のバージョンを表示](https://qiita.com/ekzemplaro/items/3ad75619d32e92ccc866)

```rb:maria_create.rb
#! /usr/bin/ruby
#
#	ruby/create/maria_create.rb
#
#					Feb/24/2023
# ---------------------------------------------------------------------
require 'mysql2'
load 'config_mariadb.rb'
#
# -------------------------------------------------------------
def dict_append_proc (dict_aa,id,name,population,date_mod)
	unit = {}
	unit['name'] = name
	unit['population'] = population
	unit['date_mod'] = date_mod
	key = id.to_s
	dict_aa[key] = unit
	return dict_aa
end
# ---------------------------------------------------------------------
def prepare_data_proc ()
dict_aa = {}
dict_aa=dict_append_proc(dict_aa,'t3321',"岡山",729638,"2006-9-18")
dict_aa=dict_append_proc(dict_aa,'t3322',"倉敷",318472,"2006-2-25")
dict_aa=dict_append_proc(dict_aa,'t3323',"津山",182564,"2006-8-8")
dict_aa=dict_append_proc(dict_aa,'t3324',"玉野",572948,"2006-11-15")
dict_aa=dict_append_proc(dict_aa,'t3325',"笠岡",893257,"2006-7-21")
dict_aa=dict_append_proc(dict_aa,'t3326',"井原",167589,"2006-9-7")
dict_aa=dict_append_proc(dict_aa,'t3327',"総社",241637,"2006-4-8")
dict_aa=dict_append_proc(dict_aa,'t3328',"高梁",438129,"2006-10-12")
dict_aa=dict_append_proc(dict_aa,'t3329',"新見",519472,"2006-6-9")
	return	dict_aa
end
# ---------------------------------------------------------------------
def	create_proc (client)
	sql_str="create TABLE cities (" \
		+ "id varchar(10) NOT NULL PRIMARY KEY," \
		+ "name varchar(20)," \
		+ "population int," \
		+ "date_mod varchar(40))"
	client.query(sql_str)
end
# ------------------------------------------------------------
def	drop_proc (client)
	sql_str="drop table cities"
	client.query(sql_str)
end
# ---------------------------------------------------------------------
def	insert_proc (client,id,name,population,date_mod)
	sql_str="INSERT into cities " \
		+ "(id, Name, Population, date_mod) values \
		('#{id}', '#{name}',#{population},'#{date_mod}')"
	client.query(sql_str)
end
# ---------------------------------------------------------------------
STDERR.puts	"*** 開始 ***"
#
host,user,password,data_base = config_mariadb_proc()
client = Mysql2::Client.new(host: host, username: user, password: password, database: data_base)
#
dict_aa=prepare_data_proc()
#
drop_proc(client)
create_proc(client)
dict_aa.each {|key,value |
	insert_proc(client,key,value['name'], \
		value['population'],value['date_mod'])
	}
#
client.close
#
STDERR.puts	"*** 終了 ***"
#
# ---------------------------------------------------------------------
```

## 実行結果

```text
$ ./maria_create.rb 
*** 開始 ***
*** 終了 ***
```