OmniAICreator/Qiita-1.07M huggingface dataset:
世界最小サイズのリアクティブUIフレームワーク「VanJS」の特徴４つ

最近メジャーバージョンが公開されたVanJSの特徴をまとめました。

VanJSはVueやReactのようにリアクティブなブラウザ描画が可能でありながら、サイズが超軽量という素晴らしいUIフレームワークです。

## VanJSとは？

> VanJS is an ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM. Programming with VanJS feels like building React apps in a scripting language, without JSX. Check-out the Hello World code below:

VanJS は、純粋なバニラ JavaScript と DOM に基づいた、超軽量、依存関係なし、固定観念のない Reactive UI フレームワークです。 VanJS を使用したプログラミングは、JSX を使用せずにスクリプト言語で React アプリを構築するような感じです。

https://vanjs.org/

## 特徴４つ

### 依存関係が無い

VueやReactで開発する場合は様々なパッケージをインストールする必要がありますが、VanJSはたった1行追加するだけでOKです。HTMLファイルにVanJSのスクリプトファイルを読み込ませれば、すぐに開発できるようになります（インストールもできます）。

依存関係がないので、既存のプロジェクトに導入することもできます。「動的なUIを作りたいけどVanilla JSで書くと大変だな」という場合に、部分的にVanJSで動的UIを構築することができます。

### リアクティブ

VanJSはVueやReactのようにリアクティブなブラウザ描画ができます。また、再利用可能なコンポーネントの作成や状態管理もできます。

### 超軽量

タイトルに書きましたが、世界最小サイズのリアクティブUIフレームワークです。VanJSをgzipで圧縮したサイズはわずか0.9kBです。Reactと比較すると約46倍の差があります。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1125523/bec351bf-2785-7118-5d3b-4fc70b6e61bf.png)

https://vanjs.org/#ultra-lightweight

ここまで軽量な理由は、VanJSの機能が標準のブラウザAPIを使用しているためです。


### 学習コストが少ない

VanJSで提供されている関数はとりあえず以下の5つを覚えればOKです。
`van.tags`、`van.add`、`van.state`、`van.derive`、`van.val`

JSXでは無いですが似たような感じで書けるので、普段Reactを書いている方であれば、すぐに書けるようになると思います。

公式ドキュメントは全て英語ですが丁寧に書かれているので、初めてVanJSを学ぶ方はチュートリアルをやってみることをお勧めします。

https://vanjs.org/tutorial

## まとめ

VanJSの特徴４つを紹介しました。私自身VanJSを使い始めて数日しか経ってませんが、これまでのVueやReactのようなフレームワークと比べても大変素晴らしい出来だと思ったので、多くの人にVanJSの良さを知ってもらいたくてこの記事を書きました。

## 最後に

### GoQSystemでは一緒に働いてくれる仲間を募集中です！

ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=5ed16f9d047aa92c5cbb
Cloud Storage からの CSV データの読み込みでのエラー

# 1.はじめに
* GCSにアップロードしたcsvデータを、colaboratory上でBigQueryにロードする際に、エラーにぶつかる。
* 後から見るとなーんだ、という感じだけれど、ネットを探してもすぐに発見できなかったのでメモ。


# 2.エラー
* [公式](https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-csv?hl=ja#python)に書いてあるコードをそのまま流用して実行。

```python
from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set table_id to the ID of the table to create.
table_id = "your-project.your_dataset.your_table_name"

job_config = bigquery.LoadJobConfig(
    schema=[
        bigquery.SchemaField("name", "STRING"),
        bigquery.SchemaField("post_abbr", "STRING"),
    ],
    skip_leading_rows=1,
    # The source format defaults to CSV, so the line below is optional.
    source_format=bigquery.SourceFormat.CSV,
)
uri = "gs://cloud-samples-data/bigquery/us-states/us-states.csv"

load_job = client.load_table_from_uri(
    uri, table_id, job_config=job_config
)  # Make an API request.

load_job.result()  # Waits for the job to complete.

destination_table = client.get_table(table_id)  # Make an API request.
print("Loaded {} rows.".format(destination_table.num_rows))

```

便利―と思いつつ実行するとこんなエラーが！

```python
NotFound: 404 POST https://bigquery.googleapis.com/bigquery/v2/projects//jobs?prettyPrint=false: Request couldn't be served.
```
エラー内容を調べると、load_job_from_uriのAPIコールに必要な情報が足りない。とのこと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/0bda2f91-d4b1-1760-cae6-dadbe982f028.png)



[ドキュメント](https://cloud.google.com/python/docs/reference/bigquery/latest/google.cloud.bigquery.client.Client#google_cloud_bigquery_client_Client_load_table_from_uri)を見ると、いろいろ引数があることが判明。
ネット情報ではlocation情報が不足してるから、など言われている。

# 3.修正
* いくつか試したところ、こう↓やればできた。load_jobの引数にproject=~~を追加しただけ。
* 
```python
from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set table_id to the ID of the table to create.
# table_id = "your-project.your_dataset.your_table_name"

job_config = bigquery.LoadJobConfig(
    schema=[
        bigquery.SchemaField("name", "STRING"),
        bigquery.SchemaField("post_abbr", "STRING"),
    ],
    skip_leading_rows=1,
    # The source format defaults to CSV, so the line below is optional.
    source_format=bigquery.SourceFormat.CSV,
)
uri = "gs://cloud-samples-data/bigquery/us-states/us-states.csv"

load_job = client.load_table_from_uri(
    uri, table_id, job_config=job_config,
    project="your-project"
)  # Make an API request.

load_job.result()  # Waits for the job to complete.

destination_table = client.get_table(table_id)  # Make an API request.
print("Loaded {} rows.".format(destination_table.num_rows))
```



変更部分を再掲。
```python
load_job = client.load_table_from_uri(
    uri, table_id, job_config=job_config,
    project="your-project"  ##これ
)  # Make an API request.
```


* またはclientを作るときに

```python
client = bigquery.Client(project="your-project")
```

でも行けた。単にprojectを特定するだけでよかった。
GASにおける日付比較メモ

# GASにおける日付比較メモ
自分でググってもわかりにくい解説が多かったのでシンプルメモ

## キモの部分
1日は「**1000 * 60 * 60 * 24**」である
1秒 = 1000
1分 = 1000 x 60秒
1時間 = 1000 x 60秒 x 60分
1日 = 1000 x 60秒 x 60分 x 24時間

## getTime

## 実際のコード
```test.js
function DayCheck(){
	// スプレッドシート取得
	const ss =SpreadsheetApp.getActiveSpreadsheet();
	// シート取得
	const sf = ss.getSheetByName('シート1');
    // セルから日付取得
	var daycell = sf.getRange(1,1).getValues();
    // 1日
    const days = 1000 * 60 * 60 * 24;
    // 今日の日付
    var today_ = new Date();
    // 今日の日付とセルの日付を比較
    var diff = today_.getTime() - daycell.getTime();
    // 1日以上差がある場合
    if( today_.getTime() - daycell.getTime() > days ){
        console.log( "1日以上差があるよ！");
    }
}
```
ubuntu(virtual box)でターミナルが起動しないときの対処

参考サイト
https://www.wantedly.com/companies/company_8457116/post_articles/494841
https://askubuntu.com/questions/1435918/terminal-not-opening-on-ubuntu-22-04-on-virtual-box-7-0-0

virtualbox(7.0.8)にubuntu(22.04.2)をインストールしたらターミナルが起動できなかったのでネットで調べた対処法を残します。

# 仮想コンソールを表示する
alt + ctrl + F3を押下する
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/195759f7-61e1-c409-506c-6701b3736d29.png)

# ログインする

# localeファイルを確認する
cat /etc/default/locale

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/fc29609b-c304-670a-4c4d-a2b55fca200b.png)


# localeファイルを編集する
vi /etc/default/locale

(修正前)
LANG="en_US"

(修正後)
LANG="en_US.UTF-8"

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/3d2ea8f5-c236-e09c-3851-778bd655af53.png)

# 再起動する
reboot

# ターミナルが起動できるようになった
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106311/5f52b39b-84e7-c993-3ea4-e97ac3ce3bfb.png)
任意のパスパラメータ名を指定しつつネストしたルーティングをしたい[routes.rb]

# 以下のような3つのAPIを作りたいとき

```
POST /api/v1/registration_requests
GET  /api/v1/registration_requests/:token
POST /api/v1/registration_requests/:token/accounts
```

## `param` で指定する
```routes.rb
namespace :api, format: :json do
  namespace :v1 do
    resources :registration_requests, only: %i[create show], param: :token do
      resources :accounts, module: :registration_requests, only: %i[create]
    end
  end
end
```

```
api_v1_registration_requests         POST /api/v1/registration_requests(.:format)                                      api/v1/registration_requests#create {:format=>/json/}
api_v1_registration_request          GET  /api/v1/registration_requests/:token(.:format)                               api/v1/registration_requests#show {:format=>/json/}
api_v1_registration_request_accounts POST /api/v1/registration_requests/:registration_request_token/accounts(.:format) api/v1/registration_requests/accounts#create {:format=>/json/}
```

となり、パスパラメータにプレフィックスがついて `registration_request_token` になってしまう

## `path` で指定する
```routes.rb
namespace :api, format: :json do
  namespace :v1 do
    resources :registration_requests, only: %i[create show], param: :token
    namespace :registration_requests, path: 'registration_requests/:token/' do
      resources :accounts, only: %i[create]
    end
  end
end
```

```
api_v1_registration_requests          POST /api/v1/registration_requests(.:format)                 api/v1/registration_requests#create {:format=>/json/}
api_v1_registration_request           GET  /api/v1/registration_requests/:token(.:format)          api/v1/registration_requests#show {:format=>/json/}
api_v1_registration_requests_accounts POST /api/v1/registration_requests/:token/accounts(.:format) api/v1/registration_requests/accounts#create {:format=>/json/}
```
となり、解決！
ServiceNow カスタムアプリケーション開発時のチェックリスト

ServiceNow-Now Platformをベースにカスタムアプリケーションを開発する際のチェックリストを残しておきます。
アプリケーション開発時、まずはこのチェックリストに従って進めていただければと思います。

■プロセスの定義
　・ビジネス上の課題
　・結果
　・入力
　・出力
　・ユーザーペルソナ/利害関係者
　・プロセスのステップ

■データモデルの設計と構築
　・テーブル
　・列
　・リレーション

■ユーザーインタフェースの設計と作成
　・デスクトップ/タブレット
　　→リストレイアウト/フォームレイアウト/アプリケーションモジュール等

■セキュリティの適用
　・ロール
　・アクセス制御（ACL）
　※ユーザー基準等

■自動化
　・フローデザイナー
　・スケジュールスクリプトの実行
　・メール
　※他イベントや、スクリプトアクション等も関与する。

■データ連携
　・SOAP/REST/CSV/Excel
　※他製品（サードパーティ）、マイグレーション時の考慮など

■ユーザインタフェースの向上
　・サービスカタログ
　サービスポータル等カタログを置く場所などユーザが利用する範囲全体を示す。

■テスト
SQLServerで末尾の列が空欄のTSVをBULK INSERTしてNULLを挿入したい！

# この記事で伝えたいこと
::: note info
改行コードも気をつけよう
末尾の列が空欄でKEEPNULLSをオプションを指定してもNULLにならないことがあるよ
デフォルトで入る改行コードはOSによって、違うよ
tsvを書き出す時に、改行コードを指定しよう
:::

# 本題
さて、普段(といってもまだ2つ)はPowerAppsの記事を書いていましたが、別のお仕事でPythonとSQLServerを触っていて詰まったので、メモがてらまとめておきたいと思います。

早速本題ですが、皆さんTSVをBULK INSERTで空文字をNULLにしたいことってありませんか？
そんなときはKEEPNULLSオプションを指定しましょう。
```SQL
BULK INSERT MyTable
FROM 'C:\path\to\sample_data.tsv' -- ファイルのパスを指定
WITH (
    FIELDTERMINATOR = '\t', -- フィールドの区切り文字をカンマと仮定
    KEEPNULLS
);
```
いかがでしたか？

# NULLで登録されない。
・・・こんなものを見に来たわけじゃないですよね。
KEEPNULLSを指定しているのにも関わらず、空文字が**NULLで登録されない**ことがあります。
今回自分が詰まった事例でいうと「**ROWTERMINATOR = '0x0A'**」が指定されていてかつ、次のようなtsvを**Windows環境**のPythonで作成していた場合です。

::: note warn
他パターンでも同じことが起きるかもしれませんが、未検証です。すみません。
また、この先は安全のためコードの一部のみ抜粋しているため、多少の誤りがあるかもしれません。
:::
```Python
with open('C:/path/to/sample_data.tsv', 'w', encoding='utf-8') as f:
# この先で書き込む処理
```
```SQL
BULK INSERT MyTable
FROM 'C:\path\to\sample_data.tsv' -- ファイルのパスを指定
WITH (
    FIELDTERMINATOR = '\t', -- フィールドの区切り文字をカンマと仮定
    ROWTERMINATOR = '0x0A'
    KEEPNULLS
);
```
```sample_data.tsv
| column1 | column2        | column3 | column4        |
|---------|----------------|---------|----------------|
| data1   | "ここに空文字"　 | data3   | "ここに空文字"  |
```

この場合の「column2」はしっかりとNULLで入るのですが、「column4」は空文字で入ってしまいます。
何となく、ピンと来る方もいると思いますが・・・
Windows環境のPythonでは何も考えずに順当にtsv等で出力すると、改行コードが自動変換され**CRLF**になってしまいます。
(正確に言うとPythonのnewlineを指定しないと自動で「**os.linesep**」というものが使われることで結果的に自動変換される、といった形です)

今回、SQLServerで「ROWTERMINATOR = **'0x0A'**」を指定していることで'0x0A'はLFの16進数表現なのでtsvの改行コードと一致せず、今回のようなことが起きてしまったものと思われます。(末尾に改行コードが入ってきてしまっているイメージでしょうかね・・・？)

# じゃあどうすればいいの？
対策は簡単で、Pythonでtsvを出力する時に改行コードを指定してあげればいいのです。
```Python
with open('C:/path/to/sample_data.tsv', 'w', encoding='utf-8', newline='') as f:
# この先で改行を'\n'でtsvに書き出す処理
```
もしくは・・・
```Python
with open('C:/path/to/sample_data.tsv', 'w', encoding='utf-8', newline='\n') as f:
# この先で改行を'\n'でtsvに書き出す処理
```
**newline**というオプションに「''」を追加することで改行コードの自動変換が無効になります。
もしくは、'\n'を指定することでも可能です。

これで、無事にNULLで登録されるはずです。


# 終わりに
いかがでしたでしょうか、PowerApps以外の記事を書くのは初めてで微妙に緊張しました。
今後もPowerApps以外のことも触っていたりするので何かあれば書いていこうと思います。
# 参考
Pandas: DataFrame.to_csv() の改行コードを制御
https://scrapbox.io/shimizukawa/Pandas:_DataFrame.to_csv()_%E3%81%AE%E6%94%B9%E8%A1%8C%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E5%88%B6%E5%BE%A1

一括インポート中の NULL または既定値の保持 (SQL Server)
https://learn.microsoft.com/ja-jp/sql/relational-databases/import-export/keep-nulls-or-use-default-values-during-bulk-import-sql-server?view=sql-server-ver16

Windows上で実行したPythonの出力ファイルの改行コードが変わる
https://qiita.com/tatsuya-miyamoto/items/f57408064b803f55cf99

Pythonでファイルを読み書きするとき、改行コードはどうなるの？
https://pythonmaniac.com/file-rw-newline-code/
KotlinSerializationを使ってJsonパースの際、Enumを利用する

KotlinSerializationのJsonパースの際に内部では固有の型として扱いたい。
イメージでは特定の動作を示すValueがStringやIntが送られてくるが、
内部ではその値がどのような挙動を示すか宣言から示したいなと思い調べた。

## 実装
~~~ Data.kt
@Serializable
data class Data(
    val status : Status? 
)
~~~

今回利用するデータクラス。
Status型として受け取れるようにします。
今回は0，1...などパラメータがInt型で送られてくると仮定します。

~~~CustomSerialization.kt
@Serializable(with = Status.Companion.Serializer::class)
enum class Status : StatusEnum{
    OFF {
        override val param: Int = 0
        override val bool: Boolean = false
    },
    ON {
        override val param: Int = 1
        override val bool: Boolean = true
    }
    ;

    companion object {
        object Serializer : StatusEnum.Companion.Serializer<Status>(Status::class)
    }
}

interface StatusEnum {
    val param: Int
    val bool: Boolean

    companion object {
        abstract class Serializer<T:Enum<T>>(
            private val kClass: KClass<T>
        ) : KSerializer<T?> {
            override val descriptor: SerialDescriptor =
                PrimitiveSerialDescriptor(this::class.jvmName, PrimitiveKind.INT)

            override fun serialize(encoder: Encoder, value: T?) {
                when(val label = (value as StatusEnum).param){
                    else -> encoder.encodeInt(label)
                }
            }

            override fun deserialize(decoder: Decoder): T? {
                val decode = decoder.decodeInt()
                return kClass.java.enumConstants?.firstOrNull { (it as StatusEnum).param == decode }
            }
        }
    }
}
~~~
KotlinSerializationはカスタムクラスにシリアライズする場合は、カスタムシリアライザーを実装しなければいけません。
カスタムシリアライザーで受け取った値をEnumへと変換できます。
これは【0,1での例＋想定外の値はnullとして扱う】ですが
Status.Noneなどを入れてそれ以外を加えることで想定外の値にも対応できるはず。
（Stringなどならencodeの際は適切なメソッドを使用する）

### 感想
ここまでやったが、（自分は）実際にはResponse用のクラスとModelクラスでは分けて実装することが多いのでModelクラスへのConvertのところでこういうのはやればいいかなとも思った。
アノテーションとかでｽｯと出来ないので、あまりカスタムすることは想定してないのかな？
（リフレクション不使用やTypeSafeで扱う仕様からかもしれないけど）
でもせっかく調べて、何かに役に立つかもしれないので備忘録として。
アプリケーションオリジナルのエラーコードなどのハンドリングに使えば、同時にエラーメッセージを内包できたりしそうなのでそういった部分では活用できるか。

他に最近ではenumでやっていたようなことは、sealed Class(interface)で扱うことも多いので、そちらへの変換もしたい。

#### 追記
Sealed Classへのパースはこちらに記載がありました。

https://qiita.com/morayl/items/6d4f3726ab0ed811e444

ポリモーフィズムによってSealded Classの方がEnumより柔軟に扱えるかと思います。
データ部を複雑なJsonにすること自体は実務上中々ないと思いますが、
やはり（アプリ限定）エラーハンドリングは早期に分かった方が嬉しいですかね。
Postgresql で連続した日付を作成する方法

普段 orm で済ましているから機会がなかったが、SQLだけでクエリ〜集計まで全てやることがあったので備忘録として

`generate_series` を使用して作成。当然 PostgreSQL 専用。
`now()` や `interval` の範囲を変えればいろんなケースに対応可能。


```
-- 1年以内の yyyy-MMのリスト
with year_month_list as (
  select 
    to_char(generate_series, 'yyyy-MM') as date
  from 
    generate_series(
      (now() - interval '1 year') at time zone 'jst', 
      now() at time zone 'jst',
      '1 month')
)
```
tailwindcss　シンプル構築

mkdir $1
cd $1
npm init
mkdir public
mkdir src
npm install -D tailwindcss
npx tailwindcss init
cat << EOF > tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./public/**/*.{html,js}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
EOF
cat << EOF > src/style.css
@tailwind base;
@tailwind components;
@tailwind utilities;
EOF
npx tailwindcss -i ./src/style.css -o ./public/style.css
cat << EOF > pakage.json
{
  "name": "testcss",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "tailwindcss": "^3.2.0"
  },
  "scripts": {
    "build": "npx tailwindcss -i ./src/style.css -o ./public/style.css",
    "watch": "npx tailwindcss -i ./src/style.css -o ./public/style.css --watch"
  }
}
EOF
閉じたネットワーク内の　Windwos クライアントをリモートメンテナンス

閉じた LAN 内にある、Windows クライアントをメンテナンス作業する。

普通はリモートメンテナンスのために VPN ゲートウェイや ssh でポートフォワーディングする仕組みを作っておく。

だけれども何も設定していないクライアントPC に対し、最小限の設定をエンドユーザーにしてもらってリモートメンテナンスをする、あるいは第三者に一時的に開放してメンテナンスしてもらう、などの場合は以下のような方法を使うと便利。


- USB の 無線LAN アダプタを用意する
- 無線LANアダプタをエンドユーザに接続してもらい、それ経由でリモートメンテナンスを行う
- リモートメンテナンスが終われば、無線LANアダプタをエンドユーザに取り外してもらう

装着している間はリモートメンテナンス可能ということで、エンドユーザにもわかりやすいメリットがある。

# 前提条件

- クライアントPC は有線LANで接続して通常業務を行う。インターネット接続はできない。
- インターネット接続可能な無線LAN環境がターゲットの屋内にある。
- 無線 LAN アダプタはクライアントPC に装備していない。あるいは有効化していない。

# 事前に設定

- 必要に応じ、使用する無線LANアダプタの設定をあらかじめクライアントPC に行っておく。
- あらかじめクライアントPC に「NTT 東日本 - IPA 「シン・テレワークシステム」サーバ」をインストール

# リモートメンテナンスを行う手順

- リモートメンテナンスをはじめる際、エンドユーザーがクライアントPC に無線LANアダプタを装着し、インターネット接続を有効化作業を行う
- 外部から「シン・テレワークシステム」を使いリモートメンテナンス
- リモートメンテナンス終了時にインターネット接続を無効化する
- エンドユーザーがクライアントPC から無線LANアダプタを取り外す

# Wi-Fi を有効にする手順

Wi-Fiアダプタを装着したあと、エンドユーザーに行ってもらう、インターネット接続の有効化。
以下は Windows10 の手順。


画面右下に Wi-Fi の電波インジケーターが表示されていて、電波が強く表示されていることを確認する。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/27912a5b-4363-095c-21d9-7aa519d55411.png)

もし、電波が弱かったら本体やアンテナの位置を変えて工夫。

電波インジケータが表示されていなかった場合は、「電波インジケータが表示されておらず、地球儀マークになっている場合」を見て直す。


電波インジケータを押して、指示のある ID に接続して「接続済み」とする。

![コメント 2023-08-23 125500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/0fb2a0b2-0f15-b7fc-296a-847468b9ef77.png)



## 電波インジケータが表示されておらず、地球儀マークになっている場合

もし、以下のような表示になっていたら Wi-Fi が無効なので有効にする。
![コメント 2023-08-23 135723.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/3dfdc1a0-ef49-29ce-ede8-f6b5341bf81c.png)

Wi-Fiが無効になっていたら、地球儀マークを押して以下の表示を出す。以下の表示が出ない場合はWi-Fiアダプタが有効になっていないので設定をし直す必要がある。

![コメント 2023-08-23 134021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/db2f0300-2725-0de8-08dd-098895065a34.png)

Wi-Fiボタンを押して有効にする

![コメント 2023-08-23 135911.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8b9c68d6-c7bf-4f1b-bdd8-995c9797e90f.png)

## Wi-Fi を無効にする手順

メンテナンスが終わったら、Wi-Fi アダプタを取り外す。

Wi-Fi アダプタを取り外せない場合は、画面右下の電波インジケータを押して


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/27912a5b-4363-095c-21d9-7aa519d55411.png)

青い Wi-Fi ボタンを押して


![コメント 2023-08-23 135911.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8b9c68d6-c7bf-4f1b-bdd8-995c9797e90f.png)

地球儀マークにする

![コメント 2023-08-23 135723.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/3dfdc1a0-ef49-29ce-ede8-f6b5341bf81c.png)
Missing required client configuration options: region: (string) A "region" configuration value is required for the "s3" service (e.g., "us-west-2"). 

s3にアクセスしようとすると、突然件名のようなエラーに見舞われました。

`dd(env('AWS_DEFAULT_REGION'));`
`dd(config('filesystems.disks.s3.region'));`

と出力するとnullしか返ってこない.....

.envにもdocker-compose.ymlにもregionの記述はしてあるのにどうしてなのか？

## 解決方法
`docker compose exec app php artisan config:cache`
を実行

直った！！
Deploy a VanJS App to Cloudflare.

この抜粋の内容は次のとおりです。

- VanJS について
- Project 構成
- Deploy a VanJS site
- Summary

さらに詳しく見たい方は読み続けてください。

---

2023年8月5回目です。

このメモは、[VanJS](https://vanjs.org/) についてです。

https://vanjs.org/

> VanJS is an ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM.
>
> VanJSは、純粋なバニラJavaScriptとDOMをベースとした、超軽量、ゼロ依存、無依存のReactive UIフレームワークです。

今月に入り、Svelte、Remix、Qwik と検証しました。

最後に VanJS について見ていきます。

題材とする実装は、簡易のポートフォリオ サイトです。

今回のサイトとコードはこちらです

https://my-portfolio-vanjs.pages.dev/

https://github.com/danny-yamamoto/my-portfolio-vanjs

## VanJS について
- JavaScript と DOM。jQuery を思い出します。命令的記述。

https://github.com/danny-yamamoto/my-portfolio-vanjs/blob/81a337a072e3b64e23a2c8e6539ed30d64560fdf/src/main.ts#L33-L51

- VanJS の開発元は、Google の senior staff software engineer です。About[^2] を読むと、VanJS 開発の経緯を知ることができます。

[^2]: https://vanjs.org/about

- Chrome の Largest Contentful Paint (LCP)の結果は、以下のとおりです。
   - Remix: `0.65s`
   - Svelte: `0.62s`
   - Qwik: `0.36s`
   - VanJS: `0.13s` 👈
![スクリーンショット 2023-08-22 19.06.48.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569971/d1572ab3-a618-5f82-d479-441f0378a97d.jpeg)

## Project 構成

<details><summary>Project Structure</summary>

```bash
├── favicon.ico             # add
├── index.html              # edit
├── package.json
├── package-lock.json
├── public
│   └── vite.svg
├── README.md
├── src
│   ├── footer.ts           # add
│   ├── head.ts             # add
│   └── main.ts             # add
├── styles                  # add
│   └── styles.css          # add
└── tsconfig.json
```

</details>

## Deploy a VanJS site
- Cloudflare Pages に deploy できます。
- Framework Preset は、`None` です。
- Build configurations は、Vite[^3] の default です。
![qiita_vanjs_a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569971/de7389cb-9229-0cae-d14f-32fb6de8db33.jpeg)

[^3]: https://ja.vitejs.dev/

https://github.com/danny-yamamoto/my-portfolio-vanjs/blob/81a337a072e3b64e23a2c8e6539ed30d64560fdf/package.json#L6-L10

## Summary
- VanJS について書きました。
- 個人的には、宣言的 UI の方が好みです。
- 依存関係が無いことが素晴らしいと思います。
- Enterprise 視点では、開発元の安定性という意味で、使いにくいです。Qwik や Remix の方が安心感を感じます。

この投稿をみて何か得られた方は、いいね ❤️ をお願いします。

それでは、また別の話でお会いしましょう。👋
wslにneovimの最新バージョンをインストールする方法

# 概要

wslでneovimの最新バージョンが入らなかったので備忘録としてインストール方法をまとめます
**これだとできません**

```sh
sudo apt update & sudo apt upgrade
sudo apt install neovim
```

# 手順
## 1. 既に入っているneovimをアンインストール
```
sudo apt remove neovim -y
```

## 2. nvimインストール

こちらの動画と同じです。
[How to install Neovim 0.8 on WSL (Ubuntu) — Neovim & VsCode](https://www.youtube.com/watch?v=2wapxsfzLho)


最新安定版のNvim 0.9.1をダウンロードしたいので、スクロールしてNvim0.9.1のリンクをクリックします。
https://github.com/neovim/neovim/releases


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261812/8997d0e6-fd5d-a626-8bac-166b4a1a3a7a.png)

ここから```nvim-linux64.tar.gz```をダウンロード

# 3. パスを通す
wslに入り、```nvim-linux64.tar.gz```のダウンロード先のディレクトリに移動

以下の処理をする
```shell
mv nvim-linux64.tar.gz ~/.local/bin
cd ~/.local/bin

tar xzvf nvim-linux64.tar.gz
rm -rf nvim-linux64.tar.gz

# シンボリックリンクを作り、nvimでコマンドが起動するようにする
ln -s ./nvim-linux64/bin/nvim ./nvim
```

ご自分のターミナルでaliasを貼ります。
これで、`nvim-linux64/bin/nvim`が`nvim`で呼び出されます。
```config.fish
alias nvim=$HOME/.local/bin/nvim
```


最後に
```nvim -v```
で正しく表示されれば完了です。
OCI Compute のシェイプ変更方法(新しいシェイプへの変更手順)

OCI Computeのシェイプを拡張したりより新しいものに変更する手順です。
現在お使いのシェイプを再起動のみで簡単に変更できます。CPUやメモリを拡張したい場合や、コストパフォーマンスの高い新しいシェイプへ変更したい場合、フレキシブルシェイプで任意のCPU/メモリを設定したい場合等でお使い頂けます。

# OCI Computeでのシェイプ変更方法
VM.Standard2.1 から VM.Standard3.Flex に変更してみます。
変更前のシェイプはVM.Standard2.1です。
![スクリーンショット 2023-08-23 10.32.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/9280fd5f-93a3-0597-bb23-7fdc79ca9769.png)

1.「その他のアクション」から「編集」を選択します。
![スクリーンショット 2023-08-23 10.36.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/4a27985c-5a01-cea3-7702-e66e708a2f1c.png)

２.「インスタンスの編集」画面の「シェイプの編集」をクリックします。
![スクリーンショット 2023-08-23 10.38.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/0772987e-4e3b-d052-c349-d9a25a346b91.png)

3.変更したいシェイプ ①「Intel」②「VM.Standard3.Flex」を選択し ③「変更の保存」をクリックします。
![スクリーンショット 2023-08-23 10.48.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/b36e516e-093a-4df1-9287-7bb469adf057.png)

4.「インスタンスの再起動」をクリックします。
![スクリーンショット 2023-08-23 10.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/5b1ac919-e8cd-c56f-d466-032d72410545.png)

５.ステータスが「停止中」となりインスタンスがシャットダウンします。
![スクリーンショット 2023-08-23 10.23.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/09e1ba00-2800-03c4-1a73-3791bdf6a9e4.png)

6.その後「起動中」に変わります。シェイプが VM.Standard3.Flex に変更されています。
![スクリーンショット 2023-08-23 13.55.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/02484193-9f2e-1e45-d476-ba46fbeea858.png)

7. VM.Standard3.Flex シェイプでインスタンスが起動しました。
![スクリーンショット 2023-08-23 11.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245091/8bcdf8b2-b20b-cb84-e452-7ce3119d81ca.png)

関連ドキュメントはこちら↓です。
https://docs.oracle.com/ja-jp/iaas/Content/Compute/Tasks/resizinginstances.htm
Always Free のVM.Standard.E2.Microなど変更できないシェイプがあります。
その場合は、ブートボリュームやカスタムイメージを使用して他のシェイプに移す必要があります。
Josh Longって誰だ

# 1.はじめに

　過重な仕事は社会人にとって負担になることがあります。必死に知識をインプットして成長するのはやりがいのあることですが、疲れるときもあります。たまには薄い味の経験も欲しくなります。自分も新人エンジニアとして時々それを感じて思います。エンジニアのための気軽な経験とは何だろう？面白いのは何だろう？

　この記事は新人エンジニアが頭を少し冷やせるような小さな経験談ときっかけを共有します。そしてJosh Longという謎の男性についてもお話しします。社会人5ヶ月目の検索力を活用して。


# 2.彼との出会い

　Qiitaで同期エンジニアに面白くて有益な情報を提供したいと思いました。そこから「面白い+有益=イベント、セミナー」という結論に至ります。まずは適当にググってみましょう。新人エンジニア、イベント、セミナー。数多くの情報の中で目立つタイトルがありました。 JJUG（Japan Java User Group）。名前にJapanが入っているとなんだかオフィシャルな感じがしますね。 深く考えずにTryしてみることにしました。セミナーはすべて英語で行われますが自分の言語力を活用して、よりユニークな情報伝達ができると思いました。

　7月31日の月曜日、19時から始まったオンラインセミナー「Bootiful Springboot」。エンジニアとしての初めてのセミナーにドキドキしましたが、結論から言うと参加自体はErrorでした。全く内容が理解できなかったからです。簡単にまとめると、Spring Boot Version 3を活用してアプリケーションをリアルタイムで作り、その過程でversion3でどのようなものを実現できるかを披露する時間でした。しかし、あまり理解できずエンジニアとしての能力不足を実感しました。

　でもライブコーディングをしているこの男、Josh Longという男が気になりました。この人は何でテキパキとライブコーディングができるのか。何で日本まで来て講演をしているのか。

検索が再開されました。


# 3.彼はどんな人なのか

　なんと彼には専用ホームページもありました。 紹介欄を簡単にまとめてみます。

__*彼は2010年以来、最初のSpring Developer Advocateです。そしてJavaチャンピオンです。*__

最初から知らない単語が出てくるんですね。Spring Developer Advocateとは何？Javaチャンピオンは？ 皆で集まってコーディングする大会でも開くのでしょうか？

検索は続きます。

__*"Spring Devloper Advocate"
「Spring Developer Advocate is a role at Pivotal, a software company that provides tools and services for building modern applications. The Spring Developer Advocate is responsible for promoting the Spring Framework, a popular Java-based framework for building web applications, and helping developers to use it effectively. Josh Long is one of the Spring Developer Advocates at Pivotal.」*__

なるほど。Pivotalというソフトウェア会社での役割で、Spring Frameworkのプロモーションをするんですね。つまり今まで私たちが使っていたSpring Frameworkとこの人は密接な関係があるということです。

__*"Javaのチャンピオンです。"
「Oracleがスポンサーするプロジェクトで、コミュニティで選択されたJavaテクノロジーのリーダーを指す。Javaチャンピオンは、OracleがJavaを発展させるためのフィードバックやアイデアを提供する機会を得る。」*__

大会ではなく、ユーザーから選ばれるものなんですね。追加で調べてみたところ、Java Championは全世界で375人で、その中には日本人も7人がいるそうです。彼は思ったよりすごい人ですね。初めて来日した時、トイ・ストーリーを知らない友達がいてびっくりした記憶があります。Josh Longは実は、エンジニア業界では有名なトイ・ストーリーだったかもしれません。彼のような優秀なプログラマーになりたいですね。


# 4.感じた点

①<font color="Red">新しい経験の重要性</font>

：インプット作業はいつも難しいです。紙の資料と動画を整理する作業の繰り返し... 効率のいい方法ですが他の種類の勉強法もあります。それは「無駄な時間じゃない？」と思わせるような経験です。いつもとは違う経験をするだけでも新しい刺激になり、より広い視野で自分の現住所を把握することができます。私の場合、今回のセミナーに参加して業務に関する知識は全く得られなかったかもしれません。しかし、このような世界があることを知り、新しい目標意識を持てるようになりました。世の中の新しい技術を理解するレベルのエンジニアになりたい、と考えるようになっただけで成功です。たまには無駄な時間も大切です。

②<font color="Red">検索の重要性</font>

：社会人には検索力が必要だと言われています。特にエンジニアにとってはさらに重要です。知らないものを探索し、自分の武器を増やすプロセスは新人エンジニアだけでなくすべてのエンジニアにとって必須です。私もJosh Longについて調べながらJavaの世界についてももう少し詳しく理解できるようになりました。検索力を高めることは着実に成長しながら未来を設計する良い方法だと思います。

# 5.おすすめのイベント、セミナーサイト

最後に、今回の検索で面白そうなサイトを見つけたので共有します。

[techplay](https://techplay.jp/calendar)

[doorkeeper](https://www.doorkeeper.jp/)

[itinfoshop](https://itinfoshop.com/)

[connpass](https://connpass.com/)

[aws event](https://aws.amazon.com/jp/events/explore-aws-events/?events-master-main.sort-by=item.additionalFields.startDateTime&events-master-main.sort-order=asc&awsf.events-master-type=*all&awsf.events-master-series=*all&awsf.events-master-level=level%23100&awsf.events-master-audience=*all&awsf.events-master-location=*all&awsf.events-master-tech-category=*all&awsf.events-master-use-case=*all)

新しい経験の共有ができればと思います。
【ChatGPT無】にメールなどからカタカナ語を抽出して説明してもらう

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　会議が白熱して、
　　アップが遅れました。
***
　今回は、
　　文章中のカタカナ語を抽出して、
　　　それを説明してくれる
　　　　Promptです。
***
　最近は、
　　メールに限らず、
　　　カタカナ語が
　　　　氾濫していますよね。

　書いた本人は、
　　わかっているつもりなのかも
　　　しれませんけど、
　　　　使い方も間違っていたり
　　　　　意味不明な言葉も
　　　　　　あります。

　意思疎通する気があるの？、と
　　言いたくなるくらい
　　　カタカナ語が
　　　　使われています。
***
　そこで
　　ChatGPTさんに、
　　　教えてもらうことに
　　　　しました。

　まずは、
　　使用例からです。
　　　某量販店からのメールを
　　　　入力しました。
```Text:カタカナ語を抽出して説明例
User
某量販店
SNSを中心に人気のコアラマットレスをいよいよ取り扱い開始！

コアラマットレス取り扱い開始
進化したコアラマットレス。
振動を瞬時に吸収する独自開発のゼロ・ディスターバンス技術。体の各部位を点で支えるため、寝返りがしやすく快適に眠ることができます。
リバーシブルのトッパーレイヤーをひっくり返すだけで、季節や寝姿勢に合わせていつでも「ふつう」「かため」の寝心地に変えることができます。

Newコアラマットレス シングルサイズ
koala

Newコアラマットレス シングルサイズ

89,900円(税込)さらにポイントサービス

寝心地を選べる
サイズ
商品詳細はこちら

吸湿速乾性に優れたモデル。
Newコアラマットレスに、さらに吸湿速乾性に優れたCOOLMAX技術と多層ゾーニングを搭載。
柔らかく包み込んでくれる表面の質感としっかり体のサポートをしてくれるゾーニング層で上質な睡眠を実現。

NewコアラマットレスBREEZE シングルサイズ
koala

NewコアラマットレスBREEZE シングルサイズ

129,900円(税込)さらにポイントサービス

COOLMAX（R）繊維を使用。
サイズ
詳細はこちら

マットレスの他にも、枕とベッドフレームを取り扱ってます。
人気のコアラピローは日本人の体型や好みに合わせて、理想的な厚みと弾力性を追求した枕です。
アーバンベッドフレームはどんなお部屋にも相性がいいシンプルなデザインが特徴です。

コアラピロー
コアラピロー

アーバンベッドフレーム
アーバンベッドフレーム

生毛工房
詳細はこちら

決算セール
詳細はこちら

このメールをブラウザで見る
記載内容は送信日時点の情報です。予告なく変更する場合がございます。
本メール送信専用アドレスから送信されています。ご返信いただいてもお答えができませんので、あらかじめご了承ください。
お問い合わせは以下からお願いします。

よくあるご質問（各種お問い合わせはこちら）

配信停止・変更は会員メニューからご指定ください。
メルマガのみに登録をされている方はこの下にURLが表示されますので、こちらから変更をお願いいたします。


ChatGPT
この文章から抜き出したカタカナ語は以下の通りです：
- コアラマットレス
- ゼロ・ディスターバンス技術
- リバーシブル
- シングルサイズ
- ポイントサービス
- COOLMAX技術
- 多層ゾーニング
- ゾーニング層
- コアラピロー
- アーバンベッドフレーム
- 生毛工房
- 決算セール

こちらのカタカナ語に関する説明を以下に示します：
- コアラマットレス: 進化した寝具の一種。ゼロ・ディスターバンス技術やリバーシブルの特徴があります。
- ゼロ・ディスターバンス技術: 振動を瞬時に吸収する技術のことで、安定した睡眠を提供します。
- リバーシブル: 両面が異なる仕上げやデザインのもの。トッパーレイヤーをひっくり返すことで寝心地を調整できます。
- シングルサイズ: 一人用の寝具のサイズ。
- ポイントサービス: 購入時にポイントが付与される特典やサービス。
- COOLMAX技術: 吸湿速乾性に優れた技術で、快適な寝心地を提供します。
- 多層ゾーニング: 異なる硬さや支持力のゾーンを持つ寝具構造。
- ゾーニング層: 寝具の特定の部分に異なる寝心地やサポートを提供する層。
- コアラピロー: コアラブランドの枕。体型や好みに合わせた設計がされています。
- アーバンベッドフレーム: 都市的なデザインのベッドフレーム。
- 生毛工房: 特定の工房やブランドの名前。
- 決算セール: 特定期間中に行われるセールイベント。

上記の説明が理解できましたら、「はい」とお答えください。
```
　こんな感じに説明してくれます。

　なるほど、
　　こんな商品を
　　　紹介していたのか。

　しかし、
　　カタカナ語と
　　　指定しているのに、
　　　　漢字が混ざっているやん。

　なんなら、
　　カタカナないやん。

　決算セールくらい、
　　わかるわw

　ということもありますw

　では、Promptをどうぞ。
　
```Text:カタカナ語を抽出して説明Prompt
# 目的
入力された文章から、カタカナ語を抜き出して、説明する。

# 処理手順
・入力された文章から、カタカナ語を抜き出して、リストアップして、わからなければ「不明」、それ以外はそれの説明をしてください。
・最後に、不明のものがなければ、「ない」と答えてください。あったならば、リストアップしてください。

# 最終確認
あなたが理解できない箇所があるならば、指摘してください。
あなたが理解できたなら、「はい」と答えて、待機してください。
```
Goの日付フォーマットは0埋めしない24時間表記を作れない

Goで時刻のフォーマットを作る時に、0埋めしない24時間表記（例えば`6:15`）が作れないことに気づきました。

`06:15`じゃなくて`6:15`じゃないとダメなんだ！というのはレアケースなのかなぁ、とも思ったのですが、画面表示や文章の中に入る場合は0埋めしないケースもそれなりにある気がします。

本記事では、どうして作れないのかという解説と代替方法を紹介します。

## Goの日付フォーマットについて

Goの日付フォーマットについてのおさらいです。
Goの経験者で既にご存じの方は読み飛ばして結構です。

Goの日付フォーマットは独特なことで有名で、アメリカ式の日付表記で各パートを1から順に振ったものが書式文字列となっています（月、日、時、分、秒、年の順）。

例えばこんな感じです。

```
"Mon Jan _2 15:04:05 2006"
2006-01-02T15:04:05Z07:00
```

分かりづらいですが、上記はフォーマットして生成された文字列ではなく、**書式文字列**です。
例えば`2006`と書くと、そこが具体的な年に置き換わり、`01`は2桁の月に置き換わる、といった感じです。

詳しいことは下記の記事などを参考にしてください。

- 公式ドキュメント: [time package - time - Go Packages](https://pkg.go.dev/time)
- [Goのtimeパッケージのリファレンスタイム（2006年1月2日）は何の日？ - Qiita](https://qiita.com/ruiu/items/5936b4c3bd6eb487c182)
- [Goの日付フォーマット 〜＜2006年1月2日＞の謎〜 - Hack Your Design!](https://blog.toshimaru.net/go-time-format/)

## 時間の書式について

時間の書式については次のようになっています（[公式ドキュメント](https://pkg.go.dev/time#pkg-constants)から抜粋）。

```
Hour: "15" "3" "03" (PM or AM)
Minute: "4" "04"
Second: "5" "05"
AM/PM mark: "PM"
```

`0`をつけて`03`などとすると、0埋めした2桁の値になります。
しかし、時間（Hour）の24時間表記の方は`15`しか定義されておらず、これだけで`00`〜`23`までの値にフォーマットされます。
先頭に`0`をつけて`015`（それも変ですが）としたわけでもないのに、最初から0埋めされた表現になります。

では0埋めしない24時間表記にしたい場合はどう指定すればよいのかというと、そんな指定は存在しないようです。

## どうすればよいか

機能が提供されていない以上はどうしようもないので、私は時間の部分だけ`fmt.Sprintf()`で組み立てることにしました。

```go
timePart := fmt.Sprintf("%d:%02d", d.Hour(), d.Minute())
```

## 参考

- [time/format: how to add custom formats (24-hour without 0 padding)](https://groups.google.com/g/golang-nuts/c/Wz6p43lH5g4)
SSHのポートを変更して、SSHログインをセキュアにする

# はじめに
https://qiita.com/kztktr/items/3d255879eca179fb8734

こちらの話の続きのようなものになります。
今回はSSHログイン時に使用するポートを変更して、セキュリティを高めます。

# なぜSSHログイン時のポートを変更した方がいいのか
SSHの接続ポートは22がデフォルトになっています。このようなデフォルトで設定されているプロトコルのポート番号は<b>「ウェルノウンポート」</b>と呼ばれています。
ウェルノウン（よく知られている）と言うだけあって、悪い奴らも知っているわけです。
というわけで、クラッカーなどの悪意を持った人間がSSHでのブルートフォースで不正アクセスを試みる際は、まずウェルノウンポートから攻めてくると考えられます。
ところがデフォルトのSSHポートが変更されていた場合、クラッカーは試行錯誤して別のポートを試す必要があり、開いているポートを見つけることが非常に困難になります。
もちろん接続ポートを当てられても、認証で不正アクセスを防ぐことは可能ですが、セキュリティにおいては少しでも隙を減らすことが大切です。

# 環境
今回もこちらの環境でやっていきます。
Ubuntu20.04
sshdインストール済み

# 変更手順
作業開始前に作業するターミナルとはまた別に、もうひとつターミナルを開いて当該ホストにログインしておきましょう。
万一、設定にミスがあった場合<b>二度とログインできない事態が起こり得ますので</b>、そのカバーのためです。

* sshd_configファイルを編集します。
<b>ssh_configではありませんので注意してください。</b>
configファイルを変更する前に、念のためにファイルをバックアップしておきましょう。

```
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config_org
```
* バックアップができたら、設定ファイルの編集に入ります
```
sudo vim /etc/ssh/sshd_config
```


* 16行目あたりに下記の記述が存在します。
SSHログインで使用するポートを設定している箇所ですので、ここの記述を変更します。
例として今回はSSHログインのポートを2222へと変更します。
コメントアウトがされていた場合は外してください。
```
変更前
Port 22

変更後
Port 2222
```

* sshdプロセスを再起動します。
```
sudo service sshd restart
```

ここまでの設定作業が終了しましたら、当該ホスト対して変更したポートでSSHログインが可能か確認してください。
ログインできましたら、設定成功です。
AIエンジニアに転職するまでにやること


## はじめに

本記事はAIエンジニアとして転職するにあたって、入社日までにやることを挙げました。
今後、AIエンジニアとして就職する人の勉強内容の一案にでもなれればとの思いで執筆しております。
（ちなみに初めてのqiita投稿です:clap:）

## 目次
[1.前提](##1-前提)
[2.勉強内容](##2-勉強内容)

## 1. 前提
### 筆者の現状
転職前は大手SierのSEとして、お客様と会話しながらシステム開発を行うフロントエンドエンジニアをしておりました。資格として応用情報までを有しております。

### スケジュール
スケジュールとしては現在（2023/8/23）から入社前日（2023/9/30）までにやりたいと思っています。

## 2. 勉強内容
まず勉強の流れとして、勉強法としては有名な山口真由氏の「７回読み勉強法([参考URL](https://pharma.mynavi.jp/theword/vol7.html))」を参考に、繰り返すことを重視したいと思っています。

基本的には以下の書籍もしくはUdemyの講座を繰り返します。
|#|媒体|タイトル|URL|
|:--|:--|:--|:--|
|1|書籍|深層学習教科書 ディープラーニング G検定（ジェネラリスト）公式テキスト 第2版|https://www.shoeisha.co.jp/book/detail/9784798165943|
|2|書籍|組込みエンジニアの教科書|https://www.c-r.com/book/detail/1308|
|3|書籍|人工知能プログラミングのための数学がわかる本|https://www.kadokawa.co.jp/product/321708000339/|
|4|Udemy|現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル|https://www.udemy.com/course/python-beginner/|
|5|Udemy|【世界で55万人が受講】データサイエンティストを目指すあなたへ〜データサイエンス25時間ブートキャンプ〜|https://www.udemy.com/course/python-beginner/|
|6|Udemy|【世界で91万人が受講】基礎から理解し、Pythonで実装！機械学習26のアルゴリズムを理論と実践を通じてマスターしよう|https://www.udemy.com/course/ml-with-python/|
|7|Udemy|豊富な演習問題とKaggle実践で身に付ける！『Python データ分析 & 機械学習 ～パーフェクトスターターコース』|https://www.udemy.com/course/kagglepython/|
|8|Udemy|一週間で身につくC/C++言語|https://www.udemy.com/course/cc-lubmn/|
|9|Udemy|【Pythonで学ぶ】OpenCVでの画像処理入門|https://www.udemy.com/course/pythonopencv/|
|10|Udemy|【Hands Onで学ぶ】PyTorchによる深層学習入門|https://www.udemy.com/course/hands-on-pytorch/|
|11|Udemy|もう絶対に忘れない Linux コマンド【Linux 100本ノック+名前の由来+丁寧な解説で、長期記憶に焼き付けろ！】|https://www.udemy.com/course/linux100test/|
|12|Udemy|もう絶対に忘れないGit・GitHub【Git 100本ノック+300枚の図解+丁寧な解説で長期記憶に焼き付けろ！】|https://www.udemy.com/course/git100test/|

## おわりに
ひととおり勉強が終わりましたら感想を追記しようと思います。
VBAでxlsとxlsxを読み込む際に注意したいこと

# 概要
古いデータに触る機会があると、弊社では否が応でも.xlsと.xlsxが乱舞しています。
それだけならまだいいのですが、VBAでそのどちらにも触れるとなるとちょっと苦労が発生します。

# 実際にハマった箇所
やりたい事としては、
①VBAでExcelを読み込む
②読み込んだExcelのシートの最終行の行番号を取得する
③その他諸々……。
になるのですが、②でハマってしまいました。

というのも、どうやら.xlsxのファイルであれば正常に取得できるのですが、.xlsのファイルで読み込もうとすると「エラー箇所」のところで実行時エラー：1004が出てしまいました。

```VB
'外部のexcelブックを読み込む
    Dim strDir As String, strFile As String
    Dim xls As New Excel.Application
    Dim wb As Workbook, ws As Worksheet
    strDir = Application.GetOpenFilename("Excelファイル,*.xls*")

'ファイル名読み取り
    strFile = Dir(strDir)
    Set wb = xls.Workbooks.Open(strDir)
    Set ws = wb.Worksheets(1)

'エラー箇所
    Dim R As Long
    R = ws.Cells(Rows.Count, "B").End(xlUp).Row
```

# 対策
どうやら、.xls側でRowsプロパティを参照にする際はきちんとオブジェクトを指定する必要があるようです。

```VB
'修正箇所
    Dim R As Long
    R = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
```

普段は.csvや.xlsxしか取り扱わないので、そちらでは動作するのに何故この箇所でエラーが出るのかと悩んでおりました。
具体的に何故.xlsではここまで丁寧に指定しないと動かず、.xlsxや.csvでは動いたのかについては分かっておりません。
詳しい方がいらっしゃれば補足頂けると助かります。

## 追記
.xlsの最大行数は65536行、.xlsxの最大行数は1048576行となっています。
オブジェクトを指定しなかったときのRows.Countの挙動は、ActiveSheetを参照としますので、今回のエラーの内容としては「.xlsのファイルを開いて1048576行目を参照しようと思ったけど、.xlsにはそんな行数が無かった！！」ということでした。

今まではActiveSheetを指定されようが、.xlsmで実行している限り.xlsmや.csvの行数には支障が無かっただけのようです。

コメント下さった@towa_skm様、ありがとうございます。

# おわりに
Python in Excelが発表された日にVBAの記事をUPしているのもなんですが、何はともあれオブジェクトはきちんと定義するに越したことは無いですね。
スクリプト実行時に"この変数は読み取り専用です"エラーが出た

次のように`UID`変数に`id -u`結果を取得して処理を実行しようとした際に、タイトルにあるようなエラーが出て少し詰まったので記録。
```sh
#!/bin/bash

UID=`id -u`
echo "user id -> ${UID}"

```

# 原因
`UID`はシステムで定義済みの環境変数だったようです。
https://www.ibm.com/docs/ja/i/7.2?topic=language-shell-variables
この他にも知らなかった定義済み変数があったので、この機会に勉強になりました。


# 解決策
* 定義済み変数をそのまま使う
```sh
#!/bin/bash

echo "user id -> ${UID}"
```

* 定義されていない変数名を使う
```sh
#!/bin/bash

USER_ID=`id -u`

echo "user id -> ${USER_ID}"
```
【flutter】marginを使ってcontainerの周りに余白をつけたい

こんにちは！
今回は、containerの周りに余白をつけるため、marginを使って余白をつける方法を紹介していきたいと思います。最後まで見ていただけたら、嬉しいです！

## 1,余白をつけるためのmarginとは？
marginとは、`EdgeInsets`というデータ型を受け取り、上下左右それぞれのマージンを設定するためのオブジェクトを利用します。

<table>
  <caption>具体的なプロバティ</caption>
  <thead>
    <tr>
      <th>プロパティ</th> <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>`EdgeInsets.all(double value)` </td> <td>上下左右の辺すべてに同じマージンを設定します。</td>
  </tr>
  <tr>
    <td> `EdgeInsets.only({ double? left, double? top, double? right, double? bottom })`</td> <td>指定した辺にだけマージンを設定します。</td>
  </tr>
    <tr>
        <td>`EdgeInsets.symmetric({ double? vertical, double? horizontal })` </td> <td> 垂直方向と水平方向の2つの辺に同じマージンを設定します。
</td>
    </tr>
</table>

## 2,containerを作ろう
今回は、縦と横の余白を紹介したいので、縦並びのcontainer３つと横並びのcontainer３つを例にとって紹介します。
しかし、二つの画像から分かる通り、containerの間に余白をつけなければ少し窮屈に見えてしまいますね...

縦並び
![スクリーンショット 2023-08-23 11.18.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/04c6140c-6273-c125-aba8-e1b0f6403e0a.png)

横並び
![スクリーンショット 2023-08-23 11.16.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/4c7d3eda-2369-d277-14ed-5926d98c5d64.png)

## 3.青色のcontainerにmarginを設定しよう！
今回はcontainerが3個並んでいるため、真ん中の青色のcontainerにmarginを使って余白をつけていきます。

### 縦並び
垂直方向(上下)に余白をつけるため、`EdgeInsets.symmetric(vertical:~)`を利用
```php
 Container(
        width: 100,
        height: 100,
        margin: EdgeInsets.symmetric(vertical: 30),//垂直方向の余白を指定
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(20),
            border: Border.all(color: Colors.blue)),
            color: Colors.white
) 
```
![スクリーンショット 2023-08-23 11.20.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/5829d95c-fead-9f2a-589c-c2edea21614e.png)

### 横並び
水平方向(左右)に余白をつけるため、`EdgeInsets.symmetric(horizontal:~)`を利用
```php
 Container(
        width: 100,
        height: 100,
        margin: EdgeInsets.symmetric(horizontal: 30),//水平方向の余白を指定
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(20),
            border: Border.all(color: Colors.blue)),
            color: Colors.white
) 
```
![スクリーンショット 2023-08-23 11.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/f5cf49b9-83dd-d18f-5621-f16c2a9e9d77.png)


## おわり
以上で、今回の記事を終了いたします！
今回もお読みいただき、ありがとうございました！
💭はじめてのJavaScript

***:cherries:学んだことを随時まとめてく:cherries:***
<font color="MistyRose">~間違っている点があれば是非教えてください~<font>
***
# 変数について
```javascript
//変数宣言
let xxx;  //変数宣言
xxx = "文字列";  //文字列や数値など
//再代入が可能 
xxx = 123;
xxx = 456;  //最後に代入された値が格納される
```

# 定数について
```javascript
//定数宣言および値代入
const yyy = "文字列";  //文字列や数値など値を代入しないとエラーになる
//再代入ができない
```

# 出力について
```javascript
//コンソールへの出力
///console.log(変数、定数、値など);
console.log(xxx);
>>456

//文字列に改行を含める場合①
console.log("あいうえお\nかきくけこ");
>>あいうえお
  かきくけこ

//文字列に改行を含める場合②(長文の時に)
let message;
message = `あいうえお
           かきくけこ
           さしすせそ`;
>>あいうえお
  かきくけこ
  さしすせそ

//文字列に変数を埋め込む
let xxx;
    xxx = "いうえ";
console.log(`あ${xxx}お`);
>>あいうえお
```

# データ型
・文字列(String)
・数値(Number)

# 配列について
```javascript
let array = ["あれ", "これ", "それ"];
  //インデックス番号　　０　　　１　　　２
  //[](ブラケット)記法
console.log(array[0]);
>>あれ

//連想配列(ハッシュ キーでアクセス)
let human = {name: "花子", age: 20, hight: 160};
//①[](ブラケット)記法
console.log(human[キー名"name"]);
>>花子
//②ドット記法
consloe.log(human.age);
>>20
Docker-composeを使ってMySQLを建てた際に、"Access denied for user 'root'@'localhost' (using password: YES)"に悩まされた話。

# 起こったこと
1. コンテナを立ち上げる。
2. MySQLコンテナに入る。
3. ```mysql -u root -p``` でログインを試みる。
⇒```"Access denied for user 'root'@'localhost' (using password: YES)```と言われ、ログインができない。


# 使用した環境
Docker Desktop for Windowsにて、
Node.jsを内包したLinuxコンテナと、MySQLコンテナの2種類を建てました。

**Docker-compose.yml**
```yml
version: '3'
services:
  app:
    build: .
    tty: true
    ports:
      - 8000:8000
    volumes:
      - .:/Service
    
    depends_on:
      - mysql

      
  mysql:
    image: mysql:8.0
    tty: true
    ports:
      - 3306:3306
    volumes:
      - ./mysql:/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 000000
```
※パスワードは実際と異なる数字を記載しています。

**Dockerfile**
```dockerfile
FROM --platform=linux/x86_64 node:18.15.0-slim

RUN apt-get update && \
    apt-get install -y locales git procps
RUN locale-gen ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP

ENV LANG=ja_JP.UTF-8
ENV TZ=Asia/Tokyo
WORKDIR /Service
```

# 原因
Docker-compose.ymlの**環境変数**にて
```yml
environment:
    MYSQL_ROOT_PASSWORD: 000000
```

と記載していたこと。

正しくは

```yml
environment:
    MYSQL_ROOT_PASSWORD: "000000"
```
と、**文字列として書く必要がある。**


# まとめ

いかがでしたでしょうか。
半ば備忘録のような感じで書いたので中身はだいぶ雑ですが、皆様の開発の一助になれば幸いです。

なお、「**パスワードが正しく設定されているか確認したい！**」という場合は
1. Docker Desktopを開く
2. `Containers->対象のコンテナ->mysql->Inspect->Environment`を確認する

以上の手段で確認できますのでご参考に。

~~私はこれに一日溶かしたので、くれぐれも同じ道をたどらないように！~~
input要素はパスワードジェネレーターを思いやれ

## 先に結論だけ

前提として、パスワードには最小の長さ以外の制限を課すべきではありません。

その上で、htmlの[`<input type="password">`](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/password)要素に

- minlength / maxlength属性
- autocomplete属性
- passwordrules属性

を設定すると、パスワードジェネレーターとの相性がよくなります。

## はじめに

この記事は、パスワードジェネレーターとinput要素の属性がどのように関係するのかを記録、共有するためのものです。

複数サービスでのパスワードの使い回しはセキュリティリスクを上昇させます。しかし安全なパスワードをサービスごとに考えたり覚えるのは大変です。パスワードの生成と記録には、パスワードマネージャーの補助が必須となっています。

文字種や長さに制限があると、ジェネレーターはそのサービスでは利用できないパスワードを生成してしまいます。その場合ユーザーは

- ブラウザーを離れてパスワードマネージャーの画面に移り、パスワードを再生成する。
- 提案されたパスワードをテキストエディターに貼り付け、編集した後に再入力する。

といった作業を強いられます。この手順はユーザー体験に悪影響を与えます。

こうした作業を回避する方法はないか、input要素の属性を検証していきます。

### 想定する環境

- 1Password 8.10.9
- Google Chrome 116.0.5845.96
- Safari 16.5.2

### 想定する読者

- パスワードマネージャー / パスワードジェネレーターを使っている
- フロントエンドエンジニア
- サーバーサイドの処理は変更できない

:::note warn
パスワードから文字種と長さの制限をなくすのが理想ですが、この記事ではサーバーサイドの変更はせずhtmlのみを対象とします。
:::

## input要素の属性

input要素には、パスワードジェネレーターに関連する属性があります。

### minlength属性

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/minlength

入力文字数の最短文字数を指定する属性です。たとえばこの属性に12を指定すると、12文字未満の入力は無効と判定されinput要素に`:invalid`擬似クラスが追加されます。

各種パスワードマネージャーはこの属性を読み取り、これ以上の長さのパスワードを生成します。

### maxlength属性

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/maxlength

maxlengthは、最大文字数を指定する属性です。パスワードマネージャーはこの属性を読み取り、これ以下の長さのパスワードを生成します。

### pattern属性

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/pattern

pattern属性は、そのinputフィールドに入力された値の検証に利用されます。この属性はメールアドレスや電話番号などのタイプミスを検証する目的で利用されます。

:::note warn
パスワードジェネレーターは、この属性を無視します。
:::

ジェネレーターはパスワード生成の前にはpattern属性を利用せず、サービスに利用できないパスワードを生成することがあります。

### autocomplete属性

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/autocomplete#%E5%80%A4

autocomplete属性は、input要素に自動入力される値を指定します。

#### autocomplete="new-password"

この属性は、input要素に新しいパスワードを入力することを示します。パスワードマネージャーに記録されている、既存のパスワードのオートコンプリートは無効化されます。

パスワードジェネレーターによっては、同じページに複数の"new-password"属性を持ったinputがある場合、パスワード生成後にそれらの要素を同じパスワードで埋めます。パスワード再設定画面では積極的にこの属性を利用しましょう。

#### autocomplete="current-password"

この属性は、設定済みのパスワードを入力することを示します。この属性があるとパスワードジェネレーターの動作は抑制されます。既存のパスワードを入力してほしいinput要素には、この属性を設定しましょう。

### passwordrules属性

passwordrules属性は、パスワードジェネレーターに生成ルールを教えるために提案された属性です。

https://github.com/whatwg/html/issues/3518

独自の書式で、必須となる文字種と文字数を指定します。

#### 対応はSafariと1passwordに限られる

https://developer.apple.com/password-rules/

https://developer.1password.com/docs/web/compatible-website-design/#provide-password-requirements

現在この属性に対応しているのは、Safariと1Passwordだけです。他の環境ではこの属性は無視されます。

#### mozillaはネガティブ

https://mozilla.github.io/standards-positions/#passwordrules-attribute

mozillaはこの提案に対してネガティブの姿勢をとっています。

- 既存のpattern属性と機能が重複する
- 悪いパスワードルールを広める
  - サイトが不注意で弱いパスワードを推奨してしまう可能性がある

という理由です。

passwordrules属性が将来広くサポートされるかは未知数です。採用する前にメンテナンスコストや副作用について検討してください。


以上、ありがとうございました。
Rails 7.0.7.2, 6.1.7.6 のアップデートの内容を検証してみる

## Rails 7.0.7.1, 7.0.7.2, 6.1.7.5, 6.1.7.6 のアップデートがあった

https://rubyonrails.org/2023/8/22/Rails-Versions-7-0-7-1-6-1-7-5-have-been-released
https://rubyonrails.org/2023/8/22/Rails-Versions-7-0-7-2-6-1-7-6-have-been-released

Railsのアップデート(7.0.7.1, 7.0.7.2, 6.1.7.5, 6.1.7.6)が配信された。脆弱性 CVE-2023-38037 のパッチであるという。

https://discuss.rubyonrails.org/t/cve-2023-38037-possible-file-disclosure-of-locally-encrypted-files/83544

>Impact
ActiveSupport::EncryptedFile writes contents that will be encrypted to a temporary file. The temporary file’s permissions are defaulted to the user’s current umask settings, meaning that it’s possible for other users on the same system to read the contents of the temporary file.
>
>Attackers that have access to the file system could possibly read the contents of this temporary file while a user is editing it.

- [`ActiveSupport::EncryptedFile`](https://api.rubyonrails.org/v7.0/classes/ActiveSupport/EncryptedFile.html) は、暗号化したい内容を一時ファイルに書き込んでいる。
- [`umask` の設定](https://atmarkit.itmedia.co.jp/ait/articles/1907/26/news011.html)によっては同じシステムのユーザがその一時ファイルを覗き見れる状態にあった。
  - ファイルシステムに侵入した攻撃者は、一時ファイルを覗き見できていた。



ファイルシステムに侵入されてるかつ秘密ファイルを編集中に可能な攻撃ってことでかなり特殊なケースっぽい？


([7.0.7.2, 6.1.7.6 は 7.0.7.1, 6.1.7.5 の対応時にファイルパーミッションを変えていて、それをそのまま配信してしまったので元に戻したっていう内容なのでコードの変更とかはない](https://rubyonrails.org/2023/8/22/Rails-Versions-7-0-7-2-6-1-7-6-have-been-released))

## 検証してみる

7.0.7.0, 6.1.7.4 のrails アプリを用意して秘密ファイルを編集中にする

```bash
# umask は 0022
$ umask
0022
# 秘密ファイルを開いた状態にしておく
$ EDITOR=vim bin/rails credentials:edit
```

秘密ファイルは開いたままで、別の端末から同じシステムの別のユーザで覗き見てみる
```sh
# 別ユーザ追加
$ groupadd -g 1000 user
$ useradd -m -s /bin/bash -u 1000 -g 1000 testuser
```

 `/tmp` をみてみると

```sh
$ su testuser

# /tmp に編集中の credentials.yml の一時ファイルがある
# 7.0.7.0, 6.1.7.4 だとread権限がある
$ ls -l /tmp
...
-rw-r--r-- 1 root root  305 Aug 23 03:10 **.credentials.yml
...
# ファイルの内容が見れちゃう
$ cat /tmp/**.credentials.yml
```

```bash
$ su testuser

# /tmp に編集中の credentials.yml の一時ファイルがある
# 7.0.7.2, 6.1.7.6 だとread権限がない
$ ls -l /tmp
...
-rw------- 1 root root   305 Aug 23 02:52 **-credentials.yml
...

# ファイルの内容は見れない
$ cat /tmp/**-credentials.yml
**-credentials.yml: Permission denied
```

## rails の diff みてみた

https://github.com/rails/rails/compare/v6.1.7.4...v6.1.7.6#diff-a9f0886d363d08b4bb483324f68f676be9a9079f599695db37a967773d95e40aR71-R82

rails の diff をみてみたら、今まではファイルへの出力を [`Pathname#binwrite`](https://docs.ruby-lang.org/ja/latest/class/Pathname.html#I_BINWRITE) していたのが、 [`Tempfile` を使うよう](https://docs.ruby-lang.org/ja/latest/class/Tempfile.html)になっていた。 `Tempfile` の説明を読んでいると、

> テンポラリファイルのモードは 0600 です。

なので他のユーザからは見れなくなったみたい。
Laravel 10.x + ViteでBootstrapを使う

# まずはよくある手順通りに準備

```sh
# プロジェクトの作成
composer create-project --prefer-dist laravel/laravel sample-app
cd sample-app

# laravel/uiのインストール
composer require laravel/ui

# Bootstrapの有効化
php artisan ui bootstrap

# Bootstrap等のインストール
npm i
```

# ここが違う

[公式](https://laravel.com/docs/10.x/vite#loading-your-scripts-and-styles)ではblade.phpでのリソースの読み込みのコードとして以下のように書かれています。

```php
@vite(['resources/css/app.css', 'resources/js/app.js'])
```

しかし、上記の手順で`/vite-config.js`には以下のように書かれます。

```js
input: [
    'resources/sass/app.scss',
    'resources/js/app.js',
],
```

`/resources/css/app.css`は空なので、もちろんBootstrapは読み込まれません。

つまり、以下のようにリソースを読み込みます。

```php
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
```

# 参考

https://qiita.com/riiiii/items/77764a41364eb3b00478
質問するときは「目的」を話すと解決の近道になる（ことがある）

こんにちは。
私の会社で新人がそれぞれの部に配属され、実際の業務に携わることになったのでその助けになればと思い記事を書くことにしました。

地味に Qiita 初投稿になるので、書き方的に分かりづらいところやその他改善点があればご指摘いただけると助かります🙏🏻

## はじめに

プロジェクトマネージャーを任せてもらえる機会が増え、後輩を下につけてお仕事することも多くなってきました。

後輩がエラーで詰まったときや分からないことがあったときに質問をしてくれますが、経験年数が浅いほど遠回りな質問の仕方をしているケースが見られます。
目の前のことばかりに焦点を当ててしまうと、目的を見失い間違った方向にいきかねません。

この記事はそうならないための質問の仕方の参考になればと思います。

:::note warn
ただし、あくまで私の経験則に基づくため、必ずしもこの記事の内容が正しいわけではないことをご了承ください。
:::

~~※何番煎じかわからないネタかもですが。。~~

## 目的から話すときの例

例えば、ある機能の実装をしようとしてエラーが出て詰まってしまったときの質問の仕方は、下記のように `目的 → 手段 → 結果` の順で話すと解決の近道になることがあります。
この場合に大切なのは順番ではなく、あくまで目的を話すことにあるので話す順番が異なってしまっても問題ありませんが、私はこの順番で話すのがわかりやすいと思っています。

```:質問をする側:Question
〇〇をしたいのですが、 ← 目的
✗✗をしてもうまくいかず、 ← 手段 
△△のエラーが発生してしまいます。 ← 結果
どうしたらよろしいでしょうか？
```

```:質問を受ける側:Anser
あれ？そもそもその手段だと目的が達成できないかも。
手段をこういう風にしてみて！
```

## 「目的」から話すとどう近道になるのか？

上記の例でわかる通り、質問を受ける側が目的をわかっていると、 __目的を達成するための手段がそもそも間違っていたときにその先の結果に対して悩む時間を節約__ できます。

特に、経験が浅いうちは手段が誤っていることも少なくありません。
経験を積んだ先輩たちはみな優秀です！
「目的」がわかればその「手段」も大抵はわかるので、「目的」から話す癖をつけましょう！

## 注意点

逆に目的だけ話さないようにしましょう。
__目的を達成するために行った手段や理由、結果はすべて大事な要素であり必要な情報__ です。
情報が多ければ多いほど質問を受ける側はその質問内容に対する回答を出しやすく正確なものになります。

自分が行った手段が全然違っていたらどうしよう…のような不安な気持ちになることもあるかもしれませんが、恐れずしっかりやったことを伝えましょう！間違いや失敗を恐れないことが成長への近道にもなります！

## 色々な例

目的から話したときに近道となる質問例をいくつか紹介します。
と思ったのですが、考えようとすると意外と良い例が思いつかず…。
レパートリーが少なく例も微妙かもしれませんごめんなさい🙇🏻‍♂️

今後思いついたり遭遇したら追記していきます。

### エラーを解決したい

```:質問をする側:Question
ユーザー更新画面で保存ボタンを押したときに入力した内容をDBに保存したいのですが ← 目的
ユーザー登録画面を実装を参考にしましたがうまくいかず、 
◯◯のエラーが発生していてサーバー側に情報を送信できていないみたいです。
エラーになる原因は何が考えられるでしょうか？
```

```:質問を受ける側:Anser
更新画面を実装するときに登録画面を参考にしてそのエラー内容なら、
もしかしたらHTTPリクエストメソッドが間違っているのかも。
HTTPリクエストメソッドが PUT じゃなくて POST になっていないかまず確認してみて！
```

目的が明確になっていることによって、エラー内容と合わせて考えたときに原因が推測しやすくなっています。
エラー内容によってはその内容だけでは原因が特定しづらいものを少なくありません。
なるべく情報は多く提供するように心がけましょう。

### クエリの実行速度を改善したい

```:質問をする側:Question
請求テーブルを検索するクエリの実行速度が遅いので改善する必要があるのですが、 ← 目的
インデックスやクエリチューニングの観点からアドバイスいただけないでしょうか？
```

```:質問を受ける側:Anser
請求テーブルなら、
もしかしたら◯◯カラムにインデックスをつけたら検索の速度が改善するかもしれないから試してみて！
```

この場合、目的を話さないことはほとんどないかもしれませんが、目的の中にどのテーブルに対してなんのクエリなのか明確な情報があることによって、質問を受ける側が問題箇所について推測しやすくなります。

### 作業の優先順位を確認したい

```:質問をする側:Question
〇〇で不具合が発生しちゃったので優先して修正したいのですが、 ← 目的
今対応中のタスクはどれくらいのスケジュール感でしょうか？
```

```:質問を受ける側:Anser
たしかにその不具合は優先して直したいね。
対応中のタスクはスケジュールを調整するから後回しにして良いよ。
```

スケジュール感を把握できていないのはどうなんだという問題はさておき、スケジュール感だけ確認していたらもう何テンポか会話が必要になっていたかもしれません。
目的を話したことによって解決したい問題を即座に対応してもらえました。

## さいごに

若干記事の中身がうすいような気もしますが、とにかくこの記事で伝えたいことは目的を話すことを癖付けよう！ってことです。
私自身も遠回りな質問の仕方をしてしまうことがあるので、これからも気をつけていきたいと思います。