OmniAICreator/Qiita-1.07M huggingface dataset:
React公式ページで学んでみた16（備忘録）

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:
その中でもこれってどういう意味？とかつまづいたところを念入りに書いていこうかと思います。:fist:

# 今回の目的
前回の続きです。今回は「refでDOMを操作する」。被る部分もあると思いますが、後で振りかえって深掘りするきっかけになるのが理想です。細かく書くと大変なのであっさりめ。

https://qiita.com/mr_noppo/items/50ad5175fc3882b9d704

# 使用したものや事前準備
・Macbook Pro
・Visual Studio Code

# 主に参考にさせていただいた記事
https://ja.react.dev/learn/manipulating-the-dom-with-refs

# refが必要な場面
Reactが管理するDOM要素へのアクセスやReact外部の情報の格納
ノード情報が欲しい場合は、レンダー中（コンポーネント呼び出し中）ではなくコミット中（DOMが作成され変更されている時）に呼び出す。
(一例）
・ノードにフォーカスを当てる
・スクロールさせる
・サイズや位置を測定する
・タイマー管理

DOMノードの変更や削除はしないこと。Reactが管理できないため。

詳しくは下記の内容

https://developer.mozilla.org/ja/docs/Web/API/Element

# DOMノードへのアクセスを取得
```react
import { useRef } from 'react'
...
const myRef = useRef(null);
...
//この時点でmyRef.currentにdivに対応するDOMノードが作成される
return(
<div ref={myRef}>
)
```

# 例：focus
対象のDOMノードにフォーカス
```react
function handleClick() {
    inputRef.current.focus();
}
```

# 例：scroll
対象のDOMノードにスクロール
behavior：スクロールの動作について（smootmは スクロールをスムーズなアニメーションで行う）
block：垂直方向でブラウザのどこに表示するか（startなら上部、endなら下部、nearestなら一番近いところ）
inline：水平方向でブラウザのどこに表示するか

詳細

https://developer.mozilla.org/ja/docs/Web/API/Element/scrollIntoView

```react
function handleScrollToSecondCat() {
    secondCatRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    });
}
```

# リストの管理は？
refコールバックを使用する。

https://ja.react.dev/reference/react-dom/components/common#ref-callback
```react
//nodeを引数として取得することができる。Map（）を使用することでnodeのリスト化が可能
<li
  key={cat.id}
  ref={(node) => {
    const map = getMap();
    if (node) {
      map.set(cat.id, node);
      ...
```
idに沿ってnodeを取得する。
```react
function scrollToId(itemId) {
    const map = getMap()
    const node = map.get(itemId);
    node.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    })
}
```

# 別のコンポーネントにアクセスするには
下記の例だと、nullが返されてしまう可能性がある。これはReactが意図的にそうしている。
```react
<MyInput ref={inputRef} />
```

コンポーネント側で明示的にrefを受け取ることを記述することが必要である。forwardRefでラップし、props({})の後に記述することがルール。CSSのスタイルを変更するは基本的でないので、操作を制限したい場合は、useImperativeHandleを使用する。
```react
const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});
```

# 同期的にDOMを更新
イベントハンドラ内に下記の記載をすると、末尾が更新される前の位置にスクロールされる
```react
setTodos([ ...todos, newTodo]);
listRef.current.lastChild.scrollIntoView();
```
更新後の末尾にスクロールしたい場合はフラッシュする
```react
flushSync(() => {
  setTodos([ ...todos, newTodo]);
});
listRef.current.lastChild.scrollIntoView();
```

# 次
https://qiita.com/mr_noppo/items/86089370e89f7bfdcda5
AWSアカウント作成後やること

## 対象者
・AWSアカウント作成し、まず何をするか（特にセキュリティ的に）を確認したい人
・AWS初心者

:::note alert
参考にした情報が数年以上前のものであり、課金や記載情報自体が不正確の可能性があります。公式ホームページをご参照ください。
:::

## 1. ユーザーの保護
#### ルートユーザーでMFA有効化
IAMを検索し、セキュリティステータスを確認
MFAの管理→有効化ボタンを押す

#### ルートユーザーでのアクセスキーの削除
現状普通にはアクセスキーは作成されない。
※利用されていないかを確認してから削除する。

#### IAMパスワードポリシーの適応
「アカウント設定」→「パスワードポリシー」→「設定する」
最強にすることができる

#### IAMユーザーを作成
Administrater権限だと強い権限。
グループを作成して、そのグループ内にユーザーを作成すると管理しやすい。

#### IAMユーザーでMFA有効化
ユーザー名を押す→「セキュリティ認証情報」→MFA

また、ルートユーザーで名前の部分を押す→アカウント→「IAM ユーザーおよびロールによる請求情報へのアクセス」→有効化　しておくとIAMユーザーで請求情報が確認できるようになる。

##### セキュリティステータスを確認して、やり残しがないか確認する。


## 2.　アラート設定を行う
考えられることとしては不正にアクセスされて、不正に利用されること。
→この場合高額な請求が来ることになる。
→請求に対してアラートを設定することで異常に気づくことができる。

#### AWS Budgets　を設定（★課金の可能性あり）
IAMユーザーで作業できる
Budgetsと検索→「予算を作成する」ボタンを押す
※Budgetsレポート（予算レポート）を作成すると、日毎などで予算のレポートで定期的にレポートを届かせることができる

#### AWS Cost Explorerを設定
「Cost Explorer」で検索→「有効化ボタン」を押す

#### AWS Cost & Usage Report を設定(★課金あり、レポートの保存でS3使用するため)
Cost Usage report で検索・・・


※Billingを見るとコストを確認できる
※Cost Explorerでより詳細に検索できる　リージョンや日毎で確認できる
※「コストと使用状況レポート」の従来のページは非推奨になっている？？

## 3. ログを取得できるようにする
#### CloudTrailを設定する（★課金。証跡保存でS3使用するため）
IAMユーザーで設定可能
「証跡の作成」を行う（証跡はS3に保存される）

#### AWS Configを設定（★課金）
aws config　で検索→「始める」を押す
どのリソースにどのような変更が加わったのかを確認できる

## 4. 脅威を検出させる
#### Amazon GuardDutyを有効化する(★30日後課金)
「今すぐ始める」を押す。

## 5. 対策を確認する
Trusted Adviserを検索し、セキュリティで対策が必要なものがないかを確認する。

## 参考
AWSのハンズオン動画
https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Security-1-2022-reg-event.html?trk=aws_introduction_page
（動画ではバージニア北部で作業していた）
JavaScriptのクロージャーについて理解しようとしてみた

## はじめに
JavaScriptについて勉強する機会があり、その中でクロージャーなるもの(名前は知っていた)を講義してもらったのですがイマイチどう使えばいいものかわからなかったので今回調べてみました！

## クロージャーとは
`クロージャは、組み合わされた（囲まれた）関数と、その周囲の状態（レキシカル環境）への参照の組み合わせです`(参考:[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures))

```js
function makeFunc() {
  const name = "Mozilla";
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc(); // Mozilla
```
再度MDNからのコピーとなりますが、この時`myFunc（）`は`Mozilla`をログに表示します。
これは冷静に考えると、すこし理解し難い結果です。`const myFunc = makeFunc();`が完了した時点で`name`が破棄され、`name`は参照できなくなりエラーとなる方が直感的には理解できます。

しかしJSに限ってはそうではなく、`name`は`Mozilla`という値を保持し続けます。これは**レキシカルスコープ**という仕組みによるものです。

レキシカルスコープは 関数を定義した時点でスコープが決まります。
再度上のコードを見てみましょう。

```js
function makeFunc() {
  const name = "Mozilla";
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc(); // Mozilla
```
関数を定義した時点でスコープが決まる。という約束に則れば、`displayName()`が`name`を参照できることが理解できるのではないでしょうか。

ここで最初の`クロージャは、組み合わされた（囲まれた）関数と、その周囲の状態（レキシカル環境）への参照の組み合わせです。`を読み返すと、これもまた納得できませんか?

ちなみに、この時クロージャーは`displayName()`です。`displayName()`がクロージャーになって`myFunc`に代入されているという認識で大丈夫なはずです。

### 実際どう役立つのか?を調べてみた
#### 変数を外部から変更されないようにできる
調べているとよく出てくる使い方の中に、変数を外部から変更されないようにできる、というものがあります。
オブジェクト指向言語のプライベートプロパティと同じようなことができます。

```js
function setToken(userToken) {
    var token = userToken;
    return function () {
        return token;
    };
}

const getToken = setToken("0123456789");

console.log(getToken()); // 0123456789
```

この例では、tokenは変更できない変数として保存できます。
しかし、これはそもそもconstで宣言すればいい話なので実用性は低いんでしょうか?🧐
グローバルな変数を増やさないという点での恩恵が大きいのかなと思います。

#### カウンターなど、外部から値を弄られない且つ、呼び出すたびに値を変化させる

```js
function counter() {
    let count = 0;
    return function () {
        count++;
        console.log(count);
    };
}

const myCounter = counter();

myCounter(); // 1
myCounter(); // 2
myCounter.count = 100;
myCounter(); // 3
```

この例では、呼び出すたびに値が1足され続ける処理を実現できます。
さらに、`count`の値は外からいじることはできません。

#### 動的な関数を作る

```js
function counter(initCount) {
    let count = initCount;
    return function () {
        count++;
        console.log(count);
    };
}

const myCounter10 = counter(10);
const myCounter100 = counter(100);

myCounter10(); // 11
myCounter10(); // 12
myCounter100(); // 101 
```

この例では、前項のカウンターに初期値を持つ機能を足した例です。
また、クロージャーは実行するたび別の関数を作るので(今回の例だと`count`が10の関数、100の関数)、別々のカウンターとして存在できます。

### クロージャーのデメリット
クロージャーのデメリットとしてはメモリリークの原因になってしまうことが挙げられます。
使用していない変数を持ち続けることになるので、さもありなんといったところですが...
あまりに巨大な変数をクロージャーで持ち続けたり、クロージャーを多用するのはやめた方が良いということですね。


### おわりに
最後までお読みいただきありがとうございました！
今までReactばっかり触っていたので、少し理解に苦しんでいましたがなんとなく理解ができました。
認識が間違っている箇所などあればコメントにお願いいたします🙇‍♂️
エンジニア転職して1ヶ月の総括。

# 自己紹介
初投稿なので、簡単に自己紹介をいたします。
- 現在23歳
- 大学2年〜新卒まで8年目のベンチャー企業でWEBディレクター
- 社会人2年目の今、3年目のスタートアップにフロントエンジニアとして転職←イマココ

こんな感じです。
エンジニア転職の理由は色々ありますが、将来自分でサービスを作って世界と勝負したい！という夢に向かって転職したというのがいちばんの理由です。

# 本題：転職して1ヶ月→率直な感想
すごい辛い。けど楽しい。特に「スタートアップ」で「未経験文系エンジニア」というお先真っ暗ルートで挑戦すると最初の1ヶ月は辛酸を舐めるだろうと思いますので、これから転職を考える人は注意してくださいね。

## 何が辛いか
ぶっちゃけコーディングなんて辛くないです。ググれば正解はありますし、"良きタイミング"で先輩に聞けば保守性とかFBくれます。あと僕自身大学の時にちょっとマークアップとかLP作るとかやってたので、それに毛が生えた程度の業務は全く問題ないレベルでした。
いちばん辛いのは「リリース」でした。僕は前職のゆかりもあってShopify案件にアサインされてます。Shopifyで「カート追加を追従ボタン形式にしたい」という依頼があり、調べながら１人日くらいかけて作成しました。実装難易度的には程よく難しくといったものでした。

コードレビューは問題なくパスして、先輩から
「リリースは問題ない？」
と言われました。ちゃんと購入導線も確認できたし、問題ないだろうと思い「OKです〜」と言って、当日を迎えました。

立てたPRをマージすると、クライアントからも先輩からも、「追従ボタンが出ないぞ！」と報告を受けました。。
初めてのリリースが大失敗して頭が真っ白になりました。
この時切り戻し用のPRとか立てておけばよかったんですが、、その時の僕にはそんな余裕はなく、結局先輩に切り戻してもらい事なきを得ましたが、なんでこんなことになったんだと、泣きそうなくらい悔しかったです。

結局理由は単純で、使ってないJSのライブラリを削除し忘れておりこれが競合してたっぽいです。該当のコードをとった瞬間正常に機能しました。

## 入社1ヶ月の学び

ここから学んだことは以下です。
- リリースは失敗するものだと考える
- 作業場は常に綺麗にする

### リリースは失敗するものだと考える
失敗しないように入念にテストすることも大事です。もちろん。
ただ、僕のような抜けるところがある人、初心者の人は絶対に見逃しているところがある　と考えて、上司やレビュワーに厳し目にみてもらうことが大事です。所詮1ヶ月のエンジニアなんて初心者と一緒なので、変なプライドは捨てて自分だけでタスクを完結させない。悪く言えば、「自分のせいじゃなくする」くらいの巻き込みは大事かも。
また、僕は2ヶ月目に差し掛かる今でも、どんなリリースにも先輩を招待したり、切り戻し用のPRを立ててリリースに臨んでます。いよいよこの前先輩に「こんなちっちゃい機能のリリースに切り戻し用のPRは大丈夫だし、招待も大丈夫だよ」と言われました。正体については実装内容によっては遠慮してますが、PRだけは絶対に2つ立ててます。これは明確な理由があって、「リバートを無意識にできるように、何度もやって覚える」という目的があります。あと3ヶ月くらいはPR立てて脳死でもできるように体に刷り込むことで、マジの緊急事態に超スピードで切り戻せるようになりたいと思ってます。

PR立てるだけならお金はかからないですしね。1分2分のアクションで未来の自分を救えるかもしれないと考えて面倒でも作ってます。

### 作業場は常に綺麗にする
これ意外と思いましたが、優秀なエンジニアの方々はパソコン以外何もないくらい綺麗な机だなと思いました。勝手にエンジニアは汚ねえデスクで作業してると思ってましたすみません。。

作業場ってまあ色々捉え方はあると思ってて、コードも常に綺麗にして、余分なコードはすぐに削除する、別のタスクに移るときはローカルだけに作業履歴を残さないでリモートに上げておく　みたいな考えたら当たり前のことをしっかりできるように意識づけることの大切さを学びました。
特にタスクの多いスタートアップ企業は注意が必要で、マジで綺麗にタスク管理しておかないと1時間前にもらったタスクですら見失いますよ？！

# まとめ
最初は大変。これはなんでも一緒です。
幸いにも会社は僕を丁寧に育ててくれてるので失敗も寛容ですし、僕のわがままにも付き合ってくれる環境ではあります。
甘えるところは甘えて、成長するべきところは早く成長して、一人前のエンジニアになりたいと思いました。

これからも何かしらQiitaに残していきたいので、応援いただけると助かります。
[EC2 Image Builder] エラーを乗り越え起動するまで

# この記事について

ImageBuilderを始めて使ってみたところ、エラーが出てBuildプロセスが完了しなかった。
ネットを検索するも、今回の原因にすぐたどり着けなったので同じ症状の方の助けになればとアップします。

# 出ていたエラー

CloudWatchLogsに以下のエラーがでていました。
```
2024-04-22T07:57:49.049Z
Instance status 'reachability' is passed (instance id: i-06b16484a909xxxxx)

2024-04-22T07:57:51.234Z
Action successful for step LaunchBuildInstance

2024-04-22T07:57:52.336Z
Sending command to instance to run

2024-04-22T07:57:52.849Z
Error while calling ssm:SendCommand: InvalidInstanceId

2024-04-22T07:57:55.058Z
Action failed for step LaunchBuildInstance. Retry attempt: 2

2024-04-22T07:57:55.589Z
Retry action after 90 second delay (attempt number 2)

#この後、ずっとRetryがタイムアウトまで続く...
```


# 結論

インフラストラクチャ設定に登録したサブネットで、「パブリックIPv4を自動割り当て」に"いいえ"が入っていたのがよくなかった。

# この部分でした
![2024-04-27_4_image_builder.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244714/d4da50ef-91f7-71b7-c6db-e8a6800f948b.png)



# 公式ドキュメントを見てみよう

[公式ドキュメント- EC2Image Builderのトラブルシュー](https://docs.aws.amazon.com/ja_jp/imagebuilder/latest/userguide/troubleshooting.html)
このページにも今回の原因が直に載ってなかったので、起動が難航したのでした。

パブリックIPが割り当てられないのでベースとなるEC2は準備できても、その後SSMと連携できなかったのだと思われます。


# 今回の原因がトリガーとなって起こりえる同種のトラブル

Cloud9を起動するときも、パブリックサブネットにEC2を立てると思います。その場合も、サブネットが外部にアクセスするため、IPV4の割り当てが必要ですし、サブネットにインターネットゲートウェイがあることが必要です。

ELBとAutoScalingを利用し高負荷時に追加でEC2が立ち上がる際にも、IPV4の自動割り当てが必要になるはずです。(未検証)

# 先行記事
【DeveloperIO】
[reivent2019_report_01](https://dev.classmethod.jp/articles/report-session-about-ec2-image-builder-building-virtual-machine-images-made-easy/)
[reivent2019_report_02](https://dev.classmethod.jp/articles/cm-reinvent-2019-ec2-imagebuilder/)
[reivent2019_report_03](https://dev.classmethod.jp/articles/ec2-image-builder-create-components/)

[reivent2019_report_03]: https://dev.classmethod.jp/articles/ec2-image-builder-create-components/


# 補足情報
イメージ構築に使ったbuild用コンポーネントは下記のyamlです。
先行記事[reivent2019_report_03]で使われたいたものと同一です。

```
name: Apache Install
description: This is Apache Install testing document.
schemaVersion: 1.0

phases:
  - name: build
    steps:
      - name: InstallLinuxUpdate
        action: UpdateOS
      - name: InstallApache
        action: ExecuteBash
        inputs:
          commands:
            - sudo yum install httpd -y
            - sudo systemctl enable httpd
            - sudo systemctl start httpd
```
ArrayListまわり

##
■固定の配列から可変のリストに変換したいとき
Arrays.asList

```java
List<E> 変数名 = new ArrayList<>(Arrays.asList( E型の配列 ));
```

Arrays.asListと同じく、カッコ内に渡された配列をリストに変換する「List.of」がある。
Arrays.asListは、add、removeができないがset(変更)はできる。
一方で、List.ofはまったくもって**不変**のリスト。

##
■sublistとclearの合わせ技で、指定したインデックス範囲の要素を削除できる

subList( 第一引数start, 第二引数end-1)
・第一引数：取り出したい先頭のインデックス番号
・第二引数：ここで指定したインデックスのひとつ前で取り出し終了

clear
全ての要素を削除する

```java
//numbersAには[0, 1, 2, 3, 4]の配列が詰め込まれているとして…
numbersA.subList(1, 3).clear(); // 1, 2 が削除される
```
##
■リストの昇順降順

```java
import java.util.Comparator;

// numbersBを自然順序(昇順)に並べ替え
numbersB.sort(Comparator.naturalOrder());

// numbersBを自然順序(降順)に並べ替え
numbersB.sort(Comparator.reverseOrder()); 
```

##
■ラムダ式とforEachメソッド

・forEachメソッドはリスト内の要素を一つづつ取得し、各要素に対して処理を行う。
・ラムダ式は、forEachと見比べて考えるとわかりやすい。

▼拡張for文の場合
```java
for ( 型 リスト内の要素 : リスト ) {
    要素に対する処理
};
```
▼ラムダ式の場合
```java
リスト.forEach( リスト内の要素 -> {
            要素に対する処理 });
```
##
■contains()メソッド
対象のリスト.contains(調べたい値)
・対象のリスト内の要素に、カッコ内の引数の値(数値や文字列)があるか調べる。
・答えはtrue/falseで返ってくる

```java
List<Integer> intList = new ArrayList<>(List.of(0, 1)); 
// リスト内に引数の要素を含む場合は`true`、含まない場合は`false`を返す
intList.contains(1) // true
intList.contains(2) // false
```
Web記事で見かけた「指数平滑法」を使ったアニメーションを p5.js で試してみる

以下の記事で見かけた「指数平滑法」を使ったアニメーションを、p5.js で試してみたという話です。

●アニメーションをスムーズに見せるためのテクニック「指数平滑法」とはどんなものなのか？ - GIGAZINE
　https://gigazine.net/news/20240427-animation-trick/

上記の記事の内容は、以下のブログが元になっているようです。

●My favourite animation trick: exponential smoothing | lisyarus blog
　https://lisyarus.github.io/blog/posts/exponential-smoothing.html

「指数平滑法」を使ったアニメーションで、ポイントになるのは以下の式のようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/21a741d2-6001-2165-ed87-aa497ad0387a.png)

これを、p5.js の単純なアニメーションに適用してみます。

## p5.js Web Editor で試す
それでは p5.js で試してみます。

環境として、手軽に使える p5.js Web Editor を利用します。

### 作成したプログラム
プログラムは以下としました。

```javascript
let ball = {
  x: 0,
  y: 100,
  speed: 3,
  target: 400,
};

function setup() {
  createCanvas(ball.target, 200);
  noStroke();
}

function draw() {
  background(220);

  let dt = 1.0 / frameRate();
  ball.x += (ball.target - ball.x) * (1 - exp(-dt * ball.speed));

  ellipse(ball.x, ball.y, 20, 20);

  if (ball.x >= width - 10) {
    ball.target = 0;
  }
  if (ball.x <= 10) {
    ball.target = width;
  }
}

function mouseClicked() {
  ball.target = width - ball.target;
}
```

左右方向へのボールの移動に、指数平滑法を適用してみました。

また、冒頭の記事に書かれていた「アニメーションの途中で、移動方向を変化させたときの、アニメーションの切り替わり」という話がありました。それを検証できるように、mouseClicked() を使って、マウスクリックによる移動方向の途中での切り替えを試せるようにしました。

### 動作確認
上記を動かしてみた結果は、以下のとおりです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/oNxn1KO9Zcc?si=g9g_6a0sixxAPU12" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

移動途中で、マウスクリックの操作を行って、移動方向を強制的に変えたりもしてみています。

移動方向が途中で変化した際にも、うまくアニメーションがつながることが確認できました。
VScodeで.gitディレクトリを表示する

VScodeで.gitディレクトリの中身が見たいのに見つからない！
どうやら、デフォルトでは.gitは非表示になっているよう。
なので.gitが表示されるようにしてみた。

# 手順

「ファイル」→「ユーザー設定」→「設定」の順に選択

![スクリーンショット 2024-04-28 221349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780466/0c3d1614-9bf3-c784-2889-b40ad46ef12f.png)

「ユーザー」・「リモート（WSL:ubuntu）」・「ワークスペース」のどの範囲で有効な設定を編集するか選択。
左のナビゲーションウインドウを「テキストエディタ」→「ファイル」の順に選択
Excludeの**/.git の×をクリックして削除

![スクリーンショット 2024-04-28 221541.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780466/f982dad2-f87a-85df-8897-e9cad079ff65.png)

以上！

--- 

簡単な設定ですが、windowsかつ日本語の環境での例が検索上位に見つからなかったので忘備録的に
初投稿なのでqiitaの投稿練習もかねて

# 参考

[Visual Studio Codeで.gitフォルダを表示する – Hubbit 開発者ブログ](https://techblog.hubbit.io/2020/10/05/visual-studio-code-show-git-folder/)

[VSCodeで.git配下のファイルを表示する - Nothing Behind](https://nothing-behind.com/2022/09/02/vscode%E3%81%A7-git%E9%85%8D%E4%B8%8B%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B/)
Webアプリ開発 ホーム画面編

# 初めに
webアプリの開発ができたので、手順を公開していきます。

# 開発環境
macOS Sonoma 14.4.1
PHP 8.3.3
Laravel Installer 5.2.0

# ソースコード
こちらのリンクから取得できます。

https://github.com/opatu07/portfolio



# 手順
## レイアウト編
管理がしやすいのでレイアウトのファイルをコンポーネントに入れました。
viewsディレクトリにcomponentsディレクトリを配置します。
そこにlayout.blade.phpを配置します。
これがすべてのファイルの基準になります。


![スクリーンショット 2024-04-17 11.12.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682713/6549cc8a-5aa2-b043-87b3-ece19ce9ef70.png)

左上のアイコンをクリックするとこのホーム画面に戻るようになってます。

ユーザー登録を押すとユーザーの新規登録画面が出てきます。

ログイン画面を押すとログインができます。

カテゴリー検索では記事ごとにカテゴリーがついているのでそれを検索できます。

タイトル検索では記事のタイトルで検索できます。

# 保守性の意識
だいたい全てのファイルで意識したことがあってそれは
```layout.blade.php
<a href="{{ route('home') }}">
~
</a>
```
みたいにルートに名前をつけるようにしました。
なぜかというとルートの管理がしやすいからです。
もしルートに名前をつけていないとweb.phpとlayout.blade.phpの両方を編集しなければならないし該当箇所を探すのも手間がかかるのでなるべく名前をつけるようにしました。

# レスポンシブ対応
使われるスマホがiPhone8以上の画面サイズなのでiPhone8に対応させました。
![responsive_function.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682713/ddf77386-5289-06a9-90b9-ab7a11eadbd3.gif)
NestJSについてキャッチアップしてみた

案件で絶賛対応中になります。
初めて触るため、備忘がてらキャッチアップした内容を書いてみようと思います。

# NestJSとは
>Nest（NestJS）は、効率的でスケーラブルなNode.jsサーバーサイドアプリケーションを構築するためのフレームワークです。プログレッシブJavaScriptを使用し、TypeScriptで構築され、TypeScriptを完全にサポートし（それでも開発者は純粋なJavaScriptでコーディングできる）、OOP（オブジェクト指向プログラミング）、FP（関数型プログラミング）、FRP（関数型反応プログラミング）の要素を組み合わせている。

https://docs.nestjs.com/

Node.jsのフレームワークということは理解できました。
今度はNode.jsについてサクッと調査します。


# Node.jsとは
>Node.js は、オープンソースのクロスプラットフォームの JavaScript ランタイム環境です。ほぼあらゆる種類のプロジェクトで人気のあるツールです。

https://nodejs.org/en/learn/getting-started/introduction-to-nodejs

公式ドキュメントの表現っていまいちイメージしづらいですよね...笑
こういう時はQiitaで分かりやすい表現を探すに限ります。
@non_cal さんの記事がめっちゃ分かりやすかったので共有しますね。

https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb

@non_calさんの記事（抜粋）によると

>Node.jsは **「JavaScriptの実行環境」** になります。

>Node.jsではJavaScriptでOSの機能にアクセスするプログラムを組むことができます。

>「Node.jsはサーバサイドのJavaScript実行環境としてもクライアントサイドJavaScriptの開発環境としても利用される」というのが実態となっています。

との事です。
分かりやすい！ありがとうございます！


# NestJSのフォルダ構成
では本題。
npmがインストールされている前提で
```
$ npm i -g @nestjs/cli
$ nest new project-name
```
を実行することで以下のコアファイルが配置されるようになります。
今回の記事では以下ファイルに絞ってご紹介します。

**app.controller.ts**
**app.service.ts**
**app.module.ts**

![スクリーンショット 2024-04-28 22.11.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744730/66207b32-6061-a33b-bfff-30b760c45114.png)

### app.controller.tsファイル

```JavaScript:app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
```
**デコレータ**と呼ばれる仕組みを使いコードを構成していきます。
デコレータは上記のコードで言う「@ Controller」や「@ Get」の部分を指します。
上記の場合、getHello関数（CRUD：Rを指す）を定義してます。
では、上記関数の詳細はどこで記述されているかで言うと、**app.service.ts**で記述されています。

### app.service.tsファイル

```JavaScript:app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}
```
公式の情報によると、serviceは「Providers」として紹介されていますが、ファイルとしてはserviceになるみたいです。
今回の「getHello関数」では、'Hello World'を返す内容が記述されています。
Controllerでは関数のみ定義する、serviceでは関数の詳細を定義するとの事で、役割が明確で個人的には好きな書き方です。

### **app.module.tsファイル**


```JavaScript:app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```
ここでもデコレータが使われてますね。「@ Module」がデコレータになります。
このファイルでは、アプリケーション全体の設定や構成を行います。
本記事では触れないですが、データベースの環境変数を設定する「database.module.ts」ファイルなどは、本ファイルの「imports」の配列の中に設定したりもします。

# さいごに
パッと触ってみた感想をお伝えすると「直感的な実装」ができそうな印象でした。
TypeScriptを絡めた実装もできそうなので、公式ドキュメントを見ながら少しずつキャッチアップしていこうと思います。
まだまだ知見が足りない箇所もたくさんあると思うので、過不足あればぜひアドバイスをいただきたいです。
最後まで読んでいただき、ありがとうございました！
１年間のPHP系のカンファレンス時系列まとめ（2024年）

# 概要
気がついたら、気になるカンファレンスが既に終わっていたということも往々としてあり、１年間のPHP系カンファレンス時系列を本記事にはまとめる。
今回は2024年の時系列でまとめているが、他の年でも継続的に行われていれば参考になる時系列であると思う。
※ 更新があれば随時書いていきます。

# 時系列
## 1月
### PHPカンファレンス北海道
https://phpcon.hokkaido.jp/

1月12日（金）～ 1月13日（土）
in 北海道（札幌市民交流プラザ クリエイティブスタジオ）

## 2月
### PHPカンファレンス関西
https://2024.kphpug.jp/

2月11日（日）
in 大阪（グランフロント大阪 北館）

## 3月
### PHPerKaigi
https://phperkaigi.jp/2024/

3月7日（木）～ 3月9日（土）
in 東京（中野セントラルパークカンファレンス）

## 4月
### PHPカンファレンス小田原
https://phpcon-odawara.jp/

4月13日（土）
in 神奈川（おだわら市民交流センター「UMECO」）

## 5月
### PHPカンファレンス香川
https://phpcon.kagawa.jp/2024/

5月10日（金）～ 5月11日（土）
in 香川（玉藻公園内 披雲閣）

## 6月
### PHPカンファレンス福岡
https://phpcon.fukuoka.jp/2024/

6月22日（土）
in 福岡（福岡ファッションビル）

## 9月
### PHPカンファレンス沖縄
https://phpcon.okinawa.jp/

9月28日（土）
in 沖縄（沖縄県市町村自治会館）

## 12月
### PHPカンファレンス
https://phpcon.php.gr.jp/2024/

12月22日（日）～ 12月24日（火）
in 東京（大田区産業プラザPiO）

# 補足
以前はLaravelJPConferenceもあったみたいですね（復活しないだろうか）
https://twitter.com/laraveljpcon

--- 
記事をお読みいただき、ありがとうございました！
もし参考になったと感じましたら、「いいね」や共有など頂けたら嬉しく思います！
何卒よろしくお願い致します！
OEISに載っていない正の整数

# OEISに載っていない正の整数を探す

## はじめに

OEISには、多くの整数列が載っている。

現在 20990※がOEISに出てきていない最小の正の整数であると、wikipediaの「[面白い数のパラドックス](https://ja.wikipedia.org/wiki/%E9%9D%A2%E7%99%BD%E3%81%84%E6%95%B0%E3%81%AE%E3%83%91%E3%83%A9%E3%83%89%E3%83%83%E3%82%AF%E3%82%B9)」に載っているが、これを確認してみる。

※記事作成時は20067が最小だった。

## 全数列データの取得

CC-BY-NC 3.0 licenseの元で、[全数列データ](https://oeis.org/stripped.gz)を利用できる。

ダウンロードして解凍した、strippedというファイルを利用する。

## OEISに載っていない正の整数を探す

　まず、strippedファイルを開くと、５行目から数列のデータがあるとわかるので、5行目以降読み取る。

```ipynb
import pandas as pd
from collections import Counter

# strippedファイルの５行目から
df = pd.read_csv('stripped', skiprows=4, header=None, delim_whitespace=True,
                 names=['A_number', 'seq_str'])
```

数列は文字列なので、リストに変換したカラムを追加。

```ipynb
def modify_seq(row):
    numbers = [int(num) for num in row.split(',') if num.strip()]  # 空の文字列を除外
    return numbers

df['seq'] = df['seq_str'].apply(modify_seq)
```

数列をリストに変換したカラムを用いて、出てきていない正の整数を探す。

```ipynb
def find_missing_positve_integers(a_list, num_missing):
    a_set = set(a_list)

    missing_integers = []
    num = 1
    while len(missing_integers) < num_missing:
        if num not in a_set:
            missing_integers.append(num)
        num += 1

    return missing_integers

def interesting_num(column):
    all_integers = [integer for row in column for integer in row]
    # 出現するkeyを取得
    return Counter(all_integers).keys()


interesting_integers = interesting_num(df['seq'])
print(find_missing_positve_integers(interesting_integers, 10))
```

出力結果は

```
[20990, 22978, 23543, 23735, 24085, 24159, 24555, 26301, 26673, 26708]
```

となり、20990が載っていないことが確認できた。(2025/01/04更新)


## 参考

[OEIS　wiki　download](https://oeis.org/wiki/Download)
articleタグ、sectionタグ、asideタグでアウトラインを整える

## アジェンダ
この記事では、HTMLの`article`タグ、`section`タグ、`aside`タグを用いてアウトライン（階層構造）を整える方法についてまとめます。

## タグの使い分け
### article
`article`タグは、ブログなどの記事のページではその記事全体を囲みます。また、一覧ページでは個別の記事一つ一つを囲う要素として使用されます。

### section
`section`タグは、アウトラインの構造を明示的に表現することができるタグです。これは、ドキュメント内の特定のセクションが自立したセクションとして意味を持つ場合に利用します。

※似たようなものにdivタグがありますが、divタグはsectionタグとは違いアウトラインの構造を明示的に表現したりはしない抽象化されたタグで、区切りを表す時に使います。

### aside
`aside`タグは余談や補足情報を表すためのタグです。記事の本文には関連しているものの、主要な内容からは外れる情報に使用されます。例えば、サイドバーや広告バナーの表示に便利です。

## 実際のコード例
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>タイトル</title>
</head>
<body>
    <header>
        <nav>
            <ul>
                <li><a href="#">ホーム</a></li>
                <li><a href="#">記事一覧</a></li>
                <li><a href="#">お問い合わせ</a></li>
            </ul>
        </nav>
    </header>

    <main>
        <article>
            <h1>タイトル</h1>
            <p>記事の説明文</p>
            <section>
                <h2>記事の見出し</h2>
                <p>記事本文</p>
            </section>
            <section>
                <h2>SNS</h2>
                <ul>
                    <li><a href="#">Instagram</a></li>
                    <li><a href="#">x</a></li>
                </ul>
            </section>
            <section>
                <h2>関連記事</h2>
                <ul>
                    <li><a href="#">記事リンク1</a></li>
                    <li><a href="#">記事リンク2</a></li>
                    <li><a href="#">記事リンク3</a></li>
                </ul>
            </section>
            <aside>
                <h3>補足情報</h3>
                <p>この記事に関連する追加情報</p>
            </aside>
        </article>
    </main>

    <footer>
        <p>&copy; 2024 タイトル</p>
        <ul>
            <li><a href="#">プライバシーポリシー</a></li>
            <li><a href="#">利用規約</a></li>
        </ul>
    </footer>
</body>
</html>
```

### 解説
- **articleタグ**は記事全体を囲い、独立したコンテンツブロックとして機能します。
- **sectionタグ**はそれぞれのセクションが独立したコンテンツを形成していることを示し、見出しタグを使って明確に区分します。
- **asideタグ**は記事の本文と直接関連しないが、読者に有益な情報を提供するための余談や補足情報に適しています。
※ asideタグ内のheadingタグがh2ではなく、h3タグが使用している理由としては、articleタグ内の主要なセクションにh2タグを使用しています。asideタグにはそれに関連しつつも主題からは少し離れた補足情報が含まれるため、h3タグでマークアップすることで、h2タグで示された主要なセクションの下位に位置する補足的な内容であることを示しています。

## 参考
[articleとsectionとasideの違いと使い方 | HTML | WeBuddy](https://webuddy.info/html/asa/)
Qiskit 1.0.0の量子プログラミング(実機編)

# Qiskit 1.0.0の量子(実機)プログラミング
先日、[Qiskit 1.0.0の量子プログラミング(シミュレータ編)](https://qiita.com/trtrbohz/items/aca3cf24bb0ecd8b57b6)を投稿しました。今回は同様の回路を実機を使って実行したいと思います。
ここでは、実機へのアクセス準備、前回使ったシミュレータ用のコードを実機向けに改修し、実機にて実行します。


# 実機へのアクセス準備
## IBM Quantum Platform 
今回扱う実機の状況を確認するため[IBM Quantum Platform](https://quantum.ibm.com/)にアクセスします。
※こちらにアクセスする際にIBMidが必要となります。
アクセスすると以下の左に示すような画面になります。そこで上タブにある「Computer resources」(赤枠)をクリックすると右に示すような画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682574/0c992b6b-c56d-02a9-e40d-bf8d1f193680.png)

さらに下図左のように上タブにある「Jobs」(赤枠)をクリックすると右に示す画面になります。こちらで、自身が投じたジョブの実行状況を把握することが可能となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682574/70de5738-1425-cdf3-c011-c92e9bc58a4f.png)

次章で実機上の回路を使って演算するのですが、その際に自分の投げたタスクがどんな状況であるか確認する際に参照します。

## IBM Quantum Learning
[IBM Quantum Learning](https://learning.quantum.ibm.com/)にアクセスして、画面上にある「Lab」タブをクリックすると(下図の上)、Labに切り替わります(下図の左下)。右側に表示されているタイルの中から「Qiskit v1.0.2(ipykernel)」をダブルクリック(下図の左下)すると、下図の右下のようなNotebookを開くことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682574/608dd4da-8dd6-5f61-eaa2-c659cb76f8dd.png)

コードはこのNotebook上で組んでいきます。


# 実機用コード作成
ここでは[Qiskit 1.0.0の量子プログラミング(シミュレータ編)](https://qiita.com/trtrbohz/items/aca3cf24bb0ecd8b57b6)で作ったコードを流用します。シミュレータ編のコードに対し追加一行(下図右の14行目)、変更一行(下図右の16行目)です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682574/143636a1-c221-242c-50ce-e2d2aa48f62b.png)
14行目では、IBMProviderオブジェクトに先の[IBM Quantum Platform](https://quantum.ibm.com/)から取得とってきたAPI Tokenを設定してます。
また、16行目では、使用する実機を指定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682574/c8033c96-a9a7-bdf8-2b93-7733858ad0fb.png)

※実機を指定する際、[IBM Quantum Platform](https://quantum.ibm.com/)に表示されている実機群の中から積まれているジョブが少ないものを選ぶようにするとよいでしょう。

# 実機実行
前節で示した実機版のコードをQiskit上で実行すると以下のようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682574/d99185d9-95a8-9d14-c7ec-bb74cf7ec12a.png)


# 参照
[Qiskit 1.0.0 Release note](https://github.com/Qiskit/qiskit/releases/tag/1.0.0)
[Migrate from qiskit_ibm_privider](https://docs.quantum.ibm.com/api/migration-guides/qiskit-runtime-from-ibm-provider)
[Qiskit 1.0.0の量子プログラミング(シミュレータ編)](https://qiita.com/trtrbohz/items/aca3cf24bb0ecd8b57b6)
Pythonで高速フーリエ変換をして周波数スペクトルを分析する

## はじめに
無名と言います。
これから信号関連の記事を投稿していこうと思います。
まだまだ勉強中なのでわかりにくい部分があると思いますが、よろしくお願いします。

## フーリエ変換とは
フーリエ変換は時間領域で表されている信号を周波数成分に分解することが出来ます。
フーリエ変換の式は以下の通りです。
$$ X(ω)=\int_{-∞}^∞
​
 x(t)e ^{−iωt}
 dt $$

時間領域で表されている信号x(t)が周波数領域で表された信号X(ω)に変換されます。

## 高速フーリエ変換(FFT)
高速フーリエ変換はデジタル信号を高速で離散フーリエ変換してくれるアルゴリズムです。
サンプル数をNとしたとき、通常の離散フーリエ変換をすると時間が$$𝑂(N^2)  $$かかるが、高速フーリエ変換をすると時間が$$O(NlogN) $$となりNが大きい場合大幅に時間が短縮できます。
Pythonのnumpyを使えば高速フーリエ変換が簡単にできるので今回はランダムな波を生成して高速フーリエ変換をし、周波数スペクトルを見ていこうと思います。

## Pythonで実装
Pythonでコードを書いていきます。
今回は5つの周波数がランダムな正弦波を生成してその波の合成波をFFTしていこうと思います。
必要なライブラリをインポートします
```
import numpy as np
import matplotlib.pyplot as plt
import math
```
mathは無くても問題ないです。

## 初期設定
パラメータの設定をします
```
pi = math.pi
f_s = 44100 #サンプリングレート
t_fin = 1 #終了時間(秒)
dt = 1/ f_s #サンプリング周期
N = int(f_s * t_fin) #サンプル数
t = np.arange(0, t_fin, dt)
```
※サンプリングレートは1秒間あたりどのくらいサンプリングするかのこと
今回は時間を1秒にしています。

## 波の生成
正弦波を数式で表すと以下の通りになります
$$ y = Asin(2πft)$$

A : 振幅(amplitude)
f : 周波数(frequency)
t : 時間になります。

ランダムな波を5つ生成し、それらの合成波をPythonで作っていきます。


まず、合成波を入れる配列を初期化し、numpyを使い、周波数がランダムな正弦波を作ります。
その後for文を使い正弦波を配列の中に足して格納していきます。
```
#波の初期化
num_waves = 5 #5つの波を生成(任意の数)
makewave = np.zeros_like(t)

#ランダムな周波数の波の生成
for i in range(num_waves):
    frequency = np.random.uniform(100 , 500) #周波数が100Hzから500Hzの範囲(任意)
    amplitude = np.random.uniform(2 , 30) #振幅の範囲が2から30(任意)

    wave = amplitude * np.sin(2 * pi * frequency * t)

    makewave += wave #合成波の生成

#グラフの描画
plt.plot(t, makewave) #時間領域のグラフ
plt.xlim(0,10**-2) #横軸の範囲
plt.show()
```
作成した波を描画するとこんな感じになります。

![gouseeinami.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778844/6df8ef94-935a-8f6e-953c-19e438c40a2b.png)

これを高速フーリエ変換してどんな周波数の波からできているのか見ていきます。

numpyでフーリエ変換するには
```
y_fft = np.fft.fft(makewave) #離散フーリエ変換
freq = np.fft.fftfreq(N, d=dt) #周波数を割り当て
Amp = abs(y_fft/(N/2)) #振幅
```
このコードでできます。
変換後の波をグラフに描画すると
```
plt.plot(freq[1:int(N/2)], Amp[1:int(N/2)]) #A-f グラフのプロット
plt.xlim(50 , 550) # 横軸
plt.show()
```
![hu-rie_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778844/bc54e197-8b67-02c5-ff88-c1489634d7fe.png)
拡大すると
![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778844/9e9ae162-9d3d-74ba-d67b-af58b4724c27.png)

大体100Hz,170Hz,210Hzあたりの周波数の波でできていることがわかりました。

## おわり
初めて記事を書いてのでまだまだですがこれから気が向いたらいろいろな分野の記事を書いていきたいと思います。最後めっちゃ駆け足気味になってしまいました...
これからもよろしくです
Snowflakeで複数のLISTやSHOW結果をSELECTでまとめて表示したい時

## 概要
LISTとかSHOWってちょっと不便な関数で、呼び出しと同時にSELECTにかける事ができず

源泉が複数あり、源泉ごとにステージがある場合
それぞれのステージごとにファイルの状況をみようとおもったら

+ それぞれのステージを対象にLISTって打つ
+ RESULT_SCAN経由でSELECT〜でステージ単位の集計を見る
+ 別のステージ対象にして繰り返し…

と考えるだけでものすごくめんどくさくなってくるので
以下のサンプルを元に、集計してくるクエリを考えようと思います

### サンプルデータ

```
TEST_DB
  └ TEST
      ├ TEST_STAGE
      │     ├ hoge_202404252050.csv
      │     └ hoge_202404282050.csv
      └ TEST2_STAGE
      　      ├ fuga_202404272050.csv
      　      └ fuga_202404282050.csv
```

こんな感じでステージごとにファイル名にデータ日付がある場合
例えばステージのファイル種別ごとの更新日とか1回で取りたいですよね？

と、いうことで…

### 各ステージのファイル種別（分割した上で左側をファイル種別とする）ごとの最終ファイル名と最終更新時刻を取るクエリ

```:SQL
DECLARE
    QUERIES ARRAY DEFAULT [];
BEGIN
    LET STG_RESULT RESULTSET := (SELECT STAGE_NAME,STAGE_SCHEMA FROM INFORMATION_SCHEMA.STAGES );
    LET STG_CUR CURSOR FOR STG_RESULT;
    
    FOR STG IN STG_CUR DO
        LET STG_NAME TEXT := STG.STAGE_NAME;
        LET STG_SCHEMA TEXT := STG.STAGE_SCHEMA;
        EXECUTE IMMEDIATE ('LIST @'|| :STG_SCHEMA || '.'|| :STG_NAME );
        QUERIES := ARRAY_APPEND(QUERIES,LAST_QUERY_ID());
    END FOR;
    
    LET Q_RS RESULTSET := (SELECT VALUE FROM TABLE(FLATTEN( INPUT => :QUERIES)));
    LET Q_CUR CURSOR FOR Q_RS;

    LET GET_LIST_QUERY TEXT := '';

    FOR QID IN Q_CUR DO
        LET Q TEXT := QID.VALUE;
        IF (GET_LIST_QUERY != '') THEN
            GET_LIST_QUERY := GET_LIST_QUERY || '\n UNION ALL \n';
        END IF;

        GET_LIST_QUERY := GET_LIST_QUERY || 'SELECT
            SPLIT_PART($1,''/'',-2) AS STAGE ,
            SPLIT_PART(SPLIT_PART($1,''/'',-1),''_'',1) AS FILE_TYPE, 
            MAX(TRY_TO_TIMESTAMP(SPLIT_PART(SPLIT_PART(SPLIT_PART($1,''/'',-1),''_'',2),''.'',1),''YYYYMMDDHH24MI'')) AS FILE_DATE,
            MAX_BY($4,TRY_TO_TIMESTAMP(SPLIT_PART(SPLIT_PART(SPLIT_PART($1,''/'',-1),''_'',2),''.'',1),''YYYYMMDDHH24MI'')) AS LAST_MODIFIED
            FROM TABLE(RESULT_SCAN(''' || :Q || ''')) GROUP BY 1,2';
    END FOR;
    LET RS RESULTSET := (EXECUTE IMMEDIATE :GET_LIST_QUERY);
    RETURN TABLE(RS);
END;
```

ちょーっと後半が奇怪な処理になってしまっていますが…


### 実行結果
![スクリーンショット 2024-04-28 21.33.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150914/687068e4-36c3-7f89-0f08-b866b56b8ff2.png)

複数ステージの最大日付とファイル日付、最終更新日が取れました (∩´∀｀)∩

## ちょっとした説明

LISTの結果を加工する場合はRESULT_SCANを通してからSELECTするしかないのですが
上にも書いたように、RESULT_SCANに渡せるのはQUERY_ID、そして実行ごとにクエリIDを取るのは**ものすごいめんどくさい**

のでちょっと力こそパワーで解決するべく下記の感じで処理を行っています。

+ INFOMATION_SCHEMAからステージをGET
+ LISTを実行
+ LAST_QUERY_IDを使い、LISTが実行された時のクエリIDを取得
+ 取得したクエリIDを行に戻す
+ RESULT_SCANごとに集計
+ 集計結果をUNION ALL…

SHOWとかLISTがもうちょい加工しやすくなればこんな処理はいらないんですが… (´･ω･`)
暗号化SharedPrefarenceの書き方

# はじめに
今回はローカルでデータを持っておく時に使うSharedPrefarenceの暗号化バージョンの書き方を紹介していきます
### 本文
早速コードですが下記になります。
実際に保存するときは`sharedPreferences.edit().putString()`で保存することができ、読み込むときは`sharedPreferences.getString()`でアクセスすることができます
```kotlin
private val sharedPreferences: SharedPreferences

    init {
        val masterKey = MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()
        sharedPreferences = EncryptedSharedPreferences.create(
            context,
            "secret_shared_prefs",
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }
```
### 最後に
今回は暗号化SharedPrefarenceの書き方を紹介していきました
ローカルで保存するのに何気なく使っていたSharedPrefarenceですが、こういった書き方をすることで秘匿性を高く保持することができます
Lambda関数の実行予約をする


■適当なLambdaを選択する
以下のコードを入力する
``` python
import json

def lambda_handler(event, context):
    # TODO implement
    print('test成功')
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```


■イベントを設定する
『設定』⇒『トリガー』と進め『EventBridge』と選択しする。
スケジュール式で『cron(35 12 27 04 ? 2024)』と入力する♢
※UTCの時間指定なので、日本との時差は9時間で計算する。上記の場合は、日本時間の21時35分に実行される


■モニタリングの『CloudWatchログを表示』から実行を確認できる
![demo](https://gyazo.com/9ce7f57761f7b1a5dc552b1eac300a15/raw)


♢ローカルタイムの時間確認ができた
Amazon EventBridge⇒ルールと進む
![demo](https://gyazo.com/af4e1121ab3c7d759a69bc262f89cc80/raw)
イベントスケジュールから確認できる
![demo](https://gyazo.com/67a87b29920375a807c1b2b426b37d58/raw)
![demo](https://gyazo.com/6cc4a76227a40b9f57b6552508d1f46a/raw)
⇒Lamdbaの関数に紐づけると、トリガーとして追加されていた

♢パラメーターを渡す方法
ルール編集のターゲット選択から『入力トランスフォームを設定』を選んで、以下のように設定すると『テンプレート』のほうのパラムを渡すことができる
![demo](https://gyazo.com/b5ec3e99e9502d9b84b46d61aed7c811/raw)
![demo](https://gyazo.com/94e00c7820c1684eb02af0fffd7da7e3/raw)
Flutter で Android と iOS のスワイプして戻る画面遷移機能を無効化する

# なにこれ
この戻る機能を無くしたいので、それを実装した時のメモを書く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/82a1a37c-2c3f-7b0d-1883-297374b3cf65.png)

# 解決方法
`PopScope` を利用して `canPop: false` を実装するだけで大丈夫でした。

### Before
```dart
class _HomeViewState extends State<HomeView> {
  int selectedIndex;

  _HomeViewState({Key? key, required this.selectedIndex});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // コードが続く
```

### After
```dart
class _HomeViewState extends State<HomeView> {
  int selectedIndex;

  _HomeViewState({Key? key, required this.selectedIndex});

  @override
  Widget build(BuildContext context) {
    return PopScope( // ここを追加
      canPop: false, // false で無効化
      child: Scaffold( // Scaffold は child に入れる
        // コードが続く
```

# おわりに
この実装方法については公式サイトで紹介されていました。
デフォルトでは canPop は true ですよということでした。
https://api.flutter.dev/flutter/widgets/PopScope-class.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/94af2d76-850f-b53b-05a7-74822f93588e.png)


# 追記
### 2024/08/03

Android の戻るボタンによってアプリをバックグラウンドへ移動させて、ホームに戻る処理を実装したくなったので以下をまとめました。

https://qiita.com/su3-hokkaido/items/d9454744832450cb6629
Tempoで日付変換

# はじめに
今回は、たまたま便利なJavaScript・TypeScriptライブラリを見つけたので記事にします。本記事では、JavaScript・TypeScriptで使える日付データを操作することができる「Tempo」でDate型のデータを変換してみます。
参考：公式ドキュメント(https://tempo.formkit.com/)
# インストール
今回は、npmでインストールしました。公式ドキュメントによると、Tempoはpnpm・npm・yarn・bunでインストールすることができるとのことです。
```
npm install @formkit/tempo
```
# 単純な日付形式の指定
現在日付の日付形式を指定してみます。下記の場合は、「yyyy年m月d日」の形式で現在日付を表示することができます。
```index.ts
import { format } from "@formkit/tempo"

const date = new Date()

format(date, "medium", "zh")
```
# 異なる日付形式間の形式変換
今回は、APIから「YYYY-MM-DDhh:mm:sssZ」形式で取得したDateデータを「YYYY/MM/DD」に変換します。
```index.ts
import { format } from "@formkit/tempo"

// 日付の形式をYYYY-MM-DDThh:mm:sssZからYYYY/MM/DDに変換する
function convertDate(date: string): string {
  const oldDate = new Date(date);
  return format(oldDate, "YYYY/MM/DD", "ja")
}

console.log(convertDate("2024-04-01T10:00:000Z"))
// -> 2024/04/01
```
# 様々な日付文字列の形式変換
parseメソッドを使えば、様々な形式の日付(+時間)っぽい文字列をDateデータに変換することができます。
```index.ts
import { parse, format } from "@formkit/tempo"

// 日付の形式をMM/DD/YYYYからYYYY-MM-DDThh:mm:sssZに変換する
function convertToDate(dateSlash: string): string {
  return parse(dateSlash, "MM/DD/YYYY")
}

// 日付の形式をYYYY-MM-DDThh:mm:sssZからYYYY/MM/DDに変換する
function convertDateFormat(date: string): string {
  const oldDate = new Date(date);
  return format(oldDate, "YYYY/MM/DD", "ja")
}

console.log(convertDateFormat(convertDate("04/01/2024")))
// -> 2024/04/01
```
# 終わりに
この他、Tempoでは日付・時間っぽい文字列を使って、日時の加減算をすることもできるようです。私は、microCMSからの日時データを加工する際に使用しましたが、あまり使わないような日付(+時間)っぽい文字列を簡単に加工できるため、便利なライブラリだと感じました。個人的には、JavaScriptやTypeScriptの日付形式の変換はめんどくさいと思っていたのですが、このライブラリでそれがかなり楽になりそうなので、今後も使っていこうと思います。
【2024年12月版】Ubuntu24.04 で sshdの待ち受けポートの変更【ssh, sshd】

# はじめに

Ubuntu24.04　で sshdの待ち受けポートを変更するメモ。

ここでは、待受ポートを 22 から 22222 に変更しています

:::note warn
Ubuntu22.10 から、待受ポートの変更は `/etc/ssh/sshd_config` の変更やオーバーライドでだけはできなくなっています。
:::

:::note info
`/usr/lib/systemd/system/ssh.socket` を修正するように変更しました。
:::

:::note info
ssh.socketと、ssh.serviceの設定をそれぞれ変更する必要があります。

ssh.socket → /usr/lib/systemd/system/ssh.socket
ssh.service → /etc/ssh/sshd_config.d/*.conf
:::


# 環境

- Ubuntu22.04

# 変更手順

- /etc/ssh/sshd_config をオーバライドして設定を変更する
- systemctl edit を使って、ssh.socket を変更する
- service を再起動する

## 変更前の確認

ポート 22 が開いてる

```terminal
$ ss -anlt
State             Recv-Q             Send-Q                         Local Address:Port                          Peer Address:Port            Process            
LISTEN            0                  4096                              127.0.0.54:53                                 0.0.0.0:*                                  
LISTEN            0                  128                                  0.0.0.0:22                                 0.0.0.0:*                                  
LISTEN            0                  4096                           127.0.0.53%lo:53                                 0.0.0.0:*                                  
LISTEN            0                  128                                     [::]:22                                    [::]:*      
```

## 設定の変更

### /etc/ssh/sshd_config のオーバーライド

/etc/ssh/sshd_config をコピーして設定ファイルを作る

```terminal
$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.d/99-override.conf
$ sudo vim /etc/ssh/sshd_config.d/99-override.conf
```

必要な行だけ残す、ここではポート番号を変更する行だけ残す

```terminal
$ cat /etc/ssh/sshd_config.d/99-override.conf
Port 22222
```

### ssh.socket の変更

```terminal
sudo vim /usr/lib/systemd/system/ssh.socket
```

以下の部分のポート番号を変更

```
[Socket]
ListenStream=22222
```

## サービスの再起動

```terminal
$ sudo systemctl darmon-reload
$ sudo systemctl restart ssh
```

## 変更後の確認

ポート 22222 が開いてる

```terminal
$ ss -anlt
State             Recv-Q             Send-Q                         Local Address:Port                          Peer Address:Port            Process            
LISTEN            0                  4096                              127.0.0.54:53                                 0.0.0.0:*                                  
LISTEN            0                  128                                  0.0.0.0:22222                              0.0.0.0:*                                  
LISTEN            0                  4096                           127.0.0.53%lo:53                                 0.0.0.0:*                                  
LISTEN            0                  128                                     [::]:22222                                 [::]:*           
```

# さいごに

かんたんでしたね。

# 関連リンク

[SSHd now uses socket-based activation (Ubuntu 22.10 and later)](https://discourse.ubuntu.com/t/sshd-now-uses-socket-based-activation-ubuntu-22-10-and-later/30189/9)
Windowsメインの開発環境でBash / Zshっぽい操作感がほしいとき

最近Windows前提の開発環境で作業するプロジェクトが結構あったのですがそのときにつらいのがGitを中心とするコンソール作業。Windows TerminalとPowerShellの組み合わせは昔と比べるとはるかに快適ではあるものの。MacやLinuxでバキバキにカスタムしたZshに慣れている自分としては苦行に近いものがあります。

そんなときにまず思いつくのはWSL2です。もちろん使ってます…がWindows側のドライブ (`/mnt/c/...`) においてあるGitレポジトリを触ると[耐えがたいレベル](https://github.com/microsoft/WSL/issues/4197)で遅いことが発覚。WSL2はWSL2内のドライブで完結する場合は問題ないもののWindows側へのアクセスにパフォーマンス問題があるようです。

VMを利用していないWSL1なら良いかもしれませんが、すでにWSL2は別で利用しているので触りたくない、ということで第三の選択肢MSYS2を試してみました。

### MSYS2とは
Windowsアプリケーションを開発するための開発環境というコンセプトだそうです。CygwinのようにPOSIX環境を完全再現することは目指しておらず、Windowsのツールセットと混ぜて使いやすいらしいです。パッケージシステムとしてはArch LinuxのようにPacmanを利用していて主要なUNIX的ツールをインストールできます。

### MSYS2インストール
以降は執筆時点の最新のWindows 11の場合です。
MSYS2を普通にインストールします。最近のWindowsならWingetが最初から入っているのでPower Shellで

```
> winget install MSYS2.MSYS2
```

そのあとはMSYS2 / MSYS2をスタートメニューから開いて各種ツールをインストールします。ただし割とクセがありvimを入れてもviがaliasされないなどがある、そこは各自で直す必要がある。

```bash
$ pacman -S zsh vim ruby
```

.zshrcに追記する例
```bash
alias vi=vim
```


### Windows Terminal
MSYS2のはminttyというterminalがデフォルトで付属しているのですがWindows Terminalのほうが使いやすいです。Windows Terminalの設定画面左したにOpen JSON fileというボタンがあるのでそこから設定ファイルを開き以下を追加。Zshの箇所とかフォントはお好みで。

```json
    "profiles": 
    {
...
        "list": 
        [
            {
                "antialiasingMode": "cleartype",
                "commandline": "C:/msys64/msys2_shell.cmd -defterm -here -no-start -msys -shell zsh",
                "font": 
                {
                    "face": "Cascadia Mono"
                },
                "guid": "{71160544-14d8-4194-af25-d05feeac7233}",
                "icon": "C:/msys64/msys2.ico",
                "name": "MSYS / MSYS2",
                "startingDirectory": "C:/msys64/home/%USERNAME%"
            },
...
```


### Git
個人的に最重要なGitです。MSYS2のGitも（WSL2とは別のなんらかの理由により）かなり遅いです。Git For Windowsを利用しましょう。まだ入ってない場合は入れておいてください。

PowerShell
```
> winget install Git.Git
```

さて、MSYS2ではデフォルトではsymlinkを作成できないため（オプションで複数の実装、挙動でのsymlinkが利用できるようです）、 `/usr/bin/git` をこんなshell scriptにしたところ動作しました。

```bash
#!/usr/bin/sh

exec /c/Program\ Files/Git/bin/git.exe "$@"
```

MSYS2
```bash
$ chmod +x /usr/bin/git
```

Zshなどのプロンプトでbranch名や状態(clean / dirty)を表示している場合も問題なく動作してます。

```bash
~ $ cd /c/foo/bar/repo
repo git:(branch-name) ✗ $ 
                       ↑ has changes
```

### 余談
Git For Windows自体はMSYS2のForkであり、MSYS2にGit For Windowsをインストールする手段というものが存在するようなのですが、無保証であり、自分が試したときにはうまくビルドできませんでした。そのため普通にWindowsにインストールされたものを利用しています。


### 余談2
WSL2と違いVMではないのでサーバーを建ててLAN内から参照できるようにすることも簡単で、設定の変更も不要です。例えばRubyの場合、以下で指定したディレクトリ内のファイルを公開できます。

```bash
$ gem install webrick
$ ruby -run -e httpd . -p 9000
# ここでUAC的なポップアップが出るので許可
```


### 結論
MSYS2を利用することでWindowsのディレクトリ、Windowsのワークフローを利用している場合でも快適にZshを利用しつつネイティブのツールを利用することができました。他の使えそうな選択肢は試していないのでこれがベストかは不明ですがすべてが快適に動作しているのでしばらくはこの構成のまま使う予定です。

試していないやつ↓
- [WSL2からGit For Windowsを実行](https://nnao45.hatenadiary.com/entry/2021/02/12/134852)
- Git Bash (Git For WindowsについてくるBash)を使う
  - MSYS2のforkであるためほぼ同じ操作感が得られそう
  - PacmanがついてこないためZshやその他の追加インストールは難しいらしい。vimとBashくらいしか使わない人はいいかも
- WSL1とWSL2併用
  - WSL1の将来性どうなんでしょうか。WSL1ベースのWindows Subsystem for Androidは終わるし
- Cygwin
[Windows] JuliaでPyPlotつかうときのPython問題

WindowsでJuliaにPyPlotいれようとしたらてこずったので，メモ。

家のWindows11だと，一旦ホームの下にある.juliaを全部消してから，PyCallインストールしたらうまくいった。このときconda 24.3.0がインストールされる。バージョンが23とかだとインストールできても，実行したら強制終了するとかあった。

なにも設定しないとPyCallでつかうPythonは，.julia/conda/3/x86_64/condabinの中のもので，condaでPythonのライブラリを管理する。システムに入ってるPythonとは別物で関係ない。（これを認識してないとややこしいことになる）

PyCallで使うPythonを変えるには，ENV["PYTHON"]で使いたいpythonの実行ファイル（python.exe）のあるPATHを設定する。

## 不具合あったときの対応

- ENVでPythonのPATHを変更する
- .juliaを削除して，PyCallインストールして，condaも入れ直す

## 追記
大学のパソコンで.julia以下を削除して，add PyPlotからやり直してもエラーした。

```
 .\.julia\conda\3\x86_64\condabin\conda.bat install libtiff
```

として，libtiffをインストール（インストールは済んでて，実質はアップデートがかかる）すると，うまくいった。

参考　

https://qiita.com/KenichiroHirose/items/ec916cb0269869b8a924
Raspberry Pi+Juliusで音声認識（かなり昔に試してみた）

## はじめに
今回はかなり昔に試してみた初代Raspberry PiにJuliusを入れて音声認識を試したときの備忘録です（以前に試した当時の記事内容ですので、最新のRaspberry Piなどでは動作が違う可能性があります）。

## Juliusとは
Juliusとは音声認識の開発・研究の為に京都大学の研究室が中心となって開発されたオープンソースの音声認識エンジンです。
以前は以下のリンクからjuliusをDLできていましたが、今はDLできなくなっています。

## 動かしてみました
2024/04現在ではDLできなくなっていますので、インストール方法などは割愛します。
当時試行錯誤したときのポイントと感想を記載します。

私は音声認識で使用するためにUSBで接続可能なマイクを購入しました。
![DSC01151.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/973276cb-143e-d0f8-c2a2-d490219fbe99.jpeg)

まずUSBオーディオアダプタの優先度を確認します。（下記の場合、内蔵オーディオが優先されているので、USBオーディオを最優先にする設定を行います）
```
$ cat /proc/asound/modules
0 snd_bcm2835
1 snd_usb_audio
```

この場合、USBオーディオを優先的に利用したいので、優先度を上げるため、alsa-base.conf内のUSBオーディオのindexをindex=0にします。

```
sudo vim /etc/modprobe.d/alsa-base.conf
```
index=-2をindex=0にします。
```
# options snd-usb-audio index=-2
options snd-usb-audio index=0
```

Raspberry Piを再起動します。これでUSBオーディオが優先的に使用できます。

次にカード番号を環境変数に指定します。
```
export ALSADEV=hw:0
```

以下のコマンドでJuliusを起動できます。
```
$ ~/raspberry/julius-4.3.1/julius/julius -C main.jconf -C am-gmm.jconf -demo
```

`<<<please speak>>>`と表示されているときに、マイクに向かって何か言葉を話すとjuliusが音声認識を開始します。
![DSC01147.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/128594db-eb83-760f-6a85-147f460955e0.jpeg)

`こんにちは`、`おはよう`、`今日はいい天気`、`今日は暑いね`と話してみましたが、そこまで精度は高くないようです。当時のバージョンなので、最新版などを使えば制度も上がっていそうですね。
あととても動作がもっさりしています。初代Raspberry Piでスペックが低いせいだと思いますが、マイクで話して数秒かかってやっと認識された文字が表示されます。

## 終わりに
新しいRaspberry Piを使って最新のJuliusを試してみたいと思います。
JetpackComposeでアニメーションを使った表示・非表示の切り替え

# 実践
```
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.White)
            .padding(40.dp)
    ) {

        var isVisible by remember {
            mutableStateOf(true)
        }
        val animation by animateFloatAsState(
            targetValue = if (isVisible) 1.0f else 0f,
        )
        Box(
            modifier = Modifier
                .size(200.dp)
                .graphicsLayer {
                    alpha = animation
                }
                .clip(RoundedCornerShape(8.dp))
                .background(Color.Green)
        ) {}

        Button(onClick = {
            isVisible = !isVisible
        }) {
            Text(text = "切り替え")
        }
    }
}
```

![Record_2024-04-28-20-21-10_703d6d0c1a2cc5d78cdb74dea5dc787d (online-video-cutter.com).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/534d4998-8d3f-b363-15a5-f922b24a53c6.gif)

# 説明
サクッと説明します。
**animateFloatAsState**はアニメーションの使うStateを設定しておけます。
今回の場合はif文で分岐させてアニメーションのvalueの中身を1.0fか０fかで切り替えられるようにしています。
(0.5fとかを設定すると半透明になる。)
ここまでに設定しておいたアニメーションを**graphicsLayer**に渡します。

その後、ボタンでアニメーションのvalueに設定する変数を切り替えるようにしています。
# 参考

https://developer.android.com/develop/ui/compose/animation/quick-guide?hl=ja
AWS DVAに合格しました

# はじめに
AWS DVAに合格したため、振り返りと備忘録を兼ねてやったことをまとめておきます。

# 投稿者の情報
- 新卒3年目
- 所持資格：IPA FE/AP/SC/DB | AWS SAA
- AWSの業務経験：約1年程度
- AWS DVA受験回数：1回目



# 受験の感想と結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3748131/742a7a47-393f-6af9-ebc4-023c8821a471.png)
受験結果ですが、合格点720点に対して819点での合格でした。
開発における設定やら構築やらを問う問題がメインですが、細かい設定というよりはWell-Architectedやベストプラクティスに準拠してコスト最適化を行う際の構成や設定についての知識をメインとして問われているようなイメージがありました。
4択のうち、アーキテクチャ的に設問の内容を実現不可能な選択肢が0-2択、コストパフォーマンスの異なる選択肢が4-2択のような設問が多く、各サービスに対するコスト感覚がある程度あると問題を解きやすかった印象です。

# やったこと
受験にあたり行った学習内容は以下の通りです

- 全体を通しての学習時間：20h程度  
    - 模擬問題を解く(20h程度)
→Udemyから200問程度を解き、わからない設定やサービスについて都度調べる形で学習をしていました



# 利用した教材と所感

### 【DVA-C02対応】AWS認定 デベロッパー アソシエイト 模擬問題集＋詳解 【2024年版最新】

https://www.udemy.com/course/dva-c02aws-2024

模擬問題を解いて分からない問題について解説や公式ドキュメントを読むスタイルで学習を行いました。
この教材では解説が比較的詳しく、公式ドキュメントを利用する場面は少なかったです

# 受験費用
- 1回目受験 16,500円
- Udemy 1講座 1,800円

計 18,300円

# 今後受験する人へ
- 問題文の読解に慣れた方が楽なので、模擬問題はある程度やるといいと思います
- SAAの知識があるとアーキテクチャ的に不適なものが分かりやすいので、よくオススメされるSAA→DVAの流れは理にかなっていると思います
- Well-Architectedや事例集にざっくりでも目を通しておくと出題範囲の知識の理解に役立つと思います

# 今後の予定

4/21にST受験してからの4/28DVAは体力的にきつかったので、次回はのんびり6月にSOAを予定しています。
ところで無線技士の資格証、かっこいいですねぇ…
陸上特殊無線技士取ろうかと思ったら今年の申込み期間が過ぎていたので、アマチュア無線だけ取ろうか悩み中です