OmniAICreator/Qiita-1.07M huggingface dataset:
passport.jsでユーザー認証を実装してみた

## はじめに
Passportは、認証や認可を簡単に実装できるNode.js用ミドルウェアです。
非常に柔軟なPassportはExpressベースのWebアプリケーションで利用できるため、ローカル認証やTwitter、FaceBookなどの外部認証にも使用されます。
今回はその中のローカル認証機能を実装していきます。

・使用するライブラリのインストール
```zsh:zsh 
npm install passport passport-local bcrypt express-session
```

## ストラテジの設定
はじめに、ストラテジの設定を行います。新しく`config`フォルダを作成し、その下の`passport.ts`ファイルに設定内容を記述します。

```typescript:config/passport.ts
import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";

const prisma = new PrismaClient();

passport.use(
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
    },
    async (email, password, done) => {
      const user = await prisma.user.findUnique({
        where: {
          email,
        },
      });

      if (!user) {
        return done(null, false, { message: "Incorrect email or password." });
      }

      const isMatch = await bcrypt.compare(password, user.password);
      if (!isMatch) {
        return done(null, false, { message: "Incorrect email or password." });
      }

      return done(null, user);
    }
  )
);

```

ローカル認証ストラテジにはユーザー名とパスワードを使用します。それぞれのフィールドの値はinputタグのname属性から取得していますので、認証にメールアドレスを使用したい場合は、以下のように`usernameField`の値を変更することで可能になります。
```typescript:config/passport.ts
{
    usernameField: "email",
    passwordField: "password",
}
```

リクエストと同時に渡されたデータを元に`function(email, password, done) {}`内で認証処理を行います。今回、認証処理にはprismaを使用し、データベース操作を行なっていきます。


## シリアライズとデシリアライズの設定

passportJsにおけるシリアライズとは、認証後のユーザー情報をセッションに保存する機能であり、デシリアライズとは、セッションIDからユーザー情報を特定する機能になります。

これにより認証後のユーザー管理が容易になります。

```typescript:config/passport.ts
//シリアライズの設定
passport.serializeUser((user: Express.User, done) => {
  done(null, user);
});

//デシリアライズの設定
passport.deserializeUser(async (user: User, done) => {
  const user = await prisma.user.findUnique({
    where: {
      id: user.id,
    },
  });

  if (!user) {
    return done(null, false);
  }

  done(null, user);
});
```

## パスポートの初期化とセッション設定

`app.use(passport.initialize())`によりパスポートを初期化することで、認証として使われます。また、パスポートのセッションを設定することで、リクエストの度にデシリアライズされ、ユーザー情報が`req.user`に格納されるようになります。

```typescript:app.ts
import express from "express";
import passport from "passport";
import expressSession from "express-session";

const app = express();

const session = expressSession({
  secret: "your-secret-key",
  resave: false,
  saveUninitialized: false,
});

app.use(session);
app.use(passport.initialize());
app.use(passport.session());
```
`/login`にリクエストとがあると、`passport.authenticate()`により認証を行います。第一引数にストラテジの指定を行います。今回はローカル認証の実装のため、`"local"`とします。

`successRedirect`は認証に成功すると指定のパスにページ遷移し、`failureRedirect`は失敗したときに遷移するページのパスを指定します。`failureFlash`はエラーが起こった場合のエラーメッセージを返すかどうかの指定になります。

```typescript:app.ts
app.post('/login', passport.authenticate('local', {
    successRedirect: '/',
    failureRedirect: '/login',
    failureFlash: false,
  }
));
```

今回はローカル認証の実装をご紹介していきましたが、Twitter、FaceBookなどの外部認証もパスポートを使用することで比較的容易に実装できるみたいなので是非チャレンジしてみてください！！
【Laravel】PHPstanをGitHub上で動かす


# はじめに

こんにちは、エンジニアのkeitaMaxです。

前回の続きです。

前回の記事

https://qiita.com/keitaMax/items/a63e3a93f1d2f2d10473


下記の記事を参考に、PHPstanをGitHub上で動かして、自動でテストするものを作成します。

https://qiita.com/hidao/items/8576729e3a253a2cd1ea

# ymlファイルを作ってGitで動かしてみる

参考元のymlファイルを参考にして以下のように作成しました。

```yml:phpstan.yml
name: LaraStan
on: [pull_request]

jobs:
  phpstan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.2"
          tools: composer, cs2pr
          coverage: none

      - name: Composer install
        run: composer install

      - name: Larastan install
        run: composer require nunomaduro/larastan --dev

      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@v29.0.3

      - name: Run PHPStan
        run: vendor/bin/phpstan analyze

```
これでPushすると、以下のように動き始めましたが、composer install の個所でエラーが出てしまいました。


```
Error: Your lock file does not contain a compatible set of packages. Please run composer update.
```

### ルート以外でGITHUB Actionsでコマンドを実行する

どうやら、Laravelのソースがルート配下ではなく`./src`配下にあるため、`composer install`ができなくなってしまったようです。

調べたら、以下のように`runs-on`の下に以下を追加います。

```yml:phpstan.yml
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./src
```

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions

これに修正して再度Pushしてみます。

`composer install`は無事エラーがなく終わり、完了しました。


# あえて失敗させてちゃんと動いているかをみる

今度はあえて変なコードを作成してPushしてみます。すると、以下のようにしっかりとエラーが出ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/fdf0786b-6d56-0c38-f0ee-73215eae6c1b.png)


# さいごに

GitHub Actions になれてきたのか、簡単に実装することができました。

つぎはPHPUnitを使用してみようと思います。

やり方が違ったり、もっといいやり方があるというご指摘がある方はコメントしていただけると幸いです。

最後まで読んでいただきありがとうございました。



# 参考文献

https://qiita.com/hidao/items/8576729e3a253a2cd1ea

https://beyondjapan.com/blog/2023/11/github-actions/

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions


# 次の記事
ChatGPT で elixir を学ぶ　（その1） Hello World

ChatGPT でプログラム言語を学習できないかと思って試してみました。
elixir を学んでみます。

Python のプログラムを示して、elixir に変換してもらいます。

## elixir のインストール

Ubuntu 23.10 にインストール

```bash
sudo apt install elixir
```

インストールされたバージョン

```text
$ elixir -v
Erlang/OTP 25 [erts-13.1.5] [source] [64-bit] [smp:16:12] [ds:16:12:10] [async-threads:1] [jit:ns]

Elixir 1.14.0 (compiled with Erlang/OTP 24)
```

## Python のプログラム

```py:hello.py
#! /usr/bin/python
#
print("こんにちは")
print("今日は良い天気です。")
```

実行結果

```text
$ ./hello.py 
こんにちは
今日は良い天気です。
```

## ChatGPT に問い合わせ

```text
次の Python のプログラムを elixir に変換して下さい。


#! /usr/bin/python
#
print("こんにちは")
print("今日は良い天気です。")
```

## ChatGPT の回答

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/16571807-d83b-059b-7bea-48785390332b.png)

```exs:hello.exs
IO.puts("こんにちは")
IO.puts("今日は良い天気です。")
```

実行結果

```text
$ elixir hello.exs 
こんにちは
今日は良い天気です。
```
optparseについて

 # はじめに
なぜoptparseを学ぶことになったかというと
Rubyでカレンダーを作成する際に、macの`cal`コマンドで表示されるようなカレンダーを表示したかったのでoptparseを使用しました。
# どういうものか
コマンドラインのオプションを取り扱うためのライブラリ
- コマンドライン引数は、ターミナルから実行時に引数を渡して読み込める仕組み。
- 引数は文字列として出力されます。
### OptionParser 基本的な使い方
1. OptionParser オブジェクト opt を生成する。
1. オプションを取り扱うブロックをoptに登録する。
1. opt.parse(ARGV)でコマンドラインを実際にparseする。

#### 1. OptionParser オブジェクト opt を生成する。
```ruby:sample.rb
require 'optparse'

opt = OptionParser.new
```
optparseライブラリをスクリプトに読み込みます。
これにより、コマンドライン引数の解析とオプションの処理が可能になります。
#### 2. オプションを取り扱うブロックをoptに登録する。
```ruby:sample.rb
require 'optparse'

opt = OptionParser.new
#aに渡ってきた引数をvに格納
opt.on('-a') {|v| p v }

```
OptionParse#onメソッドの引数でオプション-aを定義して、
引数が指定されたときの処理をブロック内に記述する
#### ３. opt.parse(ARGV)でコマンドラインを実際にparseする。
```ruby:sample.rb

require 'optparse'

opt = OptionParser.new
#aに渡ってきた引数をvに格納
opt.on('-a') {|v| p v }
# 真偽値を表示。
opt.parse!(ARGV)
p ARGV

$ruby sample.rb -a foo
# aに引数が渡っていますのでtrue。そしてfooを表示
=> true
["foo"]
```
ARGVは、プログラムに渡されたコマンドライン引数の配列です。
opt.parse!メソッドを使って、配列を解析し、指定されたオプションを処理します。

定義していないオプションを指定すると例外 OptionParser::InvalidOption が発生します。
引数が2つの場合
```ruby:sample.rb
require 'optparse'

opt = OptionParser.new
opt.on('-a') {|v| p v }
opt.on('-b') {|v| p v }
opt.parse!(ARGV)
p ARGV

$ruby sample.rb -a fooe  -b baz
=>true
true
["foo", "baz"]
```
OptionParser 自体は、どのオプションが指定されたかを記憶しないので、
 後の処理の方で、オプションによる条件判断を加えるには、 他のコンテナに格納します。
```ruby:sample.rb
require 'optparse'
opt = OptionParser.new
# オプションの値を格納
options = {}

opt.on('-a') {|v| options[:a] = v }
opt.on('-b') {|v| options[:b] = v }

opt.parse!(ARGV)
p ARGV
p options

$ruby sample.rb -a foo bar -b baz
=>["foo", "bar", "baz"]
  {:a=>true, :b=>true}
```
### ARGV の機能
OptionParser::Arguableモジュールのgetoptsメソッドによって
オプションや引数をシンプルに扱うだけであれば記述量が少なくて済みます。

```ruby:sample.rb
require 'optparse'

# 引数にオプションa, オプションbを指定
params = ARGV.getopts("a:b:")
p params

$ruby sample.rb -a foo -b bar
=>{"a"=>foo, "b"=>"bar"}
```
ワンライナーでオプションと引数を受け取り、Hashとして取得できます。オプションが引数をとる場合は後ろに ":" を付けます。


# 参考サイト
https://docs.ruby-lang.org/ja/latest/library/optparse.html 

https://docs.ruby-lang.org/ja/latest/class/OptionParser=3a=3aArguable.html

https://docs.ruby-lang.org/ja/latest/method/OptionParser=3a=3aArguable/i/getopts.html
VSCodeのVueプラグインがv2になってVolarが不要になった

VSCodeを開いたら、Volarはもう不要だよという表示が出ておりました。

![スクリーンショット 2024-03-03 8.22.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114899/f3725059-f286-b540-f914-277bbc5f06ca.png)

Show Extensionを押すとVolarの設定画面が開くのでアンインストールしちゃいましょう。

![スクリーンショット 2024-03-03 8.22.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114899/7df35b63-4bd7-3650-a93c-0e25b523b535.png)

Volarの機能がVueプラグイン本体に取り込まれたので不要になったよとのこと。
https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md#200-202432

フロントエンドの開発環境がほんのちょっとずつだが整理されていってて嬉しい。
ABC343回答メモ

# 0.はじめに
　スポンサーを冠さないコンテスト。
 全体的に歯ごたえあり目な気がしつつもとりあえず
 A~Dは解けました。
　E問題はあまり見ない3次元系の問題だったため
 いろいろ模索しましたが、うまい解き方が見つかりませんでした。
 解説を見ると、愚直に全列挙ベースで考えるみたいですね・・・。

 Cでてこずったこともあり、レートは13減で966となりました。


# 1.A - Wrong Answer
　一風変わった問題。
 正解の種類が8通りもある為、一瞬戸惑いましたが
 まぁ、A+Bが0なら1それ以外なら0を出力することで
 ACとなりました。

　https://atcoder.jp/contests/abc343/submissions/50771487


# 2.B - Adjacency Matrix
　B問題から無向辺とか出てきたむずいのか・・・とおもいきや
 インプット表の1が立っている位置を表示すればいいだけの問題でした。

　どちらかというと表示方法に難儀して長くなりましたが
 戸惑いましたが、今思えば、一旦リストに格納して表示すればよかったなと
 思いました。

　https://atcoder.jp/contests/abc343/submissions/50783851

# 3.C - 343
　一見大変そうでしたが、試しに組んだら意外に簡単にいけました。
 【考え方】
　　・変数ansに0をセット
　　・iを1から10の6乗までカウントアップするFor文を回す
  　　・iの3乗がNを超過したらその時点のansを表示して終了
    　・iの3乗が回文数の時、ansにiの3乗をセット

　と、簡単な実装だったのですが、10の18乗の時の答えが
 やけに小さく感じたので、色々悩んだのですが、回文立法数を
 列挙すると、該当する数がない桁数も多い事に気づき
 そのまま提出したらACでした。
 ここの悩みのせいでだいぶロスし、レートダウンにつながったことが
 悔やまれます・・・。
 
　https://atcoder.jp/contests/abc343/submissions/50806284

# 4.D - Diversity of Scores
　高橋君の異能の凄さと、趣向の特異さに戸惑い問題の理解が
 追いつきませんでしたが、一旦おいておいて例題を参照し
 内容を理解。まぁ、辞書つかえば何とかなるかなと開始。

 【考え方】
 　・人毎の現在の得点数の辞書DNを用意
  　　→デフォルト辞書で最初は全員0点
   ・点数ごとの該当人数の辞書DTを用意
  　　→最初は0点がN人
   ・点数の種類数変数ansを用意
  　　→最初は1種類
　 -以下T回繰り返し
  　・A・Bを読み込み
    ・変数pre(この回で1減る得点種)にDN[A]をセット
    ・変数aft(この回で1増える得点種)にDN[A]+Bをセット
    ・DN[A]にB加算(Aさんの得点を更新)
    ・DT[pre]を1減算
    　→この操作でDT[pre]が0になったら、ansから1減算
    ・DT[aft]を1加算
    　→この操作でDT[aft]が1になったら、ansに1加算
    ・ans(この回終了後の得点種数を表示)
     
　考え方どおりの実装で問題なくAC頂きました。

　https://atcoder.jp/contests/abc343/submissions/50816601


以上
Coravel Queueキュー

Coravelは、タスク/ジョブのスケジューリング、キューイング、キャッシング、メーリング（およびそれ以上！）などの高度なアプリケーション機能に簡単にアクセスして使用できるようにすることで、開発者が.NETアプリケーションを迅速に起動して実行するのを支援します。その文法はシンプルで表現力豊か、かつダイレクトです。
![alt 画像](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRDiaHo0eVlzdHBXcicmbehTcKSnFBzrjWPibKictY5VXW0jVkUD4eWniaCBqbkibTy9uoMAJibZQdiabJj4tQ/640?wx_fmt=png&from=appmsg)

Coravelは、簡単なQueueメカニズムも提供しています。タスクをキューに入れることで、システムが自動的に30秒ごとに実行し、キュー内のタスクをすべて実行完了します。
キューを使用するためには、まずサービスを注入する必要があり、Services.AddQueueで完了します。第1の使用方法は、サービスコンテナからIQueueオブジェクトを取得し、QueueTaskメソッドを介して具体的な実行タスクをキューに追加し、待機時間サイクル内で呼び出されることを待つことです。第2の方法は、IInvocableWithPayloadペイロードインタフェースを継承したペイロードクラスを定義することで、これにより、タスク機能が集中的に処理され、隔離性が向上します。当然、キューに入れる際には、IQueueのQueueInvocableWithPayload<>方法を介して完了します。

```csharp
using Coravel;
using Coravel.Invocable;
using Coravel.Queuing.Interfaces;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddQueue();
builder.Services.AddTransient<MyQueueInvocable>();

var app = builder.Build();

app.MapGet("/addqueue1", (IQueue queue) =>
{
    var guid = queue.QueueTask(() =>
    {
        app.Logger.LogInformation("シンプルなQueue");
    });
    app.Logger.LogInformation(guid.ToString());
});

app.MapGet("/addqueue2", (IQueue queue) =>
{
    var guid = queue.QueueInvocableWithPayload<MyQueueInvocable, string>("Queue開始、追加時間：" + DateTime.Now);
    app.Logger.LogInformation(guid.ToString());
});

app.Run();
```
```csharp
/// <summary>
/// ペイロード
/// </summary>
public class MyQueueInvocable : IInvocable, IInvocableWithPayload<string>
{
    readonly ILogger<MyQueueInvocable> _logger;
    public MyQueueInvocable(ILogger<MyQueueInvocable> logger)
    {
        _logger = logger;
    }
    public string Payload { get; set; } = string.Empty;
    public async Task Invoke()
    {
        _logger.LogInformation(Payload + "、実行時間：{time}", DateTime.Now);
        await Task.CompletedTask;
    }
}
```
システムのデフォルトのキュースケジュール時間は30秒ですが、appsettings.jsonに以下の設定を追加することでこの時間を変更することができます。

```json
"Coravel": {
  "Queue": {
    "ConsummationDelay": 5
  }
}
```
(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247487806&idx=1&sn=c400e088199bd689fa027a5d939f4d36&chksm=9f004e14a877c7023d15802825974602076a21ccb29ca65256be3ab9c5aab4fa2da9227538af&token=1232314813&lang=zh_CN#rd
JetpackCompose TextFieldでキーボードの決定アイコンを変える方法

`TextField`でキーボードの決定アイコンを変える方法です。


```.kt
@Composable
fun CopyButton() {
    var text = remember { mutableStateOf("") }
    TextField(
        value = text.value,
        onValueChange = { text.value = it },
        label = { /*TODO*/ },
        modifier = Modifier.padding(16.dp),
        keyboardOptions = KeyboardOptions(
            keyboardType = KeyboardType.Text,
            imeAction = ImeAction.Done,
        )
    )
}
```

こちらのコードの`imeAction = ImeAction.Done`
ここの部分で変更することが可能です。

# ImeActionの種類

https://developer.android.com/reference/kotlin/androidx/compose/ui/text/input/ImeAction

| ImeAction | 画像 |
|:-----------|------------:|
| None       | ![スクリーンショット 2024-03-03 8.14.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/2ebb0bc2-0c2a-6796-77d0-8f5f76b20398.png) |
| Default     | ![スクリーンショット 2024-03-03 8.17.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/398e7a7c-c421-a4a2-4a9f-3b153cdeda48.png) |
| Go       | ![スクリーンショット 2024-03-03 8.18.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/5f1a770a-96dd-97d4-05cb-102808e4dde7.png) |
| Search         | ![スクリーンショット 2024-03-03 8.20.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/7165ca12-0d79-537e-015e-6c75cc6681e0.png) |
| Send       | ![スクリーンショット 2024-03-03 8.21.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/24ee5130-2460-8784-55ce-06e0c24a41cc.png) |
| Previous    | ![スクリーンショット 2024-03-03 8.22.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/31daa272-4989-6ac0-a20a-01cf629e260a.png) |
| Next    | ![スクリーンショット 2024-03-03 8.23.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/bf076916-f9e9-2996-d080-fa6ab979c13c.png) |
| Done    |   ![スクリーンショット 2024-03-03 8.24.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/5a08b4a2-f495-1e19-6908-392c12be29c9.png)   |
Coravel Scheduleのタスクスケジューリング

Coravelは、タスク/ジョブのスケジューリング、キュー、キャッシュ、メール（その他もろもろ！）などの高度なアプリケーション機能を容易にアクセスし、使用しやすくすることで、開発者が.NETアプリケーションを迅速にスタートアップし実行することを支援します。シンプルで表現力豊か、そして直感的な構文を持っています。
![alt 画像](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRDiaHo0eVlzdHBXcicmbehTcKSnFBzrjWPibKictY5VXW0jVkUD4eWniaCBqbkibTy9uoMAJibZQdiabJj4tQ/640?wx_fmt=png&from=appmsg)
以下は簡単な使用例で、スケジューラーをインジェクションし、ミドルウェア内でスケジュールを定義することで、シンプルなタイミングでの使用を実現しています。
```C#
using Coravel;
var builder = WebApplication.CreateBuilder(args);//ビルダーインジェクション
builder.Services.AddScheduler();
var app = builder.Build();//ミドルウェアの使用
app.Services.UseScheduler(scheduler => {
    scheduler.Schedule(
        () => Console.WriteLine("2秒ごとに実行")
    )
    .EverySeconds(2);
});
```

スケジューリングの使用頻度は以下のメソッドを参照してください：
- EverySecond() - 1秒ごとに実行
- EveryFiveSeconds() - 5秒ごとに実行
- EveryTenSeconds() - 10秒ごとに実行
- EveryFifteenSeconds() - 15秒ごとに実行
- EveryThirtySeconds() - 30秒ごとに実行
- EverySeconds(3) - 3秒ごとに実行
- EveryMinute() - 1分ごとに実行
- EveryFiveMinutes() - 5分ごとに実行
- EveryTenMinutes() - 10分ごとに実行
- EveryFifteenMinutes() - 15分ごとに実行
- EveryThirtyMinutes() - 30分ごとに実行
- Hourly() - 1時間ごとに実行
- HourlyAt(12) - 毎時12分に実行
- Daily() - 毎日深夜に実行
- DailyAtHour(13) - 毎日13時UTCに実行
- DailyAt(13, 30) - 毎日13時30分UTCに実行
- Weekly() - 毎週実行
- Monthly() - 毎月実行（月の1日の深夜に実行）
- Cron("* * * * *") - Cron式で実行

さらに、`IInvocable`インターフェイスを実装したクラスを定義することで、スケジューラーの機能をより洗練させることができます。無引数のコンストラクターを持つ実装はインジェクションが必要ですが、引数のあるものは必要ありません。
```C#
using Coravel;using Coravel.Invocable;using Coravel.Scheduling.Schedule;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScheduler();//引数なしInvocableクラスをここで注入
builder.Services.AddTransient<MyInvocable2>();
var app = builder.Build();
app.Services.UseScheduler(scheduler => {
    scheduler
    .Schedule<MyInvocable2>()
    .EverySeconds(2);

    scheduler
    .ScheduleWithParams<MyInvocable>(3)
    .EverySeconds(3);
});
app.Run();

public class MyInvocable : IInvocable{
    readonly ILogger<MyInvocable> _logger;
    readonly int _seconds;
    public MyInvocable(ILogger<MyInvocable> logger, int seconds)
    {
        _logger = logger;
        _seconds = seconds;
    }
    public Task Invoke()
    {
        _logger.LogInformation("***{int}秒ごとに実行", _seconds);
        return Task.CompletedTask;
    }
}

public class MyInvocable2 : IInvocable{
    readonly ILogger<MyInvocable> _logger;
    public MyInvocable2(ILogger<MyInvocable> logger)
    {
        _logger = logger;
    }
    public Task Invoke()
    {
        _logger.LogInformation("---2秒ごとに実行");
        return Task.CompletedTask;
    }
}
```
Coravelのスケジューリングはシンプルで直接的であり、いくつかの軽量なスケジューリングに利用できます。スケジューリングの詳細については、https://docs.coravel.net/Scheduler/ をご参照ください。

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247487756&idx=1&sn=c47470e9e90bd4e56bf7e2ed5a55fef7&chksm=9f004e26a877c730dc2537034c571344d485fe15bd0220f4d012a4a5246b6cb0c3927add141e&token=1232314813&lang=zh_CN#rd
Dockerコマンドまとめ

# はじめに
最近dockerを使うことがあったので、dockerのコマンドについてまとめていきたいと思います。

# ドッカーコマンド集

## docker-compose exec サービス名 コマンド名 

サービスのコンテナ内でコマンド実行する

例: docker-compose app bash
appというサービスのコンテナでbashシェルを起動する

## docker-compose down 

コンテナやネットワークの停止と削除

## docker ps -a

停止しているコンテナも含めて表示

## docker-compose --version

docker-composeのバージョンを確認する

## docker-compose up -d --build

コンテナをビルドして立ち上げる

## composer create-project プロジェクト名

プロジェクトの作成

## docker-compose down --volumes

ボリュームの削除

## 終わりに

今後もコマンドを追加していこうと思っているので
ぜひ参考にしてください！
STM32C011で1GPIO(I2C)で遊ぶ。(STM32C011J4M7)


目的
i2Cのテスト

結果

![o_cop975.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3bd1e6e9-5c8a-edf3-e477-1bd851e57c2f.jpeg)



受信

```c++


//I2C_1GPIO_V1_C011_1

#include <Arduino.h>
#include <Wire.h>


//初期化
void setup() {

  delay(3000); //not delete

  //i2cの初期化
  Wire.setSDA(19);   //PA10
  Wire.setSCL(18);   //PA9
  Wire.begin( (0x80)>>1 );  //I2Cスレーブアドレスの設定
  Wire.onReceive(receiveEvent); //データが来ると呼ばれる関数

  //GPIOの初期化
  pinMode(PB7, OUTPUT);

} //setup


//メインループ
void loop() {
} //loop


//レシーブイベント
void receiveEvent(int howMany) {

  int x = Wire.read(); //I2C受信データの読み込み

  //GPIOへビットを設定
  digitalWrite(PB7,  x & 0x01);

}//receiveEvent



```

送信

```c++


//I2C_PUT_0_1_C011_1


//インクルド
#include <Arduino.h>
#include <Wire.h>


//初期化
void setup() {

  delay(3000);//マッポの手先、消したら、いかんぜょ(斎藤由紀風)

  //i2cの初期化
  Wire.setSDA(19); //PA10
  Wire.setSCL(18); //PA9
  Wire.begin();    //I2Cの初期化

} //setup


//メインループ
void loop() {

  //'0'転送
  Wire.beginTransmission( (0x80)>>1 );
  Wire.write('0');
  Wire.endTransmission();
  delay(1000); //1秒待つ

  //'1'転送
  Wire.beginTransmission( (0x80)>>1 );
  Wire.write('1');
  Wire.endTransmission();
  delay(1000); //1秒待つ

} //loop



```
CentOS7 minimal viのシンタックスハイライトを使えるようにする

CentOS7 minimalをインストールした場合、viがシンタックスハイライト非サポートになっています。

viの機能のサポート/非サポートは、「:version」のコマンドで分かります。
サポートする機能には「+」、そうでない機能には「-」が表示されます。

![スクリーンショット 2024-03-03 7.47.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/160f0da4-9b58-4a84-13ff-6f276690ff4e.png)

機能サポートの有無はコンパイル時のオプションによって決まり、後から追加できません。
以下の手順でシンタックスハイライトをサポートしているvimをインストールします。
現在のviをリネームし、退避した後、vimのシンボリックリンクを作成します。
```
yum install vim
mv /bin/vi /bin/vim-tiny
ln -s /usr/bin/vim /bin/vi
```

以上です。
Flutter ビルドしたaabファイルがリリースモードにならない

# Flutterアプリをリリースモードでビルドする方法

以前アプリをビルドした際に、リリースモードでビルドがされていないことがあり、リリースモードでビルドをするまでに少し時間がかかりました。この記事では、Flutterでのアプリをリリースモードでビルドする方法についてご紹介します。

## 目次

1. [はじめに](#はじめに)
2. [リリースモードでのビルド設定](#リリースモードでのビルド設定)
   1. [Androidのビルド設定](#androidのビルド設定)
   2. [ビルドタイプの確認と修正](#ビルドタイプの確認と修正)
3. [まとめ](#まとめ)

## はじめに

Flutterで開発したアプリをリリースする際、正しくリリースモードでビルドされていることが重要です。デバッグモードでビルドされたアプリは、パフォーマンスが最適化されておらず、セキュリティ上のリスクも高まります。この記事では、Androidアプリのビルド設定を中心に説明します。

## リリースモードでのビルド設定

### Androidのビルド設定

FlutterプロジェクトのAndroidアプリをリリースモードでビルドするためには、`android/app/build.gradle`ファイルの設定を確認し、必要に応じて修正する必要があります。

#### ビルドタイプの確認と修正

`build.gradle`ファイルを開き、`buildTypes`セクションを探します。`release`ブロック内で`signingConfig`が`debug`に設定されている場合、アプリはデバッグモードでビルドされます。これを`release`に変更することで、リリースモードでビルドされるようになります。

- デバッグモードでのビルド設定例:

    ```gradle
    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now,
            // so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
    ```

- リリースモードでのビルド設定例:

    ```gradle
    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the release keys.
            signingConfig signingConfigs.release
        }
    }
    ```

## まとめ

Flutterでのアプリ開発では、リリース前にリリースモードでのビルドが正しく行われていることを確認することが重要です。`android/app/build.gradle`ファイルの`buildTypes`セクションを確認し、リリースビルドに適した設定になっているかを確認しましょう。
【Flutter】LINEを起動してメッセージを送る

## はじめに
LINEでメッセージを送る機能をFlutterアプリに追加したいと思ったが、最新の情報が少なかったので投稿日（2024/3/3）時点でうまくいった方法をメモ。

## `url_launcher`を入れる

pubspec.yamlに`url_launcher`を追加

```
dependencies:
  url_launcher: ^6.2.5
```

## ボタン作成
それっぽいボタンを作成
```
ElevatedButton.icon(  
    onPressed: () {},  
    style: ElevatedButton.styleFrom(  
      backgroundColor: Colors.green,  
      foregroundColor: Colors.white,  
    ),  
    icon: const Icon(Icons.messenger_rounded, color: Colors.white,),  
    label: const Text('LINE', style: TextStyle(fontWeight: FontWeight.bold),)  
)
```

## `url_launcher`の処理を作成 
```
static Future<void> launchLineMessage(String url) async {  
  final uri = Uri.parse(url);  
  if (await canLaunchUrl(uri)) {  
    await launchUrl(
    uri,
    mode: LaunchMode.externalApplication
    );  
  } else {  
    print('URL起動エラー');  
  }  
}
```
- URLをuriに変換
- `canLaunchUrl`でそのuriが使用可能かチェック
- 上記がtrueだったら起動。

## LINE のURL スキームを準備

[LINE Developers ](https://developers.line.biz/ja/docs/line-login/using-line-url-scheme/#opening-chat-screen)からテキストメッセージを送るURLスキームを持ってくる。
```
final String lineUrl = 'https://line.me/R/share?text={text_message}';
```
上記のURLスキームで送信先を選択画面を開く。`{text_message}`に設定されたテキストメッセージを送信できる。

## Buttonに処理を追加 
作成したLINEっぽいボタンに処理を追加する。
```
ElevatedButton.icon(  
    onPressed: () {  
    //   送りたいメッセージを追加  
      final String addTextUrl = '$lineUrlこれはテスト';  
    //   LINEの処理を追加  
      launchLineMessage (addTextUrl);  
    },  
    style: ElevatedButton.styleFrom(  
      backgroundColor: Colors.green,  
      foregroundColor: Colors.white,  
    ),  
    icon: const Icon(Icons.messenger_rounded, color: Colors.white,),  
    label: const Text('LINE', style: TextStyle(fontWeight: FontWeight.bold),)  
)
```

## 成功
![IMG_EA433A932FD7-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/fe3c2a2c-3252-536d-293d-f4b24cbab8a1.jpeg)



参考
https://flutter.keicode.com/basics/urllauncher.php
https://zenn.dev/gahaku200/articles/81a531f28e4701
ありがとうございます。
【HTML & CSS】ねぷのフラグ

## ねぷのフラグとは？

これのこと

https://www.compileheart.com/neptune/v2/system/img/flag1.jpg

フラグが立ったり、折れたりして状態が分かりやすい素晴らしいUI

## 成果物

![nep-flag.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/121a176f-9e07-e9a5-5414-820af1f93224.gif)

https://mogamoga1024.github.io/NepFlag/

## コード

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>nep flag</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <input type="checkbox" id="nepu-checkbox" class="nep-flag">
  <label for="nepu-checkbox">ぴょいーん</label>
</body>
</html>
```

```css
label {
  font-size: 24px;
  line-height: 50px;
  -webkit-tap-highlight-color: transparent;
}

input[type="checkbox"].nep-flag {
  display: none;
}
input[type="checkbox"].nep-flag + label::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  background-image: url("./flag-off.svg");
  background-size: cover;
  width: 50px;
  height: 50px;
  -webkit-tap-highlight-color: transparent;
}
input[type="checkbox"]:checked.nep-flag + label::before {
  background-image: url("./flag-on.svg");
}
```

## チラ裏

このゲーム知ってる人いんのかな
【Android】jetpack composeのCanvas内でTextを入力する【kotlin】

# はじめに
今回この記事を書くりゆは二つで、
今回やりたい内容を調べた時にサクッと簡単には出てこなかった事と、
簡単な内容ではあるのですが アウトプットすることで自分の中に印象付けようと思いこの記事を書きました。

# 実践

Jetpack composeではない以前のやり方だと、
```
canvas.drawText("テキスト", 100, 100, paint);
```
といった感じで使っていたのですが、

Jetpack composeでは

```
 val textMeasure = rememberTextMeasurer()

   Canvas(
            modifier = Modifier.fillMaxSize(),
            onDraw = {
                drawText(
                    textMeasurer = textMeasure,
                    text = "テキスト",
                )
            }
```
こんな感じでCanvasのonDraw内で **drawText()** メソッドを使用することでCanvas内でTextを使うことができます。
MySQL(データベース)をJavaのプロジェクトで使う方法／JDBC導入方法

この記事は…
**MySQL8.xをEclipseで作成した動的Webプロジェクト（Javaのプログラム）にて使いたいときの手順を紹介します！
及び、JDBCを取得して、MySQL8.xとJDBCの接続する手順も含みます。**

# １．JDBCドライバの取得(Connector/J)
（１）公式サイトにアクセスします。
https://dev.mysql.com/downloads/connector/j/

（２）「Select Operating System」は、「Platform Independent」を選択します。
その後、ZIPと書いてある方をダウンロードします（画像の場合、下段が対象です）。
![スクリーンショット 2024-03-03 022237.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1162001/31e18f9f-807e-d4ed-0d8f-9f2f5508768e.png)

（３）画面の下にある「No thanks, just start my download.」をクリックし、JDBCドライバをダウンロードしてください。
![スクリーンショット 2024-03-03 022339.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1162001/b80a107d-daa4-0d86-6356-51914dd3ce12.png)

（４）ダウンロードしたJDBCドライバのZIPファイル「mysql-connector-j-x.x.x.zip」を展開してください。
展開したフォルダに、「mysql-connector-j-x.x.x.jar」があることを確認します。
![スクリーンショット 2024-03-03 023443.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1162001/bc6876e2-59b6-eb8b-a360-9665bb2bcba4.png)
**これで、JBDCドライバの取得は完了しました！**

**以降の作業は、Eclipseも使用します。**
# ２．JARファイルを動的Webプロジェクトに入れる
取得した「mysql-connector-j-x.x.x.jar」ファイルを「WEB-INF/lib」に配置します。
![スクリーンショット 2024-03-03 023905.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1162001/1d93ac61-5da5-f1b0-c854-ec0a7c98a321.png)


# ３．データ接続が正常に出来ているかを確認する
今回は、接続を確認するクラスを作成して接続を試みます。

（１）動的Webプロジェクトの「src」フォルダに、以下のようなクラスを作成します。
<データベース名>、<ユーザー名>、<パスワード>は自身の環境に合わせてください。

※データベース名を確認するには…「MySQL Command Line Client」を起動して、「SHOW DATABASES;」コマンドを実行するとデータベース名の一覧を確認できます。※

```ConnectSample.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectSample {

	public static void main(String[] args) {
		//DB接続用定数
		String DATABASE_NAME = "<データベース名>";
		String PROPATIES = "?characterEncoding=UTF-8&useSSL=false";
		String URL = "jdbc:mySQL://localhost/" + DATABASE_NAME + PROPATIES;
		//DB接続用・ユーザ定数
		String USER = "<ユーザー名>";
		String PASS = "<パスワード>";

		try {
			//MySQL に接続する
			Class.forName("com.mysql.cj.jdbc.Driver");
			//データベースに接続
			Connection conn = DriverManager.getConnection(URL, USER, PASS);

			// データベースに対する処理
			System.out.println("データベースの接続に成功!");

		} catch (SQLException | ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}
```

（２）ConnectSampleクラス上で、右クリックし、「実行 ＞ Javaアプリケーション」を実施してください。
**コンソールに、「データベースの接続に成功！」と表示されれば接続は成功です！**
【JavaScript】forEach, map, filter, reduce, findを正しく理解する

## はじめに
こんにちは。現在バンクーバーで未経験からエンジニア就職を目指している@JamesCroissantです。今はReact×TypeScriptを利用したフロント周りの開発中心の勉強をメインで行っています。


## きっかけ
JavaScriptを復習していて、自分自身しっかり理解していないと感じたので、コーディング面接対策として自分が調べたことをまとめます。


## この記事の対象者
・JavaScript, React初心者
・forEach, map, filter, reduce, find関数の違いがざっと抑えたい人
・JavaScriptのコーディング面接対策をしたい人

## この記事の目標
・forEach, map, filter, reduce, find関数の違いを理解する
・Reactのアプリ開発で使えるようにする


## forEach
forEachは配列の各要素に対して関数を実行するが、__新しい配列を返さない__。
```js
const numbers = [1, 2, 3];

numbers.forEach(function(number) {
    console.log(number);
});

// 1、2、3の順に出力される
```

### Reactでの使い方
**ログ出力**や**外部APIへのデータ送信**などに使うことができる。forEachは新しい配列を返さないため、通常はJSX内で直接使用されることはあまりない。代わりに**map関数**を使用する。


## map
mapは配列の各要素に関数を適用し、その結果から**新しい配列を作成**する。
```js
const numbers = [1, 2, 3];

const doubled = numbers.map(function(number) {
    return number * 2;
});

// 各要素に2が掛けられ、doubledに格納される
// doubledは[2, 4, 6]
```


### Reactでの使い方
**コンポーネントのリストをレンダリングする時**によく使用する。
例えば、Todoリスト`<li>`タグの形に変換（新しい配列を作成）して、JSX内で表示してしたい時など。

```react
function TodoList({ todos }) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
}
```



## filter
filterは条件に一致する要素だけからなる**新しい配列を作成**する。
```js
const numbers = [1, 2, 3];

const odds = numbers.filter(function(number) {
    return number % 2 !== 0;
});

// 各要素が奇数になるかチェック、Trueの場合にoddsに格納される
// oddsは[1, 3]
```
### Reactでの使い方
**特定の条件に合致する配列要素を選択する**ためによくmap関数と組み合わせて使われる。
例えば、Todoリストで**タスクが完了している場合**リストを表示するなど。

```jsx
function CompletedTodos({ todos }) {
  return (
    <ul>
      {todos.filter(todo => todo.completed).map(filteredTodo => (
        <li key={filteredTodo.id}>{filteredTodo.text}</li>
      ))}
    </ul>
  );
}
```



## reduce
reduceは配列の各要素に対して関数を適用し、**単一の値（累積結果）を生成**する。
```js
const numbers = [1, 2, 3];

const total = numbers.reduce(function(accumulator, currentValue) {
    return accumulator + currentValue;
}, 0);

// 0は初期値を表す
// accumulatorはreduceがこれまで計算してきた累積の値
// currentValueは配列の現在処理している要素

// 合計6
```

### Reactでの使い方
状態やpropsから複雑な計算を行い、その結果をコンポーネント内で表示したい時に使用される。
例えば、オンラインショッピングのカート内の各商品の**合計金額を計算して表示させる**時など。

```jsx
const Cart = ({ items }) => {
  // reduceを使用して、カート内の全商品の合計価格を計算
  const total = items.reduce((sum, item) => sum + item.price, 0);

  return (
    <div>
      <h2>カート内の合計: ¥{total}</h2>
      {/* 他のカートの要素 */}
    </div>
  );
};
```


## find
findは **条件に一致する最初の要素**を返す。一致する要素がなければ、**undefined**を返す。
```js
const numbers = [1, 2, 3];

const found = numbers.find(function(number) {
    return number > 1;
}, 0);

// foundは2
```

### Reactでの使い方
リストから特定のアイテムを選択して詳細を表示する場合などに使用される。
ユーザーのリストがあり、その中から**特定のIDを持つユーザーを見つけて詳細を表示したい時**など。

## 最後に
いかがだったでしょうか。

今回はforEach, map, filter, reduce, findの違いについてReactでの使用例と合わせて解説をしました。

実際にReactでアプリ開発をする時は、map, filter関数をメインで扱うことが多いので、最低限この2つはマスターしていきたいですね。
[コラム]光回線の乗り換えをした（楽天ひかり→とくとくBB）

初めて光回線の乗り換え(事業者変更)をしたので備忘録を兼ねて記事に

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/b7ebc767-19c6-ebb0-232d-88e6f411c959.png" width="300"><br>快適
<br>

今の住居へ引っ越した際に契約した楽天ひかりが無料解約期間になったので、
別の回線事業者へ乗り換えることにした。

## 乗り換え先の選定
乗り換え先の条件は

- 乗り換え元の楽天ひかり（税込み5,280円）より安い

- いつでも解約可能（違約金がない）

の2点だけで選んだ。

(ちなみに、楽天ひかりを選んだのは当時1年間無料キャンペーンがあったため)
<br>

正直そこまで乗り換え先選びは熟考しておらず、
回線速度もADSLやWiMAXと比べればどの光コラボでも十分快適だろうと、Google検索の上位に表示される比較サイトから安そうなところを選んだ。

サイトを見たところ、GMOとくとくBBが工事費も掛からず一番安そう(税込み4,818円)で、
かつ解約時の違約金もないようだったので、リンクされたキャンペーンページから申し込みをした。

話がそれるが
乗り換えの繋ぎに利用していた、Wi-FiルーターレンタルサービスのDMMいろいろレンタルがサービス終了してしまっていた。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/6f5182a9-51e4-2123-9581-20a5eecf9947.png)
少し悲しい
(最近はモバイル回線が安くなり、繋ぎにはテザリングで事足りるから需要がなくなったのだろうか？)

## 乗り換え手続き
乗り換えの手続きは
楽天ひかり(楽天ブロードバンド)で事業者変更承諾番号の発行手続きを行い、
とくとくBBのキャンペーンページから発行された番号と個人情報を入力して申込するだけだった。

その後、開通工事の日程調整の案内が届き、申込日から2週間ほどで開通した。
開通工事も無派遣工事のため、自宅で待機する必要もなく順調に乗り換えができた。（と思っていた）
<br>
開通工事から数日後、戸惑ってしまったのが乗り換え元である楽天ひかりの解約のタイミングについて。
事業者変更が完了すれば自動で解約されるとの記載があったため、
開通したタイミングで解約されるものと考えていたが、解約された様子がない。
開通前後で回線の切断もなかったようだったので、正しく乗り換えができたのか不安に。
<br>
後から気づいたのだが、これは楽天ひかりの契約期間が「～開通日まで」ではなく
「～開通日の月末まで」契約が継続するようで、私の勘違いだった。

そのため、開通後とくとくBBの回線に繋がっていると思っていたのは、実は楽天ひかりの回線のままで、
楽天ひかりが解約された日からインターネットへの接続ができなくなり、少し焦ってしまった。

接続するにはルーターのPPPoE認証の情報を
楽天ひかりからとくとくBBの情報に変更する必要があった。
(接続先ユーザー名/パスワードは開通工事の案内に記載されていた。)

↓ルーター(BUFFALO)の設定画面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/65c27212-6260-2a38-c31f-4a777c9b62f4.png" width="600">


また、IPアドレス取得方法(IPv4 over IPv6の接続サービス)も
楽天ひかりととくとくBBでは異なるため、クロスパスからv6プラスへ変更した。
※「インターネット@スタートを行う」でも接続できた。
![バッファロー2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/43f03cd2-a193-e7ca-08d6-02824e2bc8d0.png)


## フロー
乗り換えの流れは下のイメージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/02e9ef68-6704-a09b-0a86-20c240e9eaa2.png" width="500">

とくとくBBのv6プラスは楽天ひかりの契約が解除されるまで手続き中のステータスだったので、乗り換え元が解除されないと有効にできない様子？


## おわりに
とくとくBBに乗り換え後も特に問題なく使えているので満足している。

後は11か月後のキャッシュバックだけ貰い損ねないように気を付ける。

また、とくとくBBは無料レンタルのWi-Fiルーターが必ずセットで付いてくるようで、
解約の時は忘れず返却するように。（中身確認だけして押し入れ行き）
SML#インストール for WSL2(Ubuntu)

大堀 淳先生のコンパイラ[本](https://www.kyoritsu-pub.co.jp/book/b10003349.html)([動画](https://www.youtube.com/watch?v=gsJAqde7Rs4&list=PLp1bKoc7XHdQwbHaUzMryG6WpnN4JdR6P))では、SML#言語を用いてコンパイラ実装を行っていきます。公式サイトに記されていたインストール手法ではすんなり行かない箇所がありましたので、うまく行った手法を記載しておきます。

# インストール方法
まず、SML#の依存関係にあるライブラリやビルドに必要なライブラリ等をインストールしましょう。
```shell
$ sudo apt install -y \
    build-essential \
    wget \
    libmassivethreads-dev \
    libgmp-dev \
    llvm-11
```
SML#のコンパイルと実行には、`MassiveThreads`・`GMPライブラリ`・`LLVM 11`が必要なのでそれぞれインストールしています。

```shell
$ wget https://github.com/smlsharp/smlsharp/releases/download/v4.0.0/smlsharp-4.0.0.tar.gz \
    && tar -xzf smlsharp-4.0.0.tar.gz \
    && cd smlsharp-4.0.0 \
    && ./configure --with-llvm=/usr/lib/llvm-11 \
    && make -j$(nproc) \
    && sudo make install
```
公式サイトにはaptコマンドでSML#コンパイラをインストール、アップデートさせる手法が記載されています。しかし、SML#自体のコンパイルに使用されたGCCのバージョンが少し古くなっており、SML#コンパイラでのコンパイル時に使用するGCCのバージョンと合わず、リンク時で使用される[LTO(Link Time Optimization)](https://qiita.com/kaityo256/items/a822fc462a4de6ddd8e7)のバージョンが一致しないことによるエラーが発生しました。そのため、ソースからビルドする方がいいと思います。

また、configure実行時に、オプションを用いて設定内容を指定しています。このオプションについては--helpを引数にして実行する（`./configure --help`）と確認できるものの一つで、使用するLLVMのパスを指定するものです。未設定だと、自動的に最新のLLVMが使用されてconfigureの実行が中止してしまいました。

makeコマンドに-jオプションとプロセスの数を指定する（例：`make j4`）と、複数のスレッドでビルドされることになり、コンパイルやビルドの処理速度が向上します。また、nprocコマンドを用いると利用可能なプロセス数を知ることができ、動的に最適な数が指定できます。

```shell
$ smlsharp -v
# ....複数行の説明
# SML# 4.0.0 (2021-04-06 05:12:50 JST) for x86_64-pc-linux-gnu with LLVM 11.1.0
# ....複数行の説明
```
このような表示が出ればインストール成功です！

# サンプルプログラムの実行
きちんとコンパイルできるか確認するため、サンプルプログラムを実行します。
`smlsharp-4.0.0/sample`内に複数のサンプルプログラムがあります。今回はその中の`callback`をコンパイル・実行してみましょう。
```shell
$ make
$ ./callback
# f1
# h1
# f2
# h2
# f3
# h3
# g1
# g2
# g3
# g4
```
makeコマンドでコンパイル、生成された実行可能ファイルで実行できたらバッチリです！

# まとめ
SML#をインストールして、楽しくコンパイラを勉強していきましょう！

# 参考文献
[SML# のインストール](https://zenn.dev/hiroyukim/scraps/073ad85ee84f43)
[関数型プログラミング言語SML # の導入（Windows PC上のプログラミング環境整備 第4回）](https://www.youtube.com/watch?v=_zaB8E48sEU)
[configureの設定を変更してみる：仕事で使える魔法のLAMP（12）](https://atmarkit.itmedia.co.jp/ait/articles/1107/01/news139.html)
[make -jの値には何を指定するべき？それと注意事項。](https://enjoysoftware.hatenablog.com/entry/2020/01/19/124814)
GitHub PagesでBootStrapテンプレートを使用して爆速無料でWEBページを作成する導入（初心者向け）

## とにかく手っ取り早く無料でポートフォリオサイトを作成したい
今回は、BootStrapのテンプレートをGithubPagesで使用する方法を紹介します。BootStrapの記述方法やHTML,CSSのデザインカスタムまでは扱わないので、あくまでも導入までという点ご了承ください。**やっていることはGithubPagesが最初に表示するindex.htmlにテンプレート側のURLを仕込んで、テンプレート側のindex.htmlを表示させるようにしたい**ってことです。
あと今回初投稿です。読みにくさもあるかと思いますがよろしくお願いします！
### 対象者
・就職活動や個人実績のアピールとしてポートフォリオサイトを作りたいけど一から作成するのは少ししんどい、と感じる人
・とにかく作成から公開まで費用をかけたくない人
・デザインのカスタムとか少ししたいと感じる人
・git / html / css 少し勉強してなんとなく、わかる、かな？って感じの人

### GithubPagesとは
今回使用するGithubPagesとはGitの個人リポジトリから手軽にWEBサイトを公開できる機能です。詳しく知りたい方は公式ドキュメントどうぞ。
https://docs.github.com/ja/pages/getting-started-with-github-pages/about-github-pages

## 手順
今回は導入部分までということで以下の流れで進めます。
1.サイトを作るためのリポジトリを作成する
2.ダミーのindex.htmlを作成
3.BootStrapの無料テンプレートをダウンロード
4.templateフォルダのアップロード
5.サイトの公開と確認

## 1.リポジトリの作成
プロゲートさんの手順がとても分かりやすかったのでそれに従って進めます。
https://prog-8.com/docs/github-pages
上記のサイトに従って、「3.リポジトリの作成」の項目まで進めてください。

## 2.ダミーのindex.htmlを作成
プロゲートのサイト「4. ファイルのアップロード」に従って`index.html`を作成してください。中身は次のように記述してください。
```html:index.html
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="refresh" content="0; url=https://<reponame>.github.io/template/index.html">
    </head>
</html>
```
ここで重要なのはURL部分の`<reponame>.github.io`を自身で作成したリポジトリの名前ときちんとそろえることです。そして`<reponame>.github.io/template/<ここ！>`のパスでテンプレートの`index.html`を探しに行くので、もし下の手順を踏んでもうまく表示されない時にはこのパスを確認してみてください。


## 3.BootStrapテンプレートのダウンロード
BootStrapのテンプレートでお好みのものをダウンロードします。
今回はこちらのサイトを使用させていただきました。
![スクリーンショット 2024-03-03 1.37.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726313/a82025e3-febc-c006-8850-f8626c97f21c.png)

https://startbootstrap.com/themes
上記のサイトから適当に選んでいただき、free Dwonloadを選択しzipファイルをダウンロードします。
![スクリーンショット 2024-03-03 1.38.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726313/e397d43f-8919-7f86-1a32-f426f82bf69d.png)

リポジトリまで作成できたら今回はデスクトップ（これはどこのディレクトリでも大丈夫です）にtemplateという名前で新規フォルダを作成します。（中身はまだ何も入ってなくて大丈夫です）zipを解凍したら中にある項目をすべて選択し、先ほど作成したtemplateフォルダに入れなおしてください。すると次のような感じになると思います。

![スクリーンショット 2024-03-03 2.18.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726313/a77f07b2-669e-3d4a-862a-207ce27b939d.png)


## 4.フォルダのアップロード
3で作成したtemplateフォルダをリポジトリにアップロードします。プロゲートのサイトでindex.htmlを作成した次の項目では画像をアップロードしていますが、ここでtemplateフォルダをそのままアップロードしてください。
そしてリポジトリの表示にtemplateフォルダ / index.html / README.mdの三種があれば成功です。

## 5.サイトの公開と確認
ここまでできたらテンプレートのサイトが表示できているか確認してみましょう。「5. ページの公開」の手順に従って公開設定をします。しばらく待つとsetting > Pagesの右上メニューから[Visit site]をクリックしてテンプレートサイトが表示されていたら成功です。
![スクリーンショット 2024-03-03 2.02.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726313/290fc2fa-b764-7281-7d19-aca7d9973cff.png)



## 6.サイトをカスタマイズしてみる
「6.公開したページの更新」の項目に沿ってサイトの表示されている内容を変更します。ここからはHTMLとCSS,BootStrapの知識が必要になるのでぜひその部分は他のサイトで調べてみてください！templateの中にあるindex.htmlがメインの文字を決めているのでこの中身を変えることで表示文字を変えられます。テンプレートを改変してオリジナルなポートフォリオサイトが完成することを願っています。ありがとうございました。

## 参考
* https://prog-8.com/docs/github-pages
* https://startbootstrap.com/themes
* https://docs.github.com/ja/pages/getting-started-with-github-pages/creating-a-github-pages-site
音声生成AI「OpenVoice」と音声データセット「moe-speech」を使って好きなキャラクター音声を合成する

## OpenVoiceとは

OpenVoiceは、リファレンススピーカーの短い音声だけで、その声を複製し、多言語の音声を生成することができる、音声クローニングツールです。

OpenVoiceは、リファレンススピーカーの声色を再現するだけでなく、感情、アクセント、リズム、ポーズ、イントネーションなどの音声スタイルをきめ細かく制御することができます。  

また、OpenVoiceは、トレーニングセットに含まれていない言語に対しても、ゼロショットのクロスリンガル音声クローニングを実現します。

（引用元：https://research.myshell.ai/open-voice）

中国語と英語であれば、こちらから気軽に試すことができます。

https://huggingface.co/spaces/myshell-ai/OpenVoice


また、ソースコードはこちらにあります。 

https://github.com/myshell-ai/OpenVoice

Hugging FaceのUI上では、日本語の音声合成が出来ないため、この記事では上のGithubリポジトリ内にあるノートブックを使って、クロスリンガル音声クローニングを行います。

OpenVoiceの仕組みとしては、以下の図解のようになっているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664387/98f3517d-a4af-7e09-57d7-17c20e045cb1.png)

1. アクセントや感情、イントーネーションをコントロールしたベーススピーカーの音声を合成
2. ベーススピーカーのトーンカラー（声色）を抽出
3. リファレンススピーカーのトーンカラー（声色）を抽出
4. ベーススピーカーの音声からベーススピーカーの声色のみを消去し、リファレンススピーカーの声色を当てはめる

このようなことを行っていると筆者は解釈しました。

なお、クロスリンガルの音声クローニング（demo_part2.ipynb）では、少し異なります。
1.の部分で、感情等をコントロールすることができません。ベーススピーカーの合成にOpenAIのTTS（Text-to-Speech）を用いているためです。場合によっては自ら録音した音声を用いても良いかもしれません。

## moe-speechとは

- 日本人プロ声優による高音質でノイズ・BGM等無しのキャラクター音声データセット（男性・女性キャラクター両方含む）
- 1音声は2-15秒のモノラル44.1kHz 16bit wavファイル
- キャラクターごとにフォルダ分けされている（各キャラクターは匿名化され、ランダムな8文字の英数字による識別子を持つ）
- 現在は合計473キャラクター、約39万の音声ファイル、合計約623時間、184GBの音声が含まれる
- TTS等のタスクに使える質になるよう、機械的に音声の質によりフィルタリング済み

（引用元：https://huggingface.co/datasets/litagin/moe-speech?not-for-all-audiences=true）


## 今回やること

ざっくり言うと、OpenVoiceのリファレンススピーカーとして、moe-speechの好きな音声を使おうということです。

Amazon PollyやOpenAI TTSは、なかなか流暢な日本語を生成してくれますが、キャラクター（声質）が限られているため、ボイスコミックやオーディオブックを作るには不十分という感じでした。

moe-speechの豊富なデータセットがあれば、狙い通りのキャラクター音声を生成できる可能性が高まります。

https://github.com/myshell-ai/OpenVoice/blob/main/demo_part2.ipynb

こちらの、**Obtain Tone Color Embedding**のところを、以下のように書き換えましょう。


```python
base_speaker = f"{output_dir}/openai_source_output.mp3"
source_se, audio_name = se_extractor.get_se(base_speaker, tone_color_converter, vad=True)

#reference_speaker = 'resources/example_reference.mp3' ←元のコード
reference_speaker="../moe-speech/data/1ba0d17b/wav/1ba0d17b_010.wav"
target_se, audio_name = se_extractor.get_se(reference_speaker, tone_color_converter, vad=True)
```

reference_speakerのパスを、ダウンロードしてきたmoe-speechデータセットの任意の音声ファイルのパスに書き換えます。

そして、その下の`text=[]`の中に、生成したい日本語を入れましょう。リストですが、一つだけ入れれば良いです。

以下の文章を入れてみました。桃太郎の冒頭です。

```
むかしむかし、あるところに、おじいさんとおばあさんが住んでいました。  
おじいさんは山へ芝刈りに、おばあさんは川へ洗濯に行きました。
```

以下にいくつか、リファレンスとクローニングの結果を挙げます。

1)男性

https://drive.google.com/file/d/1KUuowzuv6M9h2DkYxiRVAb9OYvyyxo-7/view?usp=sharing


https://drive.google.com/file/d/1pJD-6b265iO3ZU9RBe21jBwfl1tsjVFL/view?usp=sharing


2)女性

https://drive.google.com/file/d/1u81DMZ16puhjXgSLnsw543fmzrXyUp1t/view?usp=drive_link

https://drive.google.com/file/d/1RNFmvdrrT3lgh5tYcoFYcRtHnlJtBkgf/view?usp=drive_link

ちなみに、同じリファレンスでも試行ごとにクローニングの結果は少し異なります。声質というよりアクセントや速度が変わっています。

https://drive.google.com/file/d/1YeUgVbCB8tg_IT2SmMkJ1-tR9I6OfDS_/view?usp=drive_link


いかがでしょうか？多少変わってしまってはいますが、同じ系統であることは確かなようです。

リファレンススピーカーを変えればいくらでも違うキャラクターの音声を生成できるので、オーディオドラマやボイスコミックへの応用が期待出来ます。
PostgreSQLで大量データをCSVからインポート:SQLチューニング#1

### はじめに

SQLチューニングの勉強をするため、大量のデータをPostgreDBにインポートしたのでその時実行した方法をご紹介します。

### 実行手順

1.CSVデータを準備
2.CSVデータに合ったテーブルをpgAdmin4からCREATE TABLE
3.SQL Shell(psql)でcopyコマンドの実行
4.インポートできたことを確認

### 実行エビデンス
1,2は割愛します。

3.SQL Shell(psql)でcopyコマンドの実行
「SQL Shell(psql)」を開き、データをインポートしたいテーブルが存在するDBにアクセスします。
アクセス後、以下の例のようなコマンドを実行します。エラーがなくコマンドが実行できれば、インポートしたデータの件数が表示されます。

![ポスグレcsvコピーコマンド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/3659daee-7624-fce6-1fa8-68c543e01ae4.png)

4.インポートできたことを確認

pgAdmin4を開き、テーブルを右クリック→「View/Edit Data」から「First 100 Rows」を選択します。今回は12万件ものデータをインポートしているため、最初の100行のみ表示させます。

![データインポート確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/341d2c51-7a08-6ef1-adf1-f7ea5b9dcdfa.png)

データがインポートできたことが確認できます。

ここまで読んで頂きありがとうございました。
よろしければいいねをいただけますと幸いです。
基本的なHTTPステータスコードをまとめてみた

# はじめに
こんにちは！エンジニア転職を目指している伊藤です！
今回はHTTPステータスコードについて、基本事項をまとめてみました。HTTPステータスコードとは何ぞやという方の参考になれば幸いです。

# HTTPステータスコードとは

HTTPステータスコードは、Webサーバーからクライアントへのレスポンスの一部として送信される3桁の数字のことです。これにより、リクエストが成功したか、エラーが発生したか等の情報が伝えられます。ステータスコードの最初の数字（百の位）は、そのレスポンスの種類を示します。

## 2xx 成功

200番台のステータスコードは、リクエストが正常に処理されたことを示します。これは、サーバーがクライアントのリクエストを正しく理解し、それに応じて適切なレスポンスを生成できたことを意味します。
以下は、代表的な200番台のステータスコードです。

- **200 OK**: リクエストが成功したことを示します
- **201 Created**: リクエストが成功し、新たにリソースが作成されたことを示します
- **204 No Content**: リクエストは成功したが、返すべき内容がないことを示します

## 3xx リダイレクト

300番台のステータスコードは、クライアントに別のURLへのリダイレクトを指示します。これは、リソースが一時的または恒久的に新しい場所に移動したことを示します。
以下は、代表的な300番台のステータスコードです。

- **301 Moved Permanently**: リクエストされたページが新しいURLに恒久的に移動したことを示します
- **302 Found**: リクエストされたページが一時的に新しいURLに移動したことを示します
- **303 See Other**: リクエストに対するレスポンスが他のURLに存在することを示します
- **304 Not Modified**: クライアントが条件付きのリクエストを行い、リソースが変更されていない場合に返されます

## 4xx クライアントエラー

400番台のステータスコードは、クライアントのリクエストに問題があったことを示します。これは、リクエストが不適切であったか、必要な認証が欠けていたことを示します。
以下は、代表的な400番台のステータスコードです。

- **400 Bad Request**: サーバーがリクエストを理解できないことを示します
- **401 Unauthorized**: クライアントがリソースにアクセスするための適切な認証が必要であることを示します
- **403 Forbidden**: サーバーがリクエストを理解したものの、それを実行する権限がないことを示します
- **404 Not Found**: リクエストされたリソースが見つからないことを示します
- **405 Method Not Allowed**: 使用されたHTTPメソッドが許可されていないことを示します

## 5xx サーバーエラー

500番台のステータスコードは、サーバー側にエラーが発生したことを示します。これは、サーバーがリクエストを正しく処理できなかったか、予期しない問題が発生したことを示します。
以下は、代表的な500番台のステータスコードです。

- **500 Internal Server Error**: サーバーに内部エラーが発生したことを示します
- **502 Bad Gateway**: サーバーがゲートウェイまたはプロキシとして機能している場合に、上流のサーバーから無効なレスポンスを受け取ったことを示します
- **503 Service Unavailable**: サーバーが一時的にリクエストを処理できないことを示します。通常、これはサーバーが過負荷状態であるか、メンテナンス中であることを示します

# まとめ
今回は、日頃よく目にする基本的なHTTPステータスコードについてまとめてみました。何百番台が何のステータスを表しているのか覚えとくだけでも、リクエストが成功したかエラーになったかがわかるので便利だと感じました。
stimulus で複数の同一 action の指定

## はじめに
本記事は[Stimulus](https://stimulus.hotwired.dev/)を参考にしています。
勉強中のため、誤りやもっといいやり方があるかも知れません。
その場合は、ご指摘いただけますと幸いです。

また、可能な限りわかりやすく記載するつもりですが、不明瞭な点、追記した方がいい点などがございましたら、合わせてご教授ください。

## この記事の目的
恥ずかしながら、英語が得意なわけではないので、探すのに時間がかかったので、書き残そうと思った次第です。
同一のDOMイベントに対し、複数のアクションが書きたかったのですが、`data-controller`、および `data-target` の指定方法がわからなかったので、やり方を記します。

今回は、`form` に対して、`data-controller` を指定するやり方で備忘録を残します。

## パーシャルの記載
`input` 要素に対して、変更が行われた場合、`hoge-hoge` と `foo` が呼び出されます。
呼び出し順序は、左から右に呼び出されます。
```ruby
= simple_form_for(hoge, url: hoge_path(hoge), html: {data: { controller: "hoge-hoge foo" } }  do |f|

    = f.input :hoge_id,
      label: 'サンプル',
      input_html: {data: { action: "change->hoge-hoge#replace change->foo#update", "hoge-hoge-target": "hogeHoge", "foo-target": "foo"}}
```

## controller の記載
特別な書き方をする必要はありません。
```javascript
// controllers/hoge_hoge_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "hogeHoge" ]

  replace() {
    // 処理を記載する
  }
}
```

```javascript
// controllers/foo_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "foo" ]

  update() {
    // 処理を記載する
  }
}
```
印刷するとセル内の文字列が隠れてしまう問題をどうにかしたい

## 問題点

昔から気になっていたが、なぜか印刷設定すると、セル内の文字列が隠れてしまう問題がある。
これについては、これまで改行を数行打ち込む面倒なことをしていました。
今回は、マクロでアプローチしてみます。

## 解決方法

選択されたセル内の改行数をチェックして、いい感じの高さにします。
これにより、印刷設定しても、文字が隠れないと思います。
※選択範囲は１列選択を前提にしています。
以下サンプル。

```vb
Const MAXCOUNT As Integer = 5000

Sub AdjustCellHeight()
    Dim selectedRange As Range
    Dim cell As Range
    Dim defaultHeight As Double
    Dim linecount As Integer
    
    Dim LimitCount As Integer
    
    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False
    
    ' 選択されたセル範囲を取得
    Set selectedRange = Selection
    
    ' デフォルトのセルの高さを取得
    defaultHeight = selectedRange.Worksheet.StandardHeight
       
    ' 選択された各セルに対してループ
    For Each cell In selectedRange
        ' セル内の改行数を取得
        linecount = CountLineBreaks(cell)
        
        ' 結合されたセルの場合は結合セル内の各セルの高さを調整
        If cell.MergeCells Then
            Dim mergedRange As Range
            Set mergedRange = cell.MergeArea
            Dim mergedCell As Range
            
            ' 結合セル内の各セルに対してループ
            For Each mergedCell In mergedRange
                ' セルの高さを設定
                If linecount > 1 Then
                    ' 改行数が1より大きい場合、改行数に応じて適切な高さを設定
                    mergedCell.RowHeight = defaultHeight + (linecount - 1) * defaultHeight
                    Exit For
                End If
            Next mergedCell
        Else
            ' 結合されていない場合は通常のセルの高さを設定
            If linecount > 1 Then
                ' 改行数が1より大きい場合、改行数に応じて適切な高さを設定
                cell.RowHeight = defaultHeight + (linecount - 1) * defaultHeight
            Else
                ' 改行がない場合はデフォルトの高さに設定
                cell.RowHeight = defaultHeight
            End If
        End If
        
        If (LimitCount = MAXCOUNT) Then
            Exit For
        End If
        LimitCount = (LimitCount + 1)
    Next cell
    
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    MsgBox "選択したセル範囲を、改行数に応じてセル高さを調整しました", vbInformation
    
End Sub

Function CountLineBreaks(cell As Range) As Integer
    Dim text As String
    Dim lines() As String
    Dim linecountCRLF As Integer
    Dim linecountLF As Integer
    Dim linecount As Integer
    ' 対象セルのテキストを取得
    text = cell.Value
    ' 改行でテキストを分割
    lines = Split(text, vbCrLf)
    linecountCRLF = UBound(lines)
    ' 改行でテキストを分割
    lines = Split(text, vbLf)
    linecountLF = UBound(lines)
    ' 改行コード数を積算
    linecount = (linecountLF + linecountCRLF)
    ' 分割された行数を返す
    CountLineBreaks = linecount + 1
End Function
```