OmniAICreator/Qiita-1.07M huggingface dataset:
合同会社ピンクペッパー紹介ページ

# 会社概要
弊社は富山県富山市に本社を置いています。代表は上林恭平です。

# 事業内容
システムの開発を請け負っています。
ヒアリングから開発・導入保守まで一貫でも行っていますし、開発・テスト等部分的な補助も行っています。

# 実績(抜粋)
## Web系
* オンラインデザインツールの開発補助 (Vue, Laravel)
* Google Apps Scriptを用いた作業の自動化
* オーダー管理アプリ
* タスク管理アプリ
* Stripeを用いた簡易ECサイト
* 製造管理アプリ

## Windowsアプリ
* 3DCADアプリの開発補助 (C++)
* セキュリティアプリの開発補助 (C++, C#)
* 書籍管理アプリの開発補助 (C#)

# 問い合わせ
システム化の範囲を相談することで予算に応じた開発が可能です。お困りごとや予算など、お気軽にご相談ください！
Tel: 050-3575-8030
Mail: pinkpepper5r@gmail.com
【アタイのつくったさいきょうCrawler♥】メルカリ2024q2決算のGMV予想 2/13 15時決算発表よ

# はじめに
オス！
【前回記事】

https://qiita.com/LightSign/items/180e068d0703df5690d7

# 3行で自己紹介
1. 元光通信の営業マンだよ
1. 31歳でプログラミング勉強し始めたよ
1. 32歳で法人向けwebアプリで起業し、今会社6年目突入したよ

# 3行で記事の概要
1. さいきょうCrawlerつくったよ
1. 出来はすんげー良いよ
1. 試しにメルカリのGMVほぼ一致させちゃうよ

# まずは結論
メルカリ2024q2(10~12月)のGMVは
<font color="red" font-size="5">2895億円</font>
と予想。

[メルカリ決算リンク 2/13 15時以降見てね♥](https://about.mercari.com/ir/library/results/)

# どゆこと？
つまりアタイのCrawlerで集めたデータからsumしたアタイ(値)だよってこと
経済アナリストみたいに前四半期のGMVから算出してるわけじゃないよってこと

# いいからこの手順通りにデータsumして
データは14GBくらいあるから気をつけて
[メルカリデータDLリンク](https://drive.google.com/file/d/1-jmrvA-GyrDVxs9lFrF15exSRj6h4aAk/view?usp=sharing)

【BigQueryに入れてsumする方法】
①BigQueryにダウンロードしたデータを投入
```bash
bq load --source_format=CSV --skip_leading_rows=1 --autodetect 
    \ --preserve_ascii_control_characters=true
    \ {DATASET}.{TABLE} mercari_2024q2_GMV_masked_data.csv
```
②sumする
```sql
select sum(price) as gmv
from {PROJECT}.{DATASET}.{TABLE}
```
③289503899475

【python pandasで頑張る方法】
①pandasでread_csvする
```python
# データデカいので気をつけて
# ちょっとデータを見てみるコード
pd.read_csv("mercari_2024q2_GMV_masked_data.csv", nrows=10)

# データ全読み込みする
df = pd.read_csv("mercari_2024q2_GMV_masked_data.csv")
```
②sumする
```python
df.price.sum()
```
③289503899475

# データに関して補足
- メルカリをCrawlしたデータ
- データは90%maskしているが、10%程度普通に確認できる
※まあ、ニキ達なら中のデータ見れば大体わかるはず

# GMV誤差が5%未満だったらﾆﾁｬﾁｬ
お金無いからおしごとちょーだい！
ウヒョヒョ
【Rails】redirect_toとは

# redirect_toとは
`redirect_to`メソッドは、コントローラーからのレスポンスとして、リダイレクトを行うためのメソッドです。これは、特定のURLや別のアクションに対してブラウザをリダイレクトさせるために使用されます。

`redirect_to`メソッドは、次のような形式で使用されます。
```ruby
redirect_to path_or_url, options
```
ここで、`path_or_url`はリダイレクト先のパスまたはURLを表し、optionsはオプションのハッシュです。

例えば、以下は`redirect_to`メソッドの使用例です。
```ruby
redirect_to root_url
```
上記の例では、`root_url`にリダイレクトします。`root_url`は、ルートパスへのURLを示します。

また、オプションとして、`flash`メッセージを設定することもできます。これにより、リダイレクト先のページでメッセージを表示することができます。
```ruby
redirect_to root_url, notice: "ログインに成功しました。"
```
この例では、`flash[:notice]`に"ログインに成功しました。"というメッセージを設定し、リダイレクト先のビューで表示されます。

`redirect_to`メソッドは、コントローラーのアクションの最後に使用され、そのアクションの実行結果としてブラウザにリダイレクトを返します。これを使用することで、ユーザーを適切なページにリダイレクトさせたり、処理の完了を通知したりすることができます。
【ChatGPT】Twitter投稿文の作成

ChatGPTにいい感じのTwitter投稿文を作ってもらう。

# プロンプト

```
# 指示
あなたはTwitterでフォロワー数を増やし、コンテンツを最適化するノウハウに長けたプロフェッショナルです。
#アカウントの特徴 を加味し、いいねが多く集まり、バズるような投稿文のアイデアを10つ教えてください。

#アカウントの特徴
（ここにアカウントの特徴や発信したこと）

#条件
以下の条件で投稿文を作成してください。
・ハッシュタグを含めず、120文字以上140文字以内にすること
・絵文字で装飾すること
・漢字、ひらがな、カタカナの割合を2:7:1にすること

#出力
|番号|投稿文|文字数|

```

# 利用例

## 入力したプロンプト
```
# 指示
あなたはTwitterでフォロワー数を増やし、コンテンツを最適化するノウハウに長けたプロフェッショナルです。
#アカウントの特徴 を加味し、いいねが多く集まり、バズるような投稿文のアイデアを10つ教えてください。

#アカウントの特徴
・栄養ドリンクを販売する製薬会社のアカウント
・頑張って働く社会人を応援したい

#条件
以下の条件で投稿文を作成してください。
・ハッシュタグを含めず、120文字以上140文字以内にすること
・絵文字で装飾すること
・漢字、ひらがな、カタカナの割合を2:7:1にすること

#出力
|番号|投稿文|文字数|
```

## レスポンス（GPT-3.5）
```
番号,投稿文,文字数
1,今日も頑張るあなたに、エナジードリンクが贈るパワー💪。仕事の合間にぜひチャージして、一日中元気に過ごそう！,123
2,疲れた体に、栄養と活力を注入💥。エナジードリンクで元気を取り戻し、明日への活力を満タンに！,125
3,やる気をチャージ！栄養ドリンクが応援する、一日中頑張るあなたにエールを送ります✨。,120
4,仕事に疲れたら、エナジードリンクでリフレッシュ💼。新しい挑戦に向けて、元気を取り戻そう！,126
5,社会人の応援団👏！エナジードリンクがあなたのパートナーです。一緒に目標に向かって頑張りましょう！,126
6,忙しい社会人の味方🌟！栄養ドリンクが、あなたのパフォーマンスをサポートします。,119
7,一息つくなら、エナジードリンクでリフレッシュ⚡。新たな挑戦に向けて、気持ちもリセットしましょう！,128
8,エナジードリンクで、毎日をエネルギッシュに✨。あなたの頑張りを応援し、更なる高みへ！,117
9,あなたの活力源はエナジードリンク🔋！忙しい日々を乗り越え、新たなチャレンジに挑みましょう！,127
10,パワーアップ！エナジードリンクが、あなたの成長をバックアップします💼。一緒に頑張りましょう！,121
```
※実際にはテーブル形式で表示されています。
![IMG_8731.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/7e22ac5b-e99e-61aa-f395-0998c730b987.png)


## レスポンス（GPT-4）
```
まず、指定された条件に基づいて各投稿文を作成します。漢字、ひらがな、カタカナの割合を考慮しながら、120文字以上140文字以内で、絵文字を使用して装飾しましょう。ここでは、社会人が頑張る瞬間を応援し、栄養ドリンクの魅力を伝える内容を中心に考えます。

1. 長い会議、締め切り前の夜🌙✨私たちの栄養ドリンクで、あなたのがんばりに活力を💪！一緒に乗り越えましょう！
2. 今週も一週間、お疲れさまでした！週末のリフレッシュに、私たちのドリンクで元気をチャージ⚡️心も体もリフレッシュしましょう✨
3. 早朝の目覚めから、夜遅くまで働くあなたへ。いつものコーヒーに変わる、新しい活力源を🌟私たちの栄養ドリンクで一日をサポートします💖
4. 締め切りに追われる日々、手に取るのは私たちの栄養ドリンク🔥疲れた体に、必要なサポートを。あなたの頑張りを全力で応援します✊
5. 月曜日の朝、一週間のスタートに不安を感じたら、私たちのドリンクで前向きな一歩を踏み出しましょう🌈一緒に頑張りましょう💪
6. プロジェクトが山積みでも、諦めないで！私たちの栄養ドリンクが、あなたの強い味方になります🌟一息ついて、また前に進もう✨
7. 疲れを感じたら、一息。私たちのドリンクで、心も体もリフレッシュ💖新たな活力で、また頑張るための準備をしましょう✌️
8. 忙しい日々、自分を労わる時間も大切に。栄養たっぷりのドリンクで、自分へのご褒美を🎁あなたのがんばりをサポートします💕
9. どんなに忙しくても、健康第一！栄養バランスを考えた私たちのドリンクで、体調管理をしっかりと🍀一緒に健康を守りましょう🛡️
10. 目標達成のための夜遅くまで、私たちの栄養ドリンクがあなたを支えます🌙✨一歩一歩、目標に近づくための力になりたい💖

それぞれの投稿文の文字数を計算し、表にまとめます。
```
→まとめてくれた表は以下
![IMG_8738.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/5b974a14-b4d1-7303-4c4c-2c146a645f87.png)
ROS2講座17 parameterを使う2

# 環境

この記事は以下の環境で動いています。

| 項目 |	値 |
|:--|:--|
| CPU | Core i5-8250U |
| Ubuntu | 22.04 |
| ROS2 | Humble |

# 概要

前回はROS2のパラメーターを操作するROSノードの記載について解説しました。今回はROS2の起動時でのROSパラメーターの動きを解説します。

# runでのパラメーターの指定

'--ros-args -p (パラメーター名):=(パラメーター値)'を後ろにつけて実行します。

```shell:パラメーターを指定して実行
source ~/ros2_ws/install/setup.bash
ros2 run rclcpp_param_lecture param_server --ros-args -p int_param:=3
```

# ros_launchでのパラメーターの指定

大きく分けてlaunchファイルで直接指定する方法とyamlファイルで指定する方法があります。指定するパラメーターの数が少ない時は前者、多い時は後者がおすすめです。なおこれらの記述を混ぜることも可能です。

## launchファイルで直接指定

```python:rclcpp_param_lecture/launch/param_by_dic.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_path

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='rclcpp_param_lecture',
            executable='param_server',
            parameters=[{'int_param': 4}],
            output='screen',
            emulate_tty=True,
        ),
    ])
```

* `Node`の引数の`parameter`のリストの中に辞書型で指定します。

## yamlファイルで指定

```python:rclcpp_param_lecture/launch/param_by_yaml.launch.py
from launch import LaunchDescription
from launch.substitutions import PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='rclcpp_param_lecture',
            executable='param_server',
            parameters=[PathJoinSubstitution([FindPackageShare('rclcpp_param_lecture'), 'config', 'param_server.yaml'])],
            output='screen',
            emulate_tty=True,
        ),
    ])
```

* `Node`の引数の`parameter`のリストの中で、yamlファイルのファイルパスを指定します。

```yaml:rclcpp_param_lecture/config/param_server.yaml
/**:
  ros__parameters:
    int_param: 5
```

* ROS2では1プロセス中で複数のROSノードを実装することが可能です。この場合は(ノード名)/ros__parameters以下がそのROSノード毎ののパラメーター指定となります。ノード名はnamespaceも含むことに注意です。
* `/**`はワイルドカードになります。ROSノードが1つの場合はこれで良いでしょう

# LaunchArgument経由で指定する

パラメーターとは別物ですが、ROS launchではlaunch argumentという引数を指定できます。この引数の値をパラメーターに渡すことで、ros launch時のコマンドでパラメーターを間接的に指定できます。

```python:rclcpp_param_lecture/launch/param_by_arg.launch.py
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        DeclareLaunchArgument(name='param', default_value='0', description='int parameter'),
        Node(
            package='rclcpp_param_lecture',
            executable='param_server',
            parameters=[{'int_param': LaunchConfiguration('param')}],
            output='screen',
            emulate_tty=True,
        ),
    ])
```

ros launch実行時に`(arg名:=arg値)`という形で指定します。

```shell:実行
source ~/ros2_ws/install/setup.bash
ros2 launch rclcpp_param_lecture param_by_arg.launch.py param:=2
```

# 目次ページへのリンク
[ROS2講座の目次へのリンク](https://qiita.com/srs/items/5f0d765343ca78f524ed)
Reactでローディングを実装する @yukilulu0229

https://www.npmjs.com/package/react-loading-icons

## install

```
npm i react-loading-icons
```

## 使う

```app.tsx
import { TailSpin } from "react-loading-icons";


const Chat = () => {
  const [isLoading, setIsLoading] = useState(false);
  
  const logic = async () => {
    setIsLoading(true);

    // なんかロジック中

    setIsLoading(false);
  };

  return (
    <div className="bg-gray-500 h-full p-4 flex flex-col">
      {isLoading && <TailSpin />}
    </div>
  );
};

export default Chat;

```

### インポート

```
import { TailSpin } from "react-loading-icons";
```

### コーディング

```
 {isLoading && <TailSpin />}
```

isLoadingがtrueなら表示

### ロジック

```
const [isLoading, setIsLoading] = useState(false);
```

useStateで変更できるようにする

```
const logic = async () => {
    setIsLoading(true);

    // なんかロジック中

    setIsLoading(false);
};
```

ロジックの最中の処理
OpenAiのAPIを設定する @yukilulu0229

https://platform.openai.com/docs/overview

## Api keys を開く

https://platform.openai.com/api-keys

create new secret key を作る


## .env ファイルを作る

```.env
NEXT_PUBLIC_OPENAI_KEY="XXXXXXXXXXXXXXX"

```

## gitignoreする

```.gitignore
.env
```


## 使い方

https://platform.openai.com/docs/api-reference

### npm install

```
npm install openai@^4.0.0
```

### コード

```app.tsx
"use client";

import OpenAI from "openai";

const Chat = () => {
  const openai = new OpenAI({
    apiKey: process.env.NEXT_PUBLIC_OPENAI_KEY,
    dangerouslyAllowBrowser: true,
  });


  const sendMessage = async () => {
    //OpenAIからの返信
    const gpt3Response = await openai.chat.completions.create({
      messages: [{ role: "user", content: inputMessage }],
      model: "gpt-3.5-turbo",
    });

    const botResponse = gpt3Response.choices[0].message.content;
  };
};

export default Chat;

```

```
import OpenAI from "openai";
```

インポートする

```
const gpt3Response = await openai.chat.completions.create({
      messages: [{ role: "user", content: inputMessage }],
      model: "gpt-3.5-turbo",
    });
```

送る側の設定

- roleでユーザーを指定する
- contentに送りたいメッセージ
- modelに使いたいモデル

```
const botResponse = gpt3Response.choices[0].message.content;
```

ボット側からの返信を格納


### 公式での表記

https://platform.openai.com/docs/api-reference/streaming

```app.tsx
import OpenAI from "openai";

const openai = new OpenAI();

async function main() {
    const stream = await openai.chat.completions.create({
        model: "gpt-4",
        messages: [{ role: "user", content: "Say this is a test" }],
        stream: true,
    });
    for await (const chunk of stream) {
        process.stdout.write(chunk.choices[0]?.delta?.content || "");
    }
}

main();

```
0xProto と白源でプログラミング用日本語フォントを作ってみた

ご存知の通り、エンジニアにとってフォントはキーボードの次ぐらいにこだわるべき大切なものである。

私は [Ricty が好き](https://qiita.com/tetutaro/items/f895a2ecb1360206aaba)でずっと使っているのだが、[0xProto](https://github.com/0xType/0xProto) というフォントが良いという噂を聞き、フォント好きとしてはたまらず使ってみた。

* 0xProto の良い点
    * 視認性（legibility）を謳っているだけあって、確かに良い
    * クセが強いが、慣れるとそのクセが病みつきになって、逆に [Inconsolata](https://fonts.google.com/specimen/Inconsolata) があっさりしすぎて物足りなくなってしまう
* 0xProto の悪い点
    * Bold 体が無い
    * Ricty に慣れた自分には、縦も横もデカすぎる

グリフには病みつきになってしまったので、自分に都合の良いように作り直したい。特に、日本語のフォントを追加したい。だって README やコメントに日本語を使うことがあるし。

# 作ってみた

最初は Ricty と同じように 0xProto に [Migu 1M](https://itouhiro.github.io/mixfont-mplus-ipa/migu/) を Merge した。しかし、Migu 1M は丸っこくて好きなのだが、0xProto と組み合わせると、クセが無くて面白味に欠ける。

もうちょっとクセが強い日本語等幅フォントを探して、[白源](https://github.com/yuru7/HackGen)に辿り着いた。

Migu 1M の不満点として、ひらがなの「へ」とカタカナの「ヘ」の見分けがつきにくい（じっくり見ると違うことが分かるが）という点があったのだが、白源はかなり違って良い。あとカンマ・ピリオド・コロン・セミコロンも白源のクセが良い感じ。

ということで、0xProto と白源を Merge するスクリプトを作った。
（[Ricty generator](https://rictyfonts.github.io/) を大いに参考にさせていただいた）

https://github.com/tetutaro/0xprogen

## 工夫した点

* 0xProto の 620 という横幅は広すぎるので、視認性の良さに甘えて、８割ほど横幅を狭めて Ricty と同じ 500 に設定（全角は 1000）
    * 白源も 1080 から 1000 に横幅を狭めて合わせている
* 高さは Ricty や白源とほぼ同じぐらいに設定
    * ほんの気持ち行間が狭いと嬉しいなぁと思っていたので、本当にちょっとだけ縮める
    * 細かな数字を気にするのが嫌だったので、0xProto を見習って思い切って切りの良い数字に設定
        * Windows Ascent: 900
        * Windows Descent: 200
        * Typo Ascent: 850
        * Typo Descent: -200
        * Typo Line Gap: 50
        * HHead Ascent: 900
        * HHead Descent: -200
    * これらの値の正確な意味は、実はよく分かってない
* 0xProto のデザインを尊重する意味でも、全角のアルファベット・数字・基本的な記号および括弧（要するにキーボードから直接入力できる文字）は元の 0xProto をそのままに、ただ横幅だけを 1000 に調整したものに変更
    * ただし、スラッシュ・バックスラッシュは、そのままだと傾きが足らないので、２倍に広げて傾きを出した
    * その際に、どうしても文字の太さが 1.15 倍になっちゃうので、それに合わせてバーも太さを 1.15 倍に
* 半角のカンマ・ピリオド・コロン・セミコロンは白源（要するに [Hack](https://github.com/source-foundry/Hack)）を使用
* 全角のカンマ・ピリオド・コロン・セミコロンも白源を使用
    * コロン・セミコロンはもっとクセを付けようかと思ったけど、変な感じになるのでやめた
* 全角空白は、白源のもの（点線の四角）をそのまま使用
    * 点線の丸にしようかと思ったけど、やめた
    * スクリプトには残しているので、コメントアウトを外すだけで変更できる
* 全角のハイフンは、0xProto のハイフンを全角にしたものに変更
    * ちなみに全角のマイナスは Unicode 的には半角で定義されている
* endash と emdash は、Ricty と同様に、破線になるよう修正
* 小文字のカタカナ「ヘ」（アイヌ語で利用）は、クセが無かったので、カタカナ「ヘ」を修正して作成

# フォントの比較

Ricty Discord（オレオレ設定）
![RictyDiscord.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84885/479dc556-467a-5a5f-cebd-58b5d32cf112.png)

白源
![HackGen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84885/3c5f5d88-ec86-eb81-a676-5971c824d097.png)

0xProto（参考）
![0xProto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84885/0a2bd2ca-a7f8-466e-a3ef-4dab22a58d90.png)

0xProGen（今回作成したもの）
![0xProGen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84885/0b27502b-4172-274e-517a-32905eb3e078.png)

そこそこ見易いフォントが出来たのではないかと思う。（ゴチャゴチャしているとも言えるが）

良ければ使ってみて、改善点などあれば教えてください。
（対応できるかどうかは分からないけど）
（0xProto Bold が出たら本気出すかもしれん）
LinuC 304合格体験記

# はじめに
2024年2月、ついにLinuC Level3（304）に合格したので合格体験記を書きます！


# 学習前の状況
#### 所有資格
応用情報
LinuC2
OSSDB Silver

# 使った教材
### 
- [徹底攻略 LPIC Level3 304 教科書+問題集[Version 2.0]対応 (通称：黒本)](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5-LPIC-Level3-304-Version/dp/4844380540)
- [Ping-t](https://mondai.ping-t.com/)

# 304を選んだ理由
~~一番簡単だからLevel3が欲しいというだけであれば304で取れ！と会社の人に言われたため~~
以前ほんの少しdockerを使ったことがあったので何となく概念は知っていたのでとっつきやすいかなと思ったため。

# やったこと
LinuC Level2合格直後から勉強を開始しました。
1. 帰宅後に黒本を１単元分読みながらノートに書く。
1. 翌日の通勤時間中に問題演習
1. 解き終わったら次の単元

の繰り返し。
１周終わったらひたすらping-tを回し続けました。
慣れると模擬演習（60問）20分くらいで回せるようになるので、通勤時間で1日2,3周をこなせるようになりました。どんどん効率化できるのはまさにビルド系のゲームに似た感触でした。


#### ノートの書き方
1. 黒本の文章を１節読む
1. 文章をほんの少しでいいから書き替えてノートを書く

文章を丸写しではなく書き替えることで、その時に頭の中で文章を組み立てる必要があり、知識の定着が効率的にできるようになったと思います。


# 結果
スコア：613
なんと600点over！これまでは500点台での合格だったのでPCの前でガッツポーズしました（大迷惑なのでやめましょう）。特に正答率100％の単元があるのは今回が初めてなのでびっくりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/91b2c84e-8ef0-4991-0986-e613cf83a1c3.png)

# 感想
304は一番簡単、というのは結構色んな方が言っているイメージですが、LinuC304という試験単体で難易度を考えると決して簡単な試験ではなかったと思いました。鬼門の202に受かってから受ける試験なので相対的に簡単だと感じるとか、生存者バイアス的なものとか、そういうものかなと。
相変わらず似たような設定項目は多いし、ツールによってコマンドが微妙に違ったり…結局、ひたすら問題演習で暗記するしかないなと思いました。

とりあえず取るべき資格は取り切ったので、少し休みたいような、ほかの勉強もしたいような。次の試験は…何を受けましょうか。
メンションを使ってみよう

GPTsが使えるようになったので、メンション機能を使ってみよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/19aeea6b-5d21-bc32-3b3f-86c201836015.png)


こいつを刃牙風にしてみよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/e19e506d-4c66-f0c8-b543-047c750b9a40.png)


メンションを使って使用するGPTsを選択します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/dc927c52-6d33-2ae2-aca4-9992b5e4cb8e.png)

なんか違う。そうです。このGptsはプロンプト作成用のGPTsです。

なので。。。プロンプトを作成してもらいます。
そして、画像生成は画像生成用のGPTsに頼みます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/7241a9ec-3cf6-bb1a-b33b-088bae5b9707.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/419d3d65-fa51-29c8-b5de-e73cb877ce9f.png)

ちょっと良くなった！のかな？

紆余曲折を経て。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/63291806-601d-4ec3-0947-263c219531ae.png)




おお！ちょっといいのができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337456/9da2df72-abc5-29e8-5094-203bfa6aacca.png)


おわり。
「成長していない感」からの脱却チャレンジ

思いつきで適当に文章書くので、変な文章になると思います。
読みたい人は読み続けてください。

最近読んだ本である”世界一流エンジニアの思考法”に影響を受けてブログを始めることにしました。
エンジニア4年目に差し掛かりますが、毎日自身の「成長していない感」に悩んでいます。
この本を読んで感じたのは、アウトプットを意識する余り理解を疎かにしていることかもしれないことです。
同じ様な悩みを持っている人は多いのではないでしょうか。

よって、今年はより基礎を固めて理解することを意識したいと思います。”世界一流エンジニアの思考法”には、どんなエンジニアも”理解には時間がかかる”と書いてあります。思い返してみれば理解に時間がかかることに劣等感を感じていました。劣等感が焦りに変わって、より理解することから遠ざかっていました。

また、エンジニアには覚えるのは悪だと考える人も結構います。
ホ⚪︎エモンとかも動画で語っていますが、本当にエンジニアに暗記は必要ないのでしょうか。ホ⚪︎エモンはとにかく、ものを作り続けることで体に染み込ませると語っていました。確かにそれも一つの方法かも知れませんが、Chatgptやネット検索が便利になった現代では、すぐに答えを手にいれることができます。私もこの考えを信じ続けましたが、このやり方だと成長した様に感じられませんでした。
続きはまた明日投稿します
Ubuntuで社内ネットワーク上のNTPサーバと同期させる

# 今回やること
UbuntuのNTPでの時刻合わせを社内に設置されたNTPサーバーで設定します。
職場で難儀している人がいたので、教えるついでに以下のように作業手順をまとめました。

# 環境
+ Ubuntu 20.04 LTS
+ 社内プロキシ認証サーバによって、インターネットに出ていく通信は制限されている社内ネットワーク
+ 社内NTPサーバは`hogehoge.local`とする

# 作業手順
+ `timesyncd.conf`を編集
```
$ sudo vim /etc/systemd/timesyncd.conf
```
+ 末尾に`hogehoge.local`を追記
```
 #  This file is part of systemd.
 #
 #  systemd is free software; you can redistribute it and/or modify it
 #  under the terms of the GNU Lesser General Public License as published by
 #  the Free Software Foundation; either version 2.1 of the License, or
 #  (at your option) any later version.
 #
 # Entries in this file show the compile time defaults.
 # You can change settings by editing this file.
 # Defaults can be restored by simply deleting this file.
 #
 # See timesyncd.conf(5) for details.
 
 [Time]
 #NTP=ntp.nict.jp
 #FallbackNTP=ntp.ubuntu.com
 #RootDistanceMaxSec=5
 #PollIntervalMinSec=32
 #PollIntervalMaxSec=2048
 NTP=hogehoge.local　←追記
```

+ timesyncdの再起動
```
$ systemctl restart systemd-timesyncd
```
* 同期されているか確認
```
 $ timedatectl
                Local time: 金 2023-05-26 14:41:56 JST
            Universal time: 金 2023-05-26 05:41:56 UTC
                  RTC time: 金 2023-05-26 05:41:56
                 Time zone: Asia/Tokyo (JST, +0900)
 System clock synchronized: yes
               NTP service: active
           RTC in local TZ: no
```
これでOK。

# 公開NTPについて
ちょっと話はズレますが公開NTPサーバといえば、福岡大学のものがあります。
そういや結構前にNTPサーバの公開をやめるやめないの話があったなーと思い出しました。

https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600011/092500040/

実情はどうなっているんだろうと公式ページを見てみたところ、「将来的には本サービスを停止」することに致しました。と具体的なスケジュールは未定ですが、公開停止が決まっているみたいですね。

https://www.itc.fukuoka-u.ac.jp/i/service/special/public_ntp

これを機にネットワーク機器のNTPの同期先を見直したほうがいいかもしれませんね。[^1]

[^1]:他の公開NTPサーバーはNICTやMFEEDのものがあります。法人での利用には事前申告などが必要だったりするので注意。
個人用OneDriveで写真を共有するとサムネイルが表示されない場合がある

# はじめに
私は写真撮影が趣味ですが、ポートレート写真を撮影することがあります。ポートレート写真の撮影方法はいろいろありますが、私の場合は撮影会に参加してモデルさんと1対1で撮影します。撮影した写真は帰宅後選定およびレタッチを行いカメラメーカーの写真共有サイトやSNSで公開します。
ポートレート写真の撮影では他のジャンル(鉄道、風景など)と違って以下の作業を行っています。
1. インターネット上に公開する写真について公開してよいかモデルさんの承認を得る
2. 撮影データをミスショットを除きほぼ全量モデルさんに送付する

1.は肖像権の関係でポートレート写真の公開では必須と考えています。私が参加した撮影会ではモデルさん本人に確認を取ればよいですが、撮影会によっては主催団体経由で承認を得る場合もありますし、公開が禁止されている場合もあります。(禁止されている例：ヨドバシカメラ主催の撮影会)
2.についてはモデルさんもカメラマンの期待に応えようと頑張っているので、お礼とご本人にも楽しんでもらうために行っています。

# 写真の共有方法
モデルさんの承認を得るときは、枚数が少ないのでSNSのダイレクトメッセージ機能を使って写真データを送付し、確認を依頼しています。
![スクリーンショット 2024-02-12 203534.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/7f6bd910-1fc7-1653-7788-1d45943c0a8b.png)
一方、共有用の撮影データを送付するときはファイル数が200近くになるのでオンラインストレージを活用しており、私はOneDriveを使っています。Microsoft365 Personalを契約しており1TBのストレージが使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/3a4da375-5d02-ed77-8298-08b2f636b534.png)


# OneDriveでファイルを共有する方法
OneDriveで写真に限らずファイルを共有するときは、フォルダの共有リンクを作ることで共有することができます。Windows11の場合は次の通りです。
1. フォルダを右クリックし、OneDrive→共有をクリックする
![スクリーンショット 2024-02-12 195433.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/c8a8a01b-82b6-c59d-cf1d-cc64cae77882.png)

2. リンクをコピーの「コピー」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/2c01307b-54c0-c968-8b9a-e107da0c7366.png)

3. 「コピー」をクリックするとリンクをクリップボードにコピーできる
![スクリーンショット 2024-02-12 195636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/a391e8df-3c76-2a41-00ce-551bc49bd705.png)

4. リンクをWebブラウザで開くとファイルを確認できる(写真は以前私が伊豆に行ったとき撮影した写真です)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/19b6faaa-2ebe-97f9-fb3b-13ce50a2e44c.png)

# OneDriveでサムネイルが表示されない場合

上記のようにファイルを共有すると、写真の場合はサムネイルが表示されますが、**リンクを開くときにパスワード入力を必須にするとサムネイルが表示されません。**

パスワード入力を必須にする手順は次の通りです。
1. この画面で「リンクを知っていれば誰でも編集できます」をクリックする
![スクリーンショット 2024-02-12 195604.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/8bf9158b-ddef-4052-cc99-4747ebd8a9bd.png)

2. その他の設定で、パスワードの設定欄があるのでここでパスワードを設定し、「適用」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/49853a0c-a7b7-ce26-f22c-3a6d7a81dd5b.png)

これでリンクを作成できます。
リンクを開くと以下の画面が表示されるのでパスワードを入力し、「送信」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/12857a31-6a25-82d9-a8c7-930a2aae4d1b.png)

この状態で開くと、**サムネイルが表示されません。**　
そのため、Webブラウザからでは1個1個開かないと写真の内容を確認できないです。

![スクリーンショット 2024-02-12 202212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92424/e9dc925b-c96f-5bce-39ea-32403ca8184d.png)

もともとパスワードをつけた方がよいと思いパスワード付きでリンクを共有しようと考えましたが、サムネイルが表示されないと1個1個開いて確認しないといけないのが手間となるのと、リンクとパスワードを同じメッセージで送ることからパスワードの意味がないのでパスワードなしでリンクを共有しています。なお、リンクはモデルさん本人や撮影会主催団体にのみ共有しています。
このOneDriveでサムネイルが表示されない仕様ですが、Microsoftのヘルプを見たり、MS Copilotで質問してもよくわかりませんでした。そのため共有およびQiita記事作成の練習として記録します。(Copilotでわからなかったのは質問の方法が悪かったかもしれませんが)

:::note warn
上記のファイル共有の方法ですが、個人用のサービスを利用しているのでプライベートの場面でファイル共有するときにした方がよいです。業務でファイル共有するときは法人用のクラウドサービスやオンプレミスのファイルサーバなどを利用しましょう。
:::
GPG error: 今日のDockerエラー

apt updatしようとして

```docker:bash
apt update
Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
Err:1 http://deb.debian.org/debian bookworm InRelease
  At least one invalid signature was encountered.
Get:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Err:2 http://deb.debian.org/debian bookworm-updates InRelease
  At least one invalid signature was encountered.
Err:3 http://deb.debian.org/debian-security bookworm-security InRelease
  At least one invalid signature was encountered.
Fetched 251 kB in 1s (484 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used.どc http://deb.debian.org/debian bookworm InRelease: At least one invalid signature was encountered.
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://deb.debian.org/debian bookworm-updates InRelease: At least one invalid signature was encountered.
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://deb.debian.org/debian-security bookworm-security InRelease: At least one invalid signature was encountered.
W: Failed to fetch http://deb.debian.org/debian/dists/bookworm/InRelease  At least one invalid signature was encountered.
W: Failed to fetch http://deb.debian.org/debian/dists/bookworm-updates/InRelease  At least one invalid signature was encountered.
W: Failed to fetch http://deb.debian.org/debian-security/dists/bookworm-security/InRelease  At least one invalid signature was encountered.
W: Some index files failed to download. They have been ignored, or old ones used instead.
```

pushしようとして

```macOS:bash
$ docker commit ffc652d1f3f8 kaizenjapan/rustnews
Error response from daemon: write /usr/share/vim/vim90/spell/en.utf-8.sug: no space left on device
```
Gemini Ultraを試しました。やはりGPT4の方が精度良いです。

先週金曜日、GoogleがGeminiの最上位モデル「Gemini Ultra」をリリースしましたので、私も登録して（月額20ドル）試しました。

Googleが公開された論文によると、GeminiUltraはベンチマークでGPT-4を上回るスコアを獲得していますが、実際はそうでもないと感じました。

![99.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/3355535c-f824-4ddb-a2e0-c0c537cb43f4.png)

基本的なタスク（要約、数学問題、コード生成など）を色々試してみましたが、個人的な感想としてはGPT-4の方が回答よかったです。

__特に、画像生成や認識に関しては、問題が複雑で抽象的になると、GPT4のようにうまく理解することはできなかったです。__


## 1.複雑な画像生成
例えば、私パワポスライドを作る際に、具体的なイメージが思い浮かばない時はよくChatGPTに聞きました。（下はChatGPTに”A”と”B”を比較する際によく使われるスライドイメージを作成してもらった例です。）



![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/211b8097-f844-c298-a5db-b8eb3e8e51bf.png)

⇧のようなイメージ図を生成することができます。これは初回の出力であるため、そこまで良いものを生成できてないですが、ChatGPTが要求されたタスクを理解していることはわかります。

Gemini Ultraにも同じ質問を試してみました。（Gemini Ultraの画像生成は現在日本語対応していないので、英語でprompt文を投げました。スクリーンショットには含まれていませんが、ChatGPTに投げた質問と全く同じものでした。）生成された画像を見ると、質問の意図を正確に理解していないようですね。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/9a406288-7535-dc20-4f24-d68bd7f7f04c.png)
ちなみに、この”スライドのイメージを作る”タスクは私が試した限りでは、GPT4以外できるLLMはなかったです。


## 2.Googleツールとの連携

Gemini Ultraが特に優れていると感じた点は、Googleツールと連携して使えることです。（gmail,colab,driveなど）
Googleツールのagentとして使ってみると非常に使いやすかったです。
例えば、Gmail内のメールを検索して要約したり、Colabに保存されているコードを検索して修正するなどの操作を試しましたが、特に間違いなく実行できました。（langchain経由でGoogleAPI使うagentよりも処理速度、精度が高かったです。）

⇩は特定の相手からのメールをまとめてもらった例です。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/65f18a2a-77b2-1ed2-5a95-f5a2a109c37c.png)





下記のGemini UltraとGPT4を比較する記事もあります、興味ある方ご覧ください：

https://weel.co.jp/media/gemini-advanced-gpt-4


END
パブリッククラウドの比較 その1

## 前置き
* 各クラウド事の特徴や勉強する際の参考資料をまとめてみました
* まずは各クラウドの基礎が勉強できるページのリンクをまとめてみました
    * 今後追記していくかも

## AWS
* アマゾンが運営しているクラウドサービス 世界で最も利用されているパブリッククラウドのためとりあえずクラウドを使うときの選択肢に上がる
* 参考サイト
    * [クラウドの基礎](https://explore.skillbuilder.aws/learn/course/external/view/elearning/15139/cloud-for-beginners-japanese-only-na-ri-ben-yu-shi-xie-ban)
    * [AWSの基礎](https://explore.skillbuilder.aws/learn/course/external/view/elearning/1875/aws-cloud-practitioner-essentials-japanese-na-ri-ben-yu-shi-xie-ban)


## Azure
* Microsoftが運営しているクラウドサービス Officeとの連携などの都合上企業などでは使われることが多い
* [Azureの基礎](https://learn.microsoft.com/ja-jp/training/paths/microsoft-azure-fundamentals-describe-cloud-concepts/)
    * Azureの資格であるAZ-900の試験に向けて基礎を学べるサイトです
* [Azureの情報がまとまっているページ](https://github.com/Azure/jp-techdocs?tab=readme-ov-file)

* [AWSとAzureの比較](https://learn.microsoft.com/ja-jp/azure/architecture/aws-professional/services)
* [GoogleCloudとAzureの比較](https://learn.microsoft.com/ja-jp/azure/architecture/gcp-professional/services)


## Google Cloud
* Googleが運営しているクラウドサービス Slackとの連携のスクリプトなどを手軽に記述できる

* [GoogleCloudの基礎](https://www.cloudskillsboost.google/paths/31/course_templates/60)
* [GoogleCloudのトレーニング](https://cloud.google.com/learn/training/)
    * 30日間無料で利用できるのでまずは挑戦してみることも可能
「再読み込みって3つあんねん」 ←4つ目作ってみた


https://forest.watch.impress.co.jp/docs/serial/chrometips/1152903.html

## きっかけ

「ステージング環境でUIが崩れているので、修正お願いします。」

「修正してデプロイしました。スーパーリロードしてみてください。」

「変わってないですね。」

「本当ですか？」

「はい、変わってないです。」

「CloudFrontのキャッシュをクリアしました。」

「あ、変わりました。」

「めんどくさいなあ...」

## 概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/b510cdf0-d81a-8b6e-8d68-3071c91df0e4.png)

*「10人のうち９人はチョコレート好き。そして10人目は嘘をついている」*
これはアメリカの漫画家、ジョンＧ.トゥリアス（John G. Tullius、1953年生まれ）の言葉です。

*「10人のうち９人は静的ファイル配信にCDNを利用。そして10人目は嘘をついている」*
これは私（Me、1998年生まれ）の言葉です。

CDN、特にAWSの[CloudFront](https://aws.amazon.com/jp/cloudfront/) は、その高速配信や負荷軽減など、多くのメリットを提供してくれます。しかし、時にはキャッシュによって頭を悩ませることもあります。

「デプロイしたのに、なぜか古いCSSが...」私は何度も経験しました。

こういった意図しないキャッシュのふるまいに対しては、デプロイパイプライン上でキャッシュの削除を行うことが好ましいです。
ただ、なんらかの理由でキャッシュ削除のタイミングが合わないこともあります。

例えば、ローリングデプロイ中に新旧のタスクが混在し、CloudFrontが古いタスクから配信された静的ファイルをキャッシュしてしまうケースです。
このケースでは、環境が安定してからキャッシュを削除するべきですが、1日に何回もデプロイが行われるステージング環境などでは、時々CIが失敗し、結果として古いキャッシュがそのまま残ってしまうことがあります。

こういった時はマネジメントコンソールにて「キャッシュ削除」を行うのですが、これが非常に面倒です。

`Ctrl+Shift+R`みたいな感覚でCloudFrontのキャッシュ削除できればいいのになぁ〜。。。

よし作ろう。

## 目的

`Ctrl+Shift+0`でCloudFrontのキャッシュを削除することが目的です。
そのために、Chrome拡張機能を開発しました。
この拡張機能では、次のフローを想定しています。

```mermaid
sequenceDiagram
    participant U as ユーザー
    participant E as 拡張機能
    participant CF as CloudFront

    U->>E: Webサイト訪問
    E->>E: ドメイン取得<br> →キー生成
    E->>E: そのキーが保存されているか確認
    alt キーが存在する
        U->>E: Ctrl+Shift+0
        E->>CF: キャッシュ削除を実行
        CF->>E: キャッシュ削除完了
        E->>U: 完了通知
    else キーが存在しない
        E->>U: 入力フォームを表示
        U->>E: 入力情報を保存
    end
```

## 完成品

こちらになります٩( ᐛ )و

https://github.com/iisyos/cf_cache_purge_extension

CRXJSというViteのPluginを使用し開発しており`Vite + React + TypeScript + TailwindCSS` という構成を採用しています。

https://crxjs.dev/vite-plugin

### ダウンロード方法
- [リリースノート](https://github.com/iisyos/cf_cache_purge_extension/releases/tag/v1.0.1)にある`cf_cache_purge_extension.zip`をダウンロードし展開します
- `chrome://extensions` を開き、デベロッパーモードをオンにして、展開したフォルダを指定します

または、リポジトリ内で`npm run build`を実行し、`/dist`以下を指定することも可能です。

### 実行方法
- 拡張機能一覧に`CloudFront cache purge`があることを確認します
- CloudFrontの`distributionId`と、下記相当のPolicyを持つIAMアクセスキーを取得します


```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": ["cloudfront:GetInvalidation", "cloudfront:CreateInvalidation"],
      "Resource": "arn:aws:cloudfront::235087485205:distribution/E26EXPHJDDBX9Q"
    }
  ]
}
```
:::note info
NOTE
リポジトリ配下で`./create-acceskey.sh　<distribution_id>` を実行すれば、該当のポリシーとユーザーが生成され、アクセスキーが払い出されます。
:::

- 拡張機能を開き、必要情報を入力します
- `Ctrl+Shift+0`を入力、もしくは拡張機能内で`purge cache`ボタンをクリックします
- キャッシュ削除が完了したら、WEB Pushが通知されます

![スクリーンショット 2024-02-12 18.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/11979570-bfb4-5272-37ec-787425eba67d.png)

## ふりかえり
CRXJSの利用により、簡単に実装を行うことができました！
（ストアへの公開はコストがかかるため、今回は見送りました。（笑））

具体的な実装方法に関しては、既に多くのわかりやすい記事が存在するため、そちらを参照していただけますと幸いです。

https://dev.classmethod.jp/articles/eetann-chrome-extension-by-crxjs/

https://blog.chick-p.work/blog/chrome-extention-with-vite/

https://zenn.dev/hamakou108/articles/6fec7a13d0f857

何かご意見ご要望ございましたら、遠慮なくコメントいただければ！！
motoのバージョン5.x以降のimportエラーについて

# motoとは？
motoは、AWSの各種サービスをモックするためのPythonライブラリです。
DynamoDBやS3などのマネージドサービスをモックにすることで、実際のAWS環境を用意せずともローカル環境でpytestなどができます。

# moto v5系でのDecoratorの変更
そして、いつの間にかmotoのバージョンが5.xに上がりました。
https://docs.getmoto.org/en/5.0.0/docs/releases.html

今回のメジャーアップデートでの注意すべき点は以下です。
> All decorators have been replaced with mock_aws

今までは、```@mock_s3```や```@mock_dynamodb```のようにAWSサービス名でDecoratorを記載していましたが、今後は全て```@mock_aws```に統一されるとのことです。

これにより今まで作成したpytestをそのままmoto v5系の環境で使おうとすると、```import Error```にはまります。

 ```DynamoDB Local```を使っている方には影響ありませんが、motoユーザも中々多そうなのでご注意ください。
【BigQuery】カンマ区切り文字列を分割して縦持ちにする（SPLIT/UNNEST/CROSS JOIN）

# やりたいこと
カラム`customer`に顧客名、カラム`orders`にカンマ区切りで注文商品名が格納されているテーブルを想定します。カンマ区切りの注文商品名を分割して縦持ちのデータに変換する方法を述べます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3341655/67411215-cfb9-b9de-a48f-cefa84bbf956.png)

# 結論
SPLITでカンマ区切り文字列を配列に変換します。
その後、UNNESTとCROSS JOINを組み合わせて配列の要素をテーブルの行に変換します。

```sql
WITH
  test_table AS (
  /*
    テスト用テーブルの作成
  */
    SELECT 'Aさん' AS customer, 'コーヒー,チョコレート' AS orders
    UNION ALL
    SELECT 'Bさん' AS customer, '紅茶,クッキー' AS orders
    UNION ALL
    SELECT 'Cさん' AS customer, 'コーヒー' AS orders
    UNION ALL
    SELECT 'Dさん' AS customer, 'コーヒー,チョコレート,クッキー' AS orders
    UNION ALL
    SELECT 'Eさん' AS customer, NULL AS orders
  )

SELECT
  customer
  ,split_order

FROM
  test_table

CROSS JOIN
  UNNEST(SPLIT(orders,',')) AS split_order
```


[BigQuery公式：配列内の要素をテーブル内の行に変換する](https://cloud.google.com/bigquery/docs/arrays?hl=ja#flattening_arrays)
[BigQuery公式：SPLIT関数](https://cloud.google.com/bigquery/docs/reference/legacy-sql?hl=ja#split)
[PowerQuery] 累積和リスト

# 背景

PowerBIの練習で、以下の記事みたいな分析をしようとしています。
[[Python] くりっく株３６５ヒストリカルデータを解析する（リピート注文） #Python - Qiita](https://qiita.com/tenmyo/items/6700b8459c81bdf24e1f)

以下のアプローチでやろうとしていています。

1. 行に前日終値と当日終値を持たせる
1. 前日終値＜買い指値＜＝当日終値　の条件列を持たせる
1. 上記条件がマッチした間の、高値・安値・間隔を計算する

「上記条件がマッチした間」を分類したいので、条件列を0/1にして、その累積和を取ることにしました。
Python(pandas)だとこんな感じ。

```python
df[f'Closs_Over_{th}'] = ((df['prev'] < th) & (th <= df['bid'])).cumsum()
```

# コード

シンタックスハイライトは、PowerQuery(mlang)がなかったため、そこそこ見栄えがよさそうなPythonにしています。
パフォーマンスはあまり良くなさそうです。約10年間の日足で数秒かかりました。

```python: 累積リスト関数
= (l) => let
        BufferedRows = List.Buffer(l),
        GroupedTh = List.Generate(
            () => [i = 0, 累積 = 0],
            each [i] <= List.Count(BufferedRows),
            each
                [
                    i = [i] + 1,
                    累積 = [累積] +  BufferedRows{[i]}
                ],
            each [累積]
        )
    in
        GroupedTh
```

引数はテーブル列などを渡します。

```python: 利用例
let
    ソース = Nikkei,
    追加されたカスタム = Table.AddColumn(ソース, "Th", each if(([前日清算価格] < Th) and (Th<= [当日清算価格])) then 1 else 0),
    並べ替えられた行 = Table.Sort(追加されたカスタム,{{"取引日", Order.Ascending}}),
    累積和リスト = 累積和リスト(並べ替えられた行[Th]),
    追加されたカスタム1 = Table.AddColumn(並べ替えられた行, "ThAcc", each 累積和リスト{[Index]}),
    グループ化された行 = Table.Group(追加されたカスタム1, {"ThAcc"}, {{"High", each List.Max([高値]), type nullable number}, {"Low", each List.Min([安値]), type nullable number}, {"Begin", each List.Min([取引日]), type nullable date}, {"End", each List.Max([取引日]), type nullable date}}),
    追加されたカスタム2 = Table.AddColumn(グループ化された行, "期間", each [End]-[Begin])
in
    追加されたカスタム2
```

テーブルはIndex列を持っています。`Table.AddColumn(..., each 累積和リスト{[Index]})`で、対応する行の累積和リストを追加してます。
使いまわしたいのでリスト生成のみで関数化しましたが、特に使いまわさない場合は [参考記事](https://qiita.com/PowerBIxyz/items/ed6ebb547a9157561ad1#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AB%E7%B4%AF%E8%A8%88%E5%88%97%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B)のように、`List.Generate`内で直接得たいテーブル形式にしてしまった方がよいと思います。

# 参考

[Power Query の List.Generate 関数ってなんだよー #Excel - Qiita](https://qiita.com/PowerBIxyz/items/ed6ebb547a9157561ad1)
[List.Generate - PowerQuery M | Microsoft Learn](https://learn.microsoft.com/ja-jp/powerquery-m/list-generate)
WordPressのセットアップで「Access denied for user 'root'@'localhost' (using password: YES)」

アフィリエイトサイトを作成して遊んでみようかなと思い、

~~一昔前に流行っていた？~~ WordPressを使用してみましたところ、

初歩的なところで躓いたのでメモメモ。

## 環境
- MacOS
- PHP 8.2.7
- DBeaver（RDBMS）

## 詰まるまでの手順
1. [WordPress](https://ja.wordpress.org/download/) をダウンロード
1. MAMPをインストール
1. ブラウザ表示できるよう、MAMPのApacheのルートディレクトリ配下に、先ほどインストールしたWordPressのフォルダを配置
1. [公式ドキュメント](file:///Applications/MAMP/htdocs/wordpress/readme.html) 通りに、スキーマとユーザーをターミナルで作成 
→ *ここがハマったポイント*
1. wp-config.phpに4で設定した内容を記入し、ブラウザで開いたら、よしなにインストールしてくれる画面が出てくれるはずだったが「Access denied for user 'root'@'localhost' (using password: YES)」が出てくる

## 詰んだ内容
エラーは読んで字の如く、MySQLにアクセスするユーザーが認証されていないようだった。
これにはいくつかの原因が考えられ、一番オーソドックスな解は、ユーザーの認証が足りていないということだ。
（ディグってもこの手の記事がたくさんあった）

しかし、何度ユーザーの権限を与え直しても、DBを作成し直しても、一向にこのエラーが解消されることはなかった…

## 結論
繋いでいたMySQLが違っていた…（お恥ずかしい//

MAMPのMySQLはlocalhost:8889だったが、コマンドでユーザーやらスキーマを作成していた環境はlocalhost:3333に繋いでたみたいでした。

なので、WordPress側からDBにアクセスしようとしても、そもそも作られていないスキーマやユーザーを認証なんてできない訳ですね…

自分が疑わない部分に潜むエラーはなかなか見つけられないですが、

見つけられた時のドーパミンはえぐいですね。

これだから開発はやめられない…
Route 53で取得したドメインのホストゾーンを削除してしまったら

## 前回の記事
こちらの記事は[AWSを使って人気物件の空き情報メール受信を電話でお知らせ](https://qiita.com/tutti618/items/1610fb0b853a92f1325f)の補足（後日談）です。

## やらかし
### Route　53で取得したドメインのデフォルトホストゾーンは削除NG
前回の記事[AWSを使って人気物件の空き情報メール受信を電話でお知らせ](https://qiita.com/tutti618/items/1610fb0b853a92f1325f)を
Qiitaにまとめるため手順を最初から復習しようと思い、
Route　53　> ホストゾーン　にて
存在しているホストゾーンをぽちぽち削除
→新規ホストゾーンとMXレコードを作成

↓

SESにメールが送信できなくなった😱😱😱

Route　53でドメイン取得時に自動生成された
デフォルトのホストゾーンを削除したため
DNS名前解決できなくなったのが原因でした。
お恥ずかしい。。

### 修正方法
新規作成したホストゾーンのNSレコード4つを確認
![Screenshot at Jan 21 16-22-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/d1cda944-5781-f90b-0932-3b34b2552194.png)


Route　53　> 登録済みドメイン　> アクション > ネームサーバーの編集
から、作成した新規ホストゾーンのNSレコード4つをドメインのネームサーバーに指定
![Screenshot at Jan 21 16-22-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/3d4d3386-c553-7db5-8b90-dbf4c84f1d86.png)

![Screenshot at Jan 21 16-22-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/f644ccd1-5ea6-ac46-3eda-aa0733705fd6.png)




ネームサーバーの反映には
最大72時間かかるとのことで、
毎日チェックはしていませんでしたので
正確な所要時間は不明ですが
1/3　14:20に設定し直し後
1/6　17:35にメール送受信を確認できました。

## まとめ
先日も「高校入試の出願システム、
Gmailにメール届かず」
というニュースがありましたが
（未だ原因は正式発表されていませんが）
メールのドメイン設定まわりは慎重に行う必要がある旨、
身を持って体験したのでした。

## 参考文献
今回参考にさせていただいた記事はこちらです。
- [【AWS】[Route53]ドメイン登録後、デフォルトのホストゾーンを削除してしまった場合の復旧](https://qiita.com/toshisanmee/items/8d0c475986f8db7ef525)
- [Route53で取得したドメインで名前解決できない](https://qiita.com/Shuhei_Nakada/items/5093b97d409389c8ad33)
【SwiftUI】星の数で評価できるViewを作成する

# はじめに
映画評価や書籍評価など、評価系のアプリは意外と多いはずです。
AppStoreのような星の評価ができるViewを調べると、整数部分を星の数として、実装しているものが多くありました。

しかし、少数部分も反映できるViewはなかったので、考えてみました

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 Pro - 2024-02-12 at 18.37.14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/f3e502fb-68c4-0318-ff19-b879836399b2.gif)

# 実装
```swift
struct ReviewView: View {
    @Binding var rate: CGFloat
    
    var rootWidth: CGFloat

    var body: some View {
        ZStack(alignment: .leading) {
            HStack {
                ForEach(0..<5) { _ in
                    Image(systemName: "star")
                        .resizable()
                        .scaledToFit()
                }
            }
            .frame(width: rootWidth, height: 100)
            .foregroundStyle(.gray)
            
            Rectangle()
                .foregroundStyle(.yellow)
                .frame(width: calcWidth, height: 100)
        }
        .frame(width: rootWidth)
        .mask {
            HStack {
                ForEach(0..<5) { _ in
                    Image(systemName: "star.fill")
                        .resizable()
                        .scaledToFit()
                }
            }
        }
    }
    
    private var calcWidth: CGFloat {
        rootWidth * (rate / 5)
    }
}
```

# 使用側
```swift
import SwiftUI

struct ContentView: View {
    @State var rate: CGFloat = 0.0
    var body: some View {
        VStack {
            Text("評価: \(rate)").font(.title)
            
            ReviewView(rate: $rate, rootWidth: 350)

            Slider(value: $rate, in: 0...5).frame(width: 350)
        }
    }
}
```

# おわり
一応形にはなっていますが、いいコードとは言えないので、改善案があれば編集リクエストください！
React✖️ZodでValidationチェックを実施する

## はじめに
表題通り、React✖️zodのvalidationチェックを実施する。

## 成果物

![zod.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/1378316d-57bd-7f9b-1415-87d972c9093d.gif)

https://github.com/kouji0705/react_zod


## ソースコード
```shell:ディレクトリ構成
~/develop/react/react_zod (feat/zod)$ tree -I node_modules 
.
├── README.md
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.tsx
│   ├── index.tsx
│   ├── logo.svg
│   └── validator.ts
├── tsconfig.json
└── yarn.lock

3 directories, 14 files
```

```tsx:src/App.tsx
import React, { useState } from 'react';
import { UserSchema } from './validator'
import { ZodError } from 'zod'

function App() {
  const [formData, setFormData] = useState({ name: '', email: '' });
  const [errors, setErrors] = useState<string[]>([]);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    try {
      // Zod スキーマを使ってバリデーションを行う
      UserSchema.parse(formData);
      setErrors([]);
      alert('Form is valid!');
    } catch (error) {
      if (error instanceof ZodError) {
        // エラーメッセージを設定
        setErrors(error.errors.map(err => err.message));
      }
    }
  };
  return (
    <div className="App">
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="name">Name:</label>
          <input type="text" id="name" name="name" value={formData.name} onChange={handleChange} />
        </div>
        <div>
          <label htmlFor="email">Email:</label>
          <input type="email" id="email" name="email" value={formData.email} onChange={handleChange} />
        </div>
        <button type="submit">Submit</button>
      </form>
      {errors.length > 0 && (
        <ul>
          {errors.map((error, index) => (
            <li key={index}>{error}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default App;
```

```tsx:src/validator.ts
import { z } from 'zod';

export const UserSchema = z.object({
  name: z.string().min(1, { message: "Name is required" }),
  email: z.string().email({ message: "Invalid email address" }),
});
```
RuntimeError: mat1 and mat2 must have the same dtype, but got ComplexFloat and Float の直し方

## はじめに
pytorchで複素ニューラルネットワークの実装をしたときのエラーとその対策のメモ書きです．
pytorchでも複素数使えるのでみんな複素ニューラルネットワークやろう！

## 環境
* Python 3.10.9
* torch==2.1.2

## 具体例
```python
x = torch.randn(3, 2)
x_complex = torch.view_as_complex(x)

l1 = nn.Linear(3,3)
y = l1(x_complex)

# 以下のエラーが発生．実際はもっと長く，最後の部分だけ抜粋した．
# File hoge\venv\lib\site-packages\torch\nn\modules\linear.py:114, in # # Linear.forward(self, input)
#     113 def forward(self, input: Tensor) -> Tensor:
# --> 114     return F.linear(input, self.weight, self.bias)
# 
# RuntimeError: mat1 and mat2 must have the same dtype, but got ComplexFloat and Float
```

### 原因
`nn.linear` は暗黙のうちに実数入力を想定しているため．
mat1, mat2 は `nn.linear` の入出力の変数のことを表していると思われる．

### 対策
`nn.linear` の型を明示的に変更しておけばよい．
```python
x = torch.randn(3, 2)
x_complex = torch.view_as_complex(x)

l1 = nn.Linear(3,3,dtype=torch.complex64)
y = l1(x_complex)
```

## 参考文献
1. https://pytorch.org/docs/stable/generated/torch.nn.Linear.html


[^label1]: 参考文献1参照
AndroidアプリのIntentの書き方

最近ChatGPT先生に教えて貰いながら自作Androidアプリを作っていました。
長らくWindowsやちょっとLinuxに慣れ親しんだ体にはAndroidのファイルアクセスが理解できなくて大変でしたが何とか動かせました。

最後の最後で躓いた部分をメモ

正しいコード
```
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.GPSLogConverter">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
```

インストールしたら起動すらしなかったコード

```
<activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.GPSLogConverter">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
```

これはChatGPT様に騙されてこう書きました。
違う流れで聞いたら前者の方が正しいと…。

結構時間使ってしまって悔しいです。
Hexabase TypeScript SDKの使い方（ActionScriptの使い方）

[Hexabase（ヘキサベース）](https://www.hexabase.com/)は企業においても安心して利用できるBaaS（Backend as a Service）を提供しています。多くのBaaSがそうであるように、主にフロントエンド開発者に利用してもらいたいと考えています。そこで現在、TypeScript SDKの開発が進められています。

この記事ではHexabase TypeScript SDKのインストールと、データストア操作に伴うサーバーサイドでのコード実行（ActionScript）の使い方を紹介します。

## インストール

インストールはnpmやyarnを使って行います。

```bash
# npmの場合
npm install @hexabase/hexabase-js

# yarnの場合
yarn add @hexabase/hexabase-js
```

## インポート

インポートすると、 `HexabaseClient` というオブジェクトが取得できます。

```jsx
import { HexabaseClient } from "@hexabase/hexabase-js";
```

## 初期化

HexabaseClientを初期化します。

```jsx
const client = new HexabaseClient();
```

## 認証

Hexabaseでは業務利用を想定しているため、利用する際に認証情報が必須になります。最初はメールアドレスとパスワードで認証し、その後はトークンを使ってGraphQLにアクセスします。 `client` を使って処理します。

初回の認証は次のようになります。emailとパスワード、またはトークンが必須です。

```jsx
await client.login({email, password, token});
```

後はこの `client` に対して処理を行います。

## データを作る

データはワークスペース → プロジェクト → データストア → データアイテムの順番にデータを取得します。

```js
client.setWorkspace(workspaceId);

// 対象プロジェクト
const project = await client.currentWorkspace.project(projectId);

// 対象データストア
const datastore = await project.datastore(datastoreId);

// 新規レコード
const item = await datastore.item();
```

## ActionScriptについて

Hexabase では、データベースのアイテムに対する操作をアクションと呼びます。このアクションに、Javascriptのコードを割り当てることができます。これがActionScriptです。

ActionScriptでは、アクションを呼び出すことで、割り当てたコードを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/72a839a3-60e4-722d-e37c-7c7914f762c8.png)


ActionScriptはプロジェクト、またはデータストアの操作に対して実行できます。詳細は以下を参照してください。

[ActionScriptの基本 \| Hexabase 開発ガイド](https://devdoc.hexabase.com/docs/features/actionscript_basic/)

### プロジェクトのActionScript

プロジェクトの `execute` メソッドに対して、関数IDと送信するパラメータを指定して実行します。

```js
const bol = await project
	.execute<boolean>('TestFunction', {aaa: 'bbb'});
```

### データストアのActionScript

データストアのActionScriptはデータの新規作成、更新、コピー、削除の4つに対して実行できます。また、ActionScriptはデータの処理前と処理後のどちらかの実行タイミングを指定できます。

#### データ作成時のActionScript

データ作成時は `save` メソッドを呼び出した際に実行されます。 `params` はオプションです。

```js
const item = await datastore.item();
item.set('name', 'Test');
await item.save({ parmas: {aaa: 'bbb'}});
```

この時、 `params` の内容はActionScriptの `data.as_params` として受け取れます。

```js
async function main (data) {
    logger.info(data.as_params); // {aaa: 'bbb'}
}
```

#### データ更新時のActionScript

更新時も `save` メソッドなのは変わりません。

```js
await item.save({ parmas: {aaa: 'bbb'}});
```

#### ステータス変更時のActionScript

ステータスを変更する際には `execute` メソッドを使います。実際にステータス更新を行うかどうかは管理画面で設定しますので、単にサーバーサイドでのコード実行を行うだけという使い方もできます。

```js
await item.execute('ExecuteActionScript', {test: 'test'});
```

### 注意点

データの作成、更新、ステータス変更時のレスポンスにActionScriptのレスポンスは含められません。ActionScriptは非同期で処理されます。

もしActionScriptの結果を受け取りたい場合には、データストアのフィールドにログを残しておいたり、Webhookを使うと良さそうです。

## まとめ

SDKを使うことで、ActionScriptは簡単に呼び出せます。メール送信やSlack通知など、サーバーサイドでしか行えない処理に使ってください。

Hexabaseには他にもバイナリファイルのアップロードや認証などの機能があります。それらの機能も利用してください。

[Hexabase \| 新規事業向け開発・競争領域でのDX実現をサポート](https://www.hexabase.com/)
Qiita用 Obsidian コマンド【文字色の変更】

# はじめに

**①Qiitaでは、今は亡き`<font>`タグで文字色を指定できます。**（早く`span style`にしてほしい）

<font color="LightGreen">こんな感じ</font>

```html
<font color="LightGreen">こんな感じ</font>
```

**②私は Obsidian というmarkdown エディタを使っています。**
<br>

**① + ② = <font color="LightPink">Obsidian で手軽に色つけたい！！！</font>**
# やり方


## ①Templater プラグインを入れる

Obsidian に「 Templater プラグイン」を入れます。
<br>

テンプレートフォルダの設定だけしてください。フォルダがなければ作ってください。

そのフォルダの中にスクリプトファイルを作成します。

他は特に設定は必要ないはずです。
<br>

念のため、設定画面を貼っておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/37634964-58c2-b292-98c2-6e69de8968f7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/3c9c6de3-dff9-6c9a-7dc5-40415aad7f0b.png)

## ②文字色変更スクリプト

先ほど設定したフォルダの中に、スクリプトファイルを作成します。
<br>
名前はなんでもいいです。私は `font-LightGreen` という名前にしています。

中身

```html
<font color="LightGreen"><%* tR +=tp.file.selection(); %></font>
```

`LightGreen` のところを別の色名に変えれば、他の色にもできます。

`rgb` なども使用できますが、Qiita では色名の指定のみ対応しているので注意してください。

色名の参考

https://qiita.com/twipg/items/d8043cd4681a2780c160

<br>

※試していませんが、`yml frontmatter` を書くとおかしくなる可能性があります。

`yml frontmatter` が何かわからない人は読み飛ばして大丈夫です。

## ③使ってみよう

デフォルトだと `Alt + E` で Templater を使った挿入（編集）ができます。

※キーが変わっている人は、`Ctrl + P` や「設定→ホットキー」でコマンドパレットを開き、

`Templater: Open ~`を探して実行してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/76a1a2b9-66fd-df63-1cae-9a2403eca015.png)

その後、ファイル名の選択画面になるので、先ほど作ったファイルを選んで実行しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/cf9bd191-f155-b98c-07ea-74bb49ccf737.png)


<font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font>
<font color="Plum">☆</font>！！完成です！！<font color="LightPink">☆</font>
<font color="LightPink">☆</font>お疲れさまでした<font color="Plum">☆</font>
<font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font><font color="Plum">☆</font><font color="LightPink">☆</font>

## ④アドバンス：fontのリセット

```
<%* const s = tp.file.selection() %><%* tR += s.match(/<font[^>]*>(.*?)<\/font>/)[1] %>
```

このスクリプトで、文字色を消すことができます。

（選択範囲内の`<font color="color_name">`と`</font>`を削除しています。）

## ⑤アドバンス：ショートカットへの設定

Obsidian では Templater のショートカット設定もできます。

今回の記事では割愛しますが、興味があれば調べてみてください。