OmniAICreator/Qiita-1.07M huggingface dataset:
VSCodeでRuffを設定したけど、うまく動かなかった時の対処法 [備忘録]

先日、RuffをVScodeに設定する話をQiitaに書きましたが、既存のプロジェクトで使用しようとした際に、Ruffが動かず右往左往したのでその備忘録です。

設定は下記記事を参照してください。
適切な設定ができている前提で話を進めます。

VSCodeの画面右下からRuffのログを出力します。

![スクリーンショット 2024-11-12 18.22.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570453/5910dc4c-661d-58f3-9cc1-e818fe2ed4eb.png)


私の場合、こんな感じになっていました。

```:command
2024-11-04 11:10:03.786 [info] Module: ruff
2024-11-04 11:10:03.786 [info] Python extension loading
2024-11-04 11:10:03.786 [info] Waiting for interpreter from python extension.
2024-11-04 11:10:05.498 [info] Python extension loaded
2024-11-04 11:10:05.693 [error] Python interpreter missing:
[Option 1] Select Python interpreter using the ms-python.python.
[Option 2] Set an interpreter using "ruff.interpreter" setting.
Please use Python 3.7 or greater.
```

ChatGPTに意味を聞いてみたら、この環境のデフォルトのPythonのバージョン低く、Python3.7以上にしなさいとエラーが出ています。
Ruffが動くためには、Python3.7以上が必要とのことでした。

今回はVScodeでPythonインタープリターを選択する方法で解決しました。

1. VS Codeのコマンドパレットを開く:
Ctrl+Shift+P（Windows/Linux）または Cmd+Shift+P（Mac）を押して、コマンドパレットを開きます。

2. Pythonインタープリターを選択:
コマンドパレットに「Python: Select Interpreter」と入力し、表示されたオプションを選択します。

3. インタープリターを選択:
使用したいPythonインタープリターをリストから選択します。Python 3.7以上のバージョンを選択してください。

## インタープリターって何？

ChatGPTに聞いてみました。
> インタープリタ（Interpreter）は、プログラムのソースコードを一行ずつ読み取り、その場で実行するプログラムです。インタープリタは、コンパイラとは異なり、ソースコード全体を事前に機械語に変換するのではなく、実行時に逐次的にコードを解釈して実行します。

リアルタイムで実行することで、Ruffとかも機能するって話なんだと思います。

上記作業で無事保存した時にRuffがフォーマットしてくれるようになりました。
変更箇所が多すぎて、GitHubが忙しいことになっています。

## 最後に

Ruffを設定した際は、なんか自然と使えていましたが、他の環境で動かずびっくりしました。
環境周りへの理解不足が原因だと思います。
環境への理解大切ですね。

エラーが出たら、とりあえずlogを確認して
あとは生成AIとうまくやっていけば大抵のことは解決できそうです。
Rails7でTailwindCSSを導入する

## 1.プロジェクトの作成
```bash
rails new rails_tailwind -j esbuild
cd rails_tailwind
```

## 2.Tailwind CSSとForemanのインストール
Gemの追加
```bash
bundle add tailwindcss-rails foreman
```

Tailwind CSSのセットアップ
```bash
rails tailwindcss:install
```

これにより、以下のようなファイルが自動的に生成されます：
- `app/assets/stylesheets/application.tailwind.css`
- `tailwind.config.js`

## 3.確認用ページの追加
コントローラーとビューの追加
```bash
rails generate controller Home index
```

これにより、以下のファイルが生成されます：
- `app/controllers/home_controller.rb`
- `app/views/home/index.html.erb`

ルートの設定
`HomeController`の`index`アクションをトップページとして表示するため、`config/routes.rb`を編集します。
```ruby
# config/routes.rb
Rails.application.routes.draw do
  root "home#index"
end
```

ビューにTailwind CSSのクラスを追加
`app/views/home/index.html.erb`を開き、以下の内容を追加します。
```html
<!-- app/views/home/index.html.erb -->
<!DOCTYPE html>
<html>
<head>
  <title>Rails Tailwind Example</title>
</head>
<body class="bg-gray-100">
  <div class="container mx-auto p-8">
    <h1 class="text-4xl font-bold text-center text-blue-500 mb-4">Tailwind CSS 導入確認</h1>
    <p class="text-lg text-gray-700 text-center">このページが正しくスタイルされていれば、Tailwind CSS の導入に成功しています。</p>
    <div class="mt-8 text-center">
      <button class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">確認ボタン</button>
    </div>
  </div>
</body>
</html>
```

## 4.サーバーを起動して確認
```bash
bundle exec foreman start -f Procfile.dev
```
クラスメソッドとは

> そのクラスに関連が深いものの、`一つ一つのインスタンスに含まれるデータは使わないメソッドを定義したい場合`があります。そのような場合はクラスメソッドを定義した方が使い勝手が良くなります。

# クラスメソッドの呼び出し方
>クラスメソッドを呼び出す場合は以下のように、クラス名の直後にドット(.)を付けてメソッドを呼び出します。
```クラス名.メソッド名```

# クラスメソッドの書き方
>```rb
> class クラス名
>   def self.クラスメソッド
>      # クラスメソッドの処理
>   end
> end
>```

>```rb
> class クラス名
>   class << self
>     def クラスメソッド
>       # クラスメソッドの処理
>     end
>   end
> end

# メソッド名の表記法について
> Rubyではインスタンスメソッドを表す場合に、`クラス名#メソッド名`と書くことがあります。例えばString#to_iであれば、「Stringクラスのto_Iというインスタンスメソッド」と表します。
　また、クラスメソッドの場合は`クラス名.メソッド名`（または`クラス名::メソッド名`）と書きます。例えばFile.exit?（またはFile::exist?)であれば、「Fileクラスのexit?というクラスメソッド」を表します。

 * File.exit?、File::exist?というクラスメソッドの呼び出し方がある

 ```rb
 irb(main):001* class User
irb(main):002*   def initialize(name)
irb(main):003*     @name = name
irb(main):004*   end
irb(main):005*
irb(main):006*   def self.create_users(names)
irb(main):007*     names.map do |name|
irb(main):008*       User.new(name)
irb(main):009*     end
irb(main):010*   end
irb(main):011*
irb(main):012*   def hello
irb(main):013*     "Hello, I am #{@name}."
irb(main):014*   end
irb(main):015> end
=> :hello
irb(main):016> names = ["Alice", "Bob", "Carol"]
=> ["Alice", "Bob", "Carol"]
irb(main):017> users = User.create_users(names)
=> [#<User:0x0000000108bc4fb8 @name="Alice">, #<User:0x0000000108bc4f68 @name="Bob">, #<User:0x0000000108bc4f40 @name="Carol">]
irb(main):018* users.each do |user|
irb(main):019*   puts user.hello
irb(main):020> end
Hello, I am Alice.
Hello, I am Bob.
Hello, I am Carol.
=> [#<User:0x0000000108bc4fb8 @name="Alice">, #<User:0x0000000108bc4f68 @name="Bob">, #<User:0x0000000108bc4f40 @name="Carol">]
```
```rb
irb(main):036* class User2
irb(main):037*   def initialize(name)
irb(main):038*     @name = name
irb(main):039*   end
irb(main):040*   class << self
irb(main):041*     def create_users(names)
irb(main):042*       names.map do |name|
irb(main):043*         User.new(name)
irb(main):044*       end
irb(main):045*     end
irb(main):046*   end
irb(main):047*   def hello
irb(main):048*     "Hello, I am #{@name}."
irb(main):049*   end
irb(main):050> end
=> :hello
irb(main):051> names = ["Alice", "Bob", "Carol"]
=> ["Alice", "Bob", "Carol"]
irb(main):052> names2 = ["Alice", "Bob", "Carol"]
=> ["Alice", "Bob", "Carol"]
irb(main):053> users = User2.create_users(names2)
=> [#<User:0x00000001089bdee0 @name="Alice">, #<User:0x00000001089bdeb8 @name="Bob">, #<User:0x00000001089bde90 @name="Carol">]
irb(main):054* users.each do |user|
irb(main):055*   puts user.hello
irb(main):056> end
Hello, I am Alice.
Hello, I am Bob.
Hello, I am Carol.
=> [#<User:0x00000001089bdee0 @name="Alice">, #<User:0x00000001089bdeb8 @name="Bob">, #<User:0x00000001089bde90 @name="Carol">]
```

https://gihyo.jp/book/2017/978-4-7741-9397-7

* 試しに書いてみたが同じように動作した
[C#]デリゲート、ラムダ式、LINQの記述を確認してみる

# はじめに
　UniRx,UniTaskの勉強を進めるうちに、前提知識として必要だったので調べてみました。筆者の感想を多く含みますので、誤りを含む可能性があります。参考元、公式の記述を参考にしてください。

# ラムダ式
　ほとんど参考記事で学びましたが、キーワードとしては「関数の記述の簡易化」のイメージでした。
 記述量がどんどん減っていくことを見ていけば、利便性はわかってくると思います。

 　例として２数の平均値が欲しいとき、下記のように書けます。
```
//A:通常の記述
private int Average(int x, int y)
{
    return (x + y)/2;
}
//B:ラムダ式による記述
(int x,int y)=>( x + y )/2;

//C:より簡略化した記述
(x,y)=> (x+y)/2
```
　とても簡単に書けました。Cについては、型推論で計算結果、引数を分析してくれているのでintが省略できているようです。
 int ave=(x+y)/2　のように一度変数に入れればよいのでは？というところもありますが、よく見る場面として変数動詞の計算というよりかは、ライブラリの返り値を簡単にいじって別のメソッドの引数にすぐ入れるというような使い方でしょうか。

 　また、引数なしの関数も作れるようです。とりあえず特定の関数を呼ぶだけということもできそうです。
```
//D：コンソールにHello Worldを出力する
() => Console.WriteLine("Hello World");
```

# デリゲート
 先ほどのラムダ式について、簡単に作った関数が使われるのは１度切り、ということはあまりないかと思います。そこで関数を呼び出せるように、「関数を入れる変数」として使われるのがデリゲートのようです。変数としてふるまうことができるので、デリゲート内の関数の差し替えもできます。

 ```
 private void SayHello()
{
    Console.WriteLine("Hello!");
}

public void Start()
{
    // Action型のデリゲートに、SayHello関数を登録
    Action action = SayHello;

    // デリゲート実行→SayHelloが呼び出される
    action();
    
    // Invoke()で起動してもよい　Invoke＝呼び出す
    action.Invoke();
}

```

デリゲートで受け取る変数にはいくつか型があり、返り値のありなしで型名が変わります。
Action型：引数なし、返り値なし
Action<>:引数あり、返り値なし <>内に引数の型
Func<>:引数なし、返り値あり　<>内に返り値の型
Func<>:引数あり、返り値あり　<>内に引数の型、返り値の型

# LINQ
 　C#他でも使える、配列、List、Dictionary型に対する技術、ライブラリのようです。使用するにはusing System.Linq;でライブラリを呼び出しておきます。
  　書き方はドットで連ねるメソッド式と、SQLのように記述するクエリ式の２種類があるようです。
  ```
  // クエリ構文
var query = from x in list
            where x % 2 == 0
            orderby x
            select x * 3;

// メソッド構文
var query = list
            .Where(x => x % 2 == 0)
            .OrderBy(x => x)
            .Select(x => x * 3);
```

　上記の文では、型推論によるvarで受け取っていますが、LINQではIEnumerable<>で返り値を受け取ります。
　ラムダ式でListに対する選択の条件式を作り、デリゲートに引数あり、返り値ありとして暗に代入して、LINQメソッドが引数としてデリゲートを受け取るというような合わせ技でしょうか。Listに対するLINQメソッドについては参考記事をご確認ください。[^1] 

 # おわりに
 　よく見ると配列操作のときにLINQの呼び出しをしたような気もして、少し理解が深まったとおもいます。引き続き学習を進めたいと思います。ちなみにこの本を読もうとしていた時にLINQ、ラムダ式が前提と言われていました。

  https://www.amazon.co.jp/UniRx-UniTask%E5%AE%8C%E5%85%A8%E7%90%86%E8%A7%A3-%E3%82%88%E3%82%8A%E9%AB%98%E5%BA%A6%E3%81%AAUnity-C-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0/dp/4048930753
  

# 参考記事
https://learn.microsoft.com/ja-jp/dotnet/csharp/linq/

https://qiita.com/nskydiving/items/c9c47c1e48ea365f8995

https://qiita.com/toRisouP/items/98cc4966d392b7f21c30

[^1]:https://learn.microsoft.com/ja-jp/dotnet/csharp/linq/
ユースケース図

**ユースケース図は、システムの機能やユーザーとの相互作用を視覚的に表現するUML（Unified Modeling Language）図の一つです。システムがどのようにユーザーや他のシステムと関わるかを理解しやすくするために利用されます。このガイドでは、ユースケース図の基本について解説します。**

# ユースケース図の目的

ユースケース図は、システムの全体像を簡潔に示し、ユーザー（アクター）がシステムをどのように利用するかを明らかにします。これにより、関係者がシステムの仕様を共通の理解に基づいて共有できるようになります。

**ユースケース図の主な目的は以下の通りです：**

ユーザーとシステムの関係を理解する

システムが提供する機能を視覚的に示す

要件の洗い出しや検討に役立てる

# ユースケース図の構成要素

ユースケース図にはいくつかの重要な要素があります：

**アクター（Actor）: システムと対話する外部の存在を示します。アクターは人だけでなく、他のシステムや外部のデバイスも含むことができます。**

**ユースケース（Use Case）: アクターがシステムを利用して行う特定の機能やプロセスを示します。例えば、"注文をする"や"ログインする"といった具体的な動作がユースケースになります。**

システム境界（System Boundary）: システムの範囲を示す枠です。ユースケースがどのシステムに属するかを明確にします。

**関係（Relationship）**: アクターとユースケースの間の相互作用を示します。これには以下の関係があります：

**関連（Association）**: アクターが特定のユースケースを利用することを示します。

**包含（Include）**: あるユースケースが他のユースケースの機能を含む場合に使用します。

**拡張（Extend）**: ユースケースの基本機能に追加の機能を拡張する場合に使用します。

# ユースケース図の例

例えば、オンラインショッピングシステムのユースケース図では、以下のような要素が含まれます：

**アクター: 顧客、管理者、配送システム**

**ユースケース: 商品の検索、カートに追加、注文の確認、支払い、アカウント管理**

**関係: 顧客が商品を検索し、カートに追加して注文を確認する流れを示す関連**

これにより、誰がシステムをどのように使うのかが明確に示され、各機能の関連性が理解しやすくなります。

ユースケース図の図例

**以下は、オンラインショッピングシステムのユースケース図の例です。**

  +----------------------------+
  |     オンラインショップシステム     |
  +----------------------------+
         /          |         \
 顧客  ------>  商品の検索  ------>  注文の確認
         \          |         /
          +------- カートに追加 ------>
         /          |
 管理者 ------>  商品管理

この図では、顧客がシステムを通じて商品を検索し、カートに追加し、注文を確認するプロセスが示されています。また、管理者は商品管理のユースケースにアクセスします。このように、ユースケース図はシステムの機能とユーザーの関係を視覚的に表現するのに役立ちます。

# ユースケース図の作成のポイント

**シンプルに保つ**: 必要な要素のみを含め、複雑になりすぎないようにします。

主要なアクターとユースケースに集中する: すべてを網羅しようとすると図が煩雑になるため、重要な部分に集中しましょう。

**関係を明確に示す**: アクターとユースケースの関連を明確にし、システムの動作を理解しやすくします。

**ユースケース図の活用方法**

ユースケース図は、システム開発の初期段階で要件を確認するために非常に役立ちます。また、関係者とのコミュニケーションを助けるために利用され、開発者、設計者、顧客がシステムの機能について共通理解を持つことができます。

例えば、プロジェクトの初期段階で顧客と共にユースケース図を作成することで、システムが提供するべき機能についての認識のズレを防ぐことができます。

# まとめ

ユースケース図は、システムの動作とユーザーとの相互作用を視覚的に表現する強力なツールです。シンプルに、主要なアクターとユースケースに焦点を当てることで、システムの全体像を効果的に伝えることができます。システムの設計や要件定義の段階でユースケース図を活用し、関係者との円滑なコミュニケーションに役立てましょう。

**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**
curlでのBasic認証を使ったファイル取得

Webサーバー上にあるファイルを自動で取得したいとき、curlは非常に便利なコマンドラインツールです。特に、Basic認証が必要なリモートサーバーのファイルを取得する場合、curlを使うことでシンプルに処理を行えます。

### curlでBasic認証を使用するためには、-uオプションを使います。

```bash
curl -u ユーザー名:パスワード URL
```

例えば、以下のhttps://example.com/protected/file.txt にBasic認証付きでアクセスするとしましょう。ユーザー名を`user123`、パスワードを`password123`としてcurlコマンドを実行します：

```bash
curl -u user123:password123 https://example.com/protected/file.txt -o file.txt
```

 URLの後に-oオプションを追加し、取得したファイルをfile.txtとして保存しています。


### パスワード入力の省略とセキュリティ対策

```bash
curl -u user123 https://example.com/protected/file.txt -o file.txt
```

このコマンドを実行すると、パスワード入力を求めるプロンプトが表示されます。


### curlの他の便利なオプション
- L: リダイレクトに対応するオプション。例えば、短縮URLやリダイレクトがある場合に使用します。
- o: ダウンロードしたファイルを特定のファイル名で保存。
「!厳しくチェック」なでしこ2024年バージョンアップを振り返る

なでしこ開発者のクジラ飛行机です。今年も、なでしこの開発をたくさん行いました。一年の振り返りに、新機能やバージョンアップのハイライトを紹介したいと思います。

### 個人的にダントツに良かった機能は？

私の中で、2024年に追加した機能の中で、ダントツに良かったのが、v3.6.11で追加された「!厳しくチェック」構文です。

- [なでしこ3マニュアル > 文法/厳しくチェック](https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2F%E5%8E%B3%E3%81%97%E3%81%8F%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF)

それまで、関数の呼び出しにおいて、引数デフォルトで厳しくチェックしていたのですが、あまり考えずに作ったプログラムで「未定義の警告」が出るようになっていました。使い捨てのバッチなんかを書く機会も多いので、デフォルトでは、それほど厳しくチェックしなくても良いかなと思っていました。

そこで、デフォルトで厳しくチェックするのを止めて、プログラムの冒頭に「!厳しくチェック」と書くと、諸々のチェックをしてくれるようになります。

### 厳しくチェックって何をチェックしてくれるの？

「!厳しくチェック」構文でチェックしてくれるのは、次の点です。

- 関数の引数にundefinedを与えた場合に警告
- 関数の戻り値がundefinedだった場合に警告
- 未定義の変数を利用した場合に警告

「!厳しくチェック」の有無で実行結果に変化があります。

![スクリーンショット 2024-11-13 15.39.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/fcf9d18a-3d58-11b7-63ed-b99b3f489540.png)


### 戻り値がない関数を定義した時にも警告が出るんだけど・・・

なお、厳しくチェックする際に、関数を定義したとき戻り値の不要な関数が多くあります。その際には、下記のように「それは戻り値無し」と書く事で警告を抑制できます。そして、戻り値が無いことを明示できるので問題が起きるのを防ぐ事ができるでしょう。

```
!厳しくチェック
●(誰に)挨拶とは
　　それは戻り値無し # ←←← これを消すと警告が出る
　　もし、誰＝「友人」ならば
　　　　「友よ、こんにちは」と表示
　　違えば
　　　　「どうも、こんにちは」と表示。
　　ここまで。
ここまで。
「友人」に挨拶する。
```

### まとめ

公開するプログラムや、プラグインなどを作った際には、厳しくチェックを有効にすると、トラブルが少なくなると思います。活用してみてください。
【メモ】インフラについて

## インフラとは
サーバーやネットワークなど、アプリケーションやシステムを運用する際の基盤のこと。

## インフラ設計
稼働率、障害発生頻度、障害復旧時間などを考慮して、インフラ環境を設計すること。

## サーバー構築の種類
- オンプレミス：自社サーバーを保有し管理すること
- クラウド：インターネット経由でサービスを利用する形態のことで、クラウドサービスでサーバーを借りて利用すること
【Ruby】シングルクォートとpの意外な性質

# はじめに
こんにちは！アメリカの大学で語学を学びながら、独学でソフトウェアエンジニアを目指している者です。
文字列の扱いにおいて「シングルクォート」と「ダブルクォート」の違いはご存じだと思います。
シングルクォートは式展開を無効にするため、プログラムの挙動を確認したいときに役立ちますが、さらに意外な性質があることをご存じでしょうか？
この記事では、シングルクォートでバックスラッシュがそのまま出力されることと、`p` メソッドと組み合わせたときの動きを詳しく見ていきます。

## シングルクォートとダブルクォートの違いをおさらい
まずは、シングルクォートとダブルクォートの基本的な違いを簡単におさらいしておきましょう。

### ダブルクォート（`"`）
式展開 `#{}` や特殊文字（例えば `\n` など）が有効です。
```ruby
name = "田中"
greeting = "こんにちは、#{name}さん"
puts greeting  # => こんにちは、田中さん
```

### シングルクォート（`'`）
式展開や特殊文字が無効で、文字列がそのまま出力されます。
```ruby
greeting = 'こんにちは、#{name}さん'
puts greeting  # => こんにちは、#{name}さん
```

## シングルクォートではバックスラッシュがそのまま出力される
シングルクォートは式展開や特殊文字が無効であるため、例えば `\n` は改行を意味せず、そのまま「`\n`」という文字列として扱われます。
バックスラッシュ自体もそのまま表示されるので、次のようなコードでは、文字列内に `\` が残ったまま出力される点に注意が必要です。
```ruby
str = 'これはシングルクォートの\n性質です'
puts str  # => これはシングルクォートの\n性質です
```

## `p` メソッドとシングルクォートの組み合わせによる挙動
では本題の`p` メソッドとシングルクォートの組み合わせについて見てみましょう。
`p` メソッドは、引数のオブジェクトをそのまま視覚化して表示するため、デバッグに役立ちます。
`p` メソッドを使用すると、特殊文字やバックスラッシュが文字列リテラルのまま表現されるため、シングルクォート内でエスケープが無効であることが際立つ場合があります。

```ruby
str = 'これはシングルクォートの\n性質です'

p str  # => "これはシングルクォートの\\n性質です"
```
## バックスラッシュが二重になる理由
シングルクォートでは `\n` などの特殊文字が通常の文字として扱われますが、`p` メソッドを使うと、オブジェクトを文字列リテラルとして再現する際に、表示する特殊文字やバックスラッシュが追加で表示されます。
これは、`p` メソッドがRubyコードの表現を意図的にそのまま再現する仕様のようです。
具体的には、`p` メソッドが出力する文字列はRubyコードのソース表現に近い形式になるため、バックスラッシュを追加することで特殊文字を明示的に示します。これにより、デバッグ時に文字列中のバックスラッシュや特殊文字を視覚的に確認しやすくなります。

## ダブルクォートでの違いを比較
ここでダブルクォートの場合も確認しておくと、違いがさらに理解しやすくなります。
```ruby
str_double = "これはダブルクォートの\n性質です"
puts str_double  # => これはダブルクォートの
                 # 性質です
p str_double     # => "これはダブルクォートの\n性質です"
```
`puts` メソッドを使うと、ダブルクォート内の `\n` が改行として解釈されます。
一方、`p` メソッドを使うと、文字列がそのまま出力されますが、改行を表す `\n` がエスケープシーケンスとして表示され、シングルクォートの場合とは異なる挙動を示します。

# まとめ
シングルクォートと `p` メソッドの組み合わせを使うと、シングルクォートで式展開が無効になることや、`p` がバックスラッシュを強調して出力するという性質が組み合わさり、普段と少し異なる出力が得られます。
特にデバッグ中にエスケープシーケンスがそのまま表示される場合や、バックスラッシュの意図しない増加が見られる場合は、シングルクォートと `p` のこの特性に注目してみると良いかもしれません。
Tailwind CSSでRailsのエラーメッセージをフォームの下に表示する方法

[株式会社TECH LUCK](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)という会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご相談をいただけますと幸いです。
以下のようなお悩みを解決できます。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご連絡いただけますと幸いです。


# 前提
Rails7.1でCSSにTailwindを利用している際に、フォームの下にエラーメッセージを出したいと思ったときがありました。
その時に実装した内容を書き出します。

実装したら以下のようなデザインと動きになります。
![error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92443/4cc5c416-fbd4-ee2c-d820-6dc13f77f64a.png)


https://gyazo.com/ceda2570744dc05eecf65f9c134e067a

# 実装方法
エラーメッセージを表示するために、`views/shared/_error_message.html.erb` というファイルを作ります。

```erb:views/shared/_error_message.html.erb
<% if model.errors[attributes].present? %>
  <% model.full_messages_for[attributes].each do |error_message| %>
    <p class="text-red-500 text-xs italic"><%= error_message %></p>
  <% end %>
<% end %>
```

以下のような形でエラーメッセージを表示したいフォームの下にデザインを組み込みます。

```erb:new.html.erb
<div class="mt-2">
  <%= f.text_field :content, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-emerald-600 sm:text-sm sm:leading-6" %>
  <%= render 'shared/error_message', model: @post, attributes: :content %>
</div>
```

また、Rails7.1ではTurboを利用しているため、createアクションでは `render :new, status: :unprocessable_entity` という記述を忘れないようにしましょう。
これを忘れるとエラー表示がされないので注意が必要です。


```rb:posts_controller.rb
class PostsController < ApplicationController
  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)

    if @post.save
      redirect_to root_path
    else
      render :new, status: :unprocessable_entity # これが大事
    end
  end

  private

  def post_params
    params.require(:post).permit(:content)
  end
end
```

以上です。
【習慣】3か月ちょっと筋トレしてみて感じたこと

# はじめに
仕事終わりの暇な時間をつぶすべく、何気なくはじめた筋トレ。
なんだかんだ3か月も続いたから自慢させてくれ。(というか褒めてくれ)
継続したときに個人的に意識したこととか書いてみるが、
続ければなんでも意外と楽しくなるんだなという実感が一番共有したい部分だ。

# きっかけ
仕事で海外出張になって、かなり時間が余ったんだ。
筋トレなんて生まれてから無縁だったが、ここ1年くらいで少し太って来ていたのも気になり、何か始めなければと突然思った。
まぁ夜中に勉強とか急に始めちゃうタイプのあれです。
とりあえず20回だけ腕立てをやった。

# 継続に対する意識
続かなきゃ100回も0回
続けば1回も100回
って信じて、一日にたくさんやって満足しないようにした。
一度にやり過ぎてしまうと、満足して次の日やらない言い訳になりそうだった。
効果がなくても、継続してれば自信に繋がるだろうと思い、効率よりも再現性に焦点を当てていた。

# 変化
「どうせ筋トレ5分しかやらないし違うこともしちゃお」というノリで、英語の勉強とか散歩とか色々チャレンジするきっかけになっている。
食事に気を付け始めたり、筋トレ後の活発状態を活用してNISAの勉強したりできている。
これまで毎日仕事とゲーム以外してこなかったと思えないエネルギー、、、、。

# 習慣作りたい人へ
まず出来そうなものから習慣化すると「これができたからこれもできるでしょ」という自信に繋がるので、
毎日継続できることから徐々に習慣にすると良いかと思う。

最近は資格の勉強をするために、ペンを持つ習慣をつけたくて、1日3行の日記を書いてみようとか思っていたり。
勉強の習慣なんて生まれてから縁がないので、まずはペンを持つ習慣から。(先は長い。)

何か一個でも継続できると、前向きな気持ちが生まれたり、それに対する興味が増したりします。
変化のない生活に飽きた人にとっては、新しいことへの興味が増すことは刺激になること間違いなしなので、
くだらないことでも毎日ちょっとずつがんばろうず
App Store Connectで不要な未配信アプリを削除できない場合の削除方法

## 配信前のアプリが削除できない。
バンドルIDなどを変えた結果、残骸のようなアプリ申請情報が残り、
それが原因で別アプリの申請がリジェクトされていた。
　
アプリ情報下部にあるアプリを削除しても削除できない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/4177bd3e-50f3-8ff7-7d03-64b98448964e.png)

## 消し方
Apple Supportからの回答通りにしたところ削除できました。

1. App Store Connect >「価格及び配信状況」をクリック

2. 「アプリの配信状況」の「管理」をクリック

3. 「配信状況」>「配信状況を管理」をクリック

4. ポップアップウィンドウ「国または地域の配信状況」をスクロールダウンし、一番下にある☑️ 「今後App Storeに追加されるすべての国または地域でアプリが自動的に配信可能になります。」のチェックマークを外して次へを押します。

5. 「変更は24時間以内に有効になります。 確認」で完了です。

このウインドウの一番下にあるチェックを外して保存
しばらくしてから先ほどの「アプリを削除」で消せます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/b1dbc0ab-8396-adae-e400-3a3e7d7df0af.png)

Apple Support様、ありがとう
blastengineのC# SDKを使って、メール配信ログを取得する

blastengine（ブラストエンジン）はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先へメールを届けられます。

現在、C#向けに、blastengine SDKを開発しています。.NET6以上を対象としているので、macOSを含め幅広い環境で実行できるはずです。

今回は、メールの配信ログを取得する方法を解説します。

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)

そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## 必要な情報について

SDKを使う上で必要なのは、先ほどのAPIキーとユーザIDになります。

## SDKのインストール

SDKはNuGetでリリースしています。Visual StudioのNuGetパッケージの管理よりインストールしてください。

[NuGet Gallery \| Blastengine](https://www.nuget.org/packages/Blastengine/)

## 初期化

先ほどのAPIキーとユーザIDを使って初期化します。

```csharp
new Blastengine.Client("YOUR_USER_ID", "YOUR_API_KEY");
```

## レポートオブジェクトの作成

メールのログを取得する際には、レポートオブジェクトを作成します。引数はメールの配信ID（Delivery ID）です。

```csharp
var report = new Blastengine.Report(2885);
```

## ジョブを取得する

続いて、ジョブを取得します。ジョブは非同期で行われるので、完了するまで待ちます。

```csharp
var report = new Blastengine.Report(2852);
var job = await report.Get();
while (!(await job.Finished()))
{
		await Task.Delay(5000);
}
```

## レポートを取得する

ジョブが完了したら、レポートを取得します。

```csharp
var res = await job.GetReport();
```

レポートはCSVとして送られるので、 res は `List<Dictionary<string, string>>` になります。

```csharp
foreach (var dict in res)
{
		foreach (var kvp in dict)
		{
				Console.WriteLine($"  {kvp.Key}: {kvp.Value}");
		}
		Console.WriteLine();
}
```

結果は以下のようになります。

```
  配信ID: 2852
  配信日時: 2024/11/12 15:27:45
  メールアドレス: test1@example.com
  開封日時: 2024/11/12 15:27:46

  配信ID: 2852
  配信日時: 2024/11/12 15:27:45
  メールアドレス: test2@example.com
  開封日時: 2024/11/12 15:27:46
```

## コードについて

コードはGitHubにアップしてあります。ライセンスはMIT Licenseになります。

[blastengineMania/blastengine-csharp: blastengineのC# SDKです](https://github.com/blastengineMania/blastengine-csharp)

## まとめ

blastengineには、他にも1クリックでの購読停止機能や、Webhookなどの仕組みがあります。他の機能も随時実装していきますので、ぜひ皆さんのシステム開発に役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
【JavaScript】文字列から基本多言語面(BMP)以外の文字（UTF-8で4バイトになる文字）を配列で返す


```typescript
// 基本多言語面(BMP)以外の文字を配列で返す
export const extractUnicode4ByteChars = (v: string) => {
  const regex = /[\u{10000}-\u{10FFFF}]/gu // BMP範囲以外
  return v.match(regex) || []
}

const text = 'ﾒッせ-z1𩸽✋☀️🥺'
console.log(extractUnicode4ByteChars(text))
// '𩸽🥺'
```
個人開発メモ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527006/06db8868-f945-4fd3-3670-c6a482a5985f.png)

* タスク追加、削除、編集、読み込み機能追加
* リスト表示追加
* タスクを「完了」「未完了」「すべて」でソートする機能追加
* 完了したタスクに取り消し線をつける機能追加
* タスクの優先度表示機能追加
* 優先度によって自動ソート

バックエンド:Next.js
フロントエンド:Nuxt.js
言語:Typescript
DB:MongoDB
MySQL データを週ごとにグループ化する方法

### はじめに

MySQLで日付データを扱う際、週単位での集計が必要になることがあります。
この記事では、YEARWEEKを使って売上データを週ごとにグループ化する方法を解説します。

### この記事でわかること

- YEARWEEKの基本的な使い方
- 売上データを週ごとにグループ化するSQLクエリの書き方
- グループ化したデータの活用方法

### 対象読者

- MySQLを使用している開発者やデータアナリスト
- 日付データの週単位集計に悩んでいる方
- SQLの基本的な知識がある方

### YEARWEEKの基本

YEARWEEKは、日付から年と週の番号を取得する関数です。

```sql
SELECT YEARWEEK('2024-03-15', 0);
```

この関数は'YYYYWW'形式の数値を返します。例えば、2024年の第11週なら'202411'となります。

### 売上データの週ごとのグループ化

以下のようなサンプルテーブルがあるとします：

```sql
CREATE TABLE sales (
  id INT AUTO_INCREMENT PRIMARY KEY,
  sale_date DATE,
  amount DECIMAL(10, 2)
);
```

このテーブルのデータを週ごとにグループ化するSQLは次のようになります：

```sql
SELECT 
  YEARWEEK(sale_date, 1) AS year_week,
  SUM(amount) AS total_sales
FROM 
  sales
GROUP BY 
  YEARWEEK(sale_date, 1)
ORDER BY 
  year_week;
```

このクエリは以下のことを行います：

1. YEARWEEK関数で売上日を年週に変換
2. GROUP BY句で年週ごとにグループ化
3. SUM関数で各週の売上合計を計算
4. 結果を年週順にソート

### 結果の解釈

クエリの結果は次のようになります：

```
+----------+-------------+
| year_week| total_sales |
+----------+-------------+
|   202410 |     1000.00 |
|   202411 |     1500.00 |
|   202412 |     2000.00 |
+----------+-------------+
```

この結果から、2024年の第10週、第11週、第12週の売上合計がわかります。

### 応用：週の開始日を取得

週の開始日を知りたい場合は、以下のようにクエリを修正できます：

```sql
SELECT 
  YEARWEEK(sale_date, 1) AS year_week,
  DATE_ADD(DATE(YEARWEEK(sale_date, 1) * 100 + 0), INTERVAL 1 DAY) AS week_start,
  SUM(amount) AS total_sales
FROM 
  sales
GROUP BY 
  YEARWEEK(sale_date, 1)
ORDER BY 
  year_week;
```

このクエリでは、YEARWEEK関数の結果を日付に変換し、週の開始日（月曜日）を取得しています。

### まとめ

YEARWEEKを使用することで、MySQLで売上データを簡単に週ごとにグループ化できます。
この方法は、週次レポートの作成や時系列分析に非常に有用です。

より複雑な分析や可視化が必要な場合は、この基本的なクエリを拡張したり、結果をビジネスインテリジェンスツールに渡したりすることで、さらに深い洞察を得ることができます。
OMC232A(616)

https://onlinemathcontest.com/contests/omc232/tasks/10401

まず、$f^n(x)$を展開した式を考えます。

$f^3(x)=f(f(f(x)))$
$=f(f(135x-246))$
$=f(135×(135x-246)-246)$
$=f(135^2x-135×246-246)$
$=135×(135^2x-135×246-246)-246$
$=135^3x-135^2×246-135×246-246$
$=135^3x-246×\Sigma_{k=0}^{3-1}135^k$

おそらく、
$f^n(x)=135^nx-246×\Sigma_{k=0}^{n-1}135^k$
になると推測します。

$f^{10}(x)$と$f^{401}(x)$に当てはめます。

$f^{10}(x)=135^{10}x-246×\Sigma_{k=0}^{10-1}135^k$
$f^{401}(x)=135^{401}x-246×\Sigma_{k=0}^{401-1}135^k$

$f^{10}(x)=f^{401}(x)$なので、
$135^{10}x-246×\Sigma_{k=0}^{10-1}135^k=135^{401}x-246×\Sigma_{k=0}^{401-1}135^k$
$246×(\Sigma_{k=0}^{401-1}135^k-\Sigma_{k=0}^{10-1}135^k)=(135^{401}-135^{10})x$
$246×\Sigma_{k=10}^{400}135^k=(135^{401}-135^{10})x$

左右を入れ替えて、$135^{10}$で括ると、
$135^{10}×(135^{391}-1)x=246×135^{10}×\Sigma_{k=0}^{390}135^k$

また、$135^{391}-1$を変形して、
$=(135-1)(135^{390}+…+135^2+135^1+1)$
$=(135-1)\Sigma_{k=0}^{390}135^k$
とできるので、

$135^{10}×\lbrace(135-1)\Sigma_{k=0}^{390}135^k\rbrace x=246×135^{10}×\Sigma_{k=0}^{390}135^k$

両辺を$135^{10}\Sigma_{k=0}^{390}135^k$で割って、
$(135-1)x=246$
$x=\frac{246}{135-1}$
$=\frac{2×3×41}{2×67}$

約分して、
$x=\frac{123}{67}$

問題文では総和となっていますが、$x$が一意に定まるので、総和も
$\frac{123}{67}$となり、$a=123,b=67$となります。

したがって、解は、
$a+b=123+67=190$
CGIについて

# CGIについてのまとめ

## CGIとは

CGI（Common Gateway Interface）は、ウェブサーバーと外部プログラムを連携させるための標準的なインターフェースです。

- ウェブサーバーがクライアントからのリクエストを受け取ると、CGIプログラムを実行し、その結果をクライアントに返します
- 動的なウェブページの生成やデータベースとの連携が可能になります
- Perl、Python、C言語など様々なプログラミング言語で作成することができます

## 普通のウェブとの違い

### 静的ウェブページ（普通のウェブ）

- サーバーに保存されている固定されたHTMLファイルをそのままクライアントに送信するのでユーザーに関係なく同じ内容を表示する

### 動的ウェブページ（CGIを利用したウェブ）

- ユーザーからのリクエストに応じて、サーバー側でプログラムが実行され、それをもとにHTMLが生成されるのでユーザーごとに表示されるものが違う
## まとめ

- **静的ウェブ（普通のウェブ）**：固定されたコンテンツを提供し、ユーザーごとに内容は変化しない
- **動的ウェブ（CGIを利用したウェブ）**：サーバー側でプログラムを実行し、ユーザーのリクエストに応じて動的にコンテンツを生成する
【超基礎】TypeScript基本型まとめ

## 前提
この記事は、初学者の私が、サバイバルTypeScriptで学んだこと+調べたことをまとめたものになります。

従って、経験則に基づいた発言ではないため、一部慣習とは違っていたり、認知にずれがあったりする可能性がありますので、ぜひコメントで指摘していただけると幸いです。

https://typescriptbook.jp/

---

## 基本的の型
### number
- 数値を扱う
- 整数も小数もnumber型として扱う
- `0.1 === .1`
- `0b~`,`0o~`,`0x~`で2、8、16進数を扱える
- min : -(2^53-1) max : 2^53-1
- 非数 : `NaN` 無限 : `Infinity`
```typescript:number
const n : number = 5;
```
### string
- 文字列を扱う
- `""`,`''`どちらでも同じ
- バックスラッシュ`\`によるエスケープ
- <code>``</code>と`${name}`でテンプレートリテラル
```Typescript:string
const name : string = Taro;
```
### boolean
- 真偽値(`true`/`false`)を扱う
```typescript:boolean
const isTaro : boolean = false;
```
### bigint
- 大きな整数を扱い、末尾に`n`を付ける
- 小数は扱えない
- 各n進数はnumber型と同様に扱い、nを末尾付ける
- 理論上上限はないがメモリによる制約はある
- `NaN`,`Infinity`はエラー
- es2020以降で対応
- number型との演算は不可
- 直接JSON.stringify()に渡せない
``` TypeScript:bigint
const bigN : bigint = 5n;
```
### symbol
:::note warn
symbol型はJavaScriptの保守性を高めるために開発されたものであるため、web開発での使用頻度は低い
:::
- 宣言した値が一意になる
    ➡値が同じでも、別々で宣言した場合、別のものとして認識される
```Typescript:symbol
const sym1 = Symbol("Hello");
const sym2 = Symbol("Hello");

console.log(sym1 === sym2); // => false
```

### undefined
- 未定義の要素にアクセスしたときに返される
- 値が格納されていない変数や未定義のプロパティ、インデックスなど。
``` typescript:undefined
const a : undefined = undefined;
```

### null
- 値がない状態
- 存在していないことを明示的にする
- `typeof`で肩を調べると`object`が返される。
``` typescript:undefined
const age : null = null;

console.log(typeof null); // => object
```

### undefinedとnullについて
| undefined | null |
|:-:|:-:|
|JavaScriptが自動的に割り当てる   |開発者が意図的に定義する   |
| 中身が何か、存在しているのかさえ分からない箱 |何も入っていないことが明らかな箱|


## まとめ
以上になります。型の制約についてはc++等で触れましたが、また少し違った癖があって面白いですね。

当方初学者なため、認知のずれや、モダンな開発現場ではもう使わない表現などがありましたらコメントで指摘していただけると幸いです。😸
【Ruby】破壊的な変更！chompとchomp！

paizaの解き方記事などみると、chompではなく、chomp!を見ることがあった。
違いを理解したのでアウトプット。

## !とは

> 破壊的な変更
> Ruby の String クラスは mutable です。つまり、オブジェクト自体を破壊的に変更できます。
> 「破壊的な変更」とは、あるオブジェクトの内容自体を変化させることです。
引用：[Rubyリファレンス](https://docs.ruby-lang.org/ja/latest/class/String.html)

元々のオブジェクトを変更（破壊！）してしまう。

chompもchomp!も文字末尾の改行を取り除けるメソッド。


【補足】getsなどで受け取った入力は末尾に改行コードが入っている。例↓

```ruby:irbでの実行結果
string = gets
hello # helloと入力する
=> "hello\n" # \nは改行コード
```

## chompの場合
```ruby
string = gets     # helloと入力
p string
=> "hello\n"

string.chomp      # stringの末尾改行を取り除く
=> "hello"
p string
=> "hello\n"     # stringオブジェクトは変わらない

new_string = string.chomp    # sringの末尾改行を取り除いたものを変数に代入
p new_string
=> "hello"          #　変数代入すれば末尾改行なしの文字が使える

string = gets.chomp    # 入力段階でchompしておけばstringの末尾改行を取り除ける
p string
=> "hello"
```

chompは一時的にオブジェクトの改行を取り除けるが、オブジェクト自体から改行を取り除いたわけではない。

## chomp!の場合
```ruby
string = gets     # helloと入力
p string
=> "hello\n"

string.chomp!
=> "hello"
p string
=> "hello"      # stringは改行のない文字列に変わった

new_string = string.chomp!       # 変数代入してももちろん改行は取り除かれたまま
p new_string
=> "hello"

string = gets.chomp!        # 入力時点で文字列から改行を取り除いて変数代入しているので改行はない
p string
=> "hello"
```

破壊的変更なので、オブジェクト自体を変更させている。

## まとめ
今回はchompとchomp!でしたが、!をつけて使用できるメソッドは他にもある。
破壊的な変更(!)をつけたメソッドは使用時注意が必要！
かと言って改行コードがついたままのオブジェクトを使い続けるのもエラーの原因。
使用時にオブジェクトの目的をよく理解することが大事だと学びました。
VPC LatticeのログをAthenaで見よう

## はじめに

VPC LatticeのログをS3に出力して、Athenaで見られるようにしたときのメモです。

## Latticeログの種類

以下２つのログを出力させることができます。

- サービスのログ
- サービスネットワークのログ

細かい違いは以下に書きますが、**ログファイルの内容は同じもの**でした。

### サービスのログ

Latticeサービス固有のログです。

S3上の保存先のパスは以下のようになっていました。
`s3://{バケット名}/AWSLogs/{アカウントID}/VpcLattice/AccessLogs/{リージョン}/svc-xxxxxxxxxxx/`

### サービスネットワークのログ

紐づくサービスすべてのログが含まれます。

S3上の保存先のパスは以下のようになっていました。
`s3://{バケット名}/AWSLogs/{アカウントID}/VpcLattice/AccessLogs/{リージョン}/sn-xxxxxxxxxxxx/svc-xxxxxxxxxxx/`

## Athenaでのテーブル作成

以下の DDL でテーブルを作成することができました。

```sql
CREATE EXTERNAL TABLE IF NOT EXISTS {データベース}.{テーブル名} (
  `hostHeader` string,
  `sslCipher` string,
  `serviceNetworkArn` string,
  `resolvedUser` string,
  `authDeniedReason` string,
  `requestMethod` string,
  `targetGroupArn` string,
  `tlsVersion` string,
  `userAgent` string,
  `serverNameIndication` string,
  `destinationVpcId` string,
  `sourceIpPort` string,
  `targetIpPort` string,
  `serviceArn` string,
  `sourceVpcId` string,
  `requestPath` string,
  `startTime` string,
  `protocol` string,
  `responseCode` int,
  `bytesReceived` bigint,
  `bytesSent` bigint,
  `duration` bigint,
  `requestToTargetDuration` bigint,
  `responseFromTargetDuration` bigint,
  `sourceVpcArn` string,
  `callerPrincipal` string,
  `callerPrincipalOrgID` string,
  `callerX509IssuerOU` string,
  `callerX509SubjectCN` string,
  `callerX509SANNameCN` string,
  `callerX509SANDNS` string,
  `callerX509SANURI` string
)
PARTITIONED BY (
 partition STRING
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
  'serialization.format' = '1'
) LOCATION 's3://{バケット名}/AWSLogs/{アカウントID}/VpcLattice/AccessLogs/{リージョン}/svc-xxxxxxxxxxx/'
TBLPROPERTIES (
    'has_encrypted_data'='false',
    'projection.enabled'='true', 
    'projection.partition.format'='yyyy-MM-dd', 
    'projection.partition.interval'='1', 
    'projection.partition.interval.unit'='DAYS', 
    'projection.partition.range'='2024-01-01,NOW', 
    'projection.partition.type'='date', 
    'storage.location.template'='s3://{バケット名}/AWSLogs/{アカウントID}/VpcLattice/AccessLogs/{リージョン}/svc-xxxxxxxxxxx/${partition}/'
);
```

S3パスでの日時のディレクトリ構造が `〜/YYYY-mm-DD/〜` となっており、パーティションに多少の工夫が必要でした。

## おわりに

どなたかの参考になれば幸いです。
もっと適したDDLがありましたら教えていただけると幸いです。
[JavaScript][L2] ボタン押下によりコンテンツ(div>ul>li)を削除する

# 実施条件
[[JavaScript][L1] テキストボックスのコンテンツ(div)を別コンテンツ(div)に転記(生成)する](https://qiita.com/Jochun/items/632babb3bd0e3710920b)を理解していること

# 環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0（23A344）
Homebrew 4.3.8
gh 2.52.0

# ソースコード外観

## HTML
~~~html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>ToDo(JS)</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div class="input-area">
      <input id="add-text" placeholder="ToDoを入力" />
      <button id="add-button">追加</button>
    </div>
    <div class="incomplete-area">
      <p class="title">未完了のToDo</p>
      <ul id="incomplete-list">
        <!-- 完成系の例としてliタグ以下を作成している
        <li>
          <div class="list-row">
            <p class="todo-item">ToDoです</p>
            <button>完了</button>
            <button>削除</button>
          </div>
        </li> -->
      </ul>
    </div>
    <script src="./index.mjs" type="module"></script>
  </body>
</html>
~~~

## JavaScript
~~~js:index.js
import "./styles.css";

const onClickAdd = () => {
  // テキストボックスの値を取得し、初期化する
  const inputText = document.getElementById("add-text").value;
  document.getElementById("add-text").value = "";

  // li生成
  const li = document.createElement("li");

  // div生成
  const div = document.createElement("div");
  div.className = "list-row";

  // p生成
  const p = document.createElement("p");
  p.className = "todo-item";
  p.innerText = inputText;

  // button(完了)タグ生成
  const completeButton = document.createElement("button");
  completeButton.innerText = "完了";
  completeButton.addEventListener("click", () => {
    alert("完了");
  });

  // button(削除)タグ生成
  const deleteButton = document.createElement("button");
  deleteButton.innerText = "削除";
  deleteButton.addEventListener("click", () => {
    // 押された削除ボタンの親にあるliタグを未完了リストから削除
    const deleteTarget = deleteButton.closest("li");
    document.getElementById("incomplete-list").removeChild(deleteTarget);
  });

  // liタグの子要素に各要素を設定
  div.appendChild(p);
  div.appendChild(completeButton);
  div.appendChild(deleteButton);
  li.appendChild(div);

  // id="incomplete-list"の`ul`タグに子要素を設定した`li`タグを追加
  document.getElementById("incomplete-list").appendChild(li);
};

document.getElementById("add-button").addEventListener("click", onClickAdd);
~~~


# 手順
1. 削除buttonとして定義した`deleteButton`に、仮の`click`イベントとして`alert("削除")`で設定する
~~~js:index.js
deleteButton.innerText = "削除";
// 仮の`click`イベントとして`alert("削除")`で設定している = clickされた時の関数はここに記載していく
deleteButton.addEventListener("click", () => {
    alert("削除");
});
~~~

1. 仮の`click`イベントである`alert("削除")`を正しい関数に直す
~~~diff_javascript:index.js
deleteButton.innerText = "削除";
- // 仮の`click`イベントとして`alert("削除")`で設定している = clickされた時の関数はここに記載していく
- deleteButton.addEventListener("click", () => {
-     alert("削除");
+ // 押された削除ボタンの親にあるliタグを未完了リストから削除
+     const deleteTarget = deleteButton.closest("li");
+     document.getElementById("incomplete-list").removeChild(deleteTarget);
});

~~~

# 参考リンク
- [Element: closest() メソッド](https://developer.mozilla.org/ja/docs/Web/API/Element/closest)
- [Node: removeChild() メソッド](https://developer.mozilla.org/ja/docs/Web/API/Node/removeChild)
VBAにSQLを埋め込むためのコードを生成するpythonコード

内容
- SQLコードを分かりやすい形でExcel VBAなどに埋め込むためのコードを生成
  - ADO(ActiveX Data Objects)での利用を想定
  - /* */コメントや--コメントは除去する仕様 
  - osqledit環境で!bind set x = 'xxx'がある場合、埋め込みコードがうまくSQL実行されない→対策: !bind setを使わない
  - SQL区切り文字「;」があるとそれを含む生成コードを埋め込んで実行した際にエラーが発生

コード
```python
import re

# Use to remove -- comment
def remove_after_string(input_string, target_string):
    index = input_string.find(target_string)
    if index != -1:
        return input_string[:index]
    else:
        return input_string

path = input("Enter OpenFilePath(ex ./fileName.sql): ")

strSQL = "    strSQL = "  + " \"\" " + "\n"
with open(path, "r", encoding="Shift-JIS") as f:
# with open(path, "r", encoding="utf-8") as f:
    for line in f:
       s = line.replace("\n", "")
       s = remove_after_string(s, "--")
       strSQL = strSQL + "    strSQL = strSQL & " + "\"" + " " + s + " " + "\"" + "\n"

# Use to remove /* */ comment
pattern = re.compile(r'/\*.*?\*/', re.DOTALL)
strSQL =  re.sub(pattern, '', strSQL)
   
outputPath = "./" + path.split("/")[1].split(".")[0] + "SqlToVBA.txt"
with open(outputPath, "w") as f:
    f.write(strSQL)
```
使い方
- 上記コードをコピーして.pyファイルとして保存
- 同じ階層に対象となる.sqlファイルを配置

実行例
```python
C:\Users\nakamura0493\Desktop> python .\SqlToVBA.py
Enter OpenFilePath(ex ./fileName.sql): ./sample.sql
```
対象ファイル
```python:sample.sql
SELECT EmployeeID,
       Name,   /*  */
       Salary, -- 
       CASE 
           WHEN Salary < 40000 THEN 'Low'
           WHEN Salary BETWEEN 40000 AND 80000 THEN 'Medium'
           ELSE 'High'
       END AS SalaryCategory
FROM Employees;
```
実行結果
```python
    strSQL =  "" 
    strSQL = strSQL & " SELECT EmployeeID, "
    strSQL = strSQL & "        Name, "
    strSQL = strSQL & "        Salary, "
    strSQL = strSQL & "        CASE  "
    strSQL = strSQL & "            WHEN Salary < 40000 THEN 'Low' "
    strSQL = strSQL & "            WHEN Salary BETWEEN 40000 AND 80000 THEN 'Medium' "
    strSQL = strSQL & "            ELSE 'High' "
    strSQL = strSQL & "        END AS SalaryCategory "
    strSQL = strSQL & " FROM Employees; "
```
【UIButton.Configuration】ボタンタイトルの自動ハイライトを抑制したい

UIButton.Configuration 初心者の @zrn-ns です。

`UIButton.Configuration.plain()` ベースのボタンを作った際、以下のようなコードを書いたのですが、 **勝手に白いハイライトが当たる状態になりました**。

```swift
import UIKit
import PlaygroundSupport

let button: UIButton = .init()
button.configuration = {
    var config: UIButton.Configuration = .plain()
    config.title = "hoge"
    config.baseForegroundColor = .darkGray
    return config
}()

PlaygroundPage.current.setLiveView(button)
```

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/70cb5e03-e5e6-3c39-add4-fac0f604dd51.gif)

かなり見づらいですが、ハイライト色を設定していないにも関わらず、タップ時に白いハイライトが当たっています。

# 試行錯誤

`configurationUpdateHandler` を実装して、ボタンの状態が変わったときに色を変えたら良いよ！という記事もあったのですが、こちらも同様に、勝手にハイライトが当たってしまいます。

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/5a2bfbe4-bcdc-b3f4-d3ab-1539dda8c3c8.gif)

# 答え

:::note warn
この記事を公開したあと、友人から `UIButton.automaticallyUpdatesConfiguration = false` すればいいよと指摘がありました。
以下の記述ももちろん動作しますが、 `automaticallyUpdatesConfiguration` のほうがシンプルなのでそちらを推奨します！
:::

AttributedStringでタイトルを設定することでハイライトが無効化されます。

```swift
import UIKit
import PlaygroundSupport

let button: UIButton = .init()
button.configuration = {
    var config: UIButton.Configuration = .plain()
    config.attributedTitle = .init("hoge", attributes: .init([
        .foregroundColor: UIColor.darkGray
    ]))
    return config
}()

PlaygroundPage.current.setLiveView(button)
```

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/3e372add-1d37-7750-8b29-f41bf223db31.gif)

もしハイライト色を任意の色に変更したい場合は、以下のように `configurationUpdateHandler` で `attributedTitle` の色を変えてあげれば良さそうです。

```swift
let button: UIButton = .init()
button.configuration = .plain()
button.configurationUpdateHandler = { button in
    let attributes: AttributeContainer = .init([
        .foregroundColor: button.isHighlighted ? UIColor.green : UIColor.blue
    ])
    button.configuration?.attributedTitle = .init("hoge", attributes: attributes)
}
```

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/3bfe5ff0-e7af-2c76-0c0f-341c885cd43a.gif)
EC2のメモリ使用率が常に高いときの対策

## 使用率や詳細を見る
Datadog　期間は1ヶ月　増えては解放されないまま80%台になっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/1bf1a598-6210-865c-9ff0-8a836da96b44.png)
　
freeコマンド　usedが80%程度
```
$ free
              total        used        free      shared  buff/cache   available
Mem:        3965164     3197448      113704       22128      654012      503072
Swap:             0           0           0
```
　
topコマンド→shift+mでメモリ使用率順　メモリ占有しているプロセスが見当たらない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/8480b369-f326-b596-1a96-62513854205a.png)


## 原因が見つかった
**psコマンド**
```
ps aux --sort -rss
```
これにメモリを10MB以上使っている条件を追加
```
ps aux --sort=-rss | awk '$6 > 10000'
```
ps: 現在のプロセス情報を表示
aux: 全てのプロセス（a: 全ユーザー, u: ユーザーフォーマット, x: 制御端末がないプロセスも含む）を表示
--sort -rss: メモリ使用量順（RSS）にソート。-rssで降順にソート、メモリ使用量が多い順に表示


**下記のようなバッチ関連のプロセスが大量にあり、合計するとメモリ使用率が85%でした。**
```
artisan command:***
artisan schedule:run
```

## 対応
**暫定対応**
　バッチサーバーの再起動またはプロセスの終了


プロセスを終了する。
一括で終了してもクーロンで1分ごとに実行されるので、大丈夫そうではある。
```
sudo pkill -f "artisan schedule:run"
```
ただ、今回はプロセスIDを全部指定してkillした。
指定が大変なのでChatGPTにコマンドは作ってもらった。
```
sudo kill プロセスID...
```
freeコマンドとDatadogで確認、20%台まで減った。OK
```
$ free
              total        used        free      shared  buff/cache   available
Mem:        3965164      671300     2664968       22236      628896     3031816
Swap:             0           0           0
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/0b50b84c-9d2f-8712-cf41-3932069a7633.png)

　
**恒久対応**　→検討中
・Laravelのスケジューラー設定を見直す。
```
->everyFiveMinutes()->withoutOverlapping();
```
・週1で、完了していない古いバッチプロセスを削除するジョブを作成して、同じ現象は起こらないようにしました。

基本的にノーメンテで済む形が理想なので、これでOKです。
[SQL Server] CSV インポートでエラー

「SQLServer インポートおよびエクスポートウィザード」を使って、
CSVファイルをインポートするときになぜかエラーになってしまう・・・。

色々調べた結果、
原因が、CSVインポート時の、「詳細設定」で、
50文字を超えている列の「OutputColumnWidth」を増やしていなかったせいと判明しました。
(OutputColumnWidthのデフォルト値は50）

https://yukamemo-ver3.blogspot.com/2016/09/sqlserver-csv.html

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284134/e0f8db91-3599-b659-c488-dc6313fd0240.png)

50を255などと大きめに取るとうまくいきました。

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284134/1327d050-6405-cd18-e3dc-f591dc02a7bb.png)

# 問題点

何回も（同じ形式の）別のCSVを入れる作業があるときに、この詳細設定を再度設定し直さなきゃいけないのが苦痛でした。。。
一度CSVを正常にインポートし終えると、ウィザードは終了してしまうので、もう一度CSVを入れる際には、ウィザードをもう一度立ち上げる必要がありますが、前回の設定はすべてリセットされてしまいます。(設定が全部デフォルト値に戻ります)
CSVの列数が多い場合は非常に面倒です。
「sympyでa+b+c から最後の項を取り除く方法を教えて下さい。」Gemini先生に聞きました。

・Gemini先生のコードが、ChatGPT先生のコードより、便利。最終行のprint文。
```python
from sympy import symbols, Add

# 変数を定義
a, b, c = symbols('a b c')

# 式を定義
expr = a + b + c

# 式を項ごとに分解し、最後の項を取り除いて再構成
terms = expr.as_ordered_terms()[:-1]  # 最後の項を除いたリスト
result = Add(*terms)
print(result)  # 出力: a + b
```

# sympyで引数が多項式から最後の項を取り除くユーザー定義関数を教えて下さい。。
・いいですね～。私には書けないコードです。
```python
from sympy import symbols, Add

# 最後の項を取り除く関数を定義
def remove_last_term(expr):
    # 式を項ごとに分解し、最後の項を除去
    terms = expr.as_ordered_terms()[:-1]  # 最後の項を取り除く
    # 残りの項を使って式を再構成
    return Add(*terms)

# 変数を定義
a, b, c, d = symbols('a b c d')

# 式を定義
expr = a + b + c + d

# 関数を使用して最後の項を除去
result = remove_last_term(expr)
print(result)  # 出力: a + b + c
```
blastengineのC# SDKを使って大量のメール配信を行うには

blastengine（ブラストエンジン）はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先へメールを届けられます。

現在、C#向けに、blastengine SDKを開発しています。.NET6以上を対象としているので、macOSを含め幅広い環境で実行できるはずです。

今回は、バルクメール（一括配信メール）でCSVインポートを行う方法を解説します。

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)

そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## 必要な情報について

SDKを使う上で必要なのは、先ほどのAPIキーとユーザIDになります。

## SDKのインストール

SDKはNuGetでリリースしています。Visual StudioのNuGetパッケージの管理よりインストールしてください。

[NuGet Gallery \| Blastengine](https://www.nuget.org/packages/Blastengine/)

## 初期化

先ほどのAPIキーとユーザIDを使って初期化します。

```csharp
new Blastengine.Client("YOUR_USER_ID", "YOUR_API_KEY");
```

## メールオブジェクトの作成

メールを大量に配信する場合には、バルクメールオブジェクトを作成します。

```csharp
var bulk = new Blastengine.Bulk();
```

## 必要な情報をセットする

続けて、必要な情報をセットします（トランザクションメールも同様に）。

```csharp
bulk.Subject = "テストメール from C#";
bulk.TextPart = "これはテストメールです to __name__";
bulk.HtmlPart = "<h1>これはテストメールです to __name__</h1>";
bulk.From = new Blastengine.From("info@example.com", "Admin");
```

## 添付ファイルを追加する

添付ファイルは `Attachments` プロパティにファイルのパスをセットします。

```csharp
bulk.Attachments.Add("path/to/file1.txt");
bulk.Attachments.Add("path/to/file2.txt");
```

## 保存する

バルクメールの場合は、 `Begin` メソッドを使って一度保存します。

```csharp
var bol1 = await bulk.Begin();
```

## 宛先データをインポートする

大量の宛先の場合は、データをインポートします。CSVファイルのパスを指定するか、ByteArrayContentで指定します。

```csharp
var job = await bulk.Import("path/to/csvfile.csv");
```

### ステータスチェック

インポートは非同期処理で行われます。返却値の `job` を使って、ステータスをチェックします。

```csharp
while (!(await job.Finished()))
{
	await Task.Delay(5000); // 5秒待つ
}
```

### エラーチェック

インポート処理が完了後、エラーの有無を確認します。 `GetError` で返ってくるデータは、エラーデータのCSVを変換したものになります。

```csharp
if (job.IsError())
{
	// エラーあり
	var errors = await job.GetError();
	// エラー内容を確認
	errors[0]["エラーメッセージ"] // エラーメッセージ
	errors[0]["email"] // メールアドレス
}
```

## 送信する

送信は `Send` メソッドを使います。引数として、配信予定日時を指定できます。

```csharp
// 即時配信
var res = await bulk.Send();
// 予約配信（10分後）
var res = await bulk.Send(DateTime.Now.AddMinutes(10));
```

## コードについて

コードはGitHubにアップしてあります。ライセンスはMIT Licenseになります。

[blastengineMania/blastengine-csharp: blastengineのC# SDKです](https://github.com/blastengineMania/blastengine-csharp)

## まとめ

blastengineには、他にも1クリックでの購読停止機能や、Webhookなどの仕組みがあります。他の機能も随時実装していきますので、ぜひ皆さんのシステム開発に役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
既存のProjectにPlaywrightを導入する

# 既存のProjectにPlaywrightを導入する

## 0. 環境

| name | version |
|:---:|:---:|
| nodejs | 23 |
| nextjs | 15.0.0 |
| @playwright/test | 1.48.2 |

## 1. packageのinstallとdependencyの更新

[with-playwright](https://github.com/vercel/next.js/tree/canary/examples/with-playwright)をベースに作成します。

### 1-1. @playwright/testのinstall

```terminal
$ npm i -D @playwright/test
$ touch playwright.config.ts
$ mkdir e2e
$ mkdir e2e-results
```

```playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
import { join } from 'path'

const PORT = process.env.PORT || 3000
const baseURL = `http://localhost:${PORT}`

export default defineConfig({
  timeout: 30 * 1000,
  testDir: join(__dirname, 'e2e'),
  retries: 2,
  outputDir: 'e2e-results/',
  // 必要がある方はこちらをお願いします。
  // webServer: {
  //   command: 'npm run dev',
  //   url: baseURL,
  //   timeout: 120 * 1000,
  //   reuseExistingServer: !process.env.CI,
  // },
  use: {
    baseURL,
    trace: 'retry-with-trace',
  },
  projects: [
    {
      name: 'Chrome',
      use: {
        ...devices['Desktop Chrome'],
      },
    },
  ],
})
```

### 1-2. dependencyのインストール

1-1.を利用した状態だとエラーが発生します。

<details>
<summary> 表示されるであろうエラー </summary>

```terminal
Error: browserType.launch: Executable doesn't exist at /usr/Library/Caches/ms-playwright/chromium-1140/chrome-mac/Chromium.app/Contents/MacOS/Chromium

   ╔═════════════════════════════════════════════════════════════════════════╗
    ║ Looks like Playwright Test or Playwright was just installed or updated. ║
    ║ Please run the following command to download new browsers:              ║
    ║                                                                         ║
    ║     npx playwright install                                              ║
    ║                                                                         ║
    ║ <3 Playwright Team                                                      ║
    ╚═════════════════════════════════════════════════════════════════════════╝

```

</details>

```terminal
$ npx playwright install --with-deps
```

driverのinstall後はテストが動くようになります。

## 2. docker containerを利用してUI ModeのPlaywrightを確認する

nextjsがdockerで動いている場合に、UI Modeが利用できないとつらいので、UI Modeを利用できるようにする。
[ui mode](https://playwright.dev/docs/test-ui-mode#docker--github-codespaces)に記載がある通りに追加する。

hostとportを固定して対応します。

```compose.yaml
services:
    web:
        ports:
            - "3100:3100"
```

```package.json
{
    "scripts": {
        "test:e2e:ui": "playwright test --ui --ui-port=3100 --ui-host=0.0.0.0"
    }
}
```

```terminal
next@8fb5af1e8346:/usr/src/app# npm run test:e2e:ui

> web-app@0.1.0 test:e2e:ui
> playwright test --ui --ui-port=3100 --ui-host=0.0.0.0


Listening on http://0.0.0.0:3100
```
[localhost:3100](http://localhost:3100)にアクセスするとブラウザから確認が可能となっています。

![スクリーンショット 2024-11-13 12.45.39 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144543/1a99e1a3-42cd-851b-eb38-c81ae40a5d79.png)
EC2初期設定 よく使うコマンド （ec2-user パスワード追加）

ec2-user にはパスワードが設定されていないため、設定を行います。
パスワードを二回問い合わせてくるので、適当なパスワードを設定して下さい。
```
$ sudo passwd ec2-user
Changing password for user ec2-user.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
```

ec2-user が sudo する際にパスワード入力が必要になるよう、設定を変更します。

```
$ sudo visudo -f /etc/sudoers.d/90-cloud-init-users
```

以下内容で編集
```
# Created by cloud-init v. 22.2.2 on Thu, 11 Jul 2024 00:38:51 +0000

# User rules for ec2-user
# ec2-user ALL=(ALL) NOPASSWD:ALL
ec2-user ALL = (ALL) ALL
```

sudo してみます。

```
$ sudo -i

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

For security reasons, the password you type will not be visible.

[sudo] password for ec2-user:
```
パスワード入力を求められるので、先に設定したec2-user のパスワードを入力して root ユーザになれる事を確認してください。