OmniAICreator/Qiita-1.07M huggingface dataset:
【TailwindCSS】font-familyを設定する方法

## `tailwind.config.js`に`fontFamily`を記述する

`tailwind.config.js`に以下のように`fontFamily`を追記します。


```js:tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        body: [
          'Helvetica Neue',
          'Arial',
          'Hiragino Kaku Gothic ProN',
          'Hiragino Sans',
          'Meiryo',
          'sans-serif',
        ],
      },
    },
  },
}
```

`body`の部分は`body`以外の名称でも大丈夫です。

## クラスを適用する

上記の設定をすると`font-body`が使用できるようになるのでこれを`class`に記述します。

```index.html
<html>
  <!-- ... -->
 <body class="font-body">
  <!-- ... -->
 </body>
</html>
```

## 参考

https://tailwindcss.com/docs/font-family#customizing-your-theme
【備忘録】Davinci Resolve18 セットアップ

# 経緯
仕事はしているが給料足りない。副業したい。
Youtuberデビュー。それには動画編集できなきゃ。

そんなあなたにDavinciResolve。

無料なのに高機能です。
個人的に今まで使っていたaviutilより使いやすい。

# 目次
１. ダウンロード
２. 初期設定

# １．ダウンロード
https://www.blackmagicdesign.com/jp/products/davinciresolve
に飛ぼう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/f8911c5e-52e9-fbc7-1b0c-6adbecab960c.png)
今すぐダウンロードをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/80792e75-1b09-2b17-9552-a0c83212fdb1.png)
ダウンロードするのは左下
（ちなみに有料なのは右下）

インストールは適当にやろう。

# ２. 初期設定
起動したらProjectを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/ee54c938-5c66-e66b-8508-e0ec3dc441c0.png)

左上のDavinci Resolve > 環境設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/c09ca588-7661-aab9-49a6-c804d1ea830d.png)

■システム欄
メディアストレージ。内部ディスクを選択すること。

■ユーザ欄
言語を日本語に変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/a4847d73-ba06-ab01-3ecc-18c49385bf88.png)

ライブ保存とプロジェクトバックアップにチェック
バックアップ頻度は10分毎くらいが良い。短すぎると重たくなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/6b049650-7ff4-b248-18f1-ace36715f8b9.png)

環境設定はこれで終わり。次はプロジェクト画面より右下の歯車を押す。

■プロジェクト設定
タイムライン解像度選択。書き出しがフルHDならフルHDにする。動画素材の解像度が低ければ高くしても意味がないので、合わせる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/da113b30-3a1b-c064-07ee-8d739adc1625.png)

フレームレートも動画のフレームレートに合わせる。一応、動画を読み込んだ時に聞いてくる。24FPSぐらいを選択しておくとよい。

最適化メディア & レンダーキャッシュ

下記の通りにする。※Windowsの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/5db0330f-5029-7387-4559-76fdac4816f0.png)

ここまで設定したら、デフォルトプリセットに登録しておく。
（次プロジェクトを開いたときにこの設定が使用できる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521517/f93b7fbc-e605-f370-4f68-f698c53e649f.png)
JavaScript で画像・動画・音声ファイルをドラッグ＆ドロップしてプレビュー表示

画像・動画・音声ファイルをドラッグ＆ドロップしてクライアントのみでプレビュー表示までやってみる
サンプルは以下のページ

https://sueasen.github.io/javascript-exercise/work/filepreviewdrop/

## HTML
HTML に ファイルドラッグの divタグ をつくり inputタグ, プレビュー用の img, video, audio タグを準備
inputタグは非表示 `display: none` を CSS で設定
label タグで inputタグを囲って pタグ にファイル入力・入力ファイル名を表示できるように準備
ファイルドラッグの div タグ に `ondrop`,  `ondragover` で処理実行

```HTML
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <link rel="stylesheet" href="./style.css">
</head>

<body>

  <hr>
  <h4>画像アップ・プレビュー</h4>
  <div class="filearea" id="image" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
    <label>
      <input type="file" accept='image/*' onchange="preview(this, 'preview-image');">
      <p class="selecter">＋ファイル選択 または ファイルドロップ</p>
      <p class="select-file" id="preview-image-file">選択されてません</p>
      <img class="preview pre-select" id="preview-image">
    </label>
  </div>

  <h4>動画アップ・プレビュー</h4>
  <div class="filearea" id="video" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
    <label>
      <input type="file" accept='video/*' onchange="preview(this, 'preview-video');">
      <p class="selecter">＋ファイル選択 または ファイルドロップ</p>
      <p class="select-file" id="preview-video-file">選択されてません</p>
      <video class="preview pre-select" id="preview-video" controls="controls"></video>
    </label>
  </div>

  <h4>音声アップ・プレビュー</h4>
  <div class="filearea" id="audio" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
    <label>
      <input type="file" accept='audio/*' onchange="preview(this, 'preview-audio');">
      <p class="selecter">＋ファイル選択 または ファイルドロップ</p>
      <p class="select-file" id="preview-audio-file">選択されてません</p>
      <audio class="preview pre-select" id="preview-audio" controls="controls"></audio>
    </label>
  </div>

</body>

<script src="script.js"></script>

</html>
```

## JavaScript
`drop` で `event.dataTransfer.files` よりファイル情報取得して処理
`drag` は 既定処理をキャンセルする

```JavaScript
/**
 * @param {HTMLInputElement} obj 入力情報
 * @param {String} previewId プレビュー表示DOMのID
 */
function preview(obj, previewId) {
    previewFile(obj.files, previewId);
}

/**
 * @param {File} files 入力ファイル
 * @param {String} previewId プレビュー表示DOMのID
 */
function previewFile(files, previewId) {
    let fileReader = new FileReader();
    fileReader.onload = (function () {
        document.getElementById(previewId).src = fileReader.result;
        document.getElementById(`${previewId}-file`).innerText = files[0].name;
    });
    fileReader.readAsDataURL(files[0]);
}

/** 
 * @param {Event} event
 */
function dropHandler(event) {

    event.preventDefault();

    if (event.dataTransfer.files.length === 0) return false;
    const files = event.dataTransfer.files;
    const previewId = `preview-${event.currentTarget.id}`;
    previewFile(files, previewId);
}

/** 
 * @param {Event} event
 */
function dragOverHandler(event) {
    event.preventDefault();
}

```
phpのオブジェクトと連想配列でつまずいたこと

# 初めに
自分が業務内でlaravelを使っていた際にphpのオブジェクトと連想配列の使い方や違いが良く分からなかったので自分が悩んだところと調べて分かったことをまとめました。

# 自己紹介
・専門学校を卒業後新卒で自社開発のweb系企業に入社
・働き始めて2か月ほど

# 実行環境
・Windows10
・php8.2.0
・xampp上で実行

# つまずいたこと

~~~php
//連想配列を作成
$array = array (
    "taxi" => "タクシー",
    "police_car" => "パトカー",
    "ambulance" => "救急車",
);

//echoで呼び出し
echo "taxiは日本語で" . $array->taxi . "です<br>";
echo "police carは日本語で" . $array->police_car . "です<br>";
echo "ambulanceは日本語で" . $array->ambulance . "です";

//出力結果（エラー）
Warning: Attempt to read property "taxi" on array in C:\xampp\htdocs\studys\php\test\error.php on line 10
Warning: Attempt to read property "police_car" on array in C:\xampp\htdocs\studys\php\test\error.php on line 11
Warning: Attempt to read property "ambulance" on array in C:\xampp\htdocs\studys\php\test\error.php on line 12
~~~
連想配列を呼び出そうとした際にエラーになりました。エラーの内容としては配列の中身を読み取ろうとして失敗したという事です。原因は呼び出す際に\\$array["taxi"]ではなく$array->taxiと記述していたため配列からではなくオブジェクトから値を取り出そうとしてしまいエラーになりました。。

# 正しい記述例


~~~php:array.php

//連想配列を作成
$array = array (
    "taxi" => "タクシー",
    "police_car" => "パトカー",
    "ambulance" => "救急車",
);

//echoで呼び出し
echo "taxiは日本語で" . $array["taxi"] . "です<br>";
echo "police carは日本語で" . $array["police_car"] . "です<br>";
echo "ambulanceは日本語で" . $array["ambulance"] . "です";

//出力結果
appleは日本語でタクシーです
lemonは日本語でパトカーです
orangeは日本語で救急車です

~~~
連想配列では
~~~
変数名 = array (
    　キー名=>キー名の中身
)
~~~
と書くことで配列を作成することができます。
中の要素を呼び出す際は変数名["キー名"]で呼び出します。
~~~php
echo $array["taxi"] //タクシーという文字列が出力される
~~~
:::note info
キー名は呼び出す際の識別子のようなものです。上の例では[]の中を"ambulance"に変えると救急車という文字列が呼ばれます。
:::

# 補足
説明の中で出てきたオブジェクトの例も載せておきます。
~~~php:object.php

//オブジェクトを作成
class Obj{
    public $name = "タクシー";
    public $english_name = "taxi" ;
}

//インスタンスを作成
$object = new Obj;
var_dump($object);
//var_dumpで呼び出すとobject(Obj)#1 (2) { ["name"]=> string(12) "タクシー" ["english_name"]=> string(4) "taxi" }の値が返ってくる

//echoで呼び出し
echo "車の名前は" . $object->name . "です<br>";
echo "英語名は" . $object->english_name . "です";

//出力結果
車の名前はタクシーです
英語名はpolice carです

~~~
上のコードから部分的に抜き出すとオブジェクトでは
~~~php
class Obj{
    public $name = "タクシー";
    public $english_name = "taxi" ;
}
//Objはクラス名
//$nameと$english_nameは変数名
~~~
でクラスと中の変数を作成して
~~~php
$object = new Obj; //Objはクラス名
~~~
インスタンス化をしてから
~~~php
$object->name 
~~~
と書くことで呼び出すことができます。

# まとめ
今回はオブジェクトと連想配列でつまずいたところと調べていく中で知った書き方などをまとめていきました。まだまだ基礎的な部分がしっかりできていないので勉強していきたいと思います。また説明途中に出てきたインスタンス化の詳しい説明もしっかり理解出来たら記事として上げていきたいと思います

# 参考文献・記事
https://qiita.com/shin_moto/items/7dc3cf0a64738f7a4d6b
https://coinbaby8.com/different-between-object-and-array.html
FlutterでAndroidアプリを開発する際の環境構築

今回はFlutterを使用してAndroidアプリを開発する際に必要な環境構築の方法を記述します
Android限定なのは私のPCがWindowsだからです…。よってWindowsでの環境構築の解説になります。

以下の流れで進めていきます。
1.FlutterSDKのインストール
2.Path環境変数の設定
3.Android Studioのインストール・初期設定
4.VSCodeにFlutterを追加

※GitとVSCode自体のインストールは完了している前提で進めます。

<h2>1.FlutterSDKのインストール</h2>

<b>SDK</b>とは？
Software Development Kitの略で、ソフトウェア開発に必要なプログラム、サンプル、文書、APIなどをパッケージ化したものです。
今回はFlutterSDKなので、Flutterでのアプリ開発に必要なものが入っているという認識でよいかと思います。

公式サイトからインストール
https://docs.flutter.dev/get-started/install/windows
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/f5589662-50a1-954c-1eb2-aacd23a03908.png)

zipを開いたらflutterファイルを任意のディレクトリに保存してください。

<h2>2.Path環境変数の設定</h2>

<b>環境変数</b>とは？
OSが提供するデータ共有機能の一つで、OS上で動作するタスク（プロセス）がデータを共有するための仕組み。タスクに外部からデータを与え、タスクの挙動・設定を変更するためのもの。
今回のPath環境変数は、ソフトウェアが配置されている場所までのフォルダ階層の道筋を設定するものです。これを設定しておくことで、コマンドプロンプトでFlutterファイルを操作することができるようになります（「Pathを通す」という言い方をすることもあります）。

スタートボタン＞設定＞システム＞システムの詳細設定の表示　から環境変数を選択し、Pathを選択後編集をクリック。
![スクリーンショット (196).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/974281d1-e6d4-5093-c05d-652e7cc8d372.jpeg)

新規をクリックし、flutter\binまでのPathを追加しOKをクリック。
![スクリーンショット (198).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/78234218-d382-dae0-08e0-cc765b3fac78.jpeg)

Pathが通ったことを確認しましょう。
コマンドプロンプトを開き、flutter --version　コマンドを実行します。
![スクリーンショット (200).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/c2202614-ac0a-789e-6698-d8feee1f89f6.png)

Flutterのバージョンが表示されれば成功です。

<h2>3.Android Studioのインストール・初期設定</h2>

Android Studioは、Androidアプリ開発のIDEです。

<b>IDE</b>とは？
Integrated Development Environmentの略で、統合開発環境と訳されます。
ソフトウェア開発を支援するための統合されたツールで、エディタ、デバッガ、ビルドツールなどが含まれます。
SDKと似ていますが、あちらは開発部分を支援するパッケージ。IDEはソフトウェア開発全体のワークフローを支援する統合環境であるという違いがあります。

公式サイトからインストール
https://developer.android.com/studio

『Download Android Studio Flamingo』をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/c87a944d-9f13-586f-bafc-55f8450ea07c.png)

同意してダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/53fe1baa-3e56-e079-e1b2-6af54b9ec380.png)

初期設定　最初は『Don't send』を選択し、あとはすべて『Next』でOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/95b342ed-6387-ea3d-f295-15035a6535f7.png)

『Licence Agreement』はすべてのライセンスに同意して『Finish』をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/0ca0adbe-067a-2f10-c897-fc6fc4341e9e.png)

これでAndroid Studioのセットアップは完了です。

<h2>4.VSCodeにFlutterを追加</h2>
プラグインからFlutterを検索しインストールでOK

![スクリーンショット (201).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/8b832125-c123-c78e-a75c-a5792f317797.png)

以上で、FlutterでAndroidアプリ開発を行う環境構築ができました！
【Laravel】マイグレーションにおける外部キー制約の削除とカラムのロールバック

## 概要
Laravelのマイグレーションは、データベースのスキーマ変更やテーブルの作成、変更を行う際に便利な機能です。しかし、外部キー制約が設定されているテーブルでカラムを削除しようとするとエラーが発生することがあります。本記事では、この問題に対する解決策として、外部キー制約を一時的に無効化してカラムを削除し、マイグレーションのロールバックを行う方法を解説します。

## 発生したエラー
外部キーを貼ったカラムを削除しようとロールバックを実行したところ、`Cannot drop column`というエラーが発生しました。
詳しく見てみると、外部キー制約が存在しているため、カラムの削除ができないというものでした。

そこで、ロールバック時に実行されるdownメソッドを見てみます。

```php
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('teams', function (Blueprint $table) {
            $table->dropColumn('user_id');
        });
    }
```
`dropColumn`メソッドを使用してカラムを削除する処理は書いていますが、それだけではエラーが出るので外部キー制約も削除する処理を追加しなければいけません。

## 外部キー制約を削除すれば解決
`dowm`メソッドに外部キー制約を削除する処理を追加します。

```php
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('teams', function (Blueprint $table) {
            // 追加 (外部キー名は{テーブル名}_{カラム名}_foreign)
            $table->dropForeign('teams_user_id_foreign');
            $table->dropColumn('user_id');
        });
    }
```
これで無事削除することができます。
ubuntu(virtual box)環境のVSCodeにgitとgithubを設定してみた



# Gitをインストールする
```shell
sudo apt update
sudo apt install git
```
## Gitの設定をする
```shell
git config --global user.name name
git config --global user.email mail@mail.com
```

# VSCodeで設定する

## リポジトリのURLを入力する
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/439fd42e-60fc-70ec-fc26-089c686f480f.png)

## クローン先のローカルフォルダを指定する
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/4dedb1ff-4ef1-bdf1-f353-2688fdb66a4f.png)

クローンされた
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/4c1b9832-531e-070b-b995-e4ae2731ccf3.png)
GBDKの導入～ゲーム作成まで

**はじめに**

ゲームボーイ（GB）のゲームが作成できるGBDKを導入したのですが、作成までの手順がまとめられている記事を見つけることができなかったため自身でまとめる用として記事作成を始めました。

（ある程度ゲームができてからSNS、YOUTUBE等のアカウントを公開します。）


**今後の予定**
1.導入手順
2.プログラム作成
3.便利ツール導入
4.キャラクターの動作付与
5.マップ作製
6.ランダムエンカウント実装
7.GBDKの関数一覧
etc.


<br>
<br>
<br>


**1.導入手順**

https://qiita.com/BubbleBubble/items/100901b7049f2b8cbed3

<r>
<r>
<r>


**2.プログラム作成**

https://qiita.com/BubbleBubble/items/04f97fdab9e61a4dcd79

<r>
<r>
<r>


**3.便利ツール導入**

https://qiita.com/BubbleBubble/items/eede1ac85efe89f74790

<r>
<r>
<r>


**4.キャラクターの動作付与**

https://qiita.com/BubbleBubble/items/d7f293ef045a76f48edd

<r>
<r>
<r>


**5.マップ作製**

https://qiita.com/BubbleBubble/items/b34e63ecac41696c2fbe

<r>
<r>
<r>


**6.ランダムエンカウント実装**

https://qiita.com/BubbleBubble/items/89990f046a7b42bcc6dc

<r>
<r>
<r>


**7.GBDKの関数一覧**

https://qiita.com/BubbleBubble/items/f16b6808d8c84fbc3517
GASで動的ページを操作してスクレイピング

# 目的
GAS（Google Apps Script）を使用した動的ページのスクレイピングを実施する。pythonでseleniumを使用した方が便利かもしれないが、様々な制約からどうしてもGASを使用したかった。
# 使用するサービス
ヘッドレスブラウザのSaaSである[PhantomJsCloud](https://phantomjscloud.com/)を使用。
無料で500 view/dayが可能らしい。
# 記事化の目的
PhantomJsCloudの使用方法に関する日本語webサイトが少なく、特に「動的ページの操作（クリックやタイプ等）を伴うスクレイピング」かつ「GASでPOSTを使用するもの」については、なかなか情報を見つけることができなかったため。
# 参考にした記事
[GASで動的なサイトをスクレイピングする方法](https://qiita.com/zumi0/items/cc3cd4276c6a254781d3)
[GASで動的ページのスクレイピング](https://qiita.com/IR0IR0/items/1bcc570e47c30558d03c)
# 前提条件
ここでは[公式のテストサイト（http://phantomjscloud.com/examples/corpus/automation.html）](http://phantomjscloud.com/examples/corpus/automation.html)でログイン操作を行いスクレイピングする。
　①IDをタイプ
　②パスワードをタイプ
　③ログインボタンをクリック
の操作を行っている。
# コーディング
ポイントは、操作を記述する`overseerScript`の書き方である。
なお、` \`の記載を忘れないように注意する。私は、ここで詰みかけました。
```dynamicPageScraping.gs
const APIKEY = 'ここにAPIキーを記載';  // PhantomJsCloudで取得するAPIキー
const LOGIN_ID = 'user';  // テストサイトのユーザ名
const LOGIN_PASSWORD = 'pass';  // テストサイトのパスワード
const DELAY_TIME = 10; // スクレイピング中の操作に対する待機時間

// PhantomJsCloudのエンドポイントを返す関数
const endpoint = apiKey => `https://PhantomJScloud.com/api/browser/v2/${apiKey}/`;

// スクレイピングの操作に関するペイロードを返す関数
const payload = (id, pass, delayTime) => (
  {
    url: 'http://phantomjscloud.com/examples/corpus/automation.html',
    renderType: 'html',
    outputAsJson: true,
    overseerScript: (` \
    await page.waitForSelector("input[name=id]"); \
    await page.type("input[name=id]","${id}",{delay:${delayTime}}); \
    await page.type("input[name=pass]","${pass}",{delay:${delayTime}}); \
    page.click("input[type=button][value=Login]"); \
    await page.waitForNavigation(); \
    `)
  }
);

// PhantomJsCloudAPIを呼ぶUrlFetchApp.fetch()で使用するオプション（上記ペイロードを伴うpostメソッド）を返す関数
const options = payload => ({
'method' : 'post',
'payload' : JSON.stringify(payload)
});

// 動的ページのスクレイピング実行関数
const dynamicPageScraping = () => {
  const response = UrlFetchApp.fetch(endpoint(APIKEY), options(payload(LOGIN_ID, LOGIN_PASSWORD, DELAY_TIME)));
  const result = JSON.parse(response.getContentText())["content"]["data"];
  Logger.log(result);
};
```
# さいごに
コンテンツを取得後は、よしなに処理してください。
私は、スプレッドシートへの出力するべく、以下を参考にしました。
[【はじめての】GASを使ったスクレイピング自動化](https://qiita.com/Noiru_CH/items/fca9e45bb819c5a74219)
TypeScriptでsetattributeを使う時Booleanでも引用符で囲む必要がある

JavaScriptでDOM操作を行うとき、次のようにsetattributeで属性を追加したいことってよくありますよね。

```
var d = document.getElementById("d1");

d.setAttribute("disabled", true);
```

実はこれをTypeScriptで書くと、trueのところでエラーが出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/12eb0806-e300-39a4-76ec-29622d8230cd.png)

## TypeScriptではsetattributeの引数はstringでなければいけない
TypeScriptでは仕様なのか、Booleanでもsetattributeで受け取り引数がstringで固定になっていて、
引用符か二重引用符で囲まないといけません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/53a94ea7-dd85-8093-692d-30f95cb1cf57.png)

GitHub上で議論されていましたが、引用符なしでも受け取るようにリクエストされているIssuesに対して、回答者は否定的な意見で暗黙的な変換になるからよくないとのこと。

どうしてもそういう動きにしたいのなら、Elementインターフェースにbooleanやnumberを受け取るsetattributeを追加してくれということみたいで、公式では仕様としているようです。

https://github.com/microsoft/TypeScript/issues/15368
radxa に tileserver-gl を動作させた際の手順

rasberry pi zero に似た radxa zero に [tileserver-gl](https://github.com/maptiler/tileserver-gl) をインストールした際の手順を記録しています。

* タイル画像を生成する時にエラーになってしまう問題ができない (2023/06)
```
terminate called after throwing an instance of 'std::runtime_error'
  what():  Cannot read GLX extensions.
```

## 手元のハードウェアスペック/OSイメージ
* emmc 付きの 4GB RAM モデル
* たしか [radxa-zero-ubuntu-focal-server-arm64-20220801-0346-mbr](https://github.com/radxa-build/radxa-zero/releases/tag/20220801-0213) のイメージを利用している

## tileserver-gl のインストール

* tileserver-gl のインストール手順として３つ(docker, npm, from source)の案内があるが, [npm からパッケージをインストール](https://maptiler-tileserver.readthedocs.io/en/latest/installation.html#npm)をしている
* [nodesource](https://github.com/nodesource/distributions#using-ubuntu-2) を使い、nodejs18 系をインストールしている

* 事前に環境変数 `LD_PRELOAD` 変数のセットしている

```
# ~/.bashrc
export LD_PRELOAD=/lib/aarch64-linux-gnu/libGLdispatch.so
```
環境変数をセットしない場合, tileserver-gl 実行時に次のエラーを得る
```
node:internal/modules/cjs/loader:1338
  return process.dlopen(module, path.toNamespacedPath(filename));
                 ^

Error: /lib/aarch64-linux-gnu/libGLdispatch.so.0: cannot allocate memory in static TLS block
}
```

## Xvfb

* tileserver-gl インストール時に Xvfb (X virtual frame buffer) が一緒にインストールされている
* タイルイメージのレンダリングには仮想ディスプレイが必要
  * [getting-started-with-linux-cli](https://github.com/maptiler/tileserver-gl#getting-started-with-linux-cli) にコマンド自体は登場している
* 事前に Xvfb (`xvfb-run`) コマンドで仮想ディスプレイを作成する必要がある
* ただし,レンダリング時に GLX に関してエラーが出てしまうので, virtualgl (bumblebee) package をインストールする必要があった

```
$sudo apt install -y bumblebee
```

* 仮想ディスプレイの作成は次の要領で行う

```
Xvfb :1 -screen 0 1024x768x24 +extension GLX +render -noreset &
```

* 環境変数 `DISPLAY` に仮想ディスプレイを指定する

```
export DISPLAY=:1
```

* 仮想ディスプレイのテストをするには `glxinfo` が利用できる
  * [mesa-utils](https://manpages.ubuntu.com/manpages/focal/man1/glxinfo.1.html) package を次の手順でインストールする

```
$ sudo apt install -y mesa-utils
```

以下のようにエラーが表示されなければ、正常に仮想ディスプレイが作られている

```
rock@radxa-zero:~/$ glxinfo -display :1 | head
name of display: :1
display: :1  screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.4
server glx extensions:
    GLX_ARB_context_flush_control, GLX_ARB_create_context, 
    GLX_ARB_create_context_no_error, GLX_ARB_create_context_profile, 
    GLX_ARB_fbconfig_float, GLX_ARB_framebuffer_sRGB, GLX_ARB_multisample, 
    GLX_EXT_create_context_es2_profile, GLX_EXT_create_context_es_profile,
```

## タイルイメージのレンダリングテスト

* ブラウザから `http://127.0.0.1:8080/` を開き、「Viewer」 のボタンを押下
* 地図が表示されることが期待される

```
$ wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip
$ unzip -q test_data.zip -d test_data
$ cd test_data
$ tileserver-gl -c config.json
```

## 現在見えている問題

* index ページでリロードすると次のエラーが表示される
  * virtualgl 関係なかった？ 

```
terminate called after throwing an instance of 'std::runtime_error'
  what():  Cannot read GLX extensions.
Aborted (core dumped)
```

* `maptiler-log.svg` などの一部の画像アセットが読み込まれない
font-familyの間違いやすい設定

まずはこちらの設定をみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/07832d7f-83dc-6c34-d1a7-d41360433e8c.png)

みなさん、この設定のどこがおかしいか分かりますか？

実は"sans-serif"というのが間違っています。
え、"Montserrat"は二重引用符で囲ってるから、sans-serifも囲むんじゃないの？って思いますよね。
実はフォントにはフォントファミリー名と総称フォント名の2種類あって区別する必要があるんです。

## フォントファミリー名と総称フォント名
フォントファミリー名はエクセルやワードなどでもよくみる「メイリオ」や「Arial」などの具体的な欧文フォント名、日本語フォント名を指します。

一方で総称フォント名とはゴシック体や明朝体など、フォントファミリー名よりも大きなカテゴリーのフォント名を指します。

## CSSでのfont-familyではフォントファミリー名か総称フォント名かで指定の仕方が異なる
一応どっちも二重引用符をつけてもエラーにはならないのですが、ブラウザが二重引用符がついているものはフォントファミリー名として認識してしまうため、意図しない動きになる可能性があります。

そのため、フォントファミリー名か総称フォント名かちゃんと区別して設定しましょう。

## まとめ
フォントファミリー名：二重引用符でくくる
総称フォント名：そのまま記述する
goのbulk処理

元の要素数が大きすぎる時に、size件ごとに何かの処理を行いたい時に使用する。

```go
func Bulk[T any](items []T, size int, f func(items []T, start, end int) error) error {
	n := 0
	for m := 0; m < len(items); m += size {
		n += size
		if n > len(items) {
			n = len(items)
		}
		if err := f(items[m:n], m, n); err != nil {
			return err
		}
	}
	return nil
}
```

```go
func main() {
	var values []int
	for i := 0; i < 10; i++ {
		values = append(values, i)
	}
	err := bulk.Bulk(values, 3, func(items []int, start, end int) error {
		fmt.Println(items)
		return nil
	})
	if err != nil {
		panic(err)
	}
}
```

output
```text
[0 1 2]
[3 4 5]
[6 7 8]
[9]
```
GoからBigQueryのトランザクションを使う

```go
query := client.Query(`
	BEGIN TRANSACTION;
	INSERT INTO table VALUES ();
    DELETE FROM table;
	COMMIT TRANSACTION;
`)
_, err := query.Read(ctx)
```

クエリの実行時にエラーが発生すると、ロールバックされる。途中で`SELECT 1/0;`などを入れると、エラーを発生させることができ、ロールバックされていることがわかる。
Raspberry Pi Imagerで32bitOSを書き込んだのに64bitOSが起動する場合の対処方法

## 32bitOSを書き込んだはずなのに64bitで起動する

現時点(2023.6.12)では32bit版で書き込んでも

<img width= 500 src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565396/a2c856bc-4c56-763e-d30f-684022bd1ea5.png>

起動後に確認すると64bit版が立ち上がっています。

```
$ uname -a
Linux test1 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64 GNU/Linux
```
二ヶ月前は問題なく32bitで起動できましたが久々に32bitイメージを作成してパッケージをインストールしたらエラー出まくりで気づきました。



## 対策

/boot/config.txtで64bit起動を無効にします。

```sh:/boot/config.txt
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
[all]
arm_64bit=0
```

一手間省くのにshellscriptにしました。

```sh:64bit-disable.sh
#!/bin/bash

if [ $(cat /boot/config.txt | grep arm_64bit=1) ]; then
  sudo sed -i "s/arm_64bit=1/arm_64bit=0/g" /boot/config.txt
elif [ -z $(cat /boot/config.txt | grep arm_64bit=) ]; then
  echo "arm_64bit=0" | sudo tee -a /boot/config.txt
fi
```
VSCodeの自動フォーマットでインデントの設定が効かない

VSCodeでコーディングしてあるあるなのですが、インデントサイズの設定変更が効かない！
元々が4に設定されていて、4だと長すぎて見づらいから2に変えました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/382243da-fb4b-7644-8523-05ea296e1f63.png)

元ファイルに対してCtrl + Sしてもインデントが4のまま！なんで？

## よく見るとカッコ書きでヒントが・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/674ca883-9586-d60f-d1ce-e2ceaee8eb4d.png)

他の場所でも変更済み・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/bfc6a0a1-658b-f0a5-6418-a90e949741bc.png)

フォーマッターとしてPrettierのプラグインを入れており、こっちの設定のほうが優先されていました。
ここを2に変えたらちゃんとフォーマットされました。
コンピュータネットワークセキュリティ

https://www.amazon.co.jp/%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3-%E5%85%AB%E6%9C%A8-%E6%AF%85/dp/4339024953

本書を手に取った背景
CISSPの勉強をするにあたって、技術的にふかいことを知りたいを思い、手に取りました。

本書のテーマ
マルウェアに関する仕組みとリスク、対策を解説しています。
マルウェアの歴史と必要な知識から始まり、攻撃手法とその対策まで書かれていて、ここまで詳細に学ぶことがなかったので面白かったです。
タイトルの通り、ネットワークに関するセキュリティ対策に着目しています。

個人的なポイント
１，マルウェアの分類
寄生、自己拡散、偽装、情報漏洩などが存在する。

２，スタック、バッファオーバーフロー
バッファサイズを超過するか検査しないことにより、入力値がバッファを超過してメモリ上にコピーされることで起きる脆弱性。
スタックにはリターンアドレスが書かれているのだが、これを任意の値に書き換えられる。
これにより、バックドアを作るようなことができる。

３，ヒープスプレー

４，リモートエクスプロイト
標的ホストに対して遠隔のホストから攻撃する。
標的ホストのプロセス日して攻撃コードを含むリクエストを送信する。
ドライブバイダウンロードはウェブブラウザに対して攻撃する。

５，マルウェアの難読化
難読化にすることで検知されづらくする。

６，DDOS攻撃

７，キャッシュポイズニング

１番心に残った部分
ハニーポットに注目して書かれていた部分。
この機能を活かすことは難しいのではないか、需要がないんじゃないかと思っていたが、未知の攻撃を防ぎたいというユーザーにヒットする機能だと思いました。

今後やれること
・本で確認した内容をもとにメーカー製品の挙動を確認する

まとめ
攻撃の種類→攻撃の詳細→その対策、詳細
という感じで、技術的に深くまで踏み込んでいなかったので、すごく参考になりました。
セキュリティを語る上では、ネットワーク、サーバーの知識もないと理解ができないと改めて思い知らされました。
難しい内容ではあったので、理解し説明できるところまで咀嚼していきたいと思います。
プライベートリポジトリの変化を検知しteamsに通知を送るツール

## 目的
チームで開発する際に、他のメンバーがdevelopにpushしたことを通知するには、無料枠だとパブリックリポジトリにしていないといけない。しかし、今回は都合上プライベートリポジトリのため、リポジトリ監視が出来ない。

そこで、pythonでプライベートリポジトリの変化を監視し、検知した結果をteamsに送信するツールを作成する

## ライブラリインストール
```
pip3 install PyGithub
pip3 install pymsteams
```

## コード本体
```python
from github import Github
import time
import pymsteams


token='___YOUR_TEAMS_GITHUB_TOKEN___'

g = Github(token)


while True:
    branch = g.get_repo("____YOUR_REPOSITORY_NAME____").get_branch("develop")
    kyu = branch.commit
    print(kyu)
    time.sleep(10)
    branch = g.get_repo("____YOUR_REPOSITORY_NAME____").get_branch("develop")
    new = branch.commit
    print(new)
    if new != kyu:
        TEAMS_WEB_HOOK_URL = "___YOUR_TEAMS_WEBHOOK_TOKEN___"
        myTeamsMessage = pymsteams.connectorcard(TEAMS_WEB_HOOK_URL)
        myTeamsMessage.title("Developリポジトリ更新確認")
        myTeamsMessage.text("Developが更新されました。git pullを実行してください。")
        myTeamsMessage.send()
    else:
        pass
```

## 解説

ライブラリのインポート
```python
from github import Github
import time
import pymsteams
```

githubメソッドの作成
```python
token='___YOUR_TEAMS_GITHUB_TOKEN___'
g = Github(token)
```

リポジトリの状態を10秒間隔で比較
```python
    branch = g.get_repo("____YOUR_REPOSITORY_NAME____").get_branch("develop")
    kyu = branch.commit
    print(kyu)
    time.sleep(10)
    branch = g.get_repo("____YOUR_REPOSITORY_NAME____").get_branch("develop")
    new = branch.commit
    print(new)
    if new != kyu:
```

Teamsの送信
```python
        TEAMS_WEB_HOOK_URL = "___YOUR_TEAMS_WEBHOOK_TOKEN___"
        myTeamsMessage = pymsteams.connectorcard(TEAMS_WEB_HOOK_URL)
        myTeamsMessage.title("Developリポジトリ更新確認")
        myTeamsMessage.text("Developが更新されました。git pullを実行してください。")
        myTeamsMessage.send()
```

## systemdで管理
### serviceの作成
/etc/systemd/system/gitsv.service
```/etc/systemd/system/gitsv.service
[Unit]
Description=Disk monitoring shell script service
Documentation=
#After=networking.service

[Service]
Type=simple
User=root
Group=root
TimeoutStartSec=0
Restart=on-failure
RestartSec=10s
#ExecStartPre=
ExecStart=/home/shoma/github/gg.sh
SyslogIdentifier=Diskutilization

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

### shの作成
/home/shoma/github/gg.sh
```/home/shoma/github/gg.sh
#!/bin/bash
cd `dirname $0`
python3 gg.py
```

## 確認
リポジトリにcommit等で変更を加える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/01748fcd-ab37-ad44-8f72-64b10e5b27fa.png)
AWS IAM Identity Centerでユーザを追加したときのメモ

# 背景・目的
AWS IAM Identity Centerでユーザを作成した時のメモになります。

# 実践
## IDを追加
1. IAM Identity Centerのトップページで右上の「有効にする」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/1728ffdc-eac6-9ee0-5f2d-833ef3b83417.png)

1. 「ユーザを追加」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e7374672-e835-e16d-9d59-b2450f14fdd6.png)

1. ユーザの詳細を指定画面で、下記を入力し「次へ」をクリックします。
    - ユーザ名
    - Eメールアドレス
    - Eメールアドレスを確認
    - 名
    - 姓
    - 表示名（デフォルトでは、姓と名が自動で入ります。）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/f2cf8eb2-9d97-7c09-1a9f-da182d5c2ddd.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/9881b17f-f254-480a-696d-126c1f28a148.png)

1. 確認画面で、入力内容を確認し問題なければ、「ユーザを追加」をクリックします。
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/21b17a32-7bef-02b4-8641-094d5aaa9aad.png" width="600">

1. しばらくするとメールが飛んできます。「Your AWS access portal URL:」に書いてあるURLをクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/170f36af-ea53-f9a7-72f7-880a662a0dab.png)

1. サインアップで、ユーザパスワードを新規に入力し、「Set new password」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/1d54f22e-0233-d582-a359-0e47ad17c6be.png)

1. サインインするため、Passwordを入力し、「Sign In」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/94820e6f-aba2-2fc5-2d08-e2987bc40002.png)

1. ログインできました。（アプリケーションを設定してないため何も表示されません。）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/0f84f572-c1c1-7fa6-9429-f76aee7663ef.png)


# 参考
https://aws.amazon.com/jp/iam/identity-center/
mongoDBに接続

# mongodbを起動

mongodbを作成するときにユーザ認証を有りにする。

- dockerの場合
```
version: "3"
services:
  db:
    build: .
    restart: always
    container_name: db-container
    hostname: db-server
    environment:
      - MONGO_DATA_DIR=/var/lib/mongodb
      - MONGO_LOG_DIR=/var/log/mongodb
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=example
      - MONGO_INITDB_DATABASE=app1
    volumes:
      - ./db:/var/lib/mongodb
    ports:
      - 27017:27017
    command: mongod
```
MONGO_INITDB_ROOT_USERNAMEとMONGO_INITDB_ROOT_PASSWORDを設定すれば認証有りになる。

このユーザはadminという認証dbに作成されスーパーユーザロールであるrootが与えられる。

# mongodbに接続

mongodbに接続するにはmongodb compassで簡単に接続可能。

cliでする場合は、
```
#認証なしでとりあえず接続（接続後、db一覧等のコマンドを打っても認証が必要なコマンドですのでエラーが出ます。）
mongosh
#認証有りで接続。@の前にユーザ名を入れて、パスワードは対話形式で聞かれる。
mongosh mongodb://<ユーザ名>@localhost:27017/
```
認証なしでとりあえず接続してから、認証することも可能。

db.auth(”ユーザ名”,”パスワード”)コマンドでOK。

mongoshのコマンドはhelpでこんな感じで見れるので適宜確認。

またjsコマンドもOK。
mongodbの認証DB

# 認証DBとは

新しいdb、ユーザを作成するときにその新しいdbの認証をするdbを選択しなければいけない。adminDBはsystem.usersコレクションが存在し、全ユーザ情報を持っている。

system.usersコレクションはdb.system.users.find()コマンドで見れる。

例えばスーパーユーザであれば
```
{
    _id: 'admin.root',
    userId: new UUID("9b410d09-8836-4e3b-b2c8-a7a7f131109d"),
    user: 'root',
    db: 'admin',
    credentials: {
    },
    roles: [ { role: 'root', db: 'admin' } ]
  },
```
rolesにどのDBにどんなロールが与えられているかわかる。

認証DBは_idのユーザ名の前に書かれているのが認証DB。

例で言うとadmin.rootのadminというDBが認証DB。

# 環境作成(Docker)

環境作成の際に使用したdocker-composeと初期情報を載せておく。

```
version: "3"
services:
  db:
    build: .
    restart: always
    container_name: db-container
    hostname: db-server
    environment:
      - MONGO_DATA_DIR=/var/lib/mongodb
      - MONGO_LOG_DIR=/var/log/mongodb
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=example
      - MONGO_INITDB_DATABASE=admin
    volumes:
      - ./db:/var/lib/mongodb
    ports:
      - 27017:27017
    command: mongod
```
```init.js(初期化)
db.createUser(
    {
        user: "test",
        pwd: "test",
        roles: [{ role: "readWrite", db: "app1" }]
    }
)
```
これはdockerでmongoDBを作成。スーパーユーザとしてrootという名前のユーザと

一般ユーザとしてtestという名前のユーザを作成。

この場合、先ほどのjsonファイルみたいなものからもわかる通りスーパーユーザは認証DBもロールが与えられているDBもadminとなる。

では一般ユーザは？

ロールが与えられているのはapp1というDB。認証DBはというと

docker-composeの環境変数にMONGO_INITDB_DATABASE=admin

と設定している。

これはinit.js(初期化)を実行するDBを表している。

mongoshで表すと

admin>db.createUser()

みたいなことである。

なので一般ユーザの認証DBはadminである。
```
{
    _id: 'admin.test',
    userId: new UUID("5effb343-3362-44b8-9f8e-b2ae3c607084"),
    user: 'test',
    db: 'admin',
    credentials: {
    },
    roles: [ { role: 'readWrite', db: 'app1' } ]
  },
```
# Mongoose
Nodeを使用していて、mongooseからDBにconnectする際に認証エラーになり調べた。
```
{
    _id: 'admin.test',
    userId: new UUID("5effb343-3362-44b8-9f8e-b2ae3c607084"),
    user: 'test',
    db: 'admin',
    credentials: {
    },
    roles: [ { role: 'readWrite', db: 'app1' } ]
  },
```
optionのauthSourceが認証DBを指定する項目。

何も指定しなかった場合、接続するDB＝認証DBとなるらしいので注意を！

https://www.mongodb.com/docs/manual/reference/connection-string/#connection-string-options


# 参考

https://www.mongodb.com/docs/manual/core/security-users/#authentication-database

https://zenn.dev/koshilife/articles/549555997e9e16

https://qiita.com/Brutus/items/8a67a4db0fdc5a33d549

https://hub.docker.com/_/mongo
テストにとってFIRSTの原則よりも大事なこと

FIRSTの原則というものがあります。

Fast（テストは早いほうがいい）
Isolated（プロダクトコードと疎な関係のほうがよい）
Repeatable（何度も繰り返し実行できる＝状態をもたない）
Self-validating（結果検証がコードで出来ている）
Timely（適切なタイミングで行われる）

これが良いテストの原則として、「Clean Code アジャイルソフトウェア達人の技」（Robert C. Martin , アスキー・メディアワークス, 2009）などど語られています。

これは正しいです。圧倒的に正しい。
だが、テストはこれだけ守ってればいいわけではありません。それよりももっと大事なことがあります。

それは「意味のあるテストをすること」です。

これは当たり前すぎて書籍では語られないのかもしれません。しかし、私の経験では多くの現場で意味のないテストが書かれていることが多いです。意味のないテストは如何にFIRST原則を守っていても、如何に素晴らしいテストコードであっても、如何に美しいパイプラインを構成していようと限りなく無価値に近いです。
「意味のないテスト」とは主に「バグが見つけられないテスト」です。
例えば以下のようなものがあります。

・必ずPassするアサーションしかない
・ほぼ同じテストが既に存在している
・同値クラスの同じ集団ばかりつかっている
・カバレッジをあげることだけ考えて意図がないためにアサーションの意味がない
・ソートするコードに、ソート済みのデータを与えるなどのバグに気付かない条件を与えている

など。
自動テストは大事だし、その実装方法も大事なのだけれど、それ以前の問題としてテスト自体の目的を見失わないようにしないといけません。
どんなテスト書けばいいんだろう、っておもったらまずはどんなバグを見つけるテストにするか、どんなリスクを顕在化させるテストにするかを考えましょう。
Laravel基本の流れ①  project・databaseの作成、phpmyadminの導入

　自分自身の備忘録のつもりで、Laravelを用いた基本的な制作の流れをまとめていきます。
誰かの参考になれば幸いです。また、理解が不十分なところも多々あるかと思います。
ミスなどありましたらぜひ教えてください。使用機材はmacです。

　今回はtwitterのようなコメント・画像の投稿、編集を行うプロダクトを作る感じで説明をしていきます。

今回は「project」・「database」の作成からデータベースを扱うための「phpmyadmin」の導入までを行います。

### Step.1 Projectを作成する。
　まずはprojectを作ります。今回は開発環境として「Dockerのsail」というものを使用しています。「Docker」の説明は省かせていただきますので、環境に関しては各自でお願いします。（後日そちらの記事も書きます）また、最新のLaravelでは、対応phpはバージョン9ですが、デプロイ先のサーバーがphp8にしか対応していないため、バージョンを落として作成しています。（2023.6月現在）

　projectを作成するには、ターミナルを開き
```
curl -s "https://laravel.build/Laravelproject?php=80" | bash
```
と入力します。`Laravelproject`とは今回作成するprojectの名前ですので、この部分は適宜変更しましょう。すると、何やらゴニョゴニョと動き出します。しばらく時間がかりますが最後にパスワードを求められて、プロジェクトが作成されます。
　ちなみにこれでローカルストレージ内に`Laravelproject`というフォルダが作成されており、中を覗くと様々なフォルダ・ファイルが入っています。全く触らないものも多いので、最初は気にしなくてOKです。
　また、この段階でgithubにリポジトリを作成し、このフォルダと紐づけておくとよいでしょう。

### Step.2 Projectを起動する。
 （Dockerを使用している場合は起動しておきます。）
 作成したフォルダへ移動します。
```
cd Laravelproject
```
Dockerのsailを使用して起動。最後に「-d」を付けておくと、バックグラウンドでデータベースも起動してくれて便利です。
```
./vendor/bin/sail up -d
```
※Dockerを使用していない方は
```
php artisan serve --port=8080
```
で起動できると思います。

:::note alert
私のmacの場合、なぜか必ずport競合を起こし起動できないので、その場合の対処も書いておきます。
①sudo lsof -i :3306 　※3306は競合しているポート番号
　->PID番号を調べる
②sudo kill (PID番号)
:::

これで、Webページはすでに作成されています。ブラウザで「localhost」へアクセスすると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959841/980f83bd-da2e-fcde-a63e-c23025079437.png)

という画面が出てくるはずです。右下にLaravelとphpのバージョンが表示されているので、ここも確認しておきましょう。

### Step.3 phpmyadminの導入
　　phpmyadminを使用するための準備をしていきます。一旦Dockerのcontainerを止めましょう。

```
./vender/bin/sail down
```
:::note alert
間違っても
./vendor/bin/sail stop
と打ってはいけません‼️containerごと消去してしまいます。
:::

※Dockerを使用していない方は「cnrl+c」で止まります。

「visual studio code」などのコードエディター上でprocjectを開き、その中にある`docker-compose.yml`に下記コードを追記します。

```php:docker-compose.yml
phpmyadmin:
  image: phpmyadmin/phpmyadmin
  links:
    - mysql:mysql
  ports:
    - 8080:80
  environment:
    MYSQL_USERNAME: "${DB_USERNAME}"
    MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
    PMA_HOST: mysql
  networks:
    - sail
 ```
追記場所はselenium の下

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959841/b468ce78-f9b2-7e20-50fd-43310221e2aa.png)

:::note alert
※重要　seleniumと同じ階層に保存する。
:::

　再び起動し
```
./vendor/bin/sail up -d
```
ブラウザで「localhost:8080」へアクセスすると、phpmyadminが使用可能になっています。
project名と同じデータベースが作成されているのが分かると思います。

:::note info
phpmyadminのログインは、設定していなければ下記の通りとなる
ユーザー名: sail パスワード: password

これらの情報は、`.env`というファイル内に記載してある。
:::
今後
・Webページ`localhost`
・データベース（phpmyadmin）`localhost:8080`
の２つのページを参照しながら作成を進めていきます。

これで作成の準備が整いました。

次の記事

https://qiita.com/taisuke-m/items/05420a243690e2e3d375
Elixirでドキュメントの動作を確認してみた

# 概要
Elixirでドキュメントの動作を確認してみました。以下のページを参考にしました。

https://elixirschool.com/ja/lessons/basics/documentation

# プログラム作成
以下のファイルを作成しました。
```greeter2.ex
defmodule Greeter2 do
  @moduledoc """
  ...
  """

  @doc """
  Helloメッセージを表示します

  ## パラメータ

    - name: 人名を表現する文字です。

  ## 例

      iex> Greeter2.hello("Sean")
      "Hello, Sean"

      iex> Greeter2.hello("pete")
      "Hello, pete"

  """
  @spec hello(String.t()) :: String.t()
  def hello(name) do
    "Hello, " <> name
  end
end
```

# プログラムをコンパイルし、動作を確認
```
$ iex
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]

Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> c("greeter2.ex",".")
[Greeter2]
iex(2)> h Greeter2.hello

                                def hello(name)                                 

  @spec hello(String.t()) :: String.t()

Helloメッセージを表示します

## パラメータ

  • name: 人名を表現する文字です。

## 例

    iex> Greeter2.hello("Sean")
    "Hello, Sean"
    
    iex> Greeter2.hello("pete")
    "Hello, pete"

iex(3)> 
```

# まとめ
何かの役に立てばと。
Railsにおけるライブラリ管理

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/81b0e194-8aa2-382d-89a9-bc480f3225b1.png)
１：Gemfileとは
アプリケーションで使用するGemの「名前」と「バージョン」の情報を記載し、管理するファイルです。

２：Gemfile.lock
bundle installによってインストール済みとなったGemの情報を記録するファイルです。
1つのGemのためにどのGemをどのバージョンで合わせてインストールしたか確認できます。

開発するRailsアプリケーションのためにインストールされたGemを記録しておくことで、PCにインストールされたGemの中から必要なものだけを使用してくれます。
vectorで凡ミスした話


:::note warn
※「この記事は～」的な言い訳はめんどいので省略です。
正確な情報が必要な方は、ちゃんとした記事を参照ください。
:::
:::note info
2023/06/12 現在のpaiza IO の場合の話です。
:::

動的計画法で解を求めたかったコード。
dpをvectorで宣言した時にサイズを指定せず、配列のようにアクセスしたら落ちた。。。

vectorは一度push_backをすると、**542個分**だけ自動的に領域が用意されるようです。
n が小さいうちは落ちなかったけど、提出したら大規模データで死んだ。。。:expressionless:
```c++

int main() {
    int n;

    cin >> n;
    __f(i,n) {
        int tmp;
        cin >> tmp;
        input.push_back(tmp);
    }

    vector<int> input;
    vector<int> dp;
    dp.push_back(input[0]);
    for (int i = 0; i < n; i++) {
        int tmp_1 = fugafuga(i);
        int tmp_2 = hogehoge(i);
        // ↓問題のコード
        dp[i] = max(tmp_1, tmp_2);
    }
    printf("%d\n", dp[n-1]);
    return 0;
}
```
OneDriveの差分同期がとても優秀だった件

OneDriveは最大250GBまでのファイルに対応しているとのことですが、差分同期を大容量のファイルでおこなったときにどうなるかテストしてみます。

:::note info
**結論**
数十GBという大容量でも、差分をうまく計算してアップロードしてくれました。
:::

# ファイルのアップロード
24GBのVHDXファイルをアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/cb38f155-15c4-1fe6-7216-f60ade0676fe.png)
16分ほどで完了しました。とても早いと思います。
# ファイルの編集

OneDriveをいったん終了します。VHDXをダブルクリックでマウントし、テキストファイルを保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/1c5f0fac-60ea-92ad-3dd4-73bed51f6c64.png)

# ファイルの再同期

OneDriveアプリを起動します。「同期の準備中です」がけっこう時間がかかっています。差分を計算しているのでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/471a30fe-53b7-da3d-8146-d32fc2f1e20a.png)

アップロードが開始されます。844.1MBという差分サイズ表示がでています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/5243fb5a-0b1f-6218-932a-712252eb0b43.png)
1分ほどで完了しました。

# 履歴の確認

ブラウザ上でもバージョン履歴が確認できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/8042f2cb-5f96-392b-d205-bb14b57f647d.png)
ちなみに「復元」を押すと、5分ほどかかってバージョン3.0が作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/29b6a64f-635d-c4fb-d32c-0f6174ddd1a4.png)

# まとめ

- OneDriveの差分同期はとても優秀でした。
- 差分の計算や、バージョンの復元には数分かかりましたが、ファイルサイズの大きさを考えると早いほうだと思います。
- 外部ユーザーとの連携もしやすく、1TBまで対応するなど、OneDrive(Sharepoint)をデータ共有の中心にするのは企業にとって非常にコスパが高いです。

# 参考にさせていただいたサイト

**「OneDrive」がすべてのファイルタイプで差分同期をサポートへ**
https://forest.watch.impress.co.jp/docs/news/1188155.html


**Microsoft、OneDriveなどにアップ可能な最大ファイル容量を250GBに引き上げ**
https://pc.watch.impress.co.jp/docs/news/1300430.html
【Swift】Xcode上からホーム画面に表示されるアプリ名を変更する。

# ホーム画面に表示されるアプリ名を変更
Xcodeで開発する際に、最初のプロジェクトを作成するタイミングで「Product Name」を入力する。
その「Product Name」がアプリを実機にインストールした際に表示される名前になる。

作成後に表示されるアプリの名前を変更する方法を記載する。

手順１
プロジェクトファイルを開く。

手順２
「プロジェクト」をクリックし、その中の「info」タブをクリックする。

手順３
KeyにBundle display nameを追加し、Valueに任意のアプリ名を入力する。

![スクリーンショット 2023-06-12 20.23.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066888/a683181e-e6d0-741d-3768-131495958cab.png)


以上。
i9 13900KFとRyzen7 5800Xを比較してみて

※僕は自作PCは詳しくないです。あくまでも体験レベル

i9 13900KFとRyzen7 5800Xを比較してみて
結論、コスパは5800X良いかも
マシン総額として正確には計算してませんが、グラボ抜きで考えて
約1.5倍以上価格差はでてしまいました
FFベンチだと1割ぐらいしか変化ありません
つまり、使い方によってはパフォーマンスが出せない

詳しい人に聞いたところFFベンチのFullHD程度だと本領発揮できないのでは？
と教えてもらいました
つまり、これ以上の用途がなければ5800Xは優れていると見ることもできるのです

でも流石にVRとか動かしてくると13900KFは速いなーって感じます

i9 13900KFの難しい問題点は、**熱が激しくて水冷でも一瞬で90℃オーバー**に行ってしまいリミットがかかります
なので、冷却問題と戦わないとならないのです…

# 結果はこちら
Ryzen7 5800X
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/62662bb4-71d8-925b-4213-777344616b8e.png)

i9 13900KF
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/c68ba23e-c7a9-738b-d42f-278f649f6dd6.png)

# 参考までにスペック

5800Xマシン
CPU Ryzen7 5800X
メモリ　DDR4 128GB
SSD M.2 2TB
GPU　RTX4070

i9 13900KFマシン
CPU i9 13900KF
メモリ　DDR5-4800 128GB
SSD M.2 2TB
GPU　RTX4070
冷却のために
・ケースファン6つ
・簡易水冷にファン3つ
参考までに高額になる理由
　・メモリがDDR5
　・熱対策の為ケースを大型化
　・簡易水冷をそれなりの物を使う
　・マザーボードも高額（i9をぶん回すため）
　・電源の大容量化
つまりi9をぶん回すって難易度高いのでは？と思い始めてます
たぶん、まだ満足に動いてないと思われる
GitとGitHubの違い

●Git（https://git-scm.com）
ファイルの変更履歴を記録できる『バージョン管理システム』のこと。

Gitのメリット
いつでも過去に戻すことが可能であり、変更場所の差分を表示してくれる。
複数で同時修正が可能で、ファイルを結合できる。


●GitHub（https://github.co.jp）
Gitを使ったチーム開発をより便利にするためのwebサービス。

GitHubの特徴
ファイルを複数人で編集できるようにデータを置く場所、のみならずチャットもついているためレビューももらえる。


●SourceTree（ソースツリー）
Gitを直感的に操作できるソフト。

以上はすべて無料で利用可。
Python3エンジニア基礎試験_模擬試験の復習⑤

# タプル、集合、辞書

```tuple.py
以下のプログラムを実行した際と等価の記述を選択肢の中から選びなさい。
t = 123,345,'test'
# t = (123,345,'test')
```

● 解説
タプル定義の問題です。
通常、タプルの定義は () で囲む必要がありますが、省略も可能です。
この場合、問題文が省略されている形で書かれています。

```ex.py
条件についての説明で誤っているものを選択肢から選びなさい。
# 比較はブール演算のand及びorによって組み合わせることができ、
# また比較の結論はnotにより否定ができる。これらの優先順位は比較演算子よりも高い。
```

● 解説
優先順位は、比較演算子よりも and / or / not が低いです。
そのため「これらの優先順位は比較演算子よりも高い」という箇所が誤りです。

```dict.py
member = {1: 'Noro', 2: 'Nakao', 3: 'Miyaoka'}
member[4] = 'Kimura'
del member[3]
print(list(member.keys()))
# [1, 2, 4]
```

● 解説
辞書機能の問題です。del で member から 3 の key を削除しています。
そして、最後に key だけを出力しているので、1, 2, 4となります。

```dict.py
dic = {'Noro': 1, 'Nakao': 2, 'Miyaoka': 3}
dic['Miyaoka'] += 1
print(dic)
# {'Noro': 1, 'Nakao': 2, 'Miyaoka': 4}
```

● 解説
辞書型データの問題です。key である Miyaoka に 1 を加算していますが、
ここで加算されるのは value の 3 です。
【SwiftUI】ナビゲーションバーのタイトルをメニューにする

# はじめに
iOS16から`toolbarTitleMenu(content:)`というものが使用できるようになっていました。
使ってみたので記事にしておきます。

# サンプルアプリ
![Simulator Screen Recording - iPhone 14 Pro - 2023-06-12 at 20.14.08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/765df73a-b072-a11d-9ff4-95a20019f13a.gif)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            Text("サンプル")
                .navigationTitle("メニュー")
                .navigationBarTitleDisplayMode(.inline)
                .toolbarTitleMenu {
                    ForEach(0..<5) { index in
                        Button {
                        } label: {
                            Text("メニュー\(index)")
                        }
                    }
                }
        }
    }
}
```

# おわり
この機能はどういう場面で使うんですかね
DNCL表記のブロックをPython,JavaScriptに変換するサイトをGoogle Blocklyで作ってみた

「DNCL表記のブロックでプログラミングしてPython,JavaScriptに変換」を省略して「どんブロック」です。
https://kaihatuiinkai.jp/DNblock/
# DNCLとは
　高等学校におけるアルゴリズムやプログラムに関する教育では、採用されるプログラミング言語は多様です。 プログラミングの実習時間も異なります。そこで、このような事情を考慮して「情報関係基礎」の出題では、 共通テスト用の手順記述言語 (DNCL) が使用されます。
　DNCLは「Daigaku Nyushi Center Language」の略ではないかといわれています。 DNCLは試験用の言語で、プログラムの開発には通常使われていません。
　大学入試センターでは、「令和７年度試験の問題作成の方向性，試作問題等」を公開しています。情報の試作問題でDNCLが使われています。
参照：https://www.dnc.ac.jp/albums/abm.php?d=395&f=abm00003277.pdf&n=6-2-1_%E8%A9%A6%E4%BD%9C%E5%95%8F%E9%A1%8C%E3%80%8E%E6%83%85%E5%A0%B1%E2%85%A0%E3%80%8F%E2%80%BB%E4%BB%A4%E5%92%8C4%E5%B9%B412%E6%9C%8823%E6%97%A5%E4%B8%80%E9%83%A8%E4%BF%AE%E6%AD%A3.pdf#page=22
# Python変換はBlocklyデモにもあるけど・・・
　Google Blocklyのサンプル「Blockly‏>Demos‏>コード」では、ブロックプログラムをJavaScript,Pythonに変換表示します。
https://blockly-demo.appspot.com/static/demos/code/index.html?lang=ja
でも、このサンプルでDNCLの問題を解くことはできません。
* 文字列を結合するブロックがない
* 剰余,商を計算するブロックがない
* for命令の初期値,最終値に変数を使用できない
* 配列ブロックが複雑で使いにくい
* 二次元配列を扱えない
* 表記がDNCLと異なる
# だから作ってみた
　理由ができたので、作ってみました。「DNCL表記のブロックでプログラミングしてPython,JavaScriptに変換」を省略して「どんブロック」です。いつも通り冴えない名前です。
https://kaihatuiinkai.jp/DNblock/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509199/2b070334-f778-223c-2ea3-94d2cc914f35.png)

高等学校　情報科の学習で、DNCL表記のブロックを使ってプログラムを作り、実行結果を確認できる教材です。2022/11/9に大学入試センターが発表した、試作問題の資料をもとに新しい表記（新DNCL）にしています。
1. DNCL表記のブロックで簡単にプログラム作成
2. プログラムを実行して、正しく作動するか確認できる
3. 作成したプログラムをPythonとJavaScriptで表示
4. 作成したプログラムの保存、読み込み可能
5. ブラウザ上で作動、インストール不要
6. 無限ループの場合にはエラー表示
7. 表示エリアの広さを変えることが可能（タッチパネル非対応）
　Pythonは作成したJavaScriptを変換処理して表示しています。Pythonには誤りが含まれる場合があります。

# 問題演習で学習しましょう
　問題演習で基礎からプログラミングの学習ができるようにしています。解答はページの下部にあります。これも「どんブロック」で表示して、作動確認ができるようにしています。
## 1は数値、"1"は文字
　Blocklyは数値ブロック、文字ブロックの区別があります。足し算などの演算ブロックの中に文字ブロックを入れようとしてもはじかれます。初心者に「値には文字と数値の区別があります」と教えるときに役立ちます。
　文字列の結合と、数値の加算の違いをブロックを使って説明することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509199/ac5c5814-4e52-28b9-bd43-6d15c59aed93.png)
実行すると「123123」と表示します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509199/5219878f-bd45-f124-faf4-c0ac0062aa1c.png)
実行すると「246」と表示します

　また「表示する」ブロックのように、文字ブロック、数値ブロックのどちらも受け入れるものもあります。これも、実際にプログラムを作ってみて体験することができます。

# 高校生用のプログラミング教材
　高等学校の情報Ⅰの教科書ではブロック型、Python、JavaScript、VBAなど各種言語でプログラミングの説明が記載されています。Scratch世代の生徒たちにはブロック型で理解を深めてコードを記入できるようになってほしいと思います。
　情報科の目指すものは「プログラマーの育成ではない」と言われています。でも、プログラミング的思考は小学校から学習しており、中学校ではライントレースカーなど制御プログラミングを経験してきています。高校生になったら基礎的なプログラムを読むことができるようになってほしいです。
今日の出来事

目標
1. 業務の効率化とスキル向上
2. コミュニケーション力の強化

できたこと
1. 業務スキルの向上
   - 結論ファーストで話す
   - 大きな業務が一人でできるようになっている
   - 個人保険や業績が任されている
2. タスク管理の強化
   - 手書きのto-doリストを作ってタスクの順位付け
   - やることを洗い出し
3. コミュニケーション力の向上
   - 挨拶を徹底している
   - 意見を求められる場面でいろいろな発言ができている
   - 案件に対してホウレンソウができている

課題
1. 業務スキルの向上
   - 電話の回答ができないことが多いので知識を身に着ける
   - 業務スピードや知識不足
   - 専門性を高める
2. タスク管理の強化
   - 段階ごとにホウレンソウをする
   - キャパが足りなくなるかもしれないので優先順位を決める
   - 物事の優先順位をつける
3. コミュニケーション力の向上
   - ゴールに目を向ける
   - 自分でも調べて質問する

今後の行動
1. 礼儀正しく仲良くする
2. メモの取り方を統一して忘れないようにする
3. 業務の効率化と計画立ての強化
   - 業務を覚える
   - 計画を立てる
4. 上司との積極的な連携
   - 受電登板の頻度を高くする
   - 上司の積極的な相談
   - ゴールの明確化と業務の引継ぎ
Flask + JavaScript (Confirm)との組み合わせについて

### 本記事の背景
JavaScriptのConfirmはよく使われているが、Flaskとの組合わせで使う場合の記事がないように見えるため、本記事でまとめました。

### 本記事の基礎知識
- Pythonの基本文法の理解
- Flaskの基本的な動作の理解
- JavaScriptの基本的な動作の理解

### HTML側(Templates）
HTMLは以下を用意する
```HTML
<!DOCTYPE html>
<html lang=“ja”>
  <head>
    <meta charset=“UTF-8“ />
    <title>confirm</title>
  </head>
  <body>
    <h1>確認内容</h1>
    <ul>
      <li>名前：{{ name }}</li>
      <li>コメント：{{ comment }}</li>
      <form action="/confirm_test" method="post"> 
        <input type="hidden" id="userInput" name="userInput"> 
        <button type="submit" name="free_button" value="free_button" onClick="confirmBooking('{{ name }}')"> registe </button> 
      </form>
      <script>
        function confirmBooking(elem) {
            if(confirm('do you want to registe this user?') == true) {
                alert("registed: " + elem); 
                document.getElementById("userInput").value = "True";
            }
            else { 
                 document.getElementById("userInput").value = "False";
                 return 0;
            }          
        }
    </script>
    </ul>
  </body>
</html>
```
### Flaskのroutingは以下のように記述する
```python
@app.route('/confirm_test', methods=['GET','POST'])
def confirm_test():
	name = 'yamada'
	comment = 'test comment'
	if request.method =="POST":
		userInput = request.form.get("userInput")
		if userInput == "True":
			print('registed this name')
		else:
			print('cancel this regist name')
	return render_template('confirm.html', name=name, comment=comment)
```
### 起動画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/5088f78c-6498-9e25-f512-2cb6ee74406e.png)
登録ボタンを押下すると以下のようにポップアップダイアログが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/2b775e60-5b2e-1885-9018-b693c862ff15.png)

### バックエンド側の処理

OK及びキャンセルボタンが押された場合はそれぞれ異なる処理が可能となる

```terminal
127.0.0.1 - - [12/Jun/2023 19:27:42] "POST /confirm_test HTTP/1.1" 200 -
registed this name
127.0.0.1 - - [12/Jun/2023 19:27:46] "POST /confirm_test HTTP/1.1" 200 -
cancel this regist name
```
### 参考文献

https://stackoverflow.com/questions/67704992/how-to-send-confirm-ok-cancel-from-js-to-flask
How to create an alias name for a branch

- Copy&Paste the below in to your ~/.gitconfig

  ```sh
  sym = "!f() { git symbolic-ref refs/heads/"$1" refs/heads/"$2";}; f"
  ```

- Create alias branch

  ```sh
  git sym ${aliasBranchName} ${branchName} 
  ```

- Check out branch

  ```sh
  git checkout ${aliasBranchName}
  ```