OmniAICreator/Qiita-1.07M huggingface dataset:
【個人用】AWS Solution Architect Associate対策ノート(ネットワーク・コンテンツ配信編)

## 扱う内容

・Route53
・CloudFront
・Global Accelerator
・Direct Connect
・AWS VPN

# 【Route53】

## Route53のルーティングポリシー

### レイテンシーベースルーティング
レイテンシーが最も低いリソースにルーティングする

### 加重ルーティング
複数のIPアドレスに設定された重みづけに従ってルーティングする

### 位置情報ルーティング
ユーザーとリソースの地理的情報に基づいてルーティングする
位置情報を基にするので、ユーザーの使用言語に合ったコンテンツがあるリソースにルーティングできる
サーバーの地理的情報は考慮しない

### フェイルオーバールーティング
リソースのヘルスチェックを行い、問題がなさそうなリソースにルーティングする

### シンプルルーティング
「ここに接続しろ」という設定に従ってルーティングする
ほかのルーティングポリシーとは組み合わせ不可能

### 地理的近接性ルーティング
接続元クライアントの位置情報から、地理的に近いリソースにルーティングする

### 複数値回答ルーティング
複数のリソースのヘルスチェックを行い、正常なリソースの中から最大8個選んで、どこかにルーティングする

## エイリアスレコード

Route53には**エイリアスレコード**という特別なDNSレコードがある
エイリアスレコードとは、特定のAWSリソース(S3バケットなど)にトラフィックをルーティングするための特別なDNSレコード
エイリアスレコードには、最上位のドメイン名である**Zone Apex**を登録できる
たとえば、「www.example.com」や「sub.example.com」だったら、example.comがZone Apexとなる

## 2種類のホストゾーン

**ホストゾーン**とは、DNSレコードを管理するコンテナのようなもの
**DNSレコード**とは、ドメイン名(example.comなど)とその関連情報を管理するためのもの

### パブリックホストゾーン
インターネットなどVPC外に公開されたドメインのDNSレコードを管理する

### プライベートホストゾーン
VPC内に公開されたドメインのDNSレコードを管理する



# 【CloudFront】

## CloudFrontディストリビューション
コンテンツを素早くユーザーに届けるための設定パッケージのようなもの

どのコンテンツを、どこのサーバーから(日本なのかアメリカなのか)、どのように(各地にキャッシュを持たせるなど)届けるかを設定する

## CloudFront署名付きURL
有効期限付きのURLで、特定のクライアントにのみコンテンツ(S3内のコンテンツなど)にアクセスさせたい場合に使う
CloudFrontの署名付きURLを使う場合は、**OAI**を有効にする
OAIを有効にすると、S3内のコンテンツにはCloudFrontを経由しないとアクセスできなくなるので、直接アクセスされるのを防ぐことができる

## フィールドレベル暗号化
ユーザーから送信されたHTMLフォームのPOSTリクエストのうち、一部フィールドを暗号化し、特定のアプリケーションでのみ複合可能にする機能
たとえば、クレジットカード情報やパスワードをPOSTした場合に、それらを暗号化して、特定のキーを持つアプリケーションに到達したらようやく複合化する、といったことができる

## 地理的制限
CloudFrontでは、クライアントの接続情報を基に、この国からのアクセスは可、この国からのアクセスは不可といった設定ができる

## キャッシュ削除機能
CliudFrontでは、エッジサーバーに保存されているキャッシュを即座に削除できる機能が存在する
削除後にクライアントからデータを受け取ると、エッジサーバーは必ずオリジンサーバーにコンテンツを取得しに行くので、配信するコンテンツが最新化される

## キャッシュTTL
キャッシュを保持する期間のこと
キャッシュTTLが過ぎた状態でクライアントからのリクエストを受けた場合、オリジンサーバーのコンテンツを確認して、更新されていればキャッシュに反映しつつ応答を返す

キャッシュTTLの値が大きければ更新頻度は下がる
キャッシュTTLの値が小さければ更新頻度は上がる

## ファイル圧縮
CloudFrontでは、**エッジロケーション**にてファイルを圧縮することができる
圧縮することにより、ダウンロード時間の短縮や通信コスト低下を見込める



# 【Global Accelerator】

## Global Acceleratorの基礎知識

・ユーザーからAWSリソースまでのアクセス経路を、AWSネットワークを利用して最適化するサービス
・レイテンシやデータ損失などのリスクを軽減する
・複数リージョンで展開しているWebアプリケーションの、リージョン間での負荷分散を行うことができる
・負荷分散先はALBやNLB、EC2インスタンスなど

## Global Acceleratorのアクセラレーター
さらに可用性とパフォーマンスを向上できるもの、くらいの認識。。。

# 【Direct Connect】

## Direct Connectの接続方法
Direct Connectでは、**Direct Connectエンドポイント**と**仮想プライベートゲートウェイ**を1対1でつなぐ。なので、通常では1つのVPCにしか接続できない
しかし、**Direct Connectゲートウェイ**を使えば、複数のVPCに接続できる

## Direct Connectロケーション
オンプレミスとAWSデータセンターを相互に接続するポイントのこと
各リージョンに複数用意されているので、ユーザーは複数のDirect Connectロケーションにつなぐことにより、可用性を高められる

# 【AWS VPN】

## Site-to-Site VPNの構成

Site-to-Site VPNは、オンプレミスとAWSをVPN接続する方法

オンプレミスの**カスタマーゲートウェイ**と、AWSの**仮想プライベートゲートウェイ**を、**VPNトンネル**を使ってつなげる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751890/ece15802-6c4b-5a9f-45f8-a04e0cfa501a.png)

VPNトンネルを経由したトラフィック情報は、**CloudWatch**で確認できる

カスタマーゲートウェイは、複数配置することで可用性を高めることができる
仮想プライベートゲートウェイは、最初からAWS側で冗長化されている
AIによる自動文字起こしの効果的な活用法7選

<br>

あなたは会議中にひたすらメモを取ることに疲れていませんか？あるいは、会議が終わった後、録音を聞き返して議事録を作成する時間を節約したいと感じたことはないでしょうか。現代のビジネスシーンでは、効率性が何よりも求められています。そして、その効率性を高めるために重要なのがAI技術の活用です。

会議やミーティング中にリアルタイムで話された内容を漏れなく記録することは難しいですよね。忙しいビジネスパーソンにとって、メモを取りながら会話の流れに集中するのは至難の業です。さらに、後でそのメモを清書し、誤解のないように議事録を仕上げるのは、多くのリソースと時間を消費します。このような状況で役立つのが「AI自動文字起こし」です。

### AI自動文字起こしの利点と解決策

1. **リアルタイムの音声認識**
    - 会議中の音声をリアルタイムでテキスト化することで、会議の進行を妨げずにその場で内容を把握できます。
    - 日本語の音声認識にも対応し、専門用語やイントネーションを高精度でキャッチ。

2. **自動議事録生成**
    - 会議終了後すぐに自動で簡略化された議事録を作成します。手直しが必要な箇所も簡単に編集可能。
    - これにより、手入力の手間が省け、議論内容に集中できる環境を作り出します。

3. **オンライン会議対応**
    - リモートワーク全盛の現代において、オンライン会議もスムーズにサポート。複数の話者がいる場合も問題なく処理できます。

4. **高い安全性とデータ保護**
    - 大事な会議内容は高いセキュリティ標準で保護され、安心して利用できます。

### Soro.jp 文字起こしがもたらす新しい作業体験

そんなあなたの味方になるのが「Soro.jp 文字起こし」です！このツールの魅力は、何といってもその高精度でリアルタイムの文字起こし能力です。音声を捕捉するだけでなく、自動で整理された議事録を提供し、後ほど簡単に検索もできます。これらはすべて、直感的なインターフェースを通じて可能となるため、誰でも簡単に扱うことができます。

- **直感的な操作性**：初心者でもすぐに使いこなせるシンプルさ
- **安全性の確保**：あなたのデータは常に安全に保管
- **検索機能**：過去の議事録もキーワードで素早く検索できる

このように、Soro.jp 文字起こしは単なる会議録音ツールを超え、効率的な作業フローを構築するための革新的な選択肢です。手間を省き、あなたのビジネスを次のステージへと導く手助けをしてくれます。

今すぐ、[Soro.jp 文字起こし](https://soro.jp/)でその機能を体験し、新しいワークライフバランスを手に入れましょう。最適な作業環境をあなたの手で作り上げてください。立即試用こちらから！

https://soro.jp/blog/ai-automatic-transcription
Oracle Bronze 合格した勉強法

お久しぶりです。
中身はハムスターの人間です。
現在は就活うまくいかなかったので業務委託やってます笑
この度はBronze DBA Oracle Databaseに合格したので、私が行なった勉強方法をこちらの記事に記します🐹

[![Image from Gyazo](https://i.gyazo.com/0dbaa2588346294e23e8df0a08a6ab46.png)](https://gyazo.com/0dbaa2588346294e23e8df0a08a6ab46)

## スペック
私のorackeやデータベースに関する大まかなスペックは以下です。
- dbに関する資格は初めて
- 実務ではmysqlを使用
- 個人開発ではpostgrelsqlを使用
- dbに関する数書の本を呼んだくらい

あと、大学は文系です。外国語学習の方法などを学んでいました。

## 受けた理由
友人から25歳(+-2)まで脳が成長すると教えてもらい、興味がある分野を勉強して脳を鍛えようと思ったからです笑

## 勉強に使用した本
メインで使用した本は以下の1冊です。
わからない単語などが出た場合は、その都度ググってました。
[オラクルマスター教科書 Bronze DBA Oracle Database Fundamentals](https://amzn.asia/d/bc8hG2s)

## 勉強方法
ざっと以下のことを行い、トータルで25時間いかないぐらいの勉強量でした。
- オラクルマスター教科書を一周ざっと読む
- 章末問題を4周する
- 巻末に載っている模擬試験を2周する

## 試験の傾向
Amazonのレビューにある通り、オラクルマスター教科書の問題の選択肢がなぜ合っているのか間違っているのかを答えられるレベルになっていたら、余裕で合格できると思います。
ところどころに本の内容に出てきた覚えがない部分が試験に出てきましたが、合格点が足りなくなる問題ないです。

## 受けてみて
内容は導入という感じでした。次はsilver sqlを狙おうと思います笑

## 最後に
お読みいただきありがとうございました！
参考になれば幸いです🐹
PDFファイルを結合する方法と無料ツール

ComPDF の無料オンライン ツールを使用すると、[PDF ファイルを結合したり](https://www.compdf.com/demo/webviewer?utm_source=qiita_20250114&utm_medium=mergepdf)、透かしなしでファイルをエクスポートしたりすることができ、登録は必要ありません。

- ドキュメントエディタをクリック

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789769/b43e518e-4f2a-cbff-0db4-315221fabf7a.png)


- [挿入] をクリックし、挿入するファイルと挿入するページ番号を選択します。次に、前 (before) または後 (after) に挿入するページを選択します。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789769/0ad40081-3df8-cb25-a83e-48f0368ea5cc.png)


- 「名前を付けて保存」をクリックしてファイルをダウンロードします
【React】SuspenseではuseEffectは使えない

# 事象
supabaseに作ったテストデータを読み込む間にローディングメッセージを出したいと思い、`Suspense`で実装しましたが、全く表示されませんでした。

## コード
(supabase周り等、関係ない部分は省略）

```react:App.jsx
import { useState } from 'react';
import { LogDisplay } from './components/LogDisplay';

export const App = () => {
  (中略）
  return (
    <div>
      （中略）
      <LogDisplay />
      （中略）
      </div>
    </div>
  );
};
```

```react:LogDisplay.jsx
import { Suspense } from 'react';
import { Loading } from './Loading';
import { LogContent } from './LogContent';

export const LogDisplay = () => {
  return (
    <Suspense fallback={<Loading />}>
      <LogContent />
    </Suspense>
  );
};
```

```react:Loading.jsx
export const Loading = () => {
  return <div>Loading...</div>;
};
```

```react:LogContent.jsx
import { useEffect, useState } from 'react';
import { getAllLogs } from '../utils/supabaseFunctions';

export const LogContent = () => {
  const [logs, setLogs] = useState([]);

  useEffect(() => {
    const getLogs = async () => {
      const logs = await getAllLogs();
      setLogs(logs);
    };
    getLogs();
  }, []);

  return (
    <div>
      {logs.map((log) => (
        <p key={log.id}>
          {log.title} {log.time}時間
        </p>
      ))}
    </div>
  );
};
```

# 原因
もうタイトルで答えは出ているのですが、`Suspense`では基本的に`useEffect`は使えないようです。
https://qiita.com/tarako314/questions/baf7e50ac1af5a926e0f
https://ja.react.dev/reference/react/Suspense#displaying-a-fallback-while-content-is-loading

>サスペンスコンポーネントをアクティブ化できるのはサスペンス対応のデータソースだけです。これには以下が含まれます：
>
>    - Relay や Next.js のようなサスペンス対応のフレームワークでのデータフェッチ
>    - lazy を用いたコンポーネントコードの遅延ロード
>    - use を用いたキャッシュ済みプロミス (Promise) からの値の読み取り
>
>サスペンスはエフェクトやイベントハンドラ内でデータフェッチが行われた場合にはそれを検出しません。

少しuseやpromiseをthrowする方法について調べてみましたが、現在のコードはほぼ使えなさそうですね……
今回は`useEffect`を使ってデータ取得・表示を行うのが目的なので、`Suspense`の使用は諦めた方が良さそうです。

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！
▼▼▼

https://projisou.jp
Podmanインストール時のUID/GIDに関する設定

## エラー発生状況
- podmanをUbuntu20.04にインストール後、`podman`コマンド動作確認時に下記のエラーが発生
    ```bash
    $ podman version
    
    ERRO[0000] cannot find UID/GID for user $USER: No subuid ranges found for user "$USER" in /etc/subuid - check rootless mode in man pages.
    
    WARN[0000] using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids
    
    Version:      3.4.2
    API Version:  3.4.2
    Go Version:   go1.15.2
    Built:        Thu Jan  1 09:00:00 1970
    OS/Arch:      linux/amd64
    ``
## 解決策
- UID, GIDのマッピング設定を行い、　podmanを再起動
    ```bash
    $ sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
    $ podman system migrate
    $ systemctl --user restart podman.socket
    ```

## 解決までの経緯
- UID, GID のマッピングを確認するとどちらも出力なし
    ```bash
    $ cat /etc/subuid
    $ cat /etc/subgid
    ```
- 設定ファイルがないため、設定する
    ```bash
    $ sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
    ```
- 確認
    ```bash
    $ grep $USER /etc/subuid /etc/subgid
    /etc/subuid:$USER:100000:65536
    /etc/subgid:$USER:100000:65536
    ```
- podman再起動
    ```bash
    $ systemctl --user restart podman.socket
    ```
- `podman`コマンド動作確認
    ```bash
    $ podman version
    Version:      3.4.2
    API Version:  3.4.2
    Go Version:   go1.15.2
    Built:        Thu Jan  1 09:00:00 1970
    OS/Arch:      linux/amd64
    ```

## 参考
- https://zenn.dev/tom_tan/articles/405ae402b43f37#subuid%2C-subgid-%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%81%AE%E7%A2%BA%E8%AA%8D
fly.ioでフリーズを防止したいあなたに

# 初めに
fly.ioの特徴は、renderと異なり、無料プランでも使用可能時間制限やDatebaseの制約がないことです
記事によってはデプロイしてもフリーズしにくいあるいはフリーズしないという意見もあります
しかし、実際、デプロイしてみてわかったこととすると一定時間触れていないと重くなる動作が頻発します
無料プランではないがスリープされてしまうサービスもあるのでご自身の使用しているデプロイサービスについて調べて、自ら調べた点についてまとめました
この対応をしておけば、フリーズの問題も解決できると思いますので、fly.ioでデプロイしている方はご確認いただければと思います

# フリーズとは何か？
簡単に言うと動作が重くなるということです
デプロイでよく使用されるRender.com, Herokuなどはコスト削減のため無料プランだと一定期間アクセスがない場合、サーバーがスリープされ、アプリのアクセスに時間がかかります

:::note warn
現状のfly.ioでは約5分以内にリクエストが行われないと、アプリはスリープ状態になります。スリープを完全になくすのは難しいと考えますが、これを**30分に増やすこと**を目標にしております
:::

# fly.ioのスリープ対策方法
### 1: fly.tomlの設定を変更する
fly.tomlを開き、 
auto_stop_machines を false に、 
auto_start_machines を true に設定変更します
```fly.toml
auto_stop_machines = false
auto_start_machines = true
```

### 2: 独自のタイムアウトを設定
server.tsを開き、独自のタイムアウトを設定します
```server.ts
// 新しいタイムアウトを開始する
clearTimeout(timeout)
timeout = setTimeout(exit, TIMEOUT)
```
タイマーが完了したら、コード 0 で終了するよう修正します
```server.ts
// SIGINTかタイムアウトできれいに終了する
// フライプロキシは次のリクエストが来たときにアプリを再起動する
function exit() {
  console.log("exiting")
  browser.close()
  process.exit()
}
```
:::note warn
server.tsがvscord上にあるかは、プロジェクトの構成によるので、確認が必要です
私の場合、プロジェクトの構成に含まれていなかったため、独自のタイムアウト設定は省いています
:::
# 3.デプロイして再起動する
下記のコマンドでデプロイし、動作が軽くなっているか確認します
```
fly deploy
```
以上です
質問、不明点ございましたら、コメントにてご連絡のほどよろしくお願いいたします

参考文献
https://community.fly.io/t/how-to-increase-app-sleep-threshold/17783
Railsでいいね機能実装後に戻るボタンが動かない問題を解決する方法

## 背景
Railsアプリで「*投稿一覧* → *投稿詳細* → *戻る*」という遷移を実装していましたが、
「いいねボタン」を追加すると戻るボタンが正しく機能しない問題に直面しました。
## 問題
戻るボタンに *request.referer* を使用していましたが
いいねボタンのクリックでリファラが上書きされ
投稿一覧ページに戻れなくなっていました。
<details open><summary>request.refererとは:point_up:</summary>

現在のリクエストがどのURLから来たかを示す情報を取得できる。
例) ユーザーがあるページから別のページに遷移する際、遷移元のページのURLを知りたいときに使える

</details>

```ruby:show.html.erb
<%= link_to　'戻る', request.referer || posts_path %>
```
```ruby:posts_controller.rb
def show
  @post = Post.find(params[:id])
end
```
```ruby:like.html.erb
<%= link_to '♡', post_likes_path(post), method: :post %>
```

## 原因
*request.referer* は、最後のリクエストのURLを参照するため
いいねボタンを押すとリファラが[いいねアクションURL]に変わってしまうため

## 解決策
投稿一覧ページのURLをセッションに保持して
戻るボタンに使用することで解決できました。

## 修正後のコード
```ruby:index.html.erb
<%= link_to '詳細ページ' post_path(post, previous_url: request.original_url) %>
```
```ruby:show.html.erb
<%= link_to '戻る', session[:previous_url] || posts_path %>
```
```ruby:posts_controller.rb
  def show
    @post = Post.find(params[:id])
    session[:previous_url] = params[:previous_url] if params[:previous_url].present?
  end
```

## 最後に
こちらにより、複数のアクション間を跨ぐケースでも安心してできます。
もっと簡単な方法などあるかもしれませんがコメントで教えていただけると幸いです:relaxed:
ありがとうございました!!
NanoKVM

# [NanoKVM](https://github.com/sipeed/NanoKVM/blob/main/README_JA.md)
PiKVMと同じようにLinuxベースのIP-KVM．RiscVベースのCPUで非常に小さく安価．
購入してすぐに使えますが，Proxyが必須のネットワークだと設定をいじらないとアップデートができなかったので，そのメモです．

## セットアップ
LANケーブルを接続し，USBを接続すれば，USBからの給電で起動する．DHCPでアドレスを取得するので，本体のOLEDに表示されるIPにブラウザから接続する．
初期のID/PWは`admin/admin`になっており，初回接続時にパスワードの更新が要求される．
sshも有効になっており，こちらは初期のID/PWは`root/root`になっている．

## Proxyの設定
NanokVMはアップデートを確認し，更新できるようになっているが，Proxy環境では動かない．いまのところGUIからも設定できないので，sshで接続して，いくつかのファイルを書き換える．

+ `/etc/profile.d/proxy.sh`を作成する．
```
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
```
+ `/etc/init.d/nanokvm`の修正
以下の内容を先頭付近に追加する．これでproxyに関する環境変数が設定された状態でnanokvmが起動する．
```
source /etc/profile.d/proxy.sh
```

## タイムゾーン
`/etc/timezone`を`Asia/Tokyo`に変更
WindowsのBest-Fit機能の脆弱性と攻撃の仕組み：わかりやすく解説

Windowsの「Best-Fit機能」の脆弱性について、初心者でも理解できるように解説します。この脆弱性は、文字コードの変換に関連し、攻撃者がこれを悪用することで、システムに不正な動作を引き起こす可能性があります。この記事では、脆弱性の仕組みや攻撃の流れ、攻撃者が似た文字を使う理由、そして効果的な対策について解説します。
※この記事は、ChatGPTの出力を基に作成しています。

---

### **Best-Fit機能とは？**
WindowsのBest-Fit機能は、Unicode（世界中の文字を扱える文字コード）からANSI（古い形式の文字コード）へ変換する際に、「変換できない文字」を「見た目が似た文字」に置き換える仕組みです。

#### **例：**
- Unicodeの「𝟙」（数学的に「1」に似た文字）は、ANSIに変換される際に「1」として扱われます。

この仕組みは、古いシステムやアプリケーションがUnicodeを直接扱えない場合でも、処理が中断しないようにするためのものです。

---

### **脆弱性が発生する流れ**
この機能が便利な一方で、攻撃者に悪用されるとセキュリティ上の問題を引き起こします。以下に脆弱性がどのように発生するかを説明します。

1. **悪意のある文字列の作成**  
   攻撃者は、特殊なUnicode文字を含む文字列を準備します。  
   - **例**: 「𝓬𝓶𝓭.exe」（「cmd.exe」に似ている文字列）

2. **UnicodeからANSIへの変換**  
   システムがBest-Fit機能を使用して変換を行う際、文字が「似た文字」に置き換えられます。  
   - **変換後**: 「𝓬𝓶𝓭.exe」が「cmd.exe」になる。

3. **システムの誤認識**  
   システムやアプリケーションが変換後の文字列を正規のものと認識し、不正な動作を許してしまう。  
   - **例**: 攻撃者が用意した不正なプログラムが「正規のcmd.exe」として実行される。

---

### **攻撃者が似た文字を使う理由**
攻撃者が、はじめから「cmd」などの正規の文字を使わず、似た文字を使うのには明確な理由があります。

#### **1. セキュリティ検知の回避**
セキュリティソフトやシステムは、「cmd.exe」などの危険な文字列を監視してブロックします。しかし、似た文字（例: 𝓬𝓶𝓭.exe）はこれらのルールを回避できる場合があります。

#### **2. 人間の目を欺く**
似た文字を使うことで、ユーザーや管理者に「正規の文字列」だと思わせ、不正な操作を許してしまう可能性があります。

#### **3. システムの変換ロジックを利用**
UnicodeからANSIへの変換が発生する環境では、似た文字が「正規の文字」に置き換わることで、攻撃者の狙い通りの結果が得られます。

---

### **具体的な攻撃例**
#### **1. ファイル名を利用した攻撃**
- 攻撃者が「𝓬𝓶𝓭.exe」というファイルを作成。
- システムが「cmd.exe」と認識し、不正ファイルを安全なものと誤解。

#### **2. Webサーバーへのディレクトリトラバーサル**
- 攻撃者が「/𝓬𝓸𝓷𝓯𝓲𝓰/」というパスを送信。
- サーバーがANSI変換を行い、「/config/」として処理し、機密データを漏洩。

#### **3. フィッシング詐欺**
- 攻撃者が「support@𝑔𝑜𝑜𝑔𝑙𝑒.com」（「google.com」に似たアドレス）を使って偽メールを送信。
- ユーザーが本物のサポートだと誤解し、情報を漏洩。

---

### **攻撃成功の比較：似た文字 vs 正規の文字**

| **攻撃方法**               | **セキュリティ検知の回避** | **人間の検知**     | **成功率** |
|----------------------------|---------------------------|-------------------|------------|
| **正規の文字（cmd.exe）**   | 難しい                   | 簡単に気づかれる   | 低い        |
| **似た文字（𝓬𝓶𝓭.exe）**     | 回避しやすい             | 気づかれにくい     | 高い        |

---

### **脆弱性を防ぐ方法**
#### **1. Unicodeを完全にサポートする**
システム設計時に、古いANSI形式ではなく、Unicodeのみを使用することで変換の必要をなくす。

#### **2. 入力検証の徹底**
外部からの入力データを厳密にチェックし、不正な文字列や特殊文字を排除する。

#### **3. Windows Updateを適用**
Microsoftが提供する最新のセキュリティパッチを適用し、Best-Fit機能の脆弱性を修正する。

#### **4. ログと監視を強化**
システムのログを監視し、似た文字が利用された場合に警告を出す仕組みを導入する。

---

### **まとめ**
WindowsのBest-Fit機能の脆弱性は、UnicodeとANSIの文字コード変換のギャップを攻撃者が悪用することで、システムの安全性を脅かします。似た形の文字を使うことで、セキュリティ検知や人間の注意をすり抜け、攻撃の成功率を高めることができます。

この問題を防ぐには、システムのUnicode対応、入力検証、セキュリティパッチの適用などの対策を徹底することが重要です。企業や個人がこのリスクを理解し、適切に対応することで、被害を最小限に抑えることができます。
PyTorchのCUDA非互換エラーを解決した方法

## 起こった問題
インストールしたPytorchのバージョンが、GeForce RTX 3070のCUDA capability(sm_86)をサポートしていない。すなわち、深層学習の処理をGPUを使って回せない。

## 動作環境
- GeForce RTX 3070
- Windows11
- [pixelNeRF](https://github.com/sxyu/pixel-nerf)をclone後、Anaconda Promptで作成した``pixelnerf``の仮想環境内で作業
- cuda 11.8

## エラー
GitHubに倣って、pixelNeRFの推論用のコマンドを入力すると、エラーが出た。

```php3:入力コマンド
#Anaconda Prompt
(pixelnerf) python eval/gen_video.py  -n dtu --gpu_id=0 --split val -P '22 25 28'  -D rs_dtu_4 -S 3 --scale 0.25
```

```php:エラー
GeForce RTX 3070 with CUDA capability sm_86 is not compatible with the current PyTorch installation.
The current PyTorch install supports CUDA capabilities sm_37 sm_50 sm_60 sm_70 sm_75.
If you want to use the GeForce RTX 3080Ti GPU with PyTorch, please check the instructions at https://pytorch.org/get-started/locally/
```

エラーの内容を要約すると
> - RTX3070のCUDA camapbility(sm_86)が現在インストールされているPytorchと互換性がない
> - 今のPytorchと互換性があるCUDAアーキテクチャはsm_37 sm_50 sm_60 sm_70 sm_75

というもの。
ちなみに、この時の機械学習ライブラリのバージョンは
- PyTorch : 2.3.1+cu118
- Torchvision : 0.18.1 +cu118

以下のサイトによると、**Pytorch 2.0.1以降はsm_86もサポートしている**ので、「互換性がない！」というのは無理がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939072/e1c831b8-87ff-d559-0a36-ab9ec40ea595.png)

https://blog.qualiteg.com/pytorch_and_supported_gpu_version/









## やったこと
### 1.torchとtorchvisionのアンインストールと再インストール 【→上手くいかず】
```php
#アンインストール
pip uninstall torch torchvision
```
再インストールは、以下のサイトからコマンドを入手してください。

https://pytorch.org/get-started/previous-versions/

結果：エラーの内容は変わらない


### 2. enviroment.ymlで指定しているバージョンを調整【→解決】
pixelNeRFに留まらず、基本的には``environment.yml``という仮想環境の作成に必要なパッケージやバージョンが記述されているファイルがある。

その中身を覗くと、
```
  - pytorch==1.6.0
  - torchvision==0.7.0
```
の記述がある。これが悪さをしていそうだ！
上述の「PyTorchがサポートするGPUの Compute Capability」の表を見ると、**PyTorch 1.6.0がサポートしているCUDA capabilityにsm_86はない！**
ということで、原因はここにあることが分かった。

ここまでのことを整理すると、

:::note info
- sm_86が対応しているPytorchのバージョンは1.9.0以降
- cuda 11.8に対応しているPytorchとtorchvisionのバージョンは2.0.0以降（[ここ](https://pytorch.org/get-started/previous-versions/)から調べられる）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939072/04563ef4-716a-0c9d-4f6c-864d248563ea.png)

:::

よって、environment.ymlを以下のように編集。
```
#編集前
  - pytorch==1.6.0
  - torchvision==0.7.0

#編集後
  - pytorch==2.0.1
  - torchvision==0.15.2
```

## environment.ymlを書き換えた後の処理とコマンド集

1．environment.ymlを書き換える
2．仮想環境から出る：`conda deactivate`

3．古い仮想環境を消す：`conda remove --name <ENV_NAME> --all`
4．新しい仮想環境を構築：`conda env create -f environment.yml`
5．作業ディレクトリに移動：`cd <project_dir>`
6．仮想環境に入る：`conda activate <ENV_NAME>`
7．実行

https://www.freecodecamp.org/japanese/news/how-to-delete-an-environment-in-conda/
【Go】Dockerでの環境構築

# はじめに
業務でDockerファイルを作成する機会があり、マルチステージビルドを使用したイメージの軽量化やビルド時間の短縮周りを色々調べたので備忘録がてらまとめておこうと思います。参考までに、マルチステージビルドによってどれくらいイメージのサイズが軽量化されたかも計測しています。
基本的にDockerfileの内容は以下の公式ドキュメントに沿って作成しています。
英語ですが、わかりやすいドキュメントなのでぜひ参考にしてみてください。

参考）https://docs.docker.com/guides/golang/build-images/
# Dockerfileの完成系
先に完成系を載せちゃいます。
```dockerfile
# Step 1: Modules caching
# コンパイルに必要なモジュールをインストールする
FROM golang:1.23.4-alpine3.21 AS modules
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod/ \
    go mod download -x
COPY . .

# Step 2: Server building
# ソースコードをコンパイルし、/bin/serverにバイナリーを配置する
FROM modules AS build-server
RUN --mount=type=cache,target=/go/pkg/mod/ \
    go build -o /bin/server ./cmd/app

FROM alpine:latest
ENV GO111MODULE=on
ENV TZ=Asia/Tokyo
COPY --from=build-server /bin/server /bin/server

EXPOSE 8080

ENTRYPOINT [ "/bin/server" ]
```

# マルチステージビルドとキャッシュの効果
上記Dockerfileでは、マルチステージビルドを使用しコンパイル結果のバイナリのみをコンテナ内に配置しているため、生成されるイメージサイズは軽量化されています。
またキャッシュを利用して、ビルド時間を短縮しています。
マルチステージビルドを使用しない場合のイメージサイズと比較して、どの程度軽量化されているか確認してみます。

### マルチステージビルドなしDockerfile
```dockerfile
FROM golang:1.23.4-alpine3.21
WORKDIR /src
COPY go.mod go.sum ./
RUN  go mod download -x
COPY . .
RUN go build -o /bin/server ./cmd/app
ENV GO111MODULE=on
ENV TZ=Asia/Tokyo

EXPOSE 8080

ENTRYPOINT [ "/bin/server" ]
```

### ビルドコマンド
```terminal
# マルチステージなしビルド
docker build --tag no-multi-stage-build -f ./docker/Dockerfile .

# マルチステージありビルド
docker build --tag multi-stage-build -f ./docker/Dockerfile .
```
### イメージサイズの比較結果
以下のスクリーンショットは、マルチステージビルドを使用した場合としない場合のイメージサイズを比較したものです。
![スクリーンショット 2025-01-14 15.15.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1576629/f0f04a15-7f0a-3088-618b-d0bad15f2006.png)
![スクリーンショット 2025-01-14 15.39.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1576629/98bb051a-03d8-4e33-e70f-445bd9051a74.png)

このように、ビルド時にのみ必要なGoツールチェーンをイメージに含めないことで容量を軽量化させることができます。これはビルド時間やデプロイ時間を短縮できるというメリットがあるだけでなく、コンテナデプロイ時のセキュリティの向上にも繋がります。

# おわりに
ビルド時間の短縮は一回で見ると大した短縮時間にはならないですが、何百回もビルドしたりデプロイしたりを繰り返していくことを考えると意外と馬鹿にならない時間になると思います。開発フェーズが進むとdockerfileを修正する時間を取るのも難しくなってきたりするので、なるべく最初にいい感じのdockerfileが作りたいですね。
[入門] Mac 環境における Git & Github の環境構築

# 対象読者
- Mac で Git と Github を扱いたい方

# 環境
MacBook Pro M3 Pro

# Mac における GitHub 環境構築 
GitHub を利用した環境構築の手順を記載します。
OS は Mac を想定しています。

## 1. Git をインストール
MacにはGitがデフォルトインストールされています。
以下のコマンドでインストールされているVersionを確認できます。
~~~
$ git --version
git version 2.39.3 (Apple Git-146)
~~~
(Apple Git- のように表示されている場合、元からmacにインストールされているものが使用されています。)

確認できない場合、Macにデフォルトで用意されているもの以外を使用したい場合は[こちらの記事](https://zenn.dev/inablog/articles/25f6ac101d0b45)が参考になります。

## 2. GitHub アカウント作成
アカウントがない方は、[GitHub](https://github.com/)のサイトに移行してサインアップします。プロンプトに従ってアカウントを作成して下さい。

後に、作成した時の**メールアドレス**と**ユーザー名**を使用します。

## 3. 個人の識別情報(gitconfig) 設定
GitのインストールとGithubアカウントを作成後、gitconfig設定を行います。
この設定が必要なのは、GitのCommit時、「誰が」変更を加えたかの識別情報を記録する必要があるためです。

Githubアカウント作成時の情報と一致させて、履歴の管理を行っていくことをお勧めします。以下のコマンドで設定します。

~~~
# ユーザー名の設定
$ git config --global user.name "ユーザーネーム"

# メールアドレスの設定
$ git config --global user.email user-mail-address@example.com

# ユーザー情報の確認
$ git config --global user.name
$ git config --global user.email
~~~

global オプションを指定することで、Gitはその後、そのシステム上で行なう全ての操作に対して常にこの情報を使用するようになります。なので、この操作を行なう必要は一度だけです。 

もし、違う名前とEmailアドレスを特定のプロジェクトで上書きしたいのであれば、そのプロジェクト(Gitディレクトリ）の中で、--global オプション無しでこのコマンドを実行することで出来ます。



# Git と Github に関して
この2つの違いを簡単に知りたい方は、下記を参照ください。

<details><summary>GitとGithubに関して</summary>

### そもそもGitって何？
Gitはパージョン管理システム(分散型)です。コードやファイルの変更履歴を追跡し、複数人での開発を可能にします。

**主な特徴**
- 変更履歴の記録と管理
  - 変更の取り消しや以前のバージョンへの復元
- リモートリポジトリを通じたチーム開発の促進
  - ブランチによる並行開発
- コマンドラインツール

このGitを利用したWeb上の開発(クラウドベース)プラットフォームとして、GitHubがあります。

:information_source: 補足
- クラウド : インターネットを通じてコンピューティングリソース（サーバー、ストレージ、データベース、ソフトウェアなど）を提供するサービス
- プラットフォーム : ソフトウェアやサービスが動作する基盤環境

### GitHubって何？
GitHubとは、Gitリポジトリのホスティングサービスです。
**リポジトリ**には、プロダクトを構成するコード・ファイル・各ファイルのリビジョン履歴が格納されています。
サーバー上にホスティングされているリポジトリのことを**リモートリポジトリ**と呼びます。
このリモートリポジトリをチームで共有し、コードの変更を追跡・管理しながら開発を進めます。

:information_source: 補足
- ホスティング : データやサービスをインターネット上のサーバーで管理・提供すること

</details>


# まとめ
この記事では、MacにおけるGitHubの基本的な環境構築について説明しました：

1. Gitのインストール確認（Macにはデフォルトで入っています）
2. GitHubアカウントの作成
3. gitconfigでの個人識別情報の設定

これらの設定が完了したら、次のステップとしてSSH認証の設定を行うことで、より安全にGitHubを利用することができます。SSH認証の設定方法については[次回の記事](https://qiita.com/generosity_hiroto_taniguchi/items/8fcb70b24d4249b3674c)で解説します。


# 参考文献


- [GitHub Docs](https://docs.github.com/ja/enterprise-cloud@latest)
     
- [Git でのユーザ名を設定する - GitHub Docs](https://docs.github.com/ja/get-started/getting-started-with-git/setting-your-username-in-git)

- [Git - 最初のGitの構成](https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-%E6%9C%80%E5%88%9D%E3%81%AEGit%E3%81%AE%E6%A7%8B%E6%88%90)
circleci/aws-ecr@7.0.0で Job was rejected because resource class medium, image ubuntu-2004:202010-01 is not a valid resource class エラーが出た場合の対応

## 背景
circleci/aws-ecr@7.0.0の`build-and-push-images`ジョブで、`Job was rejected because resource class medium, image ubuntu-2004:202010-01 is not a valid resource class`というエラーが発生した。

![build-and-push.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751808/61630845-9db5-8914-fdfe-cc4fdfee71b8.png)

## 対策
`aws-ecr`のバージョンを上げた。
それに伴って.ymlファイルの構造も一部変わるので、その点も修正が必要。

```diff:.circleci/config.yml
-  aws-ecr: circleci/aws-ecr@7.0.0
+  aws-ecr: circleci/aws-ecr@9.3.7
+  aws-cli: circleci/aws-cli@5.1.2


workflows:
  version: 2
  build-and-test:
    jobs:
      - build
      - test:
          requires:
            - build
-     - aws-ecr/build-and-push-image:
+     - aws-ecr/build_and_push_image:
          requires:
            - test
-         account-url: AWS_ECR_ACCOUNT_URL
+         auth:
+           - aws-cli/setup:
+             region: ap-northeast-1
```
C++で1を01表示にする方法(ゼロバディングする方法)

<h2>数字の頭に0をつけたい</h2>

```c++:これで解決
int num = 1;

cout << std::setw(2) << std::setfill('0') <<  num << std::endl;
//1
//↓
//01
```

setw(2)で桁数を指定できる
std::setfill('0')で０で埋めることを指定できる

```c++:ロジックを使ってベタ書きする場合
int num = 1;
string str = "";
str += "0";
str += to_string(num);

//01
```

```c++:時間表示
int hour = 0;
int minute = 0;
int second = 0;

cout << std::setw(2) << std::setfill('0') <<  hour << ":" 
     << std::setw(2) << std::setfill('0') << minute <<  ":" 
     << std::setw(2) << std::setfill('0') << second << std::endl;
     
//0 0 0
//↓
//00:00:00
```

<h2>参考</h2>

https://af-e.net/cpp-cout-0-filling/
ブラックボックステスト技法：”状態遷移テスト”について

# <font color="#00bfff">■ 状態遷移テストとは？</font>

ブラックボックステストで使用されるテスト設計技法の一つで、

システムが異なる状態に遷移する過程をテストする手法です

システムの動作が入力や条件によって異なる状態に遷移する場合、
その遷移が正しく行われるかを検証します

<INS>特に、複雑な状態遷移を持つシステムで効果を発揮します</INS>
<br>
# ・<font color="#00bfff">特徴</font>
　-> <font color="#66cdaa">状態と遷移に焦点を当てる</font>：
システムが保持する状態と、状態間の遷移に焦点を当てます
（例：「未ログイン」の状態から「ログイン済み」状態に遷移）
<br>
　-> <font color="#66cdaa">正常系と異常系をテスト</font>：
正常系：期待どおりに状態が遷移するかを確認
異常系：無効な入力や不正操作によるエラーが正しく検出されるかを確認
<br>
　-> <font color="#66cdaa">状態遷移図を使用</font>：
システムの状態と遷移の関係を視覚的に表現した状態遷移図を使うことが一般的です
これにより、システムの挙動をより明確に理解し、テストケースを設計しやすくします


[例] 認証システムの状態遷移図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3873920/b7e28f52-a3f0-11bf-eb4f-7898ffbf4415.png)

この図では、以下の5つの状態を示しています：

・未ログイン
・ログイン試行中（正しい or 間違った ID/Passwordでログインしようとした際の遷移）
・ログイン成功
・ログイン失敗
・アカウントロック（仕様で決められたログイン失敗回数をオーバーした際の遷移）

※状態間の遷移を矢印で示し、各矢印にはその遷移を引き起こす条件が記載されています
<br>
# ・<font color="#00bfff">目的</font>

　-> システムが状態間を正しく遷移することを確認し、不正な遷移やエラーを防ぐ

　-> システムが期待通りに状態を遷移し、異常な状態に入らないかを確認
<br>
# <font color="#00bfff">【例】</font>
例えば、オンラインショッピングサイトにおける注文処理の状態遷移の場合

■ 1.<font color="#66cdaa">状態</font>：
・未ログイン、ログイン済み、商品カートに商品追加、注文確認、注文完了

■ 2.<font color="#66cdaa">遷移</font>：
・ユーザーが「ログイン」すると「未ログイン」から「ログイン済み」に遷移
・商品をカートに追加すると「商品カートに商品追加」の状態に遷移
・注文を確定すると「注文確認」から「注文完了」に遷移
<br>
# ・<font color="#00bfff">利点／欠点</font></INS>

■ <font color="#FF99FF">利点</font>
・不正な遷移の検出：
　システムが不正な状態に遷移しないか確認でき、予期しない動作を防げる

・状態ごとの動作確認：
　システムが異なる状態で期待通りに動作するか検証できる
<br>
■ <font color="#FF99FF">欠点</font>
・状態が多い場合の複雑性：
　状態と遷移が多くなると、テストケースが膨大になり、管理が難しくなることがある
　また、全ケースをテストすることが困難になる

# ・<font color="#00bfff">まとめ</font></INS>
<br>
状態遷移テストは、システムが特定の状態に到達する為のイベントや条件を明確にし、

遷移が正しく行われることを確認します

特に、複雑な状態遷移を持つシステムで効果を発揮します

<INS>システムの安定性や正確性を高めるために重要なテスト手法です</INS>
<br>

<INS><font color="###ff00ff">「■ テスト技法：シナリオテスト」へ続く</font></INS>
しましまの市、ひが「しま」つ「しま」しの仲間

　なんか見たので。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/9596face-eefc-09b4-b6bc-c58a22d48102.png)

# データ取得

https://www.soumu.go.jp/denshijiti/code.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/91a2c862-e802-68c0-c3c2-0d8595984530.png)

# 解析

　このような些末な解析、AI 様の手を煩わせるまでもありません。私の手打ちコードにお任せください。

```python
import jaconv

with open('input.csv',mode='r',encoding='utf-8') as f:
    for line in f.read().split('\n'):
        line = jaconv.h2z(line,digit=True,ascii=True)
        n = len(line)
        for level in range(1,n+1):
            for left in range(0,n):
                if left+level > n:
                    break
                prefix = line[left:left+level]
                for right in range(left+level,n):
                    if right+level > n:
                        break
                    suffix = line[right:right+level]
                    if prefix == suffix and level >= 2:
                        print(f'{line[:left]}「{line[left:left+level]}」{line[left+level:right]}「{line[right:right+level]}」{line[right+level:n]}')
```

# 結果

```
キ「ョウ」ゴクチ「ョウ」
キ「ョウ」ワチ「ョウ」
オ「ウシ」ュ「ウシ」
ヒガ「シマ」ツ「シマ」シ
「キタ」ア「キタ」シ
コ「ウシ」ュ「ウシ」
シ「ョウ」ワチ「ョウ」
アイシ「ョウ」チ「ョウ」
キ「ョウ」タンバチ「ョウ」
「ヤマ」トコオリ「ヤマ」シ
サトシ「ョウ」チ「ョウ」
シ「ョウ」オウチ「ョウ」
トノシ「ョウ」チ「ョウ」
シ「ョウ」ドシマチ「ョウ」
キタキ「ュウ」シ「ュウ」シ
キタキュ「ウシ」ュ「ウシ」
キタキ「ュウシ」「ュウシ」
キジ「ョウ」チ「ョウ」
ミナミキ「ュウ」シ「ュウ」シ
ミナミキュ「ウシ」ュ「ウシ」
ミナミキ「ュウシ」「ュウシ」
```

# わかったこと

　最大被りは、「北九州市」及び「南九州市」における「ゅうし」の $3$ 文字。

# 語呂が良いやつ

- しましまの市、ひがしまつしまし
- きたきたの市、きたあきたし
- やまやまの市、やまとこおりやまし
プリザンターの選択肢一覧の改修をしました!!

## はじめに
[2025年1月14日リリースのVer.1.4.12.0](https://pleasanter.org/ja/manual/release-notes-core)に含まれる「選択肢一覧に選択項目を設定する際に、カンマを含む項目名が正しく識別されない問題を解消。」ですが、当社で改修・実装を行いましたので、ちょっとした中身の紹介をします。

## どこが困っていたところか
プリザンターの機能で[選択肢一覧](https://pleasanter.org/ja/manual/table-management-choices-text)で、保存値や表示名、スタイル用のクラス名を記述出来るモードがあります。マニュアルの記述例2や3がその記述になります。
```
100,未着手,未,status-new
150,準備,準,status-preparation
200,実施中,実,status-inprogress
300,レビュー,レ,status-review
900,完了,完,status-closed
910,保留,留,status-rejected
```
この方法で記述した場合は、プリザンターの内部ではカンマで文字列が分割されて1番目が保存値、2番目が表示名・・・というように自動的に割り振りが行われます。
```
[保存値],[表示名],[短縮表示名],[スタイル用のクラス名]
```
このようになります。ここで問題になってくるのが、保存値や表示名などの中身にカンマを含めたい場合です。
例えば表示名にカンマが含めれているケースを考えてみます。
```
100,Example Co., Ltd.,Example,status-xxxx
```
これをカンマで分割してみるとこうなります。
```
[100],[Example Co.],[ Ltd.],[Example],[status-xxxx]
```
`Example Co., Ltd.`が`Example Co.`と` Ltd.`の2つに区切られてしまい、想定した挙動になっていません。

## どうやって解決させたか
解決方法はとても簡単です。エスケープの導入です。分割してほしくないカンマの部分を`\,`とすることで、正しく取り扱いが出来るようにしました。先ほどの例だと次の様になります。
```
100,Example Co.\, Ltd.,Example,status-xxxx
```
これをVer.1.4.12.0以降で処理をさせると次の様に分割されます。
```
[100],[Example Co., Ltd.],[Example],[status-xxxx]
```
当初の想定通りの挙動になりました。

## どうやって実装しているか
今回の実装の差分を見てみましょう。[こちら](https://github.com/Implem/Implem.Pleasanter/commit/5773a27518ba352b2201f186bc9720c625128a6d#diff-83e9675d3c3681f855ef3c8f617976d24c15aa1ece5e5174a48f46dcc78a70e7L42)になります。
従来は単純に`Split(',')`で分割していたのですが、今回、正規表現による分割に書き換えました。分割に使用する正規表現は`(?<!\\),`です。
```plantuml
@startregex
title 否定後読みで\,以外の,にマッチ
(?<!\\),
@endregex
```
否定後読みで`\,`となっていない`,`のみにマッチするようにして、エスケープされていないところのみで分割処理が実施されるようにしています。その後、分割した文字列に含まれる`\,`を`,`に置換して、処理は完了です。

## ちょっとした応用
今回、分割に使用する正規表現はパラメータで設定可能なようにしています。そのため、ちょっとした応用を利かせることが可能です。`Parameters\General.json`の`ChoiceSplitRegexPattern` `ChoiceReplaceRegexPattern` `ChoiceReplaceRegexReplacement`パラメータがぞれぞれ、分割に使用する正規表現、分割後のエスケープ検出に使用する正規表現、エスケープの置換後を指定する正規表現となります。
今回の実装は後方互換性を確保するためにエスケープという選択肢と取りましたが、そこを気にしなくていい環境の場合は、カンマ区切りをタブ区切りにしたり、CSVチックな実装にしてみたりといろいろな対応が取れるようになっています。
例えばタブ区切りに変更する場合は、`ChoiceSplitRegexPattern`に`\t`を、`ChoiceReplaceRegexPattern`と`ChoiceReplaceRegexReplacement`には空文字を指定することで実現出来ます。ただし、JSONに格納するためには文字列のエスケープが必要になるので、そこは注意してください。タブ区切りの場合だと`\`はエスケープ対象なので`\\t`でファイルには記載する必要があります。

## まとめ
選択肢一覧にエスケープを導入することで、値の中にカンマを持つ文字列を指定しても想定通りの挙動をさせることが出来るようになりました。また、それらの設定値をパラメータファイルを書き換えることで変更出来るようにし、選択肢一覧の設定方法の表現幅を広げることができました。
選択肢一覧はいろいろと便利な機能ですので、今回の機能拡張を機にどんどん使ってみてください!!
【2025年01月版】Ubuntu24.04 で起動時刻の確認あれこれメモ

# はじめに

Ubuntu24.04 で、最後に起動したのがいつだったのか調べる時のメモ

uptimeは覚えてるんだけど、ほかはすぐに忘れる。。。

:::note info
カーネルバッファがlogに書き込まれるまでのラグは容認する感じで。
:::

# 確認方法

## uptime

```terminal
$ uptime -s
2025-01-13 13:55:10
```

## last

reboot のログイン時間を確認する

```terminal
$ last reboot
reboot   system boot  6.8.0-51-generic Mon Jan 13 13:55   still running
reboot   system boot  6.8.0-51-generic Mon Jan 13 13:51 - 13:55  (00:03)
reboot   system boot  6.8.0-51-generic Mon Jan 13 13:49 - 13:50  (00:00)
reboot   system boot  6.8.0-51-generic Sun Jan 12 09:27 - 13:49 (1+04:21)
reboot   system boot  6.8.0-51-generic Sun Jan 12 09:21 - 09:27  (00:06)
reboot   system boot  6.8.0-51-generic Sun Jan  5 13:33 - 13:41  (00:08)
reboot   system boot  6.8.0-51-generic Sat Dec 28 12:06 - 07:58 (7+19:52)
reboot   system boot  6.8.0-51-generic Sat Dec 28 12:02 - 12:06  (00:03)
reboot   system boot  6.8.0-51-generic Sat Dec 28 11:58 - 11:58  (00:00)

wtmp begins Sat Dec 28 11:58:16 2024
```

## journalctl

### --listboots

```terminal
$ journalctl --list-boots
IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY                 
 -8 ea537c28e5104609bddad0b6db29892b Sat 2024-12-28 11:58:17 UTC Sat 2024-12-28 11:58:45 UTC
 -7 4eb05459d274483ea0e834eba41800d6 Sat 2024-12-28 12:02:36 UTC Sat 2024-12-28 12:06:29 UTC
 -6 c034fa98f4c6425eb30ac345fb640338 Sat 2024-12-28 12:06:36 UTC Sun 2025-01-05 07:58:35 UTC
 -5 ff3ad9beca064243b0eedf07d90e8b88 Sun 2025-01-05 13:33:03 UTC Sun 2025-01-05 13:41:33 UTC
 -4 4aac5aee2cdf420f8d38060f257b5e3a Sun 2025-01-12 09:21:35 UTC Sun 2025-01-12 09:27:38 UTC
 -3 543a75150c99407c8655e3205987d917 Sun 2025-01-12 09:27:45 UTC Mon 2025-01-13 13:49:41 UTC
 -2 fd63fb66e7bf4d44933a6f72128dcc32 Mon 2025-01-13 13:49:52 UTC Mon 2025-01-13 13:50:48 UTC
 -1 189215de152a4c2aa4e94a7b60237d9f Mon 2025-01-13 13:51:30 UTC Mon 2025-01-13 13:55:01 UTC
  0 ff23d1aed7264a4e83c6b631cfe2e1da Mon 2025-01-13 13:55:12 UTC Tue 2025-01-14 06:18:00 UTC
```

### journalctl -b の最初

```terminal
$ journalctl -b
Jan 13 13:55:12 test2 kernel: Linux version 6.8.0-51-generic (buildd@lcy02-amd64-091) (x86_64-linux-gnu-gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0, GNU ld (G>
Jan 13 13:55:12 test2 kernel: Command line: BOOT_IMAGE=/vmlinuz-6.8.0-51-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro ipv6.disable=1
Jan 13 13:55:12 test2 kernel: KERNEL supported cpus:
Jan 13 13:55:12 test2 kernel:   Intel GenuineIntel
Jan 13 13:55:12 test2 kernel:   AMD AuthenticAMD
Jan 13 13:55:12 test2 kernel:   Hygon HygonGenuine
Jan 13 13:55:12 test2 kernel:   Centaur CentaurHauls
Jan 13 13:55:12 test2 kernel:   zhaoxin   Shanghai  
Jan 13 13:55:12 test2 kernel: BIOS-provided physical RAM map:
```

# 起動時刻だけでなく、最後のシャットダウンをみつけるとかやるときもある

## grep /var/log/syslog

```terminal
$ sudo grep -E "shutdown\.target" /var/log/syslog
2025-01-14T03:36:43.908893+00:00 test2 systemd[6118]: Reached target shutdown.target - Shutdown.
```

# さいごに

かんたんでしたね
【PHP】session_regenerate_id(true)でセッションが切れる問題

**問題：**
ログイン後、セッションが切れたかのように扱われ、ログインしていない状態になることがある。
しかし、session_regenerate_id(true);を削除すると、セッションが切れなくなった。
**原因：**
```php:qiita.php
session_start();
// ログイン成功時
if (!isset($_SESSION['loggedin'])) {
    $_SESSION['loggedin'] = true; // ログインフラグを設定
    session_regenerate_id(true); // セッションIDを再生成
}
// ログイン済みの確認
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
    echo "ログイン中です。";
} else {
    echo "ログインしていません。ログインページにリダイレクトします。";
}
```
session_regenerate_id(true)は、新しいセッションIDを生成するための関数であり、trueを指定すると古いセッションデータが削除される。
問題の原因は、ログイン認証時に一度この関数を使用しているにもかかわらず、フロントエンドの処理でも再度使用している点にある。その結果、$_SESSION['loggedin'] = trueが削除され、ログインしていない状態とみなされる。

また、セッション管理はサーバーの設定やセッション保存ハンドラにも依存する。session_regenerate_id(true)を使用した場合、新しいセッションIDが生成されるとともに、通常はセッションデータが保持される。しかし、サーバーの設定や実装によっては、セッションデータが引き継がれないこともある。
さらに、PHP 7.x以降ではセッションデータが新しいセッションIDに引き継がれるよう改善されているが、PHP 7.x未満のバージョンではデータが失われる場合がある。

**解決策：**
```php:qiita.php
session_start();
// ログイン成功時
if (!isset($_SESSION['loggedin'])) {
    $_SESSION['loggedin'] = true; // ログインフラグを設定
    // session_regenerate_id(true); ログイン認証を行った直後のみにする
}
// ログイン済みの確認
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
    echo "ログイン中です。";
} else {
    echo "ログインしていません。ログインページにリダイレクトします。";
}
```
session_regenerate_id(true) を呼び出すのはログイン認証を行った直後のみにすること。
Microsoft OfficeのショートカットをBetterTouchToolで上書きする

# はじめに
たとえばMacでctrlを使ったショートカット（特にctrl+Hのバックスペース）を多用している人間にとって、WordやPowerPointといったMicrosoft Officeのソフトでは別のショートカットが起動してしまうのは非常にイライラします。
これは、Microsoft Officeのソフトでは、"command + *"だけでなく "ctrl + *"でもショートカットが起動してしまうためです。たとえば手癖でctrl+Hを押す度に置換画面が開くのは、あまりにもストレスです。

一応、ツールバーの「ツール」→「ショートカット キーのユーザー設定」からショートカットの変更は可能ですが、設定ファイルに保存しても、なぜか文書を開き直すと設定がリセットされてしまいます（これは私の設定ミスかもしれません）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/4985775f-8b1d-27ba-1f80-0cf388b1e423.png)

# 解決
BetterTouchToolを使ってショートカットキーを上書きするだけです。自分がよく使うショートカットで、競合してしまうものをBTTのアプリ別設定で登録して上書きしておきましょう。BTTの方が処理の優先順位が高いようで、きちんと割り込んで動作してくれます（優先度ヘルパーツールも不要でした）。
おそらくBetterTouchTool以外のショートカットキー設定ソフトでも可能かもしれませんが、既存のショートカットキーと競合した場合にどのように動作するかはわからないので、保証はできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661623/79fab4bd-8045-9cf1-c441-fb72cb4ca7e6.png)

# おわりに
しょうもない記事ですが、個人的には非常にストレスだった点を解消できてすごく満足しています。BetterTouchTool、本当に便利ですね。おすすめです。
Pythonで簡単なアニメーションを作成する方法

# **今回行ったこと**

- `matplotlib.animation` を使用して、シンプルなアニメーションを作成。
- データが時間と共に変化する様子を動的に可視化。
- サイン波が動くアニメーションの例を紹介。

---

# **私の環境**

- **Python**: 3.10.9  
- **matplotlib**: 3.7.0  
- **numpy**: 1.23.5  

---

# **アニメーションの概要**

`matplotlib.animation` モジュールを使うことで、Python のグラフにアニメーションを付けることができます。これにより、データの動的な変化を視覚的に表現することが可能です。たとえば、以下のアニメーションでは、サイン波が徐々に変化していく様子を描画します。

---

# **サンプルコード**

以下は、サイン波のアニメーションを作成する例です。

```python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

# データ生成
x = np.linspace(0, 2 * np.pi, 100)  # X軸の値
y = np.sin(x)  # 初期のY軸の値

# グラフの初期化
fig, ax = plt.subplots()
line, = ax.plot(x, y, color='blue')

# アニメーションの更新関数
def update(frame):
    line.set_ydata(np.sin(x + frame / 10))  # フレームごとにY軸の値を更新
    return line,

# アニメーション設定
ani = FuncAnimation(fig, update, frames=100, interval=50, blit=True)

plt.show()
```
---

# 実行結果
以下は、サイン波が徐々に右方向に移動するアニメーションのイメージです。アニメーションは Python スクリプトを実行すると表示されます。

- **フレームの更新**: `update` 関数で、フレームごとにサイン波のデータを動的に変更します。
- **スピード調整**: `interval` パラメータでフレーム間の時間間隔をミリ秒単位で指定可能です。

![animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2887299/9634355a-7e2d-0c8a-fd84-a5b1072e5d31.gif)

---

# カスタマイズ例
以下のようなカスタマイズが可能です：

- **波形を変更**
`np.sin` を `np.cos` に変更して、異なる波形をアニメーション化。
- **グラフのスタイル**
ラインの色、スタイル、ラベルを追加して見やすく。
- **フレーム数の増加**
`frames` の値を大きくすることで、より長いアニメーションを実現。

---

# 実用例
- **データの時間変化の可視化**
時系列データがどのように変化するかを直感的に伝えることができます。
- **シミュレーション結果の表現**
数値解析や物理シミュレーションなど、動的なシステムの挙動を再現。
- **教育用資料**
数学や統計の授業で関数の動きを視覚化して説明する際に便利。
ChatGPTとシフト表を最適化してみた

ChatGPTを使ってシフト表を最適化してみました。
ただし、一部コードを変えているのと、データはCSVから読み込むというものです。なので最後の方思ったように動いていません。
```Python
import pulp
import pandas as pd

df_ava = pd.read_csv("shift_ava.csv", sep="\t")# 可能日
df_req = pd.read_csv("shift_req.csv")# シフト当たり必要な人数
df_ava2 = df_ava.copy()
df_ava2.index = df_ava["Time"]
df_ava2 = df_ava2.drop("Time", axis=1)
df_off = pd.read_csv("shift_off.csv")# 休みたい日

holiday = [7, 14, 21, 28]
days = list(range(1, 32))
incompatible_pair = [("A", "B")]

emp = df_ava2.columns
shift = df_ava["Time"].values
ava = {}
for col in df_ava2.columns:
    ind = df_ava2.index
    ava[col] = {ind[0]: df_ava2.loc[ind[0], col], ind[1] : df_ava2.loc[ind[1], col], ind[2] : df_ava2.loc[ind[2], col]}
req = dict(df_req.values)
off = {}
for i in range(len(df_off.values)):
    try:
        off[df_off.values[i][0]].append(df_off.values[i][1])
    except:
        off[df_off.values[i][0]] = [df_off.values[i][1]]

prob = pulp.LpProblem("shift", pulp.LpMinimize)

# 変数の定義
x = pulp.LpVariable.dicts("shift_num", [(e, s, d) for e in emp for s in shift for d in days], cat="Binary")

# 目的関数: 希望に沿わないシフトの割り当てを最小化
prob += pulp.lpSum((1-ava[e][s]*x[(e, s, d)] for e in emp for s in shift for d in days))

# 制約1　各シフトに必要な最低人数を確保
for d in days:
    if d in holiday:
        for s in shift:
            prob += pulp.lpSum(x[e, s, d] for e in emp) == 0
    else:
        for s in shift:
            prob += pulp.lpSum(x[e, s, d] for e in emp) >= req[s]

# 制約2　各従業員は1日に2つまでのシフトにしか入れない
for e in emp:
    for d in days:
        prob += pulp.lpSum(x[e, s, d] for s in shift) <= 2

# 制約3　希望休を考慮
for e, days_off in off.items():
    for d in days_off:
        prob += pulp.lpSum(x[e, s, d] for s in shift) == 0

# 制約4　ペアを組みたくない人を考慮
for d in days:
    for s in shift:
        for pair in incompatible_pair:
            e1, e2 = pair
            prob += x[(e1, s, d)] + x[(e2, s, d)] <= 1

# 解を求める
prob.solve()
print("Status:", pulp.LpStatus[prob.status])
print("Assign:")
for d in days:
    print("Day %d"%(d))
    for s in shift:
        assign = []
        for e in emp:
            if x[(e, s, d)].value() == 1:
                assign.append(e)
        print(s, assign) if assign else "No one assign"
```

```
Status: Optimal
Assign:
Day 1
Morning ['B', 'D']
Afternoon ['A', 'C', 'D']
Evening ['B', 'C']
Day 2
Morning ['B', 'D']
Afternoon ['A', 'C', 'D']
Evening ['B', 'C']
Day 3
Morning ['B', 'D']
Afternoon ['C', 'D']
Evening ['B', 'C']
・
・
・
Day 7
Day 8
Morning ['B', 'D']
Afternoon ['C', 'D']
Evening ['B', 'C']
・
・
・
Day 30
Morning ['B', 'D']
Afternoon ['A', 'C', 'D']
Evening ['B', 'C']
Day 31
Morning ['B', 'D']
Afternoon ['A', 'C', 'D']
Evening ['B', 'C']
```
実際のシフト表もこう作っているのですかね・・・
【未経験からの転職】どんな企業を選んだらいい？

## はじめに
本記事では、私の経験を踏まえて、未経験からのIT業界への転職についての考えをつづっています。
## どんな企業を選んだらいい？
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935750/a5b4adda-cfac-fd36-8190-18fc85ce469d.jpeg" width=40%>

ITの学習を一通り終え、いざ転職！の場面です。
IT企業を検索すると、無数にヒットします。
あり過ぎて、どこに応募したらいいんだろう？となりますね。

- 自分が勉強した技術を生かせそうなところ？
- 規模が大きそうなところ？
- 自社開発企業？
- Webページがキレイなところ？

**「その企業の顧客は誰？」←これで選びましょう！**

IT企業（ベンダー）は、当然ですが取引をする顧客を持っています。ベンダーは顧客の要望を叶えるアプリケーションを開発します。
ベンダーの開発者は、顧客の業界・業務知識を学んだ上でアプリを手がけていく必要があります。

私が未経験転職で入社した会社では、社会のインフラ（電気・ガス・水道など）を扱う業界を取引相手としていました。
会社の主商品は、インフラ設備を使う人の契約情報・使用料金を管理するアプリです。アプリはJavaやPHP、C#、JavaScript、AWSなどいろいろな言語と技術を使って運用されていました。

ただ、開発にもっとも必要な力は、プログラミング技術ではなく、**インフラ業界に関する知識**でした。
電気・ガスは誰が製造・管理し、どんな経路を辿り、どんな値段設定で各家庭に供給されるのかということを理解せずに、アプリを開発することはできません。
私は、それに気付いてから毎日インフラ業界について勉強しました。（今では自宅の電気・ガス料金の明細を理解できます。）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935750/0c4a7b66-1552-95c4-1467-2e186264a9c9.jpeg" width=40%>


- 個人で学習してきたのがJavaだからJavaを扱っている企業に就職しよう！
- AWSの知識があるから、リクルートページでAWSの記載があるところに面接をお願いしよう！

私はこのような気持ちで選んでいましたが、考えが甘かったと今では思います。

## 業界・業務知識の勉強にやる気が出るか

全く知識がない業界について、0から勉強する必要が出てきた時に、**勉強のやる気が出る分野の業界**を選ぶと良いと思います。

私が何も考えず最初に面接をお願いした企業は、ファッション業界を取引先としていました。結局採用されませんでしたが、ファッションに全く知識もなく、詳しくなりたいという気持ちがないので、今振り返るとゾッとします。笑

**「その企業の顧客は誰？」**
これを企業を選ぶ視点とするといいでしょう。

## とりあえず未経験を脱出
「実務を経験しなければ、いつまでも未経験」
これは事実です。どれだけすごい知識・技術を身に付けても、実務としてやっていなければ個人学習・個人開発の範囲に過ぎず、実務未経験者であることは変わりません。IT業界での自分の価値を上げることはできません。

上述の通り、自分が働きたいと思える企業をしっかり選んで就活をすることは大事ですが、選び過ぎて結局どこにも所属できないという状況が長くなってしまっては本末転倒です。
正反対の意見になりますが、**なんでもいいから、どこでもいいからとりあえずIT企業に就職する**という考え方も私は悪くないかなと思います。

## おわりに
最終的には強い思いや気合いがあればなんでもできます。どこに行っても大丈夫です。
深く考えずに転職し、インフラ業界の勉強を焦ってやりましたが、「仕事ができる人間でありたい」という思いを持ち続けることでなんとかやってこれました。
こういう選び方もあるか〜と思ってもらえたらうれしいです。

最後まで読んでいただきありがとうございました。
nvmでmacローカルのnodeのバージョンを管理する

## nvmインストール確認
1. nvmが入っていることを確認 `nvm --version` 
1. 入っていなければ `brew install nvm`

## nvm設定記述
1. `vi ~/.zshrc`
    ```
    # NVM の設定
    export NVM_DIR="$HOME/.nvm"
    [ -s "$(brew --prefix)/opt/nvm/nvm.sh" ] && \. "$(brew --prefix)/opt/nvm/nvm.sh"  # これがnvmをロード
    [ -s "$(brew --prefix)/opt/nvm/etc/bash_completion.d/nvm" ] && \. "$(brew --prefix)/opt/nvm/etc/bash_completion.d/nvm"  # これがnvmの補完をロード
    ```
1. `source ~/.zshrc`

## バージョン切り替え
1. `node -v`
1. インストール済みバージョン一覧確認 `nvm ls`
1. インストール `nvm install 20.18.1`
1. 最新安定版インストール `nvm install stable --latest-npm`
1. 切り替え `nvm alias default v*.*.*` を実行してターミナル再起動
    * `nvm alias default v20.18.1`
    * `nvm alias default v23.6.0`
1. `node -v`
XcodeでAPIキーなどを保存する方法

# Config.xcconfig を作成
![configファイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/5fe8f971-ff71-5330-5fc9-d77f61cc03a2.png)

#  プロジェクトのInfo.plistに読み込めるように追記する
```
<key>GOOGLE_API_KEY</key>
<string>$(GOOGLE_API_KEY)</string>
```
![configファイルの読み取り設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/e1191073-f831-e054-8805-0c3438a3161e.png)

# Config.xcconfigファイルを読み込めるように登録する
 `Configurations`の`Debug`や`Release`に`Config.xcconfigファイル`を登録する
![configファイルの登録.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/7eecf0ab-57f2-3c31-37d6-b05f201e448c.png)


# 読み込み処理の実装例
## AppDelegate.swift
```
//
//  AppDelegate.swift
//  OCR_TestApp
//

import Foundation

import UIKit
import GoogleSignIn

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize sign-in
        if let apikey = Bundle.main.object(forInfoDictionaryKey: "GOOGLE_API_KEY") as? String {
            print("API Key: \(apikey)")
            // Google Sign-Inの初期化
            GIDSignIn.sharedInstance.configuration = GIDConfiguration(clientID: apikey)
            return true
        } else {
            print("API Key not found")
            return false
        }
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        return GIDSignIn.sharedInstance.handle(url)
    }
}

```

# 読み込みに使用しているコード
```
Bundle.main.object(forInfoDictionaryKey: "GOOGLE_API_KEY")
```
Google Cloud 課金を有効にできるプロジェクトの上限に達しています。の解決法

# はじめに
Google Map APIキーを取得しようとした際に、Google Cloudで以下のようなエラーになりました


>課金を有効にできるプロジェクトの上限に達しています。他のプロジェクトで課金が必要なプロジェクトがさらにある場合は、課金の割り当ての増加をリクエスト できます。

はて、一体どうしたらいいのか、、、Google Cloud Consoleの管理画面の操作がわかりにくくて詰まってしまいました。

# Google Cloudプロジェクトの課金を止める

Google Map APIキーを生成する際はGoogle Cloudプロジェクトの課金を有効化しないといけません。
エラーの解決策は2つあり

**①課金割り当ての増加をリクエストする**
**②既存のプロジェクトを見直し、課金を停止する**

このどちらかです。

①は面倒なので、使っていないGoogle Cloudプロジェクトの課金を止める方針にしようと思います。

https://cloud.google.com/billing/docs/how-to/modify-project?hl=ja#how-to-disable-billing

☝️のリンクから`Cloud Billing の [マイ プロジェクト] に移動`を押す

![Screenshot 2025-01-14 at 14.21.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/4eb75cef-3f0c-7b34-fd9a-676d73eacc66.png)

`課金を無効にする`から課金を止めれます！

![Screenshot 2025-01-14 at 14.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/50f938e9-7044-af69-da46-2ea6f9058775.png)

これで新たにGoogle Cloudプロジェクトでoogle Map APIキーを取得できるようになりました
LambdaのCI/CD実装してみた

## 1.初めに

AWS Lambda 関数を手動デプロイする場合、ローカルでソースコードを ZIP 化してアップロードする、AWS コンソール上でコードを編集するなどの方法があります。

しかし、開発規模や頻度が増えるにつれて手動デプロイは手間が増え、ヒューマンエラーの温床にもなりがちです。

そこでおすすめなのが、CI/CD パイプラインを構築してコードのビルドからテスト、デプロイまでを自動化する方法です。


本記事では、AWS の主要サービス（CodeCommit, CodeBuild, CodePipeline, CloudFormation）を用いて、Lambda 関数のデプロイを自動化する流れを紹介します。

## 2.全体構成イメージ

1. リポジトリ（ソース管理)
CodeCommit や GitHub などを利用して、Lambda 関数のソースコードを管理します。

2. ビルドステージ
CodeBuild を利用して依存ライブラリのインストールやユニットテスト、Lint チェックなどを実行します。
成果物（Lambda 関数の ZIP ファイル）を S3 に格納し、次のステージに渡します。

3. デプロイステージ
CloudFormation や Serverless Framework、SAM (Serverless Application Model)などを使い、自動的に Lambda 関数をデプロイします。
Lambda のバージョン発行やエイリアス設定もここで実施できます。

## 3.必要なリソースと準備

 - リポジトリ（CodeCommit または GitHub など）
 - buildspec（buildspec.yml）
 - CloudFormation テンプレート

## 4.パイプラインの作成手順

1.  リポジトリの作成とソースコードの配置
-AWS CodeCommit もしくは GitHub 上にリポジトリを作成
-Lambda 関数のソースコード、requirements.txt、buildspec.yml などをプッシュ
1.  CloudFormation テンプレートの作成
-パイプライン用のテンプレートを作成
-CodePipeline、CodeBuild の定義や IAM 権限、S3 の場所などを記述
1.  パイプラインの起動と確認
-CodePipeline が「ソース → ビルド → デプロイ」の順にステージを実行する
-エラーがなければ Lambda 関数がデプロイされ、実行できる状態になっているはず

## 5.まとめ
AWS Lambda 関数のデプロイを自動化する CI/CD パイプラインを作成することで、開発効率の向上と運用負荷の削減が期待できます。

本記事で紹介した構成や手順はあくまで一例であり、アプリケーション特性やチーム体制によって最適解は異なります。
ぜひ自分たちのプロジェクトに合わせてカスタマイズして、柔軟なサーバーレス運用基盤を作り上げてください。

以上、Lambda 関数を自動デプロイするための CI/CD パイプラインの作成方法についての概要でした。ぜひ参考にしてください。
fbxを上書きするとｷｭｯってなったりﾓｯってなったりする現象2

# 何？
- [fbxを上書きするとｷｭｯってなったりﾓｯってなったりする現象](https://qiita.com/pandrabox/items/5c9e32591858d742690f)について一応の対応策を示したが、それで治らない場合により強制的に修正する手順を紹介する
    - どうしてもうまくいかないとき向けなので、基本的にはエクスポートスケールの設定で何とかする方法を模索することをお勧めします
    - この方法でうまくいかない場合fbxの最初から完全にアバターセットアップする方法もありますが、一般的な記事にするのは難しいので個別相談下さい


# 手順
1. [whiteflare’s vpm-repos](https://whiteflare.github.io/vpm-repos/)をVCCに追加する
1. プロジェクトにFlare's Avatar Toolsを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/9471d39f-e92d-abde-cfc8-50a493cf1ae8.png)
1. 異常になっているアバターを用意する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/19537020-6106-b820-4f49-64367390c3d5.png)
1. 該当アバターのfbxをシーンに入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/029a10f4-364c-cb6e-6769-c2ba2eaa6e35.png)
1. Avatar Copy Utilityを起動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/a6f066a9-85eb-49a9-99cc-807e630709dc.png)
1. 元に異常アバターを入れる。先にシーンに置いたfbxを入れる。「MeshRenderer」という名前の付くもの**以外**にチェックを入れてコピーを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/e28355f8-afb6-2228-a357-df303ba8f80c.png)
1. OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/3845db30-b562-d4e9-0e9e-8f3a26d86906.png)
1. 異常アバターを消す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/a963188c-14a6-ae7f-e957-f7a995bea58e.png)
1. fbxのほうがちゃんとしたアバターになっているはず
 
# 注意
- PhysBone,Contact,ViewPoint,マテリアルのアウトラインのサイズ等色々なものが別途修正の必要があります
- エクスポート設定に依存しているツールなどで不具合が起きることがあります
    - 例：フラットでこれをやるとFlatPlusの一部(おなか、ほっぺ等の機能)が異常になります