OmniAICreator/Qiita-1.07M huggingface dataset:
ネイティブエンジニアがFlutterでアプリをリリースした時の流れ（公開まで14日間）について

## はじめに
iOS/Androidともに個人アプリを10本程度作成してリリースした経験（androidはリリースしたアプリは全部Googleにアップデートしていないので削除された。。）があります。
しかしFlutterは3年ほど前から知見はありましたがリリースは初めてしたのでその時の流れを備忘録含め残しておきます。

業務でもネイティブ開発経験が長いです。クロスプラットフォームは昔にXamarinを少し触りましたが、いまいち良さを感じずに深く手を出しませんでした。

すでに5万とあるQRコードアプリはFlutterの練習兼ねて簡単なアプリなので作成をしました。QRコード読み込みはもはやネイティブの標準カメラでもできますが、読み込みのみで、他の同類アプリは広告が多くて邪魔なイメージがあったので作ってみました。

https://twitter.com/mycb750/status/1686708261024919552?s=20

仕事でFlutterを教えているため、リリースの一連フローは経験しないとよろしくないという理由もありました

https://twitter.com/mycb750/status/1691782994917523523?s=20

## 実装機能
機能はQRコードの読み込み、QRコードの生成、QRコードの読み込み履歴があればまずはいいかと考えました。

## 画面構成の検討
画面構成については他の同類アプリを10個ほどインストールしてどのような構成になっているのが多いのかを確認し、紙に画面を書き出しました。
ボトムナビにして「読み込み、生成、履歴、その他」ってイメージで配置などを紙にかいていきました。
レイアウトはQRコードアプリなのでほとんど定型にそって作成しシンプルなものにしました。

## 実装について
QRコードのライブラリはいくつかありシェアの高いものを選択しました。読み込み画面のヘッダー、登録画面、履歴画面、その他画面
のレイアウト部分は大体GPTに自動生成させてつくりました。コードに関してもGPTとCopilotで実際にコードを自分で書いたのは、ライブラリ周りでうまく実装できてない部分やQRコードで読み込めない場合があり、そこの調整などで８割はAIで生成できました。凄い時代だなと一つのアプリを作りながら改めて実感。


## アイコンとストア画像に関して
アイコンはCanvaを使い15分ほどで作成しました。X（Twitter）アプリに触発されて（真似して）背景黒でQという文字にして作成しました。それだけだとなんのアプリかわからないのでQアールアイコンも埋め込んでおきました。
ストア画像に関してはデザイナーに無料でお願いしました。5時間ほどで作成してくれました。ストア毎のサイズ調整で苦戦してさらに5時間ほど時間を使ってくれていました。感謝

## アイコンの反映
ここに関してはAndroid,iOS個別にアイコンを作成して配置する必要があるところですが、なんと一つアイコンを作るとFlutterがそれぞれを良きサイズで配置してくれます。これは便利。

https://pub.dev/packages/flutter_launcher_icons

## 審査
iOS　/ Androidともに審査落ちしました。
ここが時間を食ったところです。アプリ自体ではなく、アプリ画像や文言についての指摘だったためデザイン修正のみで解決しました。appleの審査は1日程度ですが、落ちて画像変更しても1日以上かかるのと、最初の指摘を直しても次に別の指摘が出てきたりするので非常に手間取ります。審査員の当たり外れはあると思いますが。

https://twitter.com/mycb750/status/1691782562421842168?s=20

### Android

審査落ちの連絡

![IMG_8463.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109862/a797f954-160a-a1ab-2195-33e02468c5a3.jpeg)

アプリ名に（広告なし）とアプリ画像でも広告なしを記載していたためそこの指摘でした。

### iOS

審査落ちの連絡

![ios審査落ち.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109862/86ca5ed9-0f1a-6900-7cd0-c5a5bbfe1ce5.png)

これはAndroidと同じくアプリ画像で広告なしを記載していることの指摘でした。

しかし直しても再度審査落ち。2回さらに落ちました。

![apple審査.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109862/cd4f9c15-682f-807b-7c91-b03e9ca7d9de.png)

今度はipadの画像がipadになっていないという指摘。

一回で指摘しないでバラバラに指摘してくるからappleはタチが悪い。これはApple審査あるあるネタです。

以前もこのリジェクトは喰らってました。これはよく喰らう
https://qiita.com/y-matsumoto/items/9cae33363b1df66965e3

## 制作期間
8/2から制作を始めたためリリースの審査突破までにかけて14日間です。しかし平日の夜と休みの日を利用して行なっていたため、実際かけた時間は20時間ほどでしょうか。最初思ってたほど掛かったかもです。

https://twitter.com/mycb750/status/1691784398935621902?s=20

## リリースアプリ
下記が作成したアプリです。よかったら使ってみてください。

- iOS
- https://apps.apple.com/jp/app/qrmaster/id6461163930

- Android
https://play.google.com/store/apps/details?id=co.jp.leftinc.qr_code_master_flutter

https://twitter.com/mycb750/status/1691781853701943373?s=20

## さいごに
IT業界は5年に1度程度の感じでパラダイムシフトが起きてる気がしてます。今回のChatGPTのLLMパラダイムはインターネット登場以来の大きな衝撃でしたが、これも時代。14年ほどエンジニアをしていると、これはいいことのようなあまりよくないことのようなと複雑な気持ちですが、使い手次第です。順応力を持つことが老害脱出の第一歩ということで素直に受け入れて効率的に使うことが必要だなと思います。

まだまだ溜まってるアイデアリストノートが消化しきれていないため、今度は収益目的でアプリ作成していこうと思います。
opensslで平文パスワードを暗号化でき、複合化もできます。

### シェルスクリプトなんかに結構平文パスワードをそのまま書いているケースがある。

### 以下の方法で平文パスワードを暗号化できる。
使用するときは複合化すればいい。

### 暗号化手順
```
[root@redhat69 ~]# echo "root" | openssl enc -e -aes-256-cbc -base64 -k "foo"
U2FsdGVkX18UAwEWpq7TA/sh00Am7NtaoFYZ0yNFWAY=

```

### 複合化手順

```
[root@redhat69 ~]# echo "U2FsdGVkX1+TC1qT9/DNw+xEURIyo4ab3v0oYHbKyfs=" | openssl enc -d -aes-256-cbc -base64 -k "foo"
root

```

以下のサイトの内容をそのまま

https://www.koikikukan.com/archives/2023/07/14-235555.php
EF Coreを使用したmigrationsがあまりにも簡単に過ぎてひっくり返った話

タイトル通りなんですけどコードファーストでのデータベースの作成が簡単すぎてびっくりしたので。
参考にしたやつ [移行の概要](https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#getting-started)

##### 手順  
- DbContextとModelクラスを作成する。  
これはデータベースのテーブルに合わせてクラスと作成するだけです。  
以下に簡単に例を載せます。 
モデルクラス   
```C#
using Sysmte;
using System.Collections.Generic;

namaspace sample.Models;

public class Employee
{
    public int Id {get; set;}
    public string? Name {get; set;}
}
```
DbContext
```C#
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namaspace sample.Models;
public class SampleContext : DbContext
{
    public SampleContext()
    {
    }
    public SampleContext(DbContextOptions<SampleContext> options)
        : base(options)
    {
    }
    public DbSet<Employee> Employees {get; set;}

```
- dotnet efをインストールする。  
[Entity Framework Core ツールのリファレンス - .NET Core CLI](https://learn.microsoft.com/ja-jp/ef/core/cli/dotnet)  
- Migrationを作成する。  
```
dotnet ef migrations add InitialCreate
```
- データベースをUpdateする。  
```
dotnet ef database update
```

これだけでクラス情報に合わせたテーブルが作成できるのすごい。 
リレーションなんかも設定できるみたいですね。  
接続文字列の作り方とかは調べてみてください.(僕もよくわからないので)
【備忘録】kaminariを使ってページネーションを実装する

# はじめに
Railsのgemである**kaminari**を用いて、ページネーションを機能を実装した際の手順を、
備忘録としてまとめたいと思います。

# 実装手順
## 手順概要
1. `kaminari`をGemに追加する
1. 設定ファイルを生成&設定を変更する
1. テーマを生成する(任意)
1. コントローラーのデータ取得の処理を修正する
1. 表記を日本語化する

## 手順詳細
### 1. `kaminari`をGemに追加する
以下の通り、Gemfileにkaminariを追加します。

```gemfile:Gemfile
gem 'kaminari'
```
以下のコマンドを実行して、インストールします。
```zsh:terminal
bundle install
```

Docker上で開発している場合は、以下のコマンドを実行します。
```zsh:terminal
docker-compose build
```
`docker-compose build`を実行してもインストールされない場合は、以下のコマンドを実行します。
(webの部分はdocker-compose.ymlに記載の名前に変更して実行してください)
```zsh:terminal
docker-compose exec web bundle install
```
これで、インストールが完了となりますので、次のステップへ進みます。

### 2. 設定ファイルを生成&設定を変更する
まず、設定ファイルを生成するため、以下のコマンドを実行します。

```zsh:terminal
rails g kaminari:config
```

Docker上で開発している場合は、以下のコマンドを実行します。
```zsh:terminal
docker-compose exec web rails g kaminari:config
```

実行すると`config/initializers`ディレクトリに`kaminari_config.rb`が生成されるので、ファイルを開きます。
今回は1ページに表示するデータの数を8個にしたかったので、以下のようにコードを追記しました。
(デフォルトの設定は25となっています。)
```ruby:kaminari_config.rb
Kaminari.configure do |config|
  config.default_per_page = 8
end
```

### 3. テーマを生成する(任意)
以下のコマンドを実行して、テーマを生成します。
デフォルトのページネーションのデザインでも良かったのですが、今回はbootstrap4のデザインを採用しました。

```zsh:terminal
rails g kaminari:views bootstrap4
```

Docker上で開発している場合は以下のコマンドを実行します。
```zsh:terminal
docker-compose exec web bunlde exec rails g kaminari:views bootstrap4
```
bootstrap4以外のテーマもありますので、気になる方は[こちら](https://github.com/amatsuda/kaminari_themes)から確認してみてください！

### 4. コントローラーのデータ取得の処理を修正する
ページネーションしたいデータを取得する際の処理を修正します。
以下参考例です。

```diff_ruby:products_controller.rb
class ProductsController < ApplicationContorller
  
  def index
-   @products = Product.all
+   @products = Product.page(params[:page])
  end

end
```

ちなみに以下のように`per`を用いることで、ページネーションのデータ数の設定を上書きすることが可能です。
```ruby
# データ数の上限を4に変更
@products = Product.page(1).per(4)
```

### 5. 表記を日本語化する
デフォルトでは日本語化されていないので、日本語で表記されるよう変更します。
`config/locales`ディレクトリ内にある`application.rb`に以下を追記します。

```diff_ruby:config/locales/application.rb
require_relative 'boot'

require 'rails/all'

Bundler.require(*Rails.groups)

module Myapp
  class Application < Rails::Application
    
    config.load_defaults 7.0

+   config.i18n.default_locale = :ja
    config.time_zone = 'Tokyo'
  end
end
```

次に`config/locales`ディレクトリに`ja.yml`を作成し、日本語化するための設定を記載します。
まず、以下のコマンドを実行して`ja.yml`ファイルを作成します。
```zsh:terminal
touch config/locales/ja.yml
```

`ja.yml`ファイルを作成したら、ファイルを開き以下を記載します。
```yaml:config/locales/ja.yml
ja:
  views:
    pagination:
      first: '最初'
      last: '最後'
      previous: '前'
      next: '次'
      truncate: '...'
```

画面を開くと設定が反映され、日本語化されて表示されると思います。
以上で、kaminariの設定は終わりです。

# 最後に
kaminariの設定に関して、ざっくりとまとめてみました。
皆様の参考になりますと幸いです。

# 参考文献
- [【Rails】kaminariの使い方をざっくりまとめてみた](https://zenn.dev/yukihaga/articles/3d49208638e397)
- [kaminari Github](https://github.com/kaminari/kaminari)
- [kaminar_themas Github](https://github.com/amatsuda/kaminari_themes)
cloud functionsのトリガーを実装してみる

# はじめに
最近firebaseにはまっているyappiです。
今回は、cloud functionsでトリガーについて、便利だなと思ったので、記事に残しておこうと思います。
firebase authってめちゃくちゃ便利で、よく使用するんですが、私は、authに登録したら、とりあえずfirestoreにもユーザ情報を登録しようみたいな流れになっちゃうんですね。
私だけなのか、あるあるなのか。。まぁそれはさておき。
いつもGoogle認証だけで実装していたりするんですが、Email／Passwordも追加する機会があり、その時にfunctionsを使った方が便利だなと思ったので、記事にまとめてみようかと思います！

# なぜトリガーを使ったか？
私は普段、Next.js × firebaseで個人開発してまして、基本Google認証完了後、取得したユーザデータを使用して、firestoreにユーザ情報を格納するみたいな流れで実装をしてました。

```typescript
/**
 * Googleアカウントでサインイン
 * @returns Promise<FirebaseResult>
 */
export const signInWithGoogle = async (): Promise<FirebaseResult> => {
  let result: FirebaseResult = { isSuccess: false, message: '' }
  const provider = new GoogleAuthProvider()
  try {
    const user = await signInWithPopup(auth, provider)
    const docRef = doc(db, 'users', user.user.uid)
    const docSnap = await getDoc(docRef)
    if (!docSnap.exists()) {
      setDoc(docRef, {
        uid: user.user.uid,
        username: user.user.displayName,
        email: user.user.email,
        photoURL: user.user.photoURL,
        createdAt: serverTimestamp(),
      })
    }
    if (user) {
      result = { isSuccess: true, message: 'ログインに成功しました' }
    }
  } catch (error) {
    result = { isSuccess: false, message: 'ログインに失敗しました' }
  }
  return result
}
```

しかし、Email／Password認証も追加で実装するとなると、これまでGoogle認証では取得できていた、`displayName`や`photoURL`を取得できなくなることに気づきました。
そして、なんといっても、firestoreへの登録処理を再度実装しないといけないのと、ユーザの項目を追加しようかと考えたら、どっちにも追加しないといけないなぁとか、、（共通化するっていう手もあったな・・って書いてて思いました）

ということがあって、cloud functionsでトリガー作っちゃおう！functionsも勉強したかったし、ちょうどいい！ということで、authにユーザが登録されたら、これらの項目が追加されるように設定しました。

# トリガーの実装
半分興味と勉強がてらと思ってトリガーを実装しようと思いましたが、`displayName`と`photoURL`は取れないので、そこは妥協しました。
とりあえず、`username`は、Emailの`@`の前の部分を登録して、`photoURL`はユーザアイコンを使用している部分は、`null`の場合は、デフォルトでアイコンが表示されるようにしておきました。

functionsの初期設定は、以前記事におこしたので、それを参考にしていただける幸いです。

https://qiita.com/yappi-dev/items/807040e7c71dccc91b97

コードの内容は以下になります。
```typescript
/** Authにユーザが新規登録されたときに動作する処理  */
const registerUserTriggerFromAuth = functions
  .region('asia-northeast1')
  .auth.user()
  .onCreate(async (user) => {
    try {
      await usersColRef.doc(user.uid).set({
        uid: user.uid,
        username:
          user.displayName || user.email?.split('@')[0] || 'ユーザ名未設定',
        email: user.email,
        photoURL: user.photoURL || null,
        createdAt: admin.firestore.FieldValue.serverTimestamp(),
      })
      return
    } catch (error) {
      console.error(error)
      return
    }
  })
```

authにユーザが登録されたら動作する関数は、`onCreate()`です。
これで、Google認証またはEmail／Password認証どちらで新規登録しても同じようにfirestoreにユーザ情報が登録されます！ちょっと便利になった気がします。
最近はこのトリガーを使って、自分のサービスにユーザが新規登録されたら、メールが飛ぶように設定しました。
わざわざfirebaseを開かずとも、ユーザが増えていることを確認することができます！
（そんなに利用ユーザがいないので、functionsの使用量もそこまで気になりませんが、、良いのか悪いのか・・汗）

# 終わりに
今回は、cloud functionsのトリガーについて記事をまとめました。
次回は、お問合せ内容を登録したら、メールで通知がいくようなトリガーや頻度を設定したバッチ処理など、cloud functionsを使用した処理についてまとめていきたいと思います。

この記事が何かの役に立てると幸いです。間違い等ございましたら、ご指摘等、お願いします。
ボタンを押したら処理を実行するスクリプト

```
// SwiftUIフレームワークをこのファイル内で使用するためのインポート文です。
import SwiftUI

// ContentViewという名前のViewを定義しています。SwiftUIのViewプロトコルに準拠しています。
struct ContentView: View {

    // bodyプロパティはViewプロトコルに必要です。このViewがどのように見えるか、またどのように動作するかを定義します。
    var body: some View {

        // VStackは縦に並ぶViewをまとめるコンテナです。この中にViewを追加することで縦に並べることができます。
        VStack {
            Button("ボタン") {
                // この中には、ボタンが押された時に実行したい処理を書きます。
            }
            .padding(.all)  // ボタン全体にパディングを追加しています。
            .background(Color.blue)  // ボタンの背景色を青に設定しています。
            .foregroundColor(.white)  // ボタンのテキストの色を白に設定しています。
        }
    }
}

// ContentView_Previewsは、XcodeのデザインキャンバスでContentViewのプレビューを表示するためのstructです。
struct ContentView_Previews: PreviewProvider {

    // previewsプロパティは、どのViewをデザインキャンバスに表示するかを定義します。
    static var previews: some View {
        ContentView()
    }
}

```



例:押してと書いているのに、押すと「押すなよ！」と表示してくるボタン
```
import SwiftUI
struct ContentView: View{
    @State var isPushed = true
    @State var Text = "押して！"
    var body: some View{

        VStack {
            Button(Text) {
                //ボタンが押された時に実行したい処理
                if isPushed {
                    Text = "押すなよ。"
                    isPushed = false
                } else {
                    Text = "押して！"
                    isPushed = true
                }
            }
            .padding(.all)
            .background(Color.blue)
            .foregroundColor(.white)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```
vue-window メモ

vue-windowについて覚え書き

https://www.npmjs.com/package/@hscmap/vue-window

# Props

@Prop({ type: Boolean, default: true })
isOpen!: boolean

@Prop({ type: String, default: '' })
title!: string

@Prop({ type: Boolean, default: false })
closeButton!: boolean

@Prop({ type: Boolean, default: false })
resizable!: boolean

@Prop({ type: Boolean, default: false })
isScrollable!: boolean

@Prop({ type: Number, default: 8 })
padding?: number

@Prop({ type: Boolean, default: true })
activateWhenOpen!: boolean

@Prop({ type: String })
positionHint?: string

@Prop({ type: Number, default: 0 })
zGroup!: number

@Prop({ default: 'visible' })
overflow!: string

@Prop({ type: Number })
left?: number

@Prop({ type: Number })
top?: number

@Prop({ type: Number })
width?: number

@Prop({ type: Number })
height?: number

@Prop({ type: Number, default: 1 })
minWidth!: number

@Prop({ type: Number, default: 0 })
minHeight!: number

@Prop({ type: Number })
maxWidth?: number

@Prop({ type: Number })
maxHeight?: number
【AWS】S3 Glacier

長期保存を目的として、以下の２種類が提供されている。

## S3 Glacier 
`Flexible Retrieval`ともいわれる。いわゆるノーマルGlacier。


**■ 取り出しオプション**

| オプション | 所要時間 | 特徴 |  
| --- | --- | --- | 
| 迅速 | 1〜5 分以内 | ・最大規模のアーカイブ(250MB以上)は1～5分でのデータ取り出し対象外<br>・不定期に発生する、アーカイブのサブセットに対する緊急リクエストの際にデータに迅速にアクセスできる。 | 
| 標準 | 3～5時間 | 取り出しオプションのデフォルト設定 |
| 大容量 | 5～12時間 | ・最も安価な取り出しオプション<br>・大量のデータ(ペタバイトのデータを含む)を1日以内に低コストで取得可能 |



## S3 Glacier Deep Archive
1年に1~2回しかアクセスされないようなデータを対象にしたストレージクラス。

- 取り出しに12時間かかる
- 1GBあたり月額0.002ドル(東京リージョンの場合)
- Amazon S3 Glacierより安価
error=invalid character 'o' looking for beginning of value, internal=invalid character 'o' looking for beginning of value

## 原因
json形式のデータを作成したものの、そのデータを直接引数に渡したりすると表示されるエラーっぽいです。  
僕の場合は、POSTメソッドでbodyにjson形式のデータを直接渡した結果、このエラーを喰らいました。

## 解決法
`JSON.stringify()`の中にjson形式のデータを入れるだけでした。  
無事にjson形式のデータがPOSTメソッドで送ることができました。
ファイバチャネルのリンク速度はニックネームであり実際の速度ではない

## はじめに結論

ファイバチャネル (FC) のリンク速度が例えば16 Gbpsの場合にデータ転送速度は2,000 MB/sではなく1,600 MB/sとなる[^1]。
1,600 MB/sは12.8 Gbpsであり、もはや<ins>FCにおけるリンク速度はデータ転送速度を表していない。</ins>

**FCのデータ転送速度はリンク速度の数字部分 (4/8/16/32) に100 MB/sを掛けたもの**である。

[^1]:MBは10^6 (1,000,000 bytes) のmegabyteであり、2^20 (1,048,576 bytes) のmebibyte (MiB) ではない

| リンク速度 | データ転送速度 |
|---|---|
| 4 Gbps | 400 MB/s |
| 8 Gbps | 800 MB/s |
| 16 Gbps | 1,600 MB/s |
| 32 Gbps | 3,200 MB/s |

FCは全二重通信のため、データ転送速度が2倍で表記される (例:16 Gbpsが3,200 MB/s) こともある。

:::note
FCのデータ転送速度は実データの転送速度であり、ここからさらにEthernetのように層を成す通信プロトコル (Ethernet, IP, TCP) ヘッダのオーバーヘッドが引かれることを考える必要はない[^2]。
:::

[^2]:FC上にIPを載せるIPFC (RFC 4338)もあるがこの記事のFCは一般にストレージ入出力に使われるFC-SCSI、FC-NVMeが前提

## 情報の在り処

米国ファイバチャネル評議会 (FCIA) サイトの[Webcasts](https://fibrechannel.org/webcasts/)から参照できる **How to use the Fibre Channel Speedmap** という資料が詳しい。

https://fibrechannel.org/webcasts/

資料には以下の記載がある。
- FCの目指すところとして _**1 Gigabit = 100 MB/s**_
- _**Speed Name Misnomers**_ (スピード名の誤った名称)
  - リンク速度はFCもEthernetも**製品名**であり転送速度としては正しくない主旨の記載があるが、Ethernetはリンク速度と転送速度が一致しておりFCのようにややこしくない[^3]

[^3]:FCをややこしく感じるのは私たちがEthernetに慣れているからかもしれない

もともと、FCのリンク速度は信号速度に基づいていたが16 Gbps以上から当てはまらなくなり (8 Gbpsの信号速度は8.5 Gbpsだが16 Gbpsでは14.025 Gbpsとなる[^4]) もはやリンク速度は直接的に何かしらの数字を表しておらずニックネーム[^5]のようである。

[^4]:信号速度のGbpsというのは厳密には正しくなく、GBaudが正しいがGbps表記も多くみられる (16 Gbpsまでは区別しなくても実質的な問題はない)
[^5]:16 Gbpsが1,600 MB/sのように数字の紐づきはあるのでニックネームとした (ニックネームという表記は記事作成にあたって筆者が考えたものであり、資料に記載はありません)

## あとがき

FCの速度について調べると、1つの速度に対して8 Gbps、800 MB/s、8.5 Gbpsのように複数の値が見つかるが、これらの数字を見て当時筆者は以下のように混乱した。
- 8 Gbpsと800 MB/sは単位の変換では計算が合わない (8 Gbps = 1,000 MB/s)
- 8 Gbpsは実は8.5 Gbpsだから0.5 Gbps得している？ (16 Gbpsでは14.025 Gbpsで損…？)

取り上げたFCIAの資料は筆者にとってこの混乱を解消するきっかけとなった。
リンク速度は単なる名称、FCのデータ転送速度はリンク速度に対して1 Gigabitあたり100 MB/sである、その他に信号速度がある、ということがEthernetと比較しながら説明されている。

## 参考資料

- [How to use the Fibre Channel Speedmap](https://fibrechannel.org/wp-content/uploads/2017/04/FCIA-SpeedMap-Final.pdf) (pdf)

- ストレージ技術 クラウドとビッグデータの時代 (ISBN:978-4-274-21758-6)

- SAN & NAS ストレージネットワーク管理 (ISBN:4-87311-099-8)

- BrocadeファブリックスイッチによるSAN設計／構築ガイド (ISBN:9784844316442)

- [FCoE vs 10GbE＋iSCSI、どちらが速い？ ネットアップとブロケードが共同検証 － Publickey](
https://www.publickey1.jp/blog/11/fcoe_vs_10gbeiscsi.html)
  > 8Gb FCの実行速度は6.2Gbps程度

  という記載からはスペックと実際のギャップがある印象を受けるが、8 Gbpsは800 MB/s = 6.4 Gbpsなのでスペックいっぱい付近まで出ている。
qiita CLI 使用時の注意

# 初め、プレビューが開かなかった
さーて、Qiita CLI使ってみるかと思ったら、`$ npx qiita preview` がうまくいかない。
ブラウザでプレビュー画面は開くのだが、「未投稿」の記事欄に新規作成した記事が表示されませんでした。

これは、コマンドを `[qiitaコンテンツフォルダ]\public` で打っていたためでした。
導入設定後、ぶらぶらしていて、たまたまそこに移動してしまっていました。
コマンドは `[qiitaコンテンツフォルダ]` で打ちましょう。
【2023年8月版】VyOSで作る簡単Linuxルーター

# はじめに

Linuxでルーター構築する勉強したいな。。。

そうだ、ChatGPT先生に教えてもらいながら構築しよう

# 環境

- VyOS13
  インストールは以下の記事を参考に
  [【2023年8月版】VyOSインストールiso作成から、ESXi7/8へのインストール](https://qiita.com/nouernet/items/a41b40dad2efea7b0efc)
- インターネット側インターフェイス `eth0` で 192.168.0.0/24
- 内側インターフェイス `eth1` 10.10.10.0/24
- 外部から内部への接続はできないようにするだけで、セキュリティは考慮せず

# 構築

```
conf
set nat source rule 10 outbound-interface 'eth0'               # 外側インターフェイスの設定
set nat source rule 10 source address '0.0.0.0/0'              # 内側ネットワークの設定
set nat source rule 10 translation address masquerade          # NAPT(IPマスカレード)を設定
commit
save
```

# apt

VyOSでaptによるパッケージ管理を行いたいなら、リポジトリを登録すると使える。

まずはバージョン確認。1.3なので、CODENAMEは、`buster`になっている。

```
$ cat /etc/os-release 

PRETTY_NAME="VyOS 1.3-rolling-202308081250 (equuleus)"
NAME="VyOS"
VERSION_ID="1.3-rolling-202308081250"
VERSION="1.3-rolling-202308081250 (equuleus)"
VERSION_CODENAME=buster
ID=vyos
HOME_URL="https://vyos.io"
SUPPORT_URL="https://support.vyos.io"
BUG_REPORT_URL="https://vyos.dev"
```

リポジトリを `debian` の `buster` で登録する。

```
$ echo "deb http://deb.debian.org/debian/ buster main" | sudo tee -a /etc/apt/sources.list
$ echo "deb http://security.debian.org/ buster/updates main" | sudo tee -a /etc/apt/sources.list
```

ssh server を更新するなら以下の通り。

```
$ sudo apt update
$ sudo apt install openssh-server
```

# さいごに

かんたんでしたね
Github個人利用とリポジトリ非公開化について


こんにちは teruteru_layです。

個人でgitを使用したいな～と思い、無料プランでリポジトリが非公開にできる
Githubを登録しました。登録するとき少し手間取ったので備忘録です。

# Github登録
まず**Github**に登録していきます。

:::note info
以下の操作はfirefox（ブラウザ）をお勧めします（理由は後述）
:::

https://github.co.jp/

上のリンクから飛ぶと右上の方に**サインアップ**があるのでクリック。

<img width="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528087/89b1bb23-c95d-8449-0fb9-d608f3d6a4ed.png">

サインアップ画面が以下のようになっていて、各種記入していくと
**Verify your account** が始まります。

ここで先ほどfirefoxをおすすめした理由について補足します。
私の環境のChromeではこの検証が終わらず、何回もやり直しされました。

ですので、もし正常に終了しない等あれば、
**ブラウザを変えてみたり、ゲストモードでサインアップ**など試してみてください。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528087/63b09e07-c5d0-eccf-d01d-0d3904f864dd.png">

これらが完了するとGithubのメインメニューに到達します。
お疲れさまでした。

# 非公開リポジトリ作成
Githubメインメニューの右上はこのようになっています。
**+ボタン**がリポジトリを作成するので、クリックして先に進みましょう。
![githubメインメニュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528087/78910323-e1b9-ad9c-ada5-a457d82c11ec.png)
![gitリポジトリ作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528087/5b9ae765-7170-2d91-2e17-635e69745561.png)
クリックするとこのように作成画面が出てくるので一番上の
**New repository**を選択します。
選択すると次の画面になります。
![リポジトリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528087/e8cac078-b421-9403-1efd-c0715b1ac439.png)

中段のラジオボタン、PublicとPrivateが、公開非公開のオプションになります。

:::note info
**Private**を選択してファイルを作成することでリポジトリを非公開にできます。
:::

必須入力は**Repository name**を入力するとリポジトリを作成できます。
あとのオプションはお好みですが、
Readmeファイルの作成とDescription(説明)は書いておくといろいろと便利です。

**Create repository**をクリックしましょう。

すると先ほど自分で入力したタイトルのリポジトリが作成できているので
これで完了です！

もし本当にほかの人から見えていないのか気になる方は
ログインしていない端末からリポジトリのURLをクリックして確かめてみましょう。

404エラーが出るので安心ですね！
![404.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528087/013307f8-9b52-c05d-6495-2a39797ff472.png)

閲覧ありがとうございました！