OmniAICreator/Qiita-1.07M huggingface dataset:
StateNotifierProviderの初期化メソッド内でasync/awaitを使いたい ※追記あり

# 2024/10/13 追記
Riverpod 2.0のAsyncNotifierProviderを使用するのがベストプラクティスっぽいです。

```yaml: pubspec.yaml
dependencies:
  flutter_riverpod: ^2.5.1
  riverpod_annotation: ^2.3.5
  riverpod_generator: ^2.4.0
```

ますは必要なライブラリをインポートします。

```dart item_list_provider.dart

part 'item_list_provider.g.dart';

@riverpod
class ItemList extends _$ItemList {
  @override
  Future<List<Item>> build() async {
      //初期化メソッドを追加
      final List<Item> initialItem = await ref.watch(hogeProvider).fetch();
        return initialItem;
    }
  };

  Future<void> addItem({required Item newItem}) async {
    final previousList = await future;
    state = AsyncData([...previousList, newItem]);
  }
}

```
riverpod_generatorでproviderを生成するためのファイルを作成します。

・part 〜 の部分はファイル名.g.dartとします。
・riverpod_annotation をimportしたことで`@riverpod`アノテーションが利用できます。
・freezedと同じような構文で _$クラス名 をextendsしてあげます
・buildメソッドをoverrideします。buildはproviderが初めて呼び出された時に実行される初期化メソッドです。(async/awaitが利用できる！)
・addItemのようにメソッドを追加できます。futureは予約変数になっており、現在のstateの`Future<List<Item>>`が取得できます。awaitで`List<Item>`にしてあげています。
・stateは`AsyncValue<List<Item>>`型なのでAsyncValue()でラップしてあげています。

```
flutter pub run build_runner build --delete-conflicting-outputs 
```
ターミナルからbuild_runnerで上記コマンドを実行してあげると、dart item_list_provider.dartと同じ階層にitem_list_provider.g.dartが作成されます。


```dart
ref.watch(itemListProvider);
```

作成されたproviderはいつも通り上記コードで呼び出すことができます。<br><br>

--- 追記ここまで ---

# StateNotifierProviderはasyncを使えない…
StateNotifierの初期値にDBや内部ストレージから非同期で取得した値をセットしたい！
というケースは多々あると思います。



``` dart
class FormItemList extends StateNotifier<List<Item>> {
  FormItemList(List<Item> initialState) : super(initialState);

  void set({required List<Item> itemList}) {
    state = itemList;
  }

  Future<List<Item>> addNewItem({
    required List<Item> itemList,
  }) async {

    state = [...state, ...itemList];
    return state;
  }
}
```

このようなStateNoriferをproviderで提供するとします。
非同期関数で取得した値を初期値として渡してあげる場合、以下のように書きたくなりますが、StateNotifierProviderの初期化メソッド内ではasync/awaitを使用できません。

```dart
final formItemProvider = StateNotifierProvider<FormItemList, List<Item>>((ref) async{
    // NG
    await initialItem = ref.watch(hogeProvider).fetch();
    return FormItemList(initialItem);
});
```

これと同様のことを実現するには、まずStateNotifierに初期化用のメソッドを用意してあげます。

``` dart
class FormItemList extends StateNotifier<List<Item>> {
  FormItemList(List<Item> initialState) : super(initialState);

    //初期化メソッドを追加
    Future<void> initialize({required Ref ref}) async {
        // ここで非同期処理を行う
        final List<Item> initialItem = await ref.watch(hogeProvider).fetch();
        state = initialItem
    }

    // 以下略
}
```

StateNotifierProviderの初期化時にこのメソッドを呼んであげればOKです

```dart
final formItemProvider = StateNotifierProvider<FormItemList, List<Item>>((ref) {
   
   //空のリストでインスタンスを作成 
  final notifier = FormItemList([]);

  //初期化メソッドを呼び出す
  notifier.initialize(ref: ref);
  
  return notifier;
});
```
このように記述することでformItemProviderの初回呼び出し時に、非同期で取得した初期値をセットしたStateNotifierを提供することができます。
当たり前といえば当たり前な方法ですね！
【Rails】セキュリティを強化する

こんばんは！
今日はrailsのアプリケーションでセキュリティを上げるための方法を3つ紹介します。

## 1.before_action :authenticate_user!(会員側セキュリティ)
```ruby:xxx_controller.rb
class XxxxController < ApplicationController
  before_action :authenticate_user!
  
# 中略

end
```
各コントローラーの記述に加えてください。この記述を行うことで、ログインしていないとできない操作やページを作り、他人から情報を編集・削除されたり抜き取られることを防ぎます。userの部分はcustomerなどにも変更可能です。

## 2.before_action :authenticate_admin!(管理者セキュリティ)
```ruby:xxx_controller.rb
class Admin::XxxxController < ApplicationController
  before_action :authenticate_admin!
  
# 中略

end
```
こちらも管理者側の各コントローラ―に記述してください。この記述をすることで、adminとしてログインしていない場合は弾かれるようになり、URLを打ち込むだけでは管理者ページに入れなくなります。(そもそも管理者ページに顧客が入れてしまうことはアウトなので当然ですが...笑)

## 3.timeouttableを有効にする(devise導入が必要)
devise導入が前提ですが、timeouttableの記述をすることでログイン後のタイムアウトまでの時間を決めることができ、公共の場などでログアウトし忘れた画面を晒し続ける＝情報を晒し続けることを防ぎます。時間はユーザーの使用時間とセキュリティを考慮しつつなるべく短く設定する方が良いです。方法は以下の通りです。

### app/model/user.rbにtimeouttableを追記
deviseで導入したモデルにtimeouttableの記述を加えます。
```ruby:app/model/user.rbなど
class User < ActiveRecord::Base
  devise :timeoutable
end
```
### config/initializers/devise.rbのコメントアウトを外し時間を指定
```ruby:config/initializers/devise.rb
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again. Default is 30 minutes.
# config.timeout_in = 30.minutes
config.timeout_in = 30.minutes # この部分をコメントアウト＆時間指定
```
timeouttableのタイムアウト時間のデフォルトは30分ですが、変更することも可能です。
こちらの記事が参考になります。

https://qiita.com/zenizh/items/50d64c8a42e6798bc142

## 最後に
チーム開発でセキュリティを考えたときにあまりにも自分が無知だったので、調べてまとめてみました。思ったより奥が深く、面白いなと感じたのでもう少し調べてみようかとおもいます。(まとまったら載せるかもしれないです。)
今回参考にさせていただいたサイトはこちら。

https://techracho.bpsinc.jp/hachi8833/2021_10_28/62858
xcode 15.2 でのボタンの配置方法


**xcode15.2 でのボタンの配置方法**

xcode15.2にてボタン配置方法を見つけることができなかったため手順をまとめる。


・目次
1.xcode15.2にてボタン配置

<br>

**1.xcode15.2にてボタン配置**
各サイトにてMain.storyboardを選択するとiphone等のデバイスが表示され、ボタンを追加できると記載されているが、xcode15では【Main.storyboard】が表示されない。
xcode15では【Main.storyboard】ではなく【Main】という表記のようなので、【Main】を選択することでデバイスを表示することができた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476538/fd7a8668-d7da-7be6-d497-43491d79e5bd.png)


<br>
<br>

以上
信じられるのはsetuptoolsだけ ― Stub-only packageを初めて作った話

## 結論
Stub-only packageを作るときはsetuptoolsを使いましょう。

## Stub packageとは？
Stub package は [PEP-561](https://peps.python.org/pep-0561/)で定義されるパッケージの形態です。
主にThird partyのライブラリに対してType hintを与えることを目的としたPEPです。

Type hintがあればVS Codeなどエディタから引数リストやメンバ変数の補完などの支援が得られる他、mypyやpyrightによる静的型チェックの支援を受けることができます。
一方で、歴史的な理由やC++，Cythonを利用しているパッケージでは型ヒントが付けられていない場合があります。
自分が管理するライブラリであれば色々な手段 [^1][^2] で型ヒントを付与すれば非常に便利です。

しかしながら、先述の通りThird partyのライブラリの場合、ライブラリのコードを変更せずに型ヒントを付ける必要があります。
Pythonにはそのための方法が定義されており、それが [PEP-561](https://peps.python.org/pep-0561/)であり、Stub packageになります。

## 今回作ったもの
まだテストコードを書けていませんが、実用上問題無いため実用優先でとりあえず公開することにしました。[^3]

https://github.com/elda27/tensorstore-stubs

tensorstoreというN次元配列保存に適したライブラリです。
そのうち、これはこれで記事にしたいと考えていますが、細かい話は一旦おいておきましょう。

tensorstoreは非常に高速かつメモリ効率に優れたライブラリです。
一方で、ほとんどのコードがC++で記述されており、ほとんど全ての関数・クラスメンバなどのType hintは記述されていません。
実際に使おうとすると、苦行か何かと思い、本ライブラリを作るに至りました。

本ライブラリはいわゆるStub-only packageと呼ばれるライブラリです。
[PEP484](https://peps.python.org/pep-0484)で定義されるpyiファイルのみで構成されるパッケージをStub-only packageと呼びます。
ちなみに、pyファイルとpyiファイルから構成されるパッケージは Partial Stub  Packageと言います。

細かい構文については、別の機会に記述しますが、基本的には実装がない関数やクラス、変数を定義していくだけです。
Protocolを使ったクラス実装と同一と言えば分かりやすい人も居るのかもしれません。

## ようやく本題
上記のライブラリを作ったは良いが、問題は配布にありました。
最初はじわじわとシェアを伸ばしているryeでプロジェクトを管理していました。
何となくで始めていたのですが、パッケージのbuildをしようとするとエラーになってしまい解決できず。
issueを探すとそれらしいものは見つからず。

なんでやねんと思いつつもあだ若いツールなので仕方がない。
気を取り直してpoetryでプロジェクトを作り直し、ビルドするも同じく撃沈。

流石に面倒くさくなり、setuptoolsで作り直した次第でした。
setuptoolsでパッケージを作ることは苦行としか言いようが無いのですが、Stub-only packageの場合、通常依存パッケージが無いのであまり気にせずにsetuptoolsで作りきりました。

あとから気づいたのでが、意外とpoetryがのpyproject.tomlは癖があるようで、rye→setuptoolsの差分は少ないのですが、poetry→setuptoolsはバチバチにエラーが出て修正が大変でした。
何らか方針の違いがあるのでしょうか。

## 参考
https://qiita.com/ieiringoo/items/4bef4fc9975803b08671

[^1]: [インターネットで見つけた良い例](https://gihyo.jp/article/2022/09/monthly-python-2209)
[^2]: [私が書いた一例](https://qiita.com/elda227/items/9417995d7cf33bbc29af)
[^3]: そもそもStub packageのTestコードの書き方が分からない・・・pandas-stubのTestとかを参考中
【CocoaPods】CocoaPodsとActiveSupportの特定バージョンの互換性問題を解決！

## はじめに
この記事では、Flutterでアプリ開発をしている際に、CocoaPodsの特定バージョンとActiveSupportのバージョンとの間で発生した互換性の問題とその解決策について紹介します。
最新のCocoaPodsではこの問題が解決されている可能性がありますが、同様の問題に直面した場合の参考にしてください。

## 環境
- CocoaPods 1.13.0
- Xcode 15.0
- Ruby 3.2.2 (rbenvを使用して管理)
- ActiveSupport 7.1.3

## 問題の発生
CocoaPodsのバージョン1.13.0をインストールした後、`pod --version`を実行すると、以下のようなエラーメッセージが表示されました。
```
/Users/＊＊＊＊/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/activesupport-7.1.3/lib/active_support/core_ext/array/conversions.rb:108:in `<class:Array>': undefined method `deprecator' for ActiveSupport:Module (NoMethodError)

  deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
                                                          ^^^^^^^^^^^
```

## 原因

https://github.com/CocoaPods/CocoaPods/issues/12081

こちらのCocoaPodsのIssueによると、こんなことが書かれていました。

>activesupport 7.1.0 was released today (5.10.2023) and it breaks cocoapods entirely. If you update or install cocoapods, from this day, gem will install newest activesupport (7.1.0). cocoapods-core deasn't have strict version of it
>
>s.add_runtime_dependency 'activesupport', '>= 5.0', '< 8'
>
>If cocoapods install with activesupport 7.1.0 then any cocoapods command faile:

どうやら、activesupportのバージョン7.1.0がインストールされた状態でCocoaPodsを使用すると、互換性の問題が発生してしまい、どのCocoaPodsコマンドも失敗するみたいです。
この問題はactiveSupport 7.1.3でも同様に発生し、CocoaPodsのコマンドが正常に動作しなくなりました。

## 解決方法
この問題を解決するためには、activesupportのバージョンを7.1.0より前のバージョンにダウングレードする必要があります。
そのため、activeSupportのバージョン7.1.3をアンインストールし、互換性のあるバージョンである7.0.8をインストールしました。これにより、pod --versionが正常に動作し、CocoaPodsのバージョン1.13.0が表示されるようになりました。
```
sudo gem uninstall activesupport -v 7.1.3
sudo gem install activesupport -v 7.0.8
```

```
pod --version
1.13.0
```
React + firebase 画面蒼白？！

# はじめに
どうもこんにちは！僕は現在1ヵ月本気の技術力向上を目指している現役高校生1年生です！
前回記事の続きのような感じになるのですが、firebase hostingへReactアプリをデプロイしようとしたら上手くいかなかったのでまとめます。

# 問題
画面が以下のように表示される。

![スクリーンショット 2024-02-19 224046.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554025/a5571543-9b40-f560-48eb-a82e8e25bcae.png)

# 解決策
firebase initコマンドを実行した際に、以下の設定項目が間違っていたのでfirebase initをやり直しました。

```terminal
? What do you want to use as your public directory? 
=> × public ===> dist
? File dist/index.html already exists. Overwrite?
=> × Yes ===> No
```
- 最初に示した設定項目に関しては、distディレクトリにビルド後のファイルが管理されているのでdistにする必要があります
- 2つ目に関してはせっかくビルドしたindex.htmlをYesと回答することでfirebaseによって別の内容に上書きされてしまっていました

# 終わりに
最近エラーなどの対処や調べることに慣れてきたような気がします!仮説をしっかりと立ててから対策を実行することを最近心がけています。
今週も頑張っていきます！！

# 参考
https://qiita.com/taisei_code/items/ee065476fef5a7bb34df


# About Me
- X(Twitter)
https://twitter.com/shunii_hack
firebase loginができない

# はじめに
どうもこんにちは！僕は現在1ヵ月本気の技術力向上を目指している現役高校生1年生です！
今回はReactでアプリ開発をしていたのですが、firebaseへデプロイするときにうまくいかなかったのでまとめます。

# 問題
firebase loginができない。以下のように表示されてしまいました。

![スクリーンショット 2024-02-19 224322.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554025/06bedacf-209d-1622-1dfb-0cca51a88e64.png)

# 解決策
1. 次のコマンドを使う


    ```
        terminalfirebase login --no-localhost
    ```
そのあとは画面に表示される手順に従って行います。

# 終わりに
SDKインストールしてないのが原因なのかな？とか思っています。またちゃんと調べたいと思います。

# About Me
- X(Twitter)
https://twitter.com/shunii_hack
Obsidianでフロントマターの値をGraph View / タブ / その他色々な所に表示する方法

# 小言と経緯
みなさんもObsidianでZettelkastenをやるときに、ユニークノートの機能を使うと思います。
けどユニークノートで生成されてたタイトルって意味わかんないですよね。
Zettelkastenの思想上仕方ないと割り切っていましたが、Graph Viewでも数字の羅列が延々と広がってると嫌気がさしますし、タブ上でも数字だけのタブ名だと移動先が一目で全く分からず作業効率が落ちますね。
プラグイン作ったろかな～と思いつつ先延ばしにしていたら既にありました(やっぱり)
# 神プラグイン Obsidian Front Matter Title
試しに導入してみたら感動したので共有します。
リポジトリ : [obsidian-front-matter-title](https://github.com/snezhig/obsidian-front-matter-title/tree/master "obsidian-front-matter-title")

インストールはObsidian内からでもマニュアルでもなんでもOK

## 設定
設定はめっちゃ簡単。
`Common main template`に共通するフロントマターのタイトル要素を指定するだけ！
`Features`セクション内の任意の要素をオンにするだけで便利生活が手に入ります！感動！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511291/ce40f5ed-26cd-30ab-8631-14b1621247e7.png)

デフォルトでは`title`の値が表示されるが、ここは任意で設定できます。リポジトリを見てね。
FireStore × AppStore で DBにアクセスできずハマった

# Firestoreに読み書きできない問題が発生

## 前提
✅ `GoogleService-Info.plist`はプロジェクト直下のディレクトリに配置済み
✅ `AppDelegate`はFirebaseの最初の案内に従って設定済み

```swift
class AppDelegate: NSObject, UIApplicationDelegate {
  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    let providerFactory = AppCheckDebugProviderFactory()
    AppCheck.setAppCheckProviderFactory(providerFactory)
    FirebaseApp.configure()

    return true
  }
}

@main
struct DeviceFinderIOSApp: App {
  @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    var body: some Scene {
        WindowGroup {
            EntrancePage()
        }
    }
}
```

✅ `.p8`ファイルを`AppCheck`に登録済み
![スクリーンショット 2024-02-19 23.07.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092613/7f119705-5fba-cff7-2d5c-9b8dbc447aab.png)



## エラーで詰まった部分

```shell
[Firebase/Firestore][I-FST000001] AppCheck failed: 'The operation couldn’t be completed. The server responded with an error: 
 - URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<my-project>/apps/1:<my-app-id>:ios:<id>:exchangeDeviceCheckToken 
 - HTTP status code: 403 
 - Response body: {
  "error": {
    "code": 403,
    "message": "App attestation failed.",
    "status": "PERMISSION_DENIED"
  }
}
```



## 解決方法
[Firebase公式](https://firebase.google.com/docs/app-check/ios/debug-provider?hl=en&authuser=0&_gl=1*jkrcle*_ga*NDczMzk5MjU1LjE3MDgzNDk5NzY.*_ga_CW55HF8NVT*MTcwODM0OTk3Ni4xLjEuMTcwODM1MDE5OC40Ny4wLjA.)の`Use the debug provider in a simulator` 1 - 4にてtokenを登録する必要がある。debugビルドの場合は以上のトークンを設定しないと `エラーで詰まった部分`で表示されるような `403 - Unauthorized`に遭遇する
NestJsとSwaggerとDreddではまったところ

# はじめに
本記事は「NestJs」での実装を行いながら、「Swagger」でAPI仕様書を作成し、仕様書を元に「Dredd」で自動テストを行うといった作業を行なっていた時にハマったことについて説明します。

ざっくり2つあります。
- Optionalなプロパティ
- Unionなプロパティ



# 環境
- Docker
- NestJs
- Swagger
- Dredd




# Optionalなプロパティの定義
## NG例
```
export class User {
  @IsNumber()
  @ApiProperty({ type: Number, example: 1 })
  id: number;

  @IsString()
  @ApiProperty({ type: String, example: 'hoge huga' })
  name: string;

  @IsNumber()
  @IsOptional()
  @ApiPropertyOptional({ type: Number, example: 2, required: false})
  @Transform(({ value }) => parseInt(value))
  partnerUserId?: number;
}

```
partnerUserIdはNullの場合があるため、Optionalとなっています。
上記定義では、Dreddでのテストにて「number型」に「object」型を格納しているとエラーが発生します。

## 原因とOK例
原因は@ApiPropatyOptional内での定義漏れです。
nulltable:trueが必要でした。
```
export class User {
  @IsNumber()
  @ApiProperty({ type: Number, example: 1 })
  id: number;

  @IsString()
  @ApiProperty({ type: String, example: 'hoge huga' })
  name: string;

  @IsNumber()
  @IsOptional()
  @ApiPropertyOptional({ type: Number, example: 2, required: false, nullable: true })
  @Transform(({ value }) => parseInt(value))
  partnerUserId?: number;
}
```


# unionなプロパティ
## NG例
```
class expression {
  @ApiProperty({ example: 'operator' })
  type: string;

  @ApiProperty({
    type: String || Number
      example: {
      number: 350,
      string: 'totalAmount',
    },
    required: false,
  })
  value: number | string;
}
```

計算式を格納するようなクラスです。
TypeがOperatorの時は四則演算子を、numの時は数値を格納するイメージです。
こちらはDreddでのテストにて「number」型に「string」型を格納したとエラーが発生します。

## 原因とOK例
どうやらNestJsで使用できるSwaggerアノテーションはunionに対応していないようです。
以下のように修正します。
```
class expression {
  @ApiProperty({ example: 'operator' })
  type: string;

  @ApiProperty({
    example: 350,
    required: false,
  })
  value?: number;


  @ApiProperty({ example: 'multiply', required: false })
  operator?: string;
}

```
Optionalでvalueかoperatorのどちらかを使用できるようにしました。
正直あまりいけてないのですが、APIの型定義のみで使用するClassなので妥協しました。


# 終わり
解決にすこし苦労したので記事にしました。
自動テストを通すために、実処理で使用する型を変更するのは本末転倒なので避けた方がいいなぁと思いながら作業しました。
Ruby on Railsの勉強環境の作成

# メインで参考にしたサイト
[Ruby 3\.x, Rails 7\.x, PostgreSQL の Docker 環境構築 2023 \#Rails \- Qiita](https://qiita.com/goya-hideaki/items/a0b7eae988b716724fdb)

途中以下のエラーが発生
```bash:bash
$ docker compose run frontend rails db:create
[+] Creating 1/0
 ✔ Container free-market-app-backend-1  Running                                                                                0.0s 
FATAL:  could not open file "global/pg_filenode.map": Permission denied
Couldn't create 'myapp_development' database. Please check your configuration.
rails aborted!
ActiveRecord::ConnectionNotEstablished: FATAL:  could not open file "global/pg_filenode.map": Permission denied (ActiveRecord::ConnectionNotEstablished)


Caused by:
PG::ConnectionBad: FATAL:  could not open file "global/pg_filenode.map": Permission denied (PG::ConnectionBad)

Tasks: TOP => db:create
(See full trace by running task with --trace)
```
# 解決策
ホストマシン上で以下のコマンドを実行してtmo/dbの権限を付与して解決した
```bash:bash
# ホストマシン上で実行
sudo chown -R 1000:1000 ./tmp/db
sudo chmod -R 700 ./tmp/db
```
GitHub Universe 2023 カンファレンスレポート

## イントロダクション

こんにちは！エンジニアのM.Yです。

2023年11月8日から9日にかけて、サンフランシスコで「GitHub Universe 2023」が開催されました。
弊社がサポートしたmagisystemさんがカンファレンスに参加してレポートして下さったので、その内容をまとめて紹介させて頂きます！

## カンファレンスのハイライト

### 1. LLM + GitHub連携によるセキュリティとCI/CDワークフローの自動化

「GitHub CopilotのUpdate」が大きく注目されている中、magisystemさんは、GitHub Universeを通して、「LLM + GitHub連携による、セキュリティやCI/CDワークフローの自動化」がトレンドになると感じたそうです。

理由としては、イベントに出場・展示していたスタートアップのほとんどが「LLM + GitHub連携」で開発効率を上げる目的のサービスで、その中でも、注目を集めていたのが、セキュリティ強化やCI/CDとの連携だったためです。

実際に展示されていたサービスには、Pixee.aiやTrunk.ioがあります。

Pixee.aiはGitHubと連携し、リポジトリを監視して、セキュリティ面をチェックし、問題点があった場合は自動でPull Requestを作成してくれるサービスを提供しています。

わかりやすく説明すると、開発者が作成したコードのセキュリティ面を自動でチェックして、良くない箇所を修正したコード提案してくれるようなサービスです。開発者が作成したコードを確認するためにGitHubと連携が、セキュリティ面のチェックや修正コードの提案にLLMが使用されています。
- [Pixee.ai 公式サイト](https://www.pixee.ai/)

Trunk.ioはGitHubと連携し、LLMを利用してCI/CDを自動化しています。
開発者がコードを共有リポジトリにプッシュするたびに、
自動的にビルド、テスト、およびコードの品質チェックが行われ、
ビルドとテストが成功したコードは、自動的にステージング環境にデプロイされるようです。
- [Trunk.io 公式サイト](https://trunk.io/)

LLMを活用した自動化の動きは活発で、GitHubが2024年にリリース予定の「Copilot Workspace」では、人間が一切コードを書かずにシステムを作成し、バグの修正まで行ってくれるとのこと。。。
コーディングスキルより、業務フローを理解しているか？要件定義ができるか？コミュニケーションを上手くとれるか？等の価値がより高まりそうだなと筆者は感じました。


### 2. GitHub Copilotの最新アップデート

GitHub Copilotのアップデートも大きく注目を集めており、以下の4点が発表されたようです。

- GitHub Copilot Chatの一般提供の開始: すべてのGitHub Copilotユーザーは、追加料金なしでCopilot Chatを利用できるようになりました。
- 新たなGitHub Copilot Enterpriseのサービスプレビュー: 組織がGitHub Copilotを使用する際の管理機能やセキュリティ等が提供されます。
- AIを活用した新しいセキュリティ機能: GitHubは、AIを使用して、コードの脆弱性を特定し、修正するための新しいセキュリティ機能が提供されます。
- GitHub Copilotパートナープログラム: GitHub Copilotを使用して、開発者がより効率的にコードを作成できるようにするためのツール、リソース、およびサポートが提供されます。

GitHub Copilot Chatは既に一般提供されていて、筆者も毎日使ってます。
GitHub Copilot Chatで出来ることは、コードの自動生成・コードの解説・リファクタリング・脆弱性検出など多岐にわたります。
筆者はもうGitHub CopilotとGitHub Copilot Chatなしでのコーディングは考えられなくなってます。


## 結論

「GitHub Universe 2023」はレポート内容を聞いただけでも、技術の最先端を感じさせるイベントでした！LLMによる自動化や、Copilotの進化には期待が高まりますね！！

今後、技術の進化でプロダクトを作成する効率が上がると同時に、コーディング以外のスキルがより求められるようになるのはほぼ確実かと思います。最新の技術に触れていくと同時にコーディング以外のスキルにも意識を向けていきたいですね！

カンファレンスに参加したmagisystemさんが作成して下さった記事もあります。現地の雰囲気を感じられる内容になっていますので、興味があれば[こちら](こちらのリンク)もご覧ください。

**参考リンク**

- [GitHub Universe 2023 現地会場 参加・今後のIT市場考察レポート GitHub カンファレンスレポート at サンフランシスコ](https://www.wantedly.com/companies/strategy-jp/post_articles/871116)
- [Pixee.ai 公式サイト](https://www.pixee.ai/)
- [Trunk.io 公式サイト](https://www.trunk.io/)
【Rails】ジャンル検索機能(ECサイト)

今回はECサイトのジャンル検索機能の実装を解説します！
完成形はこちらです。

![スクリーンショット 2024-02-19 222738.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677302/04d3071b-72e3-bd1b-ac8e-469f6b2a37d6.png)

## 環境
AWS Cloud9
Ruby on Rail 6系
Bootstrap Ver.4
kaminari導入済み
itemコントローラー作成済み
モデルのアソシエーション記入済み(ItemモデルとGenreモデル)

## 方法
### コントローラー作成・記述
```terminal
$ rails g controller genres show
```
今回はshowページのみ作るので、この時点で作成しておきます。
次にコントローラーに記述を加えていきます。
```ruby:genres_controller.rb
class GenresController < ApplicationController
  def show
    @genres = Genre.all
    @genre = Genre.find(params[:id])
    @items = Item.where(genre_id: @genre.id).page(params[:page]).per(5)
  end
end
```
ジャンル検索を配置したい部分に追記してください。
```ruby:items_cotroller.rb、homes_controller.rbなど
# 検索欄を配置したいところに追記してください
  def
    @genres = Genre.all 
  end
```
### ジャンル検索のview(部分テンプレートで作成)
```erb:items/genre_sidebar.html.erb
    <table class="table table-bordered table-hover text-center ec-genre-list">
      <tr>
        <td>
          <%= link_to "全商品を表示", items_path, class:"ec-genre-list-item" %>
        </td>
      </tr>
      <% genres.each do |genre| %>
        <tr>
          <td>
            <%= link_to genre.name, genre_path(genre.id), class:"ec-genre-list-item" %>
          </td>
        </tr>
        <% end %>
    </table>
```
### ジャンル検索の部分テンプレートをrenderで呼び出す
```erb:xxxx.html.erb
  <%= render 'genres_sidebar', genres: @genres %> #itemsのview
  <%= render 'items/genres_sidebar', genres: @genres %> #itemsのview以外
```
### ジャンル検索結果のshowページ
```erb:genres/show.html.erb
<div class="container">
  <div class="row">
    <div class="col-md-3">
     <%= render 'items/genres_sidebar', genres: @genres %>
    </div>
    <div class="col-md-9">
      <h2>商品一覧</h2><p>(全<%= @items.count %>件)</p>
     
      <div class="card-deck">
        <%  @genre.items.each do |item| %>
          <div class="card shadow-sm cake-box text-center" style="min-width: 230px; max-width: 250px;">
            <div class="card-img-top" >
            <%= link_to item_path(item.id) do %>
              <% if item.image.attached? %>
                <%= image_tag item.image, style: 'width: 100%; height: 150px' %>
              <% else %>
                <%= image_tag 'no_cake', style: 'width: 100%; height: 150px' %>
              <% end %><br>
              </div>
              <h5 class="card-title pt-2">
                <%= item.name %>
              </h5>
            <% end %>
            <div class="card-text">
              <p>￥<%= item.with_tax_price.to_i %></p>
            </div>
          </div>
        <% end %>
        <%= paginate @items, theme: 'twitter-bootstrap-4' %>
      </div>
    </div>
  </div>
</div>
```

これで以上です。showページにはbootstrapのカードを使って実装してみました。
SQLのDMLについて

## データ操作言語（DML)について記載。
※参考 兼 自身のメモ用
※随時追記

```sql:sampleCodeSelect.sql
-- コメント
SELECT 
    列名 AS 列別名
FROM
    テーブル名
WHERE
    条件式
Order by
    ソートの指定
;
```
※ASは省略可能
※列別名にスペースや記号を含めたい場合は""で囲む

### レコードの管理
```sql:sampleCodeInsert.sql
-- レコードの新規作成（INSERT文）
INSERT INTO
    テーブル名 (列名1, 列名2, ・・・)
VALUES
    (値1, 値2, ・・・)
;
```

```sql:sampleCodeUpdate.sql
-- レコードの更新（UPDATE文）
UPDATE
    テーブル名
SET
    列名1 = 値1, 列名2 = 値2 ・・・
WHERE
    条件式
;
```

```sql:sampleCodeDelete.sql
-- レコードの削除（DELETE文）
DELETE FROM
    テーブル名
WHERE
    条件式
;
```
※レコードの全てを高速に削除するには`TRUNCATE文`が使用できる。
ただしこちらは`COMMIT`不要で即反映されるため要注意
（`DML`ではなく`データ定義言語（DDL）`のため

### レコードの確定/戻し
INSERT/UPDATE/DELETE文で使用する
```sql:
INSERT文 or UPDATE文 or DELETE文
-- 以下を実行するとレコードが確定する
COMMIT ;
-- 以下を実行すると状態を巻き戻せる
ROLLBACK ;
【Flutter】テキストの装飾

Flutterでのテキストの装飾についてまとめました。

テキストサイズの記載がないものは一律「fontSize: 30」にしております。

## テキストサイズ

```dart:書き方
Text(
    'fontSize 5', // 表示したいテキスト
    style: TextStyle(fontSize: 5), // テキストサイズ
    ),
```

![Screenshot_20240206_221806.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641068/e0bec6fd-b8dd-7983-d2a1-ac02566d048f.png)


## テキストカラー

```dart:書き方
Text(
    'color red', // 表示したいテキスト
    style: TextStyle(
        color: Colors.red), // テキストカラー
),
```

![Screenshot_20240206_224645.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641068/8ef005f0-5be2-3f5c-6424-1f165bf5baae.png)

## テキストの太さ

```dart:書き方
Text(
    'FontWeight.w100', // 表示したいテキスト
    style: TextStyle(
        fontWeight:FontWeight.w100), // テキストの太さ
),
```

![Screenshot_20240206_225658.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641068/e8ce2118-4a3f-4486-d2c9-d39e72b8ec33.png)

> - w100 : Thin、最も細いフォントの太さ。
> - w200 : エクストラライト。
> - w400 : 通常。定数FontWeight.normal は、この値のエイリアスです。
> - w700 : 大胆。定数FontWeight.bold は、この値のエイリアスです。
> - w900 : 黒、フォントの太さが最も太い。

https://api.flutter.dev/flutter/dart-ui/FontWeight-class.html

## テキストのフォント

```dart:書き方
Text(
    'FontStyle.normal', // 表示したいテキスト
    style: TextStyle(
        fontStyle: FontStyle.normal), // フォントの指定
),
```

![Screenshot_20240206_231347.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641068/eb6f7519-2e42-9afd-7a38-1c384c469d09.png)



## テキストに線

```dart:取り消し線
Text(
    'line.single', // 表示したいテキスト
    style: TextStyle(
        decoration: TextDecoration.lineThrough),
),
```

```dart:二重取り消し線
Text(
    'line.double', // 表示したいテキスト
    style: TextStyle(
        decoration: TextDecoration.lineThrough,
        decorationStyle: TextDecorationStyle.double),
),
```

```dart:下線
Text(
    'underline.single', // 表示したいテキスト
    style: TextStyle(
        decoration: TextDecoration.underline),
),
```


```dart:二重下線
Text(
    'underline.double', // 表示したいテキスト
    style: TextStyle(
        decoration: TextDecoration.underline,
        decorationStyle: TextDecorationStyle.double),
),
```


```dart:波線下線
Text(
    'underline.wavy', // 表示したいテキスト
    style: TextStyle(
        decoration: TextDecoration.underline,
        decorationStyle: TextDecorationStyle.wavy),
),
```

```dart:点線下線
Text(
    'underline.dashed', // 表示したいテキスト
    style: TextStyle(
        decoration: TextDecoration.underline,
        decorationStyle: TextDecorationStyle.dashed),
),
```

![Screenshot_20240206_233628.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641068/2159f309-dbcf-9120-f720-866a89e6520f.png)


## その他

```dart:影
Text(
    'shadow', // 表示したいテキスト
    style: TextStyle(
        shadows: [
            Shadow(blurRadius: 8.0),
        ],
    ), 
),
```

```dart:文字間スペース
Text(
    'letterSpacing', // 表示したいテキスト
    style: TextStyle(
        lettrrSpacing: 6.0,
    ),
),
```

![Screenshot_20240206_234429.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641068/ec5e8a9c-a2a9-c144-46db-feae2ce25ee6.png)
シェルスクリプトでエスケープシーケンスを使って端末情報を取得する方法

## はじめに

シェルスクリプトでエスケープシーケンスを使ってターミナルの情報（ウインドウサイズとかカーソル位置とか）を取得する方法の（個人的？）メモです。

```sh
report() {
  (                                  # trap EXITを使うためのサブシェル
    set -- "$1" "$(stty -g)"         # 現在の端末設定のバックアップ
    trap 'stty "$2"' EXIT            # サブシェル脱出時に端末設定を戻す
    # rawだとCTRL-Cできないしtimeやminも機能しないようなので-icanon
    stty -echo -icanon time 1 min 0  # エコーバックなしとその他の設定
    printf "$1" >/dev/tty            # 問い合わせのエスケープシーケンスを端末に出力
    dd count=1 2>/dev/null           # 端末からの応答を読み取って標準出力に出力
  ) </dev/tty                        # 標準入力を端末に明示的に指定
}

# ウインドウサイズの取得
report '\033[18t' | od -An -a
#  esc   [   8   ;   4   4   ;   1   4   6   t

# カーソル位置の取得
report '\033[6n' | od -An -a
#  esc   [   1   5   ;   1   R
```

他に `read -d 最後の文字` とか使ってデータを読んでいるのも見つかりましたが、対応してないシェルがあったり最後の文字を指定するのは汎用的ではないので、良さげな感じのコードで書きました。

なお、普通は `tput lines` とか `tput cols` とかを使ったほうが簡単です。`$LINES` や `$COLUMNS` を使う方法もあります。
DMARCvisualizerでDMARCレポートを可視化に挑戦

この度DNSで、DMARCとDKIMのレコードの設定を行いました。
そしてDMARCレポートが、届くようになりました。

この解析のために、私は、ChatGPT Plusなどを使い、届いた圧縮ファイルを解凍して、XMLファイルの内容を簡易的に表示するコードを作りました。

```Python

import json

# レポートファイル名
report_file = "you-fike.xml"

# レポート情報の表示
def display_report_info(report_data):
  print("**レポート情報**")
  print("作成元組織:", report_data["org_name"])
  print("レポートID:", report_data["report_id"])
  print("レポート期間:", report_data["begin"], "～", report_data["end"])

# 受信ポリシー情報の表示
def display_policy_info(report_data):
  print("**受信ポリシー**")
  print("ドメイン:", report_data["domain"])
  print("DKIM認証:", report_data["adkim"])
  print("SPF認証:", report_data["aspf"])
  print("受信ポリシー:", report_data["p"])
  print("送信者ポリシー:", report_data["sp"])
  print("拒否率:", report_data["pct"], "%")
  print("適用除外:", report_data["np"])

# 解析結果の表示
def display_records(report_data):
  print("**解析結果**")
  print("{:<20} {:<10} {:<10} {:<10}".format("送信元IPアドレス", "メール件数", "DKIM認証", "SPF認証"))
  for record in report_data["records"]:
    print("{:<20} {:<10} {:<10} {:<10}".format(record["source_ip"], record["count"], record["dkim"], record["spf"]))

# レポートファイルの読み込み
with open(report_file, "r") as f:
  report_data = json.load(f)

# レポート情報の表示
display_report_info(report_data)

# 受信ポリシー情報の表示
display_policy_info(report_data)

# 解析結果の表示
display_records(report_data)

```

ただ、これでは、単純に表示するだけなので、解析できないです。
また、ファイルも、直接コードを書き替えないと設定できないです。

それで色々探したのですが、無料で使えるサービスが無く困っていました。

## DMARCvisualizerを知りました。
その中で、こちらの記事を知りました。

https://qiita.com/ohhara_shiojiri/items/70291393e53ed22f6e21


そして、こちらの記事を知りました。
こちらの記事で公開されているリポジトリを使い、表示できました。

https://qiita.com/chima91/items/30a701b5e057cd4a6c26

気を付ける点は、ローカルのfilesのフォルダにDMARCレポートを配置して表示するときは、下記の設定ファイルの修正が必要な点です。

```dmarc-visualizer/parsedmarc.ini
[general]
+save_aggregate = False
+save_forensic = False
-save_aggregate = True
-save_forensic = True
-output = /output/
```

私は、下記の形で、使いました。
最初に書かれているもので、上記の部分のみ差し替える形で設定しました。


```dmarc-visualizer/parsedmarc.ini
[general]
+save_aggregate = False
+save_forensic = False
-save_aggregate = True
-save_forensic = True
-output = /output/

[elasticsearch]
hosts = elasticsearch:9200
ssl = False

```

私の実行環境は、Windows11 HOMEに、Dockerをインストールしました。
そして、外付けSSDにフォルダを作り、その中に、リポジトリをダウンロードして配置しました。
そして、Dockerのコンテナを起動しました。

## 下記の記事で、最初に見つけた記事の修正内容が書かれていました。
この修正内容を反映したリポジトリが公開されていたので、とても助かりました。

https://qiita.com/chima91/items/30a701b5e057cd4a6c26

記事を書いて下さった方に、感謝しています。

## こちらの記事も、参考になると思います。

https://engineer.crowdworks.jp/entry/dmarc-visualizer

## 解析例
下記の画像を見ると、黄色い表示がSPFの項目で出ています。
このことから、SPFの設定に問題があると分かります。
今回のケースは、SPFレコードの設定漏れがありました。

DMARCレポートは、送信したメールが、どのように届いているか把握するものです。
この点が、間違えやすいかなと思いました。
![スクリーンショット 2024-02-19 214934.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/5e4e07ae-1063-fa92-bd3b-e8846c5a4b5e.png)
Python: PyPDF で page 分割する際は、add_page() ではなく、append() を使わないとファイルサイズが小さくならない

# 背景

あるデモプログラムにて、PDF を page 分割処理にて、pypdf が使われていたが、
何故か分割したファイルのサイズが、分割前と変わっていなかったので、調査した記録

# 結論

- [add_page()](https://pypdf.readthedocs.io/en/stable/modules/PdfWriter.html?highlight=add_page#pypdf.PdfWriter.add_page) は、コンテンツ保持したまま、page を追加するのでファイルサイズは元ファイルとほぼ変わらない
- [append()](https://pypdf.readthedocs.io/en/stable/modules/PdfWriter.html?highlight=add_page#pypdf.PdfWriter.append) は、対象ページだけの追加になるので、ページ分割すればちゃんと**小さくなる。**

ということで、append() を使おうってだけ

:::note warn

- [PdfMerger](https://pypdf.readthedocs.io/en/stable/modules/PdfMerger.html) はすでに deprecated なので、[PdfWriter](https://pypdf.readthedocs.io/en/stable/modules/PdfMerger.html) を使おう
- [pypdf history](https://pypdf.readthedocs.io/en/stable/meta/history.html?highlight=pypdf2#pypdf2-reborn-2022) で、最新版を確認しよう。今は、pypdf が最新
    - The Origins: pyPdf (2005-2010)
    - PyPDF2 is born (2011-2016)
    - PyPDF3 and PyPDF4 (2018 - 2022)
    - PyPDF2: Reborn (2022)
    - pypdf: Back to the Roots (2023-Today)

:::

# 調査記録

## 元々は、分割したファイルサイズを小さくする方法を探していた。

- で、以下のページを試したが、ページ単位で保存する場合、何をやってもファイルサイズ変わらず。

https://pypdf.readthedocs.io/en/stable/user/file-size.html

で、最後の以下記述で、あ、なるほど、と理解した感じ

> When a page is removed from the page list, its content will still be present in the PDF file. This means that the data may still be used elsewhere.
>
> Simply removing a page from the page list will reduce the page count but not the file size. In order to exclude the content completely, the pages should not be added to the PDF using the PdfWriter.append() function. Instead, only the desired pages should be selected for inclusion (note: PR #1843 will add a page deletion feature).

## で、実際の比較時のコード

- 以下で 40 ページだけを取得してみたところ、無事 append() ならサイズが小さくなりました。

```python
from pypdf import PdfReader, PdfWriter #, PdfMerger is deprecated and will be removed in pypdf 5.0.0. Use PdfWriter instead.
reader = PdfReader(inputFilePath)

writer = PdfWriter()
writer.append(reader, pages=(40,41))
writer.write("outputs/append.pdf")   # 小さくなる

writer_as_add_pages = PdfWriter()
writer_as_add_pages.add_page(reader.pages[40])
writer_as_add_pages.write("outputs/add_page.pdf")   # 小さくはならない
```

# あとがき

https://github.com/Azure-Samples/jp-azureopenai-samples

このサンプル用で使われてる処理だったんだけど、元となる英語版ではすでに Document Intelligence Service に舵を切ってることに気付いたので、この対策自体不要になるんですけどね :sweat:
Discord.jsで愛くるしいペンギンBotを作ってみた

# はじめに
Discord.jsを使って、
言葉に反応して返信してくれる簡単なBotを作ってみました。

# 本編
## Discord.jsとは
DiscordでBotを作れるAPIがあり、それを使用するためのライブラリ

現在のバージョン：14.14.1

https://discord.js.org/

## こんな感じ
「何か言って」のフレーズに返信してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721358/1e237f3b-2e7b-ce6e-6302-162b125807cb.png)


## 事前準備

Node.jsをインストール

https://qiita.com/hisashi_matsui/items/5b7c381a14d28b91dfc5



## DiscordのAPI登録からBot作成まで
以下の記事などを参考に、
[こちら](https://discord.com/developers/applications)の画面からBotを作ってチャンネルに追加しました。

https://qiita.com/yuto0214w/items/1ecee25efca6b5b7445b

https://qiita.com/FumiSOULs/items/47091b8ee8ef8e73f15d

https://www.geeklibrary.jp/counter-attack/discord-js-bot/

権限については、今回は必要最小限として

![スクリーンショット 2024-02-19 22.24.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721358/b66e0c1e-bf5b-47fa-9145-38c2f1dbf3a0.png)


あとは、こちらのintentの設定も必要になったかなと思います

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2721358/49e9baeb-c232-2645-51eb-f10a21a4f193.png)

## 実装していく

### ライブラリをいくつか追加
トークンを.envに定義できるように `dotenv` を追加

```npm install dotenv```

Discordのbotを実装するため`discord.js`を追加

```npm install discord.js```

### コード実装

```.env
DISCOAD_TOKEN=
```

```javascript:index.js
import { config } from 'dotenv';
import { Client, Events, GatewayIntentBits } from 'discord.js';
import { penguinResponse } from './function.js';

// .envを読み込む
config();

const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]});
const messages = [
    'ペンギンだって飛べるもん。',
    'ペンギン、Suicaでモデルデビューしたんだ。',
    'ペンギン、今日も元気に生きてるよ。',
    'ペンギンのお家、昨日シロアリが出たんだ。',
    'ペンギン、イオンのお客様感謝デーには毎回参加するよ。',
];

client.once(Events.ClientReady, client => {
    console.log(`接続を開始`);
});

/**
 * メッセージ新規投稿時のイベント
 */
client.on(Events.MessageCreate, async msg => {
    switch (msg.content) {
        case "何か言って":
            // ランダムでメッセージを返す
            let message = messages[Math.floor(Math.random() * messages.length)];
            await msg.reply(penguinResponse(message));
            break;
    }
});

client.login(process.env.DISCOAD_TOKEN);

```

### 立ち上げてみる
下記のコマンドを実行すると
`node index.js `

```
$ node index.js 
接続を開始
```

となり、実行中の間はBotがオンライン状態となり、
チャンネルに投稿されたワードを検知するようになります。

## 常駐化させる

このままだとローカルで`node index.js`を実行して立ち上げている間だけ反応するので
PCをずっと立ち上げっぱなしでないと常駐はできません。

***つまり、この愛くるしいペンギンちゃんは定時になると帰ってしまいます***

そこで、~~帰らせないために~~
借りているレンタルサーバに`git clone`で設置を行い、常駐化ツールを導入して
常に立ち上がるようにしました。


まずは`forever`をグローバルで追加します。

```
npm install -g forever
```

最後に`forever`を使って、Botのプロセスを常駐起動させます。

```
forever start ./index.js 
```

これで常にペンギンちゃんが常時稼働になりました！
めでたし、めでたし...（?） :clap:

# おわりに
ペンギンちゃんにはいろいろ教えつつ育成しているので
今ではオリジナルのセリフを覚えてくれたりするようになりました！
discord.jsは意外と動かすまでサクサク行けるので
ぜひお試しください！

# 感謝
コミュニティ的なものもあるようです。
いろいろ参考にさせていただきました！

https://scrapbox.io/discordjs-japan/

ほぼこちらの記事を参考にさせていただきました！

https://qiita.com/yuto0214w/items/1ecee25efca6b5b7445b
【Python】大きなSQLファイルを複数の小さなSQLファイルに分割する方法

# 概要
ある大きなSQLファイルを複数のSQLファイルに分割したいという必要性が生じたので、Pythonプログラムで実装しました。
分割したいSQLファイルがたくさんあるとプログラムで一括処理した方が早いですよね。

## 前提
前提として、どのSQLファイルも`INSERT INTO...`各SQLステートメントから始まるものとします。
また、分割した際のファイル名は`01_insert.sql`、`02_insert.sql`...といった形で連番のファイル名にして行きます。

# サンプルコード

```py
import os

def split_sql_file(file_path):
    dir_path = os.path.dirname(file_path)

    with open(file_path, 'r') as f:
        lines = f.readlines()

    insert_file_counter = 1
    insert_file = None

    for line in lines:
        if line.lower().startswith('insert into'):
            if insert_file is not None:
                insert_file.close()
            insert_file = open(os.path.join(dir_path, f'{str(insert_file_counter).zfill(2)}_insert.sql'), 'w')
            insert_file_counter += 1
        if insert_file is not None:
            insert_file.write(line)

    if insert_file is not None:
        insert_file.close()

split_sql_file('./sample_dir/sample_insert_sql.sql')
split_sql_file('./sample_dir2/sample_insert_sql2.sql')
split_sql_file('./sample_dir3/sample_insert_sql3.sql')
split_sql_file('./sample_dir4/sample_insert_sql4.sql')
```

# サンプルコード解説

- `os.path.dirname(file_path)`: ファイルパスからディレクトリパスを取得
- `open(file_path, 'r')`: 指定されたパスのファイルを読み込みモードで開く
- `f.readlines()`: ファイルの全行をリストとして読み込む
    - 似たメソッドに以下があります
        - `read`: ファイルから1行だけ読み込み文字列として返す
        - `readline`: ファイルを全て読み込み文字列として返す
        - `readlines`: ファイルから全ての行を読み込み、それぞれの行を要素とするリストを返す
- `insert_file_counter`: 新しく作成するSQLファイルの名前に使用するカウンター。上述の通り、今回は`01...`と採番していくため
- `if insert_file is not None:`（1つ目）: 既に開いている出力ファイルがある場合、それを閉じるようにします。これはリソースの解放のため
- `open(os.path.join(dir_path, f'{str(insert_file_counter).zfill(2)}_insert.sql'), 'w')`: 新しい出力ファイルを作成し、書き込みモードで開く。ここでゼロ埋め処理、ディレクトリ名とファイル名の結合も行う。ファイル名を変えたい場合はここを適宜編集
- `insert_file_counter += 1`で、ファイルカウンターをインクリメント。3つのファイルがあれば`03`までですし、15ファイルあれば`15`まで採番します
- `if insert_file is not None:`(2つ目): 1つ目と同じコードですが、これは一番最後のファイルを閉じるためのもの
Laravelのユニットテストで、Errorのセッション情報が存在しない時

# 確認したこと

LaravelのControllerの中でvalidateメソッドを使用していたので、エラーがblade側で表示されるかテストで確認しようとしてた時の出来事。

validateメソッドの中身はこんな感じ↓↓↓

```jsx
validate($request, [
	...	
	'user_first_name_kana' => 'required|kana|max:50|',
	...
])
```

ユーザーがカタカナ以外を入力したときにバリデーションで弾かれる処理を書いていました。

これをテストするために、以下のようなテストを書いていたのですが、なぜか通らず。

```jsx
$response = $this->post(route('hogehoge'), $params);
$response->assertStatus(302);
$response->assertSessionHasErrors('user_first_name_kana');
```

`dd(Session::all())`で、セッション情報を確認。

```jsx
null
```

何もないだと…!!!

そもそも、$responseにエラーが返ってきた時の文字が保存されているのかを確認することにした。

$responseの中身をddで、確認してみると…

```jsx
#messages: array:2 [
    "user_first_name_kana" => array:1 []
     "user_last_name_kana" => array:1 []
]
```

$messagesに、何も存在しない。

そんなことはないと思い、Web上の挙動を確認すると、ちゃんとエラーメッセージが表示されていることを確認できた。

![スクリーンショット 2024-02-19 21.50.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2597943/e0c5fcfe-e09d-78cf-8f32-3152d3f5e4ef.png)


テスト側の問題であり、かつsessionにもエラーが保存されていないことまで確認できた。

# 試したこと

今回、試したことは以下になります。

- WithoutMiddlewareの追加

かなり、沼ってようやく行き着いたのが、`WithoutMiddelware`の存在。

というのも、postで呼び出してたエンドポイントが、middlewareで、囲まれていたため、こいつが悪さをしてるようでした。

```jsx
Route::group(['middleware' => 'not_demo'], function () {
      Route::get('hoge', 'hogeController@index');
      Route::post('hogehoge', 'hogehogeController@edit');
 });
```

※調べても、具体的な原因には辿り着かず💦

ということで、WithoutMiddlewareのトレイトを使用して、テストコード内のセッション機能を無効にしてみました。

```php
use Illuminate\Foundation\Testing\WithoutMiddleware;

{
	use WithoutMiddleware;
	...
}
```

そして、再度ddでレスポンスの中身を確認すると…

```php
#messages: array:2 [
    "user_first_name_kana" => array:1 [
        0 => "姓（カナ）をカタカナで入力してください"
     ]
     "user_last_name_kana" => array:1 [
         0 => "名（カナ）をカタカナで入力してください"
     ]
]
```

今度は、ちゃんとmessagesの中身が取得できています！

あとは、assertSessionHasErrorsなどを使用してエラーメッセージがちゃんと表示されることを確認すればテスト終わり！

# まとめ

middlewareを使用することによるテストへの影響があることを今回初めて知りました。また、validateメソッドを使用すると自動的にリダイレクトをしたり、その際セッションに一時的にエラーメッセージを保存することも知らなかったので、次からテストを書くときは、一つ一つのメソッドの役割をちゃんと把握しつつ、API側の確認もしっかりしないとなと思いました。
アクセス許可の境界　学習記録

個人的なメモ

アクセス許可の境界
評価論理に基づいて、左～右へ順にAllow/Denyを見ていく流れ

そのため、何らかのポリシーがエンティティにアタッチされ、その操作がSCPのアクセス許可ポリシーで許可されているか確認し、次にリソースベースの許可ポリシーでその操作が許可されているか順に確認されるイメージ
フィルターのようなイメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3146038/c69a4331-4193-8d02-16bf-c7c2f9803587.png)
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGide/reference_policies_evaluation-logic.html
システム開発/プロダクト販売に使えそうな補助金

# はじめに

個人で開発するには自分の稼働はパケ放題状態なのですが、いざ自社でプロダクトの開発を行うには外注でエンジニアを調達したりしないといけなくなるのでそれなりにコストがかかります。
特にアーリーステージのスタートアップにおいては、売れるかどうかわからないPMF前のプロダクトに対して莫大な資金を投下しなければならず、会社が負うリスクも相当なものになります。
かといっていざ資金調達を考えたとき、エクイティで調達すると資本が希薄化しますし、銀行は売上見込がないとなかなか貸してくれません。

そんなこんなで、自社開発で使えそうな補助金について少し調べてみました。

この記事では、自社プロダクト開発やシステム開発と相性の良い補助金制度や、その活用方法についてまとめてみました。

# この記事の想定読者

- 自社プロダクトの開発をしている経営者
- スタートアップのCxO
- 外注管理をしている開発リーダー
- 先進的な技術を活用したプロダクトを開発している人

# 補助金とは

そもそも補助金とは何か、基本的な事項をまとめます。

一般に補助金とは、経産省が管轄している、事業の発展のために政府から工面される資金のことです。似たような制度に助成金がありますが、助成金とは一般に厚労省が管轄している、会社の福利厚生の向上や人材開発などに支払われる資金のことです。

補助金は申請すれば必ずもらえるものではなく、事務局による審査があります。一般には事業計画書を提出し、その事業が公金を出すに値するものかどうか、事業の性質や売上見込みの再現性、補助金で開発されるプロダクトの技術的優位性など、様々な観点で評価されます。

また補助金の重要な点として、後払い式であることがあります。VCやエンジェル投資家からの出資や銀行からの融資は、契約後すぐに振り込まれます。一方で補助金は、補助金に採択されたら、先に事業を実施し、そこでかかった経費の領収書などをもとに申請を行うことで入金手続きが行われます。先に建て替えが必要である点には注意が必要です。

# システム開発に使える補助金

自社プロダクト開発やシステム開発に使える補助金にはどのようなものがあるのか、主要なものをいくつか紹介します。

１）事業再構築補助金
コロナ後の事業転換を補助する制度として始まった事業再構築補助金は、政府のこれまでの補助金制度の中では最大級の予算規模となる大型補助金です。システム開発といった設備投資のみならず、補助金の対象となりにくい広告費なども対象です。上限は1億5,000万円です。

２）ものづくり補助金
革新的な新商品開発、新サービス開発に利用できる補助金です。システム開発を含む設備投資に活用できる補助金で、最大8,000万円まで補助されます。自社プロダクト開発を行っているスタートアップ、ベンチャーには最も適した補助金制度です。

３）小規模事業者持続化補助金
名前のとおり、社員数として20名以下の小規模事業者の支援のための補助金です。補助額は最大200万円です。広告費や旅費など、対象経費の幅が広いのも特徴です。事業再構築補助金やものづくり補助金に比べて準備の手間が少なく、要件も少ないです。

# 対象となる経費

補助金はどのような経費に対しても支払われるわけではなく、制度によって対象経費が指定されています。システム開発でも、社員の人件費は対象外です。したがって、エンジニアを自社で抱えているケースは補助されませんが、外注している場合は補助対象となります。また、家賃や旅費など一般的な経費も対象外であることが多いです。補助金制度の多くは、リスクを取る事業者を支援するものであるため、設備投資が必要であり、システム開発は無形の資産として設備投資に含まれます。

なお、主要制度ごとの対象経費の一覧は以下のページによくまとまっています。

https://financeinjapan.com/knowledge/moBJWPyY9HiGsnqQTQnOq

# その他の補助金活用方法

前述の通り、補助金は自社のプロダクト開発に活用しやすい制度ですが、視点を切り替えると、プロダクトのユーザーも活用することができる場合があります。たとえば、ユーザーが設備投資を行い、あなたのプロダクトを導入するケースです。プロダクトがSaaSアプリの場合、導入する際は一般に設備投資にはなりませんが、アプリがIT導入補助金に登録されていると、システム利用料も補助の対象となります。IT導入補助金に登録されていない場合は、カスタマイズ対応などのSIと合わせてオーダーメイドに導入するなど、プロダクトの売り方を工夫することで、資金面でクライアントの導入ハードルを下げることにつながります。

# まとめ

補助金は日常的にはあまり馴染みのない資金調達方法ですが、資本が希薄化することもなければ、返済の義務もない、うまくハマれば良い資金調達手法になりそうです。

参考：
システム開発に使える補助金は？申請時の注意点やポイントを解説  
（ https://financeinjapan.com/knowledge/3YtUV9i0PhvF8SQTJD9zrU ）
【Vuex】ストアについて

## Vuexってなに？
VuexはVue.jsアプリケーションのための情報管理パターン＋ライブラリです。またVuex アプリケーションの中心にあるものはストアです。"ストア" は、基本的にアプリケーションの 状態（state） を保持するコンテナです。単純なグローバルオブジェクトとの違いが2つあります。

1.Vuex ストアはリアクティブです。Vue コンポーネントがストアから状態を取り出すとき、もしストアの状態が変化したら、ストアはリアクティブかつ効率的に更新を行います。

2.ストアの状態を直接変更することは出来ません。明示的にミューテーションをコミットすることによってのみ、ストアの状態を変更します。



## Vuexの４つの概念
【actions】
　非同期通信し、サーバーから値を取得し、mutationsをcommit(実行)する
【mutations】
　stateを更新する
【state】
　ストアで管理する
【getters】
　stateを算出する

 Vue Components
 算出したstateを呼びactionsをDispatchする(呼ぶ)

 この４つを一纏めにしたものをモジュールと言います。





## シンプルなストアを作成してみよう

Vuexのストア作成は、ストアオブジェクトの初期状態と、いくつかのミューテーションを準備するだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/c16ea285-a6af-cf4c-832d-2cc65cd787c4.png)


これでstore.stateでストアオブジェクトの状態を参照でき、またstore.commitメソッドで状態の変更を行うことが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/cc971798-8a85-fa8c-18b5-c48509726db9.png)

Vueコンポーネントでは、this.$storeとしてストアにアクセスできます。


## Vuexの状態をVueコンポーネントにいれる
ストアにある状態をVueコンポーネントに表示するにはどうすればよいでしょうか？
Vuexストアはリアクティブなので、ストアから状態を取り出す一番シンプルな方法は、単純にいくつかのストアの状態を算出プロパティで返すことです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/71969990-6257-444e-af70-bca197d80b6b.png)
store.state.countが変わるたび、算出プロパティの再評価が発生し、関連したDOMの更新をトリガーします。
【WIP】CDK のエラー：This app contains no stacks

```
cdk bootstrap -c environment=dev

This app contains no stacks
```

# 対処法
ファイル内で，抽象化をするためにファイルを分割した際に，`bin/`内だけでなく，他の箇所でも`cdk.App()`のインスタンス定義を行なってしまっていた．
`bin/`以外でインスタンス化をしなければ，エラーは消えた．
参考にする、いいウェブサイト・ドキュメント

Rustでサイトを作るには、情報がいっぱい必要です
例えば「[HTML5・公式文書](https://html.spec.whatwg.org/multipage/)」とか
[ライブラリー・ジェネシス](http://libgen.rs/)みたいな、pdfで確保できる教科書。
みんな引っ包めて材料なんです

#
#
[C言語]
: [トライアル・サンプルコード](https://www.w3schools.com/)

#
[ツール]
: [AI・Google](https://gemini.google.com/app)
&nbsp; PDF: Portable Document Format 【Ctrl:F】で検索すればショートカットできます
&nbsp; [IMAGE・リサイズ](https://calculateaspectratio.com/)

#
もっと追加しますのでお楽しみに。
ActiveRecordモデル操作チートシート

## 初めに
日々の業務でよく使用するActiveRecordのモデル操作についてまとめていきます。
基本的な操作でも「あれ？書き方どうだっけかな？」となることが多いので、そういった方の早見表的な感じでお役に立てると非常に嬉しいです。

誤り・もっとイケてる書き方があれば、コメントいただけると嬉しいです。

## 取得

### 取得するデータの絞り込み
1つのカラムのみや配列で返されても問題ない場合は、 `pluck`を使用し、それ以外は `select`を使用するようにしています。
```ruby
  # select
  User.select(:id, :name).find_by(name: "hoge")
  # pluck
  User.where(name: "hoge").pluck(:id)
```

### データを1件取得
特定のカラムで取得
```ruby
  User.find_by(name: "hoge")
```
idで取得
データがない場合エラーになる
```ruby
  User.find(user_id)
```
idで取得
データがない場合nilを返す
```ruby
  User.find_by_id(user_id)
```
複数データの中から初めの1件のみ取得
データが空の場合でも、エラーにはならない
```ruby
  User.where(name: "hoge").first
```
複数データの中から最後の1件のみ取得
データが空の場合でも、エラーにはならない
```ruby
  User.where(name: "hoge").last
```
### 複数データ取得
```ruby
  User.where(name: "hoge")
```
### 以外
```ruby
  User.where.not(name: "hoge")
```
### あるいは・もしくは
```ruby
  User.where(name: "hoge").or(User.where(name: "foo"))
```
### あいまい検索
```ruby
  # 前方一致
  User.where("name LIKE ?", "%ho")
  # 部分一致
  User.where("name LIKE ?", "%ho%")
  # 後方一致
  User.where("name LIKE ?", "ho%")
```
### 比較
```ruby
  # 以上
  User.where("login_count >= ?", 10)
  # を超える
  User.where("login_count > ?", 10)
  # 以下
  User.where("login_count <= ?", 10)
  # 未満
  User.where("login_count < ?", 10)
```
### テーブル結合
join
```ruby
  User.joins(:posts)
```
left join
```ruby
  User.left_joins(:posts)
```
join先のテーブルで絞り込み
```ruby
  User.joins(:posts).where(posts: {title: "hoge"})
```

## 作成
### 通常
```ruby
  User.create!(name: "hoge")
  # 下記も同じ
  user = User.new(name: "hoge")
  user.save!
```
### find_by、存在しなければインスタンスを生成
作成はされない
```ruby
  User.find_or_initialize_by!(name: "hoge")
```

### find_by、存在しなければ作成
```ruby
  User.find_or_create_by!(name: "hoge")
```

## 更新
### 1件
```ruby
  User.find(id).update!(name: "foo")
```
### 複数
`updated_at`は更新されないため、明示的に更新する必要がある
```ruby
  User.update_all(name: "foo", updated_at: Time.now)
```

## 削除
### 1件
```ruby
  User.find(id).destroy!
```
### 複数

```ruby
  User.destroy_all
```
## 並び替え
### 昇順
何も指定しなければ ASCだけど、指定した方がわかりやすいと個人的には思っています。
```ruby
  User.order(:id) 
  User.order(id: :asc) 
  # これでもOK!
  User.order(id: "ASC") 
```
### 降順
```ruby
  User.order(id: :desc)
```
### 複数指定
```ruby
  User.order(id: :desc, nam: :asc)
  # これでも同じ
  User.order(id: :desc).order(name: :asc)
```
## その他
### n+1対策(`includes`)
```ruby
  User.includes(:post)
  # 複数
  User.includes(:post, :post2)
  # include したテーブルでのn+1も対策する
  User.includes(post: :comments)
```
### プレースホルダーの複数指定
```ruby
  User.where("login_count >= ? AND logout_count >=?", 10, 2)
```
自分の為だけのweb技術入門　〜ポート番号編〜


# ポート番号とは

コンピュータ上のどこに、データを送ろうか。

の、`どこ`が、ポート

そこを指し示す識別番号が、ポート番号

同じポート番号で、複数のアプリを稼働させることはできない

と言う事実認識は正しいが、

と言うより、ポート番号というのは、インターフェース：入り口、出口

なので、

サーバ側で、

3002番で：Aと言うwebアプリケーションサーバのポートで使い、
3003番で、Bと言うデータベースサーバーのポートで使う場合、

クライアントからのリクエストの流れは、

クライアントから、3002番に向けて、リクエストを送信
A（WebAPサーバ）は、3003番号に向けて、クエリを送信
B（データベースサーバ）は、3002番に向けて、データを送信
A（WebAPサーバ）は、クライアントに向けて、レスポンスを送信

と言う実現の形である



ポート番号の範囲： 0～65535

その中で、

0～1023：ウェルノウンポート
1024～49151：登録ポート番号
49152～65535：ダイナミックポート番号あるいはプライベートポート番号

となっている

ウェルノウンポート：あらかじめ用途が決められていて、設定できない




ちなみに、ポート番号は、４層目のトランスポート層のお話



# 代表的なポート番号

|ポート番号|サービス名|説明|
|---|---|---|
|22|ssh|遠隔で通信を行うときに、使用する技術|
|25|smtp|メールの送信で使用する技術|
|80|http|webサイトを表示するときに使用する技術|
|113|pop3|メールの受信する時に使用する技術|
|443|https|webサイトの通信時に、暗号化技術を用いる場合に使用する技術|

といった感じなんだが、恐ろしいのは、1023まで、全部、もれなく設定されていることだ。

全部なんて、書ききれないし、読みたくもない


# HTTP/HTTPS 通信

ブラウザでは、URLの入力窓口に、ポート番号も入力で指示することが可能である。

```
http://honyarara.com:8000
```

このように

ポート80番で、httpsを指定すると、エラーになる
ポート443番で、httpを指定すると、エラーになる

# データベースへの接続




# ポート番号の確認




```
lsof
```

このコマンドを使用すれば、全プロセスが表示される

```
lsof -i:3000
```

と実行すると、

3000番ポートは、どのサービスが使ってるか

わかる
RailsのRESTfulルーティングとパスヘルパー

<h1>目的</h1>
<p>Railsにおけるリソースフルなルーティングとパスヘルパーの確認。</P>

<h1>生成されるパスの確認</h1>

```routes.rb
Rails.application.routes.draw do
  ...
  resources :photos
end
```

```shell
> rails routes
                                  photos GET    /photos(.:format)                                                                                 photos#index
                                         POST   /photos(.:format)                                                                                 photos#create
                               new_photo GET    /photos/new(.:format)                                                                             photos#new
                              edit_photo GET    /photos/:id/edit(.:format)                                                                        photos#edit
                                   photo GET    /photos/:id(.:format)                                                                             photos#show
                                         PATCH  /photos/:id(.:format)                                                                             photos#update
                                         PUT    /photos/:id(.:format)                                                                             photos#update
                                         DELETE /photos/:id(.:format)                                                                             photos#destroy
```

| HTTP verb | パス | コントローラ#アクション | 目的 | パスヘルパー |
| --- | --- | --- | --- | --- |
| GET | /photos | photos#index | すべての写真の一覧を表示 | photos_path |
| GET | /photos/new | photos#new | 写真を1つ作成するためのHTMLフォームを返す | new_photo_path |
| POST | /photos | photos#create | 写真を1つ作成する | photos_path |
| GET | /photos/:id | photos#show | 特定の写真を表示する | photo_path(:id) |
| GET | /photos/:id/edit | photos#edit | 写真編集用のHTMLフォームを1つ返す | edit_photo_path(:id) |
| PATCH/PUT | /photos/:id | photos#update | 特定の写真を更新する | photo_path(:id) |
| DELETE | /photos/:id | photos#destroy | 特定の写真を削除する | photo_path(:id) |


<h1>参考</h1>


https://railsguides.jp/routing.html