OmniAICreator/Qiita-1.07M huggingface dataset:
Scrapy で asyncio を使ってみた

公式に [asyncio](https://docs.scrapy.org/en/latest/topics/asyncio.html) のページがあり、部分的なサポートが謳われているものの、具体例がなくてイメージが湧かなかったので、手を動かしてみました。

下記記事のプログラムの asyncio 版のようなものです。

https://qiita.com/hanohrs/private/43ae1fa2137f6e1631e1


## プログラム

簡単に書きたかったことと、好みの問題で、Item や Pipeline は使っていません。

asyncio を使って、Markdown と HTML を同時に保存しています。

```python:intellilink_column.py
import asyncio
import scrapy
from scrapy.http import Response
from markdownify import markdownify as md
from pathlib import Path

class IntellilinkColumnSpider(scrapy.Spider):
    name = "intellilink_column"
    allowed_domains = ["www.intellilink.co.jp"]
    columnlisting = "https://www.intellilink.co.jp/columnlisting.aspx"
    start_urls = [columnlisting]

    html_store = Path.cwd().joinpath("html_store")
    html_store.mkdir(exist_ok=True)

    md_store = Path.cwd().joinpath("md_store")
    md_store.mkdir(exist_ok=True)

    async def parse(self, response: Response):
        query_for_a = '//div[@class="c-block"]//a[starts-with(@href, "/column/")]'
        column_page_links = response.xpath(query_for_a)
        for request in response.follow_all(column_page_links, self.store_column):
            yield request

        query_for_n = '//span[i[contains(@class, "fa-angle-right")]]/@data-navigate-to'
        if n := response.xpath(query_for_n).get():
            yield response.follow(f"{self.columnlisting}?page={n}", self.parse)

    async def store_text(self, path: Path, text: str):
        path.write_text(text, encoding="utf-8")

    async def store_md(self, path: Path, html: str):
        await self.store_text(path, md(html))

    async def store_column(self, response: Response):
        filename = "_".join(response.url.split("/")[-2:])

        md_path = self.md_store.joinpath(filename).with_suffix(".md")
        md_task = asyncio.create_task(self.store_md(md_path, response.text))

        html_path = self.html_store.joinpath(filename).with_suffix(".html")
        html_task = asyncio.create_task(self.store_text(html_path, response.text))

        await asyncio.gather(md_task, html_task)
```


## 注意点

基本的にメソッドを `async def` にするだけで動くような印象を受けましたが、以下の点に注意が必要でした。

### `yield from` は使えない

`for` + `yeild` に書き換える必要があります。

### `gather` を忘れると、タスクを処理しないまま Scrapy が終了する

書き忘れないようにしましょう。

### create_task に普通の関数とその引数を渡してしまうと難しいエラーが出る

パッと見で何がおかしいのかわかりにくいので、`async def` のものを渡すようご注意ください。
Vue DevtoolsをExpress.jsから実行しても使えるようにする

# はじめに
VueのアプリをViteからではなくExpress.jsなど別のところから実行したときに、ブラウザでVue Devtoolsを開こうとすると
`vue.js is detected on this page. devtools inspection is not available because it's in production mode or explicitly disabled by the author.`
と出ることがあります。

プロダクション環境で実行すればいいのでしょうが、`vite build`のオプションを変えてもうまくいかず、`node main.js`に`--env development`とつけてもうまくいかず‥

調べてみると、以下のChrome拡張機能を入れると強制的に開発環境で実行されるようです。

https://chromewebstore.google.com/detail/vue-force-dev/oohfffedbkbjnbpbbedapppafmlnccmb

# 2025.03.08追記

:::note warn 

`vite.config.ts`でプロキシを設定するとサーバーへのアクセスはしつつviteのHMRの恩恵を受けられるので、開発環境ではviteからサーブしたほうが良いです。

:::

```typescript:vite.config.ts
export default defineConfig({
  //...
  server: {
    proxy: {
      "/api": {
        target: "http://localhost:8105"
      }
    }
  }
  //...
});
```

# 参考

https://community.n8n.io/t/vue-js-chrome-extension-not-working/28865

https://blog.nocorica.jp/2018/08/vue-devtools-not-works/
.NETで絵文字コードをUnicode絵文字に変換したい

こんにちは。

テックリードのTerukiです。

今日は便利なライブラリを1つ紹介。

# GEmojiSharp

https://github.com/hlaueriksson/GEmojiSharp

これはGitHub EmojiをC#で良い感じに扱えるようにしてくれるライブラリです。

例えば以下のようなテキストをUnicode絵文字に変換してくれるわけです。

```
ありがとう:+1:
```
↓
```
ありがとう👍
```

この変換を自前でやるのは絵文字コードとUnicode絵文字のマッピングを用意していろいろやらないといけないので非常に大変ですが、GEmojiSharpを使うと簡単です。


```cs
using GEmojiSharp;

var emojiCode = """
    ありがとう:+1:
    """;

var unicode = emojiCode.Emojify();
```

using GEmojiSharpをするとstringに対してEmojifyの拡張メソッドが追加されます。

その逆をしてくれるDemojifyもあります。

Oh my teethではSlackで構築されている社内システムの絵文字をうまいこと処理するために使っています。非常に便利。

Slackはテキストの絵文字をコピーすると絵文字コードにしてくれてしまうので不便な時がありますがこれで良い感じです。

MITライセンスなのもありがたいです。


# おわりに

この記事を書いている途中で、他にこのライブラリのユースケースがないかなと考えていたのですが絵文字対応していないデータベースにこれを挟むことでうまいことできそうだなと思いました。

そもそも絵文字対応していないデータベースをなんとかしなさいよと思わなくもないですが。。😇





# Oh my teethについて
[Oh my teeth](https://www.oh-my-teeth.com/?tags=qiita)では未来の歯科体験を創るために日々活動しています。

Techチームではより良いユーザー体験を提供するべく、Webフロントエンドからバックエンド、スマホアプリに機械学習モデルなど、さまざまなプロダクトを開発しています。

一緒に未来の歯科体験を創りませんか？興味がある方は是非こちらを確認してください。

https://oh.careers/

カジュアル面談も可能なので気軽に応募してみてください！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/0138b492-e02b-852e-61fa-fc065b53d285.png" width="450" />
はじめてのCTF（防衛省サイバーコンテスト 2025）

# ～前書き～
　先日、初めてCTFなるものに参加してきました！
writeUp(解答例)は他の方が全問公開して下さっているので、ここではwriteUpではなく、初心者目線でCTFの始め方について書こうかと思います。

　この記事を読んでくださった方の中には、サイバーセキュリティやCTFに興味はあるけどなかなか手を出せないといった方もいらっしゃるかと思います。
そういった方が一歩踏み出す手助けができればと思い、投稿させて頂きました。
Qiita初投稿で不慣れな部分が多いため、間違った内容があればご指摘頂けますと幸いです。

# 目次
①CTFの参加者のレベルって？
②大会当日！
③結果
④感想

# ①CTFの参加者のレベルって？
＜投稿者のスペック＞
業務経験はSE３年目でインフラ運用保守がメインで最近になってJavaでの開発を経験した程度。
大会へのエントリー時点での取得資格は下記の通りで突出しているようなスキルは無く、ぱっとしないスキルセットです。業務でもサイバーセキュリティにかかわっているという訳ではなく、一般的なSEです。
・CCNA
・LPIC1
・Oracle DBA Bronze
・Oracle Java Silver 
準備という準備なしで大会にエントリーし、エントリーしてから実感が湧いてきて、
さすがに1問も解けずに虚無の12時間を送ることになるのは嫌だということで準備を開始しました。

＜大会までの事前準備＞
〇2024年9月10日　大会概要が発表される
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001139/3dc2713b-7dff-4b8e-92a7-c365a0e1f483.png)
　大会概要　https://j-defense.ikaros.jp/docs/mod/001310.html
 
〇2024年9月20日-12月16日　大会エントリー期間　
　エントリー忘れがちなので、9月20日に即エントリーしました。
 この時点では基本情報すら取っていない状態だったため、大会当日までに下記に取り組みました。
　・脆弱性体験ツールAppGoat（後日投稿予定）による学習。
　・秋期に何とか応用情報を取得。
　・ハリネズミ本の中から得意な分野をつまみ食い（主にネットワーク、WEB系）
　・Kali Linuxのインストール方法と使い方動画を見て、Kaliの仮想マシンを作ってみたものの、仮想のNATだとかで躓き、外部ネットワークへのアクセスがやや不安だったため、急遽Kaliの実サーバも構築。
〇2024年2月2日0900-2100　開催当日

# ②大会当日！
＜直前＞
準備していたKaliサーバを起動！
無事、大会の問題サイトにアクセスできることを確認し、
そのままログインして大会開始まで待機してました。
あとはエナドリを適量摂取。

＜大会スタート！＞
奇跡的に最初の一問目はスムーズに攻略でき、106位！
※防衛省サイバーコンテスト 2025ではランキングがリアルタイムで表示されてました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001139/b516f106-de42-434e-b68e-11c917b372ae.png)

そこから何問か解いたものの時間が掛かってしまい、昼食を取っている間に200位台に転落。。。
それから順位はどんどん沈んでいき、、、

# ③結果
正答数は30問中6問。
獲得ポイントは5800pt中800pt、順位は480人中357位でした（※1,2）。
ちなみに１位の方は5800ptでした。
※1 0ptの方は表示されないっぽいので、実際には500人程度いそう?
※2 同じ800ptでも順位が違うのは、解けた時間が遅かったり誤答してしまった回数も反映されているからみたいです。

なお正解した問題の内訳は以下の通りでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001139/403e28f1-da9f-425e-896e-0ad7cd5c46c4.png)

# ④感想
日本の団体が主催なので問題文の解釈で躓くことがなく、
ＣＴＦ初心者でもなんとかできる問題が多くあったので、かなり楽しめました。
参加費も無料なので、コスパは最強です（CTFのコスパってなんやねんという感じですが）。

公式のwriteUp（答え合わせ）が無いのが難点ですが、毎年writeupを出してくださっている方もいらっしゃるので復習し易いです。
初心者用の問題があるとは言え、やはり応用情報以上のレベルの猛者たちが集まっているので、高順位に行くには勉強が必要そうです。
個人的にはLinuxコマンドをもう少し触っておけばよかったなと思いました。
7 kyu Form The Minimum

7 kyu Form The Minimum
https://www.codewars.com/kata/5ac6932b2f317b96980000ca/train/python
Task
Given a list of digits, return the smallest number that could be formed from these digits, using the digits only once (ignore duplicates). Only positive integers in the range of 1 to 9 will be passed to the function.

# Verbalization
Exclude duplicated digits = select digits only once (use set())
Sort digits from small (use sorted())
join digits (append and join() be careful that  join() can be used only for string)

# Code 
```py
def min_value(digits):
    s = set(digits)
    d = sorted(s)
    n = []
    for i in d:
        n.append(str(i))
    return int("".join(n))
```
elm327の研究 その11

# 概要
elm327の研究やってみた。
練習問題やってみた。

# ELM327とは
Microchip社のマイコンAVRに、カナダのElm Electronics社がプログラムを書き込んだチップの構成になっており、ELM327はOBDの通信をRS232に解釈・変換してくれる便利なチップです。Windows95の時代からあります。CANにも対応してる。Elm Electronics社は2022年に事業を終了しました。

![DSCN0536.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/37f24f7e-958f-81c8-faff-110dcda2acba.jpeg)

# 対応プロトコル

|番号|プロトコル|既知の車種|
|:--|:--|:--|
|1. |SAE J1850 PWM||
|2. |SAE J1850 VPW||
|3. |ISO 9141 - 2|saab 9-3|
|4. |ISO 14230 - 4 KWP ( 5 BAUD INIT )|ルノー　クリオ|
|5. |ISO 14230 - 4 KWP ( FAST INIT )||
|6. |ISO 15765 - 4 CAN ( 11 BIT ID, 500 KBAUD )|スマート　フォーフォー|
|7. |ISO 15765 - 4 CAN ( 29 BIT ID, 500 KBAUD )||
|8. |ISO 15765 - 4 CAN ( 11 BIT ID, 250 KBAUD )||
|9. |ISO 15765 - 4 CAN ( 29 BIT ID, 250 KBAUD )||
|10. |SAE J1939 CAN ( 29 BIT ID, 250 KBAUD )||

# DTCとは

診断コードで、本故障状態となって警告灯が点いたときに故障の詳細を示す診断コードが記録されます。
DTCの項目はアメリカではSAE、日本のJ-OBDⅡは国交省がデータベース化しています。


# 練習問題
dtcコードをデコードせよ。

# 参考にしたページ

https://qiita.com/suzutsuki0220/items/633b26e16da93fb7516f

https://qiita.com/gpsnmeajp/items/37def0fae1182d1bf677

# 成果物
DTCを入れて、検索をクリックする。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="azbvaQw" data-pen-title="obd2 dtc" data-user="ohisama" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ohisama/pen/azbvaQw">
  obd2 dtc</a> by ohisama (<a href="https://codepen.io/ohisama">@ohisama</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>



以上。
PostgreSQL で EXPLAIN ( pgAdmin )

# 普通に EXPLAIN

EXPLAIN ANALYZE とかチマチマやっていたのですが・・・

![スクリーンショット 2025-02-18 140306.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631853/e4a688a8-b045-493e-8225-d387f65229b0.png)

# pgAdmin に便利なボタンが・・・

注: このボタンを使う時は、EXPLAIN ANALYZE 等は抜いた素のSQLにしましょう。

![スクリーンショット 2025-02-18 140333.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631853/88501170-900b-4168-8079-6275bfc5ca44.png)


# 出力結果の例

![スクリーンショット 2025-02-18 140424.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631853/25f8a7f3-fe9f-473e-a1a4-eb91ca62c405.png)

![スクリーンショット 2025-02-18 140440.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631853/67446275-25f7-4cc9-8a8d-29b1d5f516e5.png)

こんな隠れ機能があったとは・・・ありがたや、ありがたや。
MySQL の UNSIGNED BIGINT の最大値を Ruby のビット演算で求める方法

## この記事は？

[MySQL :: MySQL 8.4 Reference Manual :: 13.1.2 Integer Types (Exact Value) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT](https://dev.mysql.com/doc/refman/8.4/en/integer-types.html)

上記のページによると、MySQL の UNSIGNED BIGINT を格納する領域は 8 bytes で、最大値は $2^{64}-1$ です。この最大値を Ruby で求める方法を残しておきます。

## 方法

以下の 2 つの方法で求められます。上の方法は $2^{64}-1$ をそのまま Ruby で計算しただけです。今回は下の方法について詳しく解説します。

```rb
2**64 - 1
#=> 18446744073709551615

(1 << 64) - 1
#=> 18446744073709551615
```

UNSIGNED BIGINT を格納する領域は 8 bytes です。これは bit に直すと 8 bytes * 8 = 64 bits です。

[Integer#<<](https://docs.ruby-lang.org/ja/latest/method/Integer/i/=3c=3c.html) を使用して 1 を 64 bits 左にシフトします。この `<<` はビット演算に慣れていない場合はよくわからない処理に見えるかもしれませんが、適宜 `to_s(2)` で 10 進数を 2 進数に変換しながら処理を追ってみると、やっていることはとてもシンプルだと分かります。

```rb
# 10 進数の 1 を 2 進数に変換する。
1.to_s(2)
#=> "1"

# 1 を 64 bits 左にシフトする。
1 << 64
#=> 18446744073709551616

# 結果を 2 進数に変換すると、1 が 64 bits だけ左にずれていることが分かる。
(1 << 64).to_s(2)
#=> "10000000000000000000000000000000000000000000000000000000000000000"

# この 2 進数の桁数は 65 桁。
(1 << 64).to_s(2).size
#=> 65
```

ここから 1 を引けば、8 bytes (64 bits) の領域に格納できる最大の整数を求めることができます。

```rb
(1 << 64) - 1
#=> 18446744073709551615

# この 2 進数はすべてのビットが 1 であり、桁数は 64 桁。つまり 64 bits で表現できる最大値。
((1 << 64) - 1).to_s(2)
#=> "1111111111111111111111111111111111111111111111111111111111111111"
((1 << 64) - 1).to_s(2).size
#=> 64

# 2**64 - 1 と一致する。
(1 << 64) - 1 == 2**64 - 1
#=> true
```
テストが書きやすいコードを書く

## テストしやすいコードを書くために

本記事では、よりテストしやすいコードを書くために意識していることを紹介します。テストのしやすいコードを書くと、バグの減少につながるだけでなく、品質向上や開発効率改善にも繋がります。

テストケースの考え方や、良いテストの書き方についてもご紹介しているので、こちらもあわせてご覧ください。
- [テストケースの考え方](https://qiita.com/KoutaKawaguchi1101/private/24e14c34b4ca055931c6)
- [なぜテストをするのか？テストの質を向上させるためのポイント](https://qiita.com/generoKoki/private/7c06f3df54766528a32b)


## テストしやすいコードとは？

そもそも、テストしやすいコードとはどういったものでしょうか。私は、次のような特性を持つコードがテストしやすいと感じます。
- モジュール性：コードが小さな単位に分割され、それぞれが独立して機能する
- 明確性：コードの意図が明確で、理解しやすい
- 独立性：外部システムや状態に依存せず、単独でテストが可能

これらの特性を備えたコードは、バグの発見が容易でありスムーズにテストコードを書くことができます。次の章では、上記の特徴を簡単に実装できる原則をご紹介します。

## テストしやすいコードを書くための原則

### 1. 関心の分離（Separation of Concerns, SoC）

関心の分離とは、一つのコンポーネントやクラスが「単一の責務のみ」を持つように設計することを意味します。
この原則を守ることで、コードの変更が他の部分に影響を与えにくくなり、個別のユニットテストが容易になるというメリットがあります。

✴︎ 悪い例

```python
class UserManager:
    def create_user(self, username, password):
        hashed_password = self.hash_password(password)  # パスワードのハッシュ化
        self.save_to_database(username, hashed_password)  # データベースに保存
        self.send_welcome_email(username)  # ウェルカムメール送信
```

上記のコードは ユーザーの作成・パスワードのハッシュ化・データベース保存・メール送信 という 複数の責務を1つのクラスで行っています。

✴︎ 良い例

```python
class UserManager:
    def create_user(self, username, password):
        hashed_password = PasswordHasher.hash(password)
        UserRepository.save(username, hashed_password)
        EmailService.send_welcome_email(username)
```

このように役割ごとにクラスや関数を分けることで、ユニットテストがしやすくなります。

### 2. 依存性の注入（Dependency Injection, DI）

外部の依存関係を直接コード内で生成するのではなく、外部から注入（インジェクション）することで、より柔軟でテストしやすいコードになります。

✴︎ 悪い例（依存関係を直接作成）
```python
class UserService:
    def __init__(self):
        self.repository = UserRepository()  # 直接依存
```

このように UserService が UserRepository を直接作成してしまうと、テスト時にモックやスタブを利用するのが難しくなります。

✴︎ 良い例（依存性の注入を適用）
```python
class UserService:
    def __init__(self, repository):
        self.repository = repository  # 外部から注入
```

これにより、テスト時にモックを渡すことができるため、データベースを使わずにユニットテストが可能になります。

```python
mock_repository = Mock()
service = UserService(mock_repository)
```


### 3. 副作用の少ないコードを書く

副作用とは、関数の実行によって グローバル変数を変更する、データベースに書き込む、ファイルを変更するなどの目に見えない影響を指します。

副作用の少ないコードを書く方法として、
- 関数型プログラミングの原則を取り入れる
- 可能な限り純粋関数（Pure Function） を使う（引数が同じなら、常に同じ結果を返す）
- それぞれの責務を明確にする

などが挙げられます。
詳細に関してはこちらの記事をご覧ください。↓

https://qiita.com/kentosity/items/bb2a5911801ce6c9a2a8

## まとめ

テストしやすいコードを書くための原則を3つご紹介しました。
1. 関心の分離を意識し、1つのクラスや関数に複数の責務を持たせない
1. 依存性の注入を活用し、テストの柔軟性を高める
1. 副作用を最小限に抑え、テストの信頼性を向上させる

これらの原則を取り入れることで、テストしやすく、保守性の高いコードを書くことができます。

次のセクションでは、実際にテストを書いてみる方法について解説します。ユニットテストの基本から、モックの活用まで詳しく見ていきましょう！
クラウド初心者のAZ-900合格体験記

# はじめに
2025年2月にMicrosoft Certified: Azure Fundamentals(AZ-900)を受験し、合格しました。
昨年12月にAzureを使ったプロジェクトにアサインされ、ちゃんとクラウドについて勉強したことが無かったのでいい機会だと思い受験しました。
今回は勉強でやったことを備忘録として残しておきます。

# 筆者について
- IT企業 ソフトウェア開発
- 情報系修士
- 社会人4年目
- ちゃんとしたクラウド開発は初、AWSを軽く触ったことがある程度

# 受験結果
- 921点(合格点700点、1000点満点)

# 勉強期間
- 約18時間

# 受験形式
- テストセンター
    - 自宅で受験もできるみたいですが、いろいろ制約があって面倒そうだったのでテストセンターにしました。

# 勉強方法
## インプット
- 合格への近道！Azure Fundamentals AZ-900 試験対策講座

まずはUdemyの講座で概要を掴みました。図解付きの動画で分かりやすく説明してくれるので初心者の方にはオススメです。

https://www.udemy.com/course/microsoft-azure-az900-video/?srsltid=AfmBOorjQ5EFv_ilAV0BZ3KCyZzOHZHNGhZBNHS-4NK4AVjZDaRui7J1

- 徹底攻略 Microsoft Azure Fundamentals教科書［AZ-900］対応 第2版 徹底攻略シリーズ

一応買って途中まで読みましたが、Udemyの内容と被っていたので途中で切り上げてアウトプットを優先しました。Udemyか本かどちらかでいいと思います。
ただ、章末問題と付録の問題集が付いていたのでそれは活用しました。

https://amzn.asia/d/0jDo4BR

## アウトプット
- 最短で合格！Azure Fundamentals AZ-900 試験対策問題集

問題集①。これを3週して大体どの回も95%以上は正解できるようにしました。

https://www.udemy.com/course/microsoft-azure-az900-exam/?srsltid=AfmBOopbYlJiiKN9Po4l9uO_R6DC_HmNPaOCjat2PhNGcqED5NZ8HRfw

- 【6万人が受講】AZ-900 Microsoft Azure Fundamentals模擬試験問題集（7回分490問）

問題集②。こちらは上記の問題集より難しめです。2周して大体75%程正解できていました。

https://www.udemy.com/course/az-900-microsoft-azure-fundamentals4176/?srsltid=AfmBOoqXOgXL5ovEVOtxGYAqL1xCg5R4iLxORCm8YpTfC2bGgFgsNOWp

- Microsoft Learnのプラクティス評価

公式の模擬問題。こちらはかなり簡単で8週しましたが、90％は切りませんでした。本番はもう少し難しい問題が出ますが、独特な(?)日本語や雰囲気を感じておくのにおすすめです。
実際の試験のデモであるサンドボックスも触っておくと本番で焦らなくて済むかもしれません。

https://learn.microsoft.com/ja-jp/credentials/certifications/azure-fundamentals/

# 試験を終えて
Azureの基本機能や一般的なクラウドの体系的な知識を身に着けることができたので良かったです。
試験は限られた範囲から出題されるのでパターンさえ掴めればかなり少ない時間で合格できるのではないかと思います。
プラクティス評価やUdemyの問題は周回しておいて損はないなと思いました。

合格はテストセンターで回答終了後その場で確認でき、2日後くらいにピアソンから試験合格メールが届きました。
合格後はMicrosoft learnから資格証明やオープンバッジ、スコアレポート(こちらは外部のピアソンのサイト)を確認できます。

今後は実務でAzureポータルなど触る機会が増えてくると思うので、実践しつつ上位資格も目指していきたいです。
NetSuiteとは？ ～クラウドERPの概要と活用方法～

こんにちは！株式会社IT働楽研究所の山本です！
私は関東に在住するファーストフードが大好きな関西人なのですが、西と東でのファーストフード店の略称に違和感を覚えています。
皆様はマクドナルドをどのように略称しますか？おそらく関西人は「マクド」、関東人は「マック」ですよね。
関東にいるとこの「マクド」呼びをよく変な呼び方だと指摘されますが、関西人からすればマクドナルドを「マック」呼びするのであればミスタードーナツを「ミスド」ではなく「ミッス」呼びするべきではと思ってしまいます。。
何事も一貫性って大事ですよね。
それでは本日の記事をお楽しみください。

## はじめに
 
この記事では、**NetSuite** について基本的な概要を解説し、その特徴や活用方法について紹介します。  
主にERP（Enterprise Resource Planning）システムに興味があるエンジニアや、企業の業務管理を効率化したい方を対象としています。
 
### この記事でわかる・できること
 
- NetSuiteの基本的な概要がわかる  
- NetSuiteの主な機能や特徴が理解できる  
- NetSuiteの活用方法や導入メリットがわかる  
 
### この記事の対象者
 
- NetSuiteを導入した直後のユーザー  
- ERPシステムの導入を検討している企業の担当者  
- 業務管理を効率化したいエンジニア  
 
## NetSuiteの概要
 
**NetSuite** は、Oracleが提供するクラウドベースのERPシステムで、財務管理、在庫管理、CRM（顧客管理）、Eコマースなどのビジネスプロセスを統合的に管理できるプラットフォームです。
 
### NetSuiteの主な特徴
 
- **クラウドベース**：インターネット環境さえあれば、どこからでもアクセス可能  
- **統合管理**：財務、会計、販売、在庫などのデータを一元管理  
- **カスタマイズ性**：スクリプトやワークフローの設定により、業務に合わせた柔軟なカスタマイズが可能  
 
NetSuiteを活用することで、業務の一元管理が実現し、リアルタイムでのデータ分析や意思決定のスピードアップが期待できます。
 
## NetSuiteの基本設定方法
 
NetSuiteを利用するには、まず基本的なセットアップを行う必要があります。  
ここでは、NetSuiteのダッシュボード設定の基本的な手順を紹介します。
 
### ダッシュボードの設定方法
 
1. **NetSuiteにログイン**  
   NetSuiteの管理画面にアクセスし、管理者アカウントでログインします。  
 
2. **ダッシュボードのカスタマイズ**  
   画面右上の「パーソナライズ」をクリックし、表示したいウィジェット（レポート、グラフ、KPIなど）を選択します。  
 
3. **必要なウィジェットを配置**  
   「ドラッグ＆ドロップ」機能を使って、よく使うレポートやグラフを見やすい位置に配置します。  
 
4. **設定を保存**  
   設定が完了したら、変更を保存し、業務に合わせたダッシュボードの活用を開始します。  
   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3987190/2e49f1b9-e452-40a5-b6f2-960b3521248c.png) 
## NetSuiteの活用事例
 
NetSuiteを活用することで、どのように業務が改善されるのか、具体的な事例を紹介します。
 
### 事例1：内資系ERPからNetSuiteへの切り替え（弊社自社導入事例）  
 
**課題**: 
①オンプレミスによる自社運用に伴い、コストが増大していた。
②勤怠システム、一部受発注システム、財務システムとERPで同期がとれておらず、データの二重入力が発生していた。
③レポーティング機能等のカスタマイズ性が低く、業務効率化が適切に行えていなかった（カスタマイズの都度、導入費用が発生していた）  
**解決策**: 
①クラウド化に伴い、運用コストの低減に成功。
②NetSuiteと勤怠システム：ccbizmate、受発注システム：Meeepa、財務会計システム：弥生会計を外部連携しデータを一元管理。  
③すべての導入・カスタマイズを自社で行い、日々の運用・追加開発も内製化に成功。
**結果**: 
①自社運用に使用していたコストを別事業に充てることでさらなる業績向上に寄与（売上32％、利益率22％アップ）  
②各システムでの二重入力が不要になり、バックオフィス業務を大幅に効率化（工数15％削減）
③社内管理業務をNetSuiteのダッシュボード上でリアルタイム確認し、経営判断の効率化・適正化に成功
 
### 事例2：レガシーシステム、俗人化業務からの脱却  
 
**課題**: 
①受発注システムと生産管理システムが分断されており、データの不整合が多発していた。
②膨大なExcel管理による俗人化業務。
③②に伴う即時の業務分析が行えず、経営判断が鈍化していた。
**解決策**:
①受発注、生産管理含むほぼすべての業務範囲をNetSuiteで導入。
②NetSuite標準機能プロセスに業務を集約し、煩雑化した業務プロセスをシンプル化。
③部門・担当ごとにダッシュボードを整備し、情報をリアルタイムで管理。  
**結果**: 
①情報が一元化され、データの不整合はゼロに。
②業務プロセス一般化により、俗人化業務から脱却。マニュアルを整備し、事業拡大にも柔軟な対応が可能に。
③部門・担当ごとに最新かつ必要な情報が即時で可視化。素早い業務判断が可能に。
 
### 事例3：在庫管理の最適化  
 
**課題**: 在庫の過剰・不足が頻繁に発生し、余剰コストや販売機会の損失が発生していた。  
**解決策**: NetSuiteの在庫管理機能を活用し、リアルタイムで在庫状況を監視。  
**結果**: 在庫コストを20%削減し、適正在庫の維持が可能に。  
 
## 結論
 
NetSuiteを導入することで、**業務の統合管理が可能になり、リアルタイムでのデータ可視化による業務効率化が実現**できます！  
ERPシステムの導入を検討している方は、ぜひNetSuiteを活用してみてください。
laravelのvalidationの日付のafter,before,after_or_equal,before_or_equalはどちらも設定する場合は片方がnullのときにfailする

Laravelのバリデーションルールには、**after**, **before**, **after_or_equal**, **before_or_equal** がある。 これらのルールは、あるフィールドの日付が別のフィールドの日付と比較して「後/前」になっているかをチェックができます。

## 問題の概要
* **ルールの動作**

```php
'start_at' => 'nullable|date|before_or_equal:end_at',
'end_at'   => 'nullable|date|after_or_equal:start_at',
```

- この設定は「**start_at** は **end_at** と同じかそれより前の日付であること」、「**end_at** は **start_at** と同じかそれより後の日付であること」をvalidationします

## **片方がnullの場合の問題**

https://readouble.com/laravel/10.x/ja/validation.html#rule-after

にも記載しているようにafter,beforeはstrtotimeに値を渡す関係上、どちらかがnullの場合はstrtotimeに渡したとき有効な日付として変換できず、結果的にバリデーションが失敗する仕様になる

## 解決方法
### 1. ルールの適用を片方にする
```php
'start_at' => 'nullable|date',
'end_at'   => 'nullable|date|after_or_equal:start_at',
```

### 2. カスタムバリデーションルールを使用する
* 匿名関数を用いて、両方のフィールドが存在する場合のみ比較を行うように設定する

```php
           'start_at' => [
                'nullable',
                'date',
                function ($attribute, $value, $fail) {
                    // end_atが存在するときだけ比較
                    if ($value !== null && $this->end_at !== null) {
                        if (Carbon::parse($value)->greaterThan(Carbon::parse($this->end_at))) {
                            $fail("start_atには、end_at以前の日付を指定してください。");
                        }
                    }
                },
            ],
            'end_at' => [
                'nullable',
                'date',
                function ($attribute, $value, $fail) {
                    // start_atが存在するときだけ比較
                    if ($value !== null && $this->start_at !== null) {
                        if (Carbon::parse($value)->lessThan(Carbon::parse($this->start_at))) {
                            $fail("end_atには、start_at以降の日付を指定してください。");
                        }
                    }
                },
            ],

```
 この方法は、両方のフィールドが存在する場合にのみ比較を実施する。片方がnullの場合は比較処理をスキップする。
## まとめ
* **比較ルールは両方のフィールドに有効な日付があることを前提**としているため、片方がnullだとバリデーションは失敗する
* **両方が存在する場合のみ比較する**ようカスタムバリデーションルールを用いる方法が良さそう
Power Platform モデル駆動型アプリ開発手順

１．管理したい（する）項目を整理する
↓
２．Dataverse でテーブルを作る
↓
３．テーブル間の関係性を決める
↓
４．アプリにする
↓
５．処理手順をアプリに追加する
↓
６．自動化処理をアプリに追加する
↓
７．セキュリティ周りを整備する
JavaScriptで条件付きNull変換

## 概要
JavaScriptで任意の値と任意の条件を受け取り、
その値が、前述の条件を満たす際はnullに変換する関数を定義します。
当該条件を満たさない場合は元の値がそのまま返ります。
## 定義
```js
function mapToNullIf(value, condition = v => false){
    return typeof condition === "function" && condition(value) === true ? null : value;
}
```
## 使用例
```js
const x = mapToNullIf(100, v => v > 100);
const y = mapToNullIf(101, v => v > 100);
console.log("x is " + x + ", y is " + y + ".");
```

## 表示
```text
x is 100, y is null.
```
Windows 11 - YAMAHA RTX1210 L2TP/IPSec接続設定 備忘録

Windows 11 Pro環境で RTX1210 を利用してのVPN設定

Windows 11 を再インストールをした際にVPN設定が消えてしまった。
再設定したときにいろいろと躓いたので備忘録として残しておく。

結果として、ログインID、パスワード、事前共有キーを手元にあったテキストファイルからのコピーペーストをWindowsの標準機能VPN設定で利用したところキーが違う可能性が高かったということで個別に設定したらつながったという結末だった。

せっかくなので、あがいたことも記載しておく。

＊環境＊
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
OS:Windows 11 Pro 24H2
ネットワーク：Yahoo BB 光ホーム 100M
接続先ルーター：YAMAHA　RTX1210
接続方式：L2TP/IPSec
認証方式：事前共有キー　ログインID　パスワード

暗号のプロトコル
CHAP-PAP　
AES256-CBC SHA256-HMAC
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

先述の通り、VPNの設定を再設定した際にいろいろ躓いたので記載しておく。

※初策※
まず、Windows 11 では、NATトラバーサル通信が、標準状態では無効になっているので、設定を有効にすることで問題が解決されたという記事が散見されたので試してみた。

やり方は、以下の通り
レジストリを変更する必要があるのでレジストリエディタを開く
スタートを右クリック→ファイル名を指定して実行をクリック→regeditと入力してEnter

レジストリエディタが開いたら、以下のパスへ移動する。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PolicyAgent
移動したらその個所に新しいキーを追加する。
DWORD（32bit値)で、AssumeUDPEncapsulationContextOnSendRuleを追加する。
追加されたAssumeUDPEncapsulationContextOnSendRuleの値を2に変更する。

これでNATトラバーサルの設定は完了したのでVPNを接続してみるがうまくいかなかった。

※2番策※
次に試したのは、VPNのセキュリティー設定の変更
まずネットワーク設定をいじらないといけないので、以下の手順でWindowsを操作する。
スタートを右クリック→ファイル名を指定して実行をクリック→ncpa.cpl→開いたウィンドウから設定する対象のVPNプロパティを開く。

セキュリティータブを選んで以下の画像の通りに設定する。
![VPN.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939374/f3c34cb3-b816-469c-8746-6372e40b3581.jpeg)

結果：接続できなかった。WindowsLogでは、788エラーを吐き出す。

※3番策※
次に、暗号規格の問題かもと思い、PowerShellを起動して以下のコマンドを実行した。

Set-VpnConnectionIPsecConfiguration -ConnectionName "自分のVPN設定名" -AuthenticationTransformConstants SHA256 -CipherTransformConstants AES256 -EncryptionMethod AES256 -IntegrityCheckMethod SHA256 -PfsGroup PFS2048 <b>-DHGroup Group14</b> -Force

DHGroupの箇所も　Group1　Group2　Group14　Group24の設定を変更してみた。

結果：接続できなかった。

※4番策※
次にやったのは、サービスの開始作業
![VPN_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939374/06bf5427-431a-4312-b391-42fae3bc7828.jpeg)
![VPN_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939374/2c16e18d-be0b-4f45-871d-48277cca78b2.jpeg)

この二つのサービスを開始してみた。

結果：エラー788を吐き出して接続できなかった。

ここで、結構万策尽きた感が強まってしまった。

最後に認証情報などを見直ししようと再入力を試みた。
ユーザーとパスワードを再入力した。
結果ダメだった。

最後に事前共有キーを再設定することにした。
VPN設定画面の共有キー入力画面では、伏字になってしまうのでVPNのプロパティでしっかりと確認しながらやることが重要。

![VPN_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939374/ca0cf833-f0f8-4f2c-b83f-5663ab3a6176.jpeg)

結果見直したらつながった。

結果的に内容の見直しだけで修正されたのかというのは疑問が残るのでイロイロやったみたことも必要な手順であると思う。

未来で同じことで躓く自分のために残しておく。
【C#】特定の時間の間、成功するまで同じ処理を続ける方法

# 概要
特定の時間の間、成功するまで同じ処理を続ける処理のサンプルコードを記載しました。

# コード
一時間の間だけ、成功するまで同じ処理を繰り返すサンプルコードです。
```C#
using System;
using System.Diagnostics;
using System.Threading;

public bool Sample()
{
    const int MaxRetryTime = 1000 * 60 * 60;
    var sw = new Stopwatch();
    sw.Start();
    while (sw.ElapsedMilliseconds < MaxRetryTime)
    {
        try
        {
            // 成功するまで続けたい処理を記載

            // 成功した場合
            return true;
        }
        catch (Exception ex)
        {
            // 失敗した場合
            
            // エラー処理 (ログ出力等)
        }

        // 失敗した場合は10秒待機して再スタート
        Thread.Sleep(1000 * 10);
    }

    // 成功しなかった場合
    return false;
}
```

### const int MaxRetryTime = 1000 * 60 * 60;
- この変数は`try`の中含めてプログラム実行中は絶対に変更されるべきではない値なので`const`を使用しています。
- `1000 * 60 * 60`は、時間を定義しています。ミリ秒単位で定義するので、「1000ミリ秒 = 1秒」 として最初に`1000`を記載しています。

### StopwatchクラスのElapsedMilliseconds
- こちらはストップウォッチが開始されてから (`Start()`が呼ばれてから) の経過時間をミリ秒単位で返すプロパティです。

### Thread.Sleep(1000 * 10);
- 処理が失敗したらすぐに再実行するのではなく、10秒間待ってから再度処理を実行するための処理です。

# 終わりに
データベースにアクセスして操作する場合や外部サービスと通信する場合等に使用できるかもと思います。
【Oracle APEX】ページの移動方法

## はじめに
ご覧いただいた方は、Oracle APEXを用いて画面開発を行っており、開発に苦労されている方かと思います。

本記事では、同一もしくは別アプリケーションへ画面遷移する方法について記述したいと思います。

※本記事は全て日本語表記で翻訳されている名称を用いています。

## 目次
１．GUI上で画面遷移を設定する方法
２．PL/SQLを用いて画面遷移を設定する方法

## GUI上で画面遷移を設定する方法について
**設定の前に注意点がございます。
GUI上で設定する場合は、遷移先が固定となるため、「条件によって遷移先を変更したい」や「条件によって遷移をしたくない」などあれば「２．PL/SQLを用いて画面遷移を設定する方法」を試してください。**

以下の画像のように遷移処理を実行するボタンを用意して、「動作」-「ターゲット」の設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/870ea0a6-0860-4318-8508-4e41c402bdcd.png)

詳細画面「リンク・ビルダー-ターゲット」にて「ページ」に遷移したいページを指定します。
※遷移元ページに作成したアイテムの値を遷移先にも紐づけたい場合は、「アイテムの設定」にて設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/042d13ec-afce-4aef-8411-6d8b5f16625b.png)

以上の設定で、特定のページへ遷移することが可能となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/2d3126fb-1750-463a-996a-b9f4ed7edb7a.png)

### 別アプリケーションへ遷移させたい場合
別アプリケーションへ画面遷移させたい場合は、一部設定内容が異なります。
「動作」-「アクション」から「別のアプリケーションのページにリダイレクト」を選択する。そして、「アプリケーション」と「ページ」に遷移したい画面のアプリケーションIDとページ番号を設定することで可能となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/fe6a9896-f97e-4d53-b76d-dacf00c5c71e.png)

## PL/SQLを用いて画面遷移を設定する方法について
「１．GUI上で画面遷移を設定する方法」と同様に遷移処理を実行するボタンを用意した後、「動作」-「アクション」を「ページの送信」と設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/170770ba-593f-4e24-b315-3c819c4cba16.png)

次にボタンが実行するプログラムを作成する。
「プロセス」上にプログラムを作成し、「サーバー側の条件」-「ボタン押下時」に実行したいボタン名を設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/845fbd52-bd66-4e62-b274-72104cc9aaf2.png)

作成したプロセスの「PL/SQLコード」にプログラムコードを挿入する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/e929689a-e5b8-4c9b-ae1b-9b349440531c.png)

```ruby:記述例
DECLARE
  l_url   VARCHAR2(4000);
BEGIN
  IF :P8_FLG = 1 THEN --遷移するフラグ設定
    /*ページ遷移*/
    l_url := apex_page.get_url(
      p_application => 102,       --遷移するアプリケーションID
      p_page        => 10,        --遷移するページ番号
      p_items       => 'P10_ID',  --遷移先で受け取るアイテム名
      p_values      => :P8_ID2    --遷移先へ受け渡すアイテム名
    );
    apex_util.redirect_url(
      p_url         => l_url
    );
  ELSE --遷移しないフラグ設定
    null;
  END IF;
END;
```
上記プログラムを設定すると、アイテム「P8_FLG」が1の場合は画面遷移して、それ以外であれば遷移しないというプログラムとなります。

以上の設定で、条件によってページへ遷移することが可能となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538663/236468ee-12d3-44d6-a784-ff2287d80b23.png)

## おわりに
本記事では、OracleAPEXで同一もしくは別アプリケーションへ画面遷移する方法について記述させていただきました。
本記事が、どなたかの役に立てたのであれば幸いです。
本記事をご覧頂き、ありがとうございました。
伝え方の重要性：散髪に行くたびにタラちゃんヘアーにされていたが、原因は自分の言語化力の不足だった件

## はじめに
散髪や髪を切りに行くたびに、思った通りの髪型にならないことがよくありました。

:::note info
***私は普段から髪型に強いこだわりがなく、明らかに変でなければ正直なんでも大丈夫です...***
:::

また、髪を切る頻度も2〜3ヶ月に1回と、特に気にせず適当に行っています。

## 書こうと思ったきっかけ
しかし、いざ「**こういう髪型にしたい**」と伝えても、仕上がりが想像と違うことがよくありました。

:::note warn
その理由として、「**美容師さんが髪を切りすぎる**」「**自分のイメージを正しく理解してくれていない**」といった外部の要因ばかりを考えていました。
:::

しかし、後になって気づいたのは、実は自分の伝え方に問題があったということです。

## 具体的に伝えること
私は具体的に自分の理想の髪型を言葉で説明することが苦手でした。曖昧な表現のまま「***短くしすぎないでほしい***」「***さっぱりした感じで***」などと伝えていたため、美容師さんも最適な判断ができなかったのかもしれません。

最近では、自分の望むスタイルの写真を見せたり、具体的な長さや形状を伝えたりすることで、想定通りの髪型になることが増えてきました。

## 相手に伝える中で意識すること
この経験を通して気づいたのは、ITの世界でも同じことが言えるということです。

:::note info
特にハッカソンなどのチーム開発では、チームメンバーに対して「**どのような仕様にしたいか**」「**どのようなデザインを想定しているか**」などを具体的に伝えることが求められます。
:::

曖昧な指示では、相手は自分が本当に求めているものを理解できず、結果として意図と異なるものができあがってしまう可能性が高くなります。

## 抽象的なことを具体的にするポイント
1. **ビジュアルを活用する**：言葉だけでなく、写真や図を使うことで相手がイメージしやすくなります。
2. **数値で表現する**：例えば「少し短め」ではなく、「耳が半分隠れるくらいの長さ」など、具体的な数値を用いると伝わりやすいです。
3. **例を示す**：他の実例や類似のデザインを示すことで、相手に意図を明確に伝えられます。
4. **比較表現を使う**：「以前の髪型よりも〇〇が短め」など、相対的な表現をすると、より理解が深まります。
5. **相手の理解を確認する**：伝えた内容を相手に繰り返してもらうことで、認識のズレを防げます。

## まとめ
つまり、明確なコミュニケーションが非常に重要だということです。

:::note warn
**髪型のオーダーでも、ITの開発でも、自分の考えをしっかり整理し、相手に伝わる形で伝えることが大事です。**
:::

特に抽象的なことを伝える際は、ビジュアルや数値を活用し、具体的な言葉に落とし込むことが重要です。

***これからも、より分かりやすく伝える力を磨いていきたいと思います。***
フリーランスエンジニアが最速で案件を獲得する戦略【営業・交渉・ポートフォリオ】

# フリーランスエンジニアが最速で案件を獲得する戦略

## 🔥 はじめに
「スキルがあれば案件が取れる」は過去の話。  
今のフリーランス市場では「営業力」がなければ生き残れない。  
本記事では、最短で案件を獲得する3つの方法を解説する。

---

## ✅ 案件獲得の3つのルート
💡 **1. エージェント経由** → 案件数は豊富だが、単価は低め  
💡 **2. 直営業（企業DM・紹介）** → 単価が高いが、営業力が必要  
💡 **3. SNS・ブログ経由** → 継続的な案件獲得が可能  

---

## ✅ 直営業の必勝法
💡 **企業の採用ページを活用** → 直接連絡することで案件に繋がる  
💡 **「営業用テンプレート」を準備** → 返信率を高める  
💡 **「面談時に案件を引き出す」** → 単価交渉を有利に進める  

---

## ✅ ポートフォリオ戦略
❌ NG：「技術の羅列」や「スキルシートのみ」  
✅ OK：「クライアントの課題を解決した実績を強調」  

例：**「Laravelで◯◯システムを開発し、運用コストを30%削減」**  

---

## ✅ まとめ
フリーランスが最速で案件を獲得するには、
✅ **エージェント・直営業・SNSを併用する**
✅ **直営業は「企業採用ページ＋DM」で効率化**
✅ **ポートフォリオは「課題解決型」に最適化**

🔥 **この戦略を実践すれば、仕事が途切れなくなる！**
【AI活用】現代っ子っぽい競合分析

こんにちは！mofmofでエンジニアとか採用とかやっている者です。  
採用なかなか難しくて困ったので、競合分析みたいなことをしてみました。

各社の訴求ポイントと技術スタックを知り、その上で自社は何が良いのかを考えたかった感じです。

## 情報を集めて整理する
よしなに求人情報を集めます。企業サイトの採用ページや、媒体に掲載されている求人票など。

情報はスプレッドシートに蓄積します。アウトプットはこんなイメージ。

![CleanShot 2025-02-18 at 10.23.48@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255661/c0018eda-7d59-4c37-b161-053b60e7eb39.png)

### 手順

1. 求人情報をコピーする
1. 以下(1)のようなプロンプトをChatGPTに置いた上で求人情報をペーストする（項目は取得したいものを具体的に入力）
1. 出てきた文字列をスプシにコピー
    1. カンマ区切りだと例えば技術スタックの区切りとごっちゃになってうまくいかないケースがあるので、セミコロン区切りで出力させるのがポイントでした
    1. 列に分割 → セミコロン区切りへ変更 はマクロ(2)にしたら良かったです
        1. クリップボードの取得はできないので、ペーストは自分でやる必要がある

これでスプシへの蓄積を進めました。わかる時間で数十件取れたので、まあ悪くない時間の使い方と思います。  
ずっと同じチャットでやってると雑念が入るので、適宜新規チャットに切り替えると良いです。

#### 手順補足

(1)プロンプト
以下の内容について、CSVとして扱うために
（項目A）,（項目B）,,,
をセミコロン区切りで文字列としてまとめてください。

(2)マクロ
めちゃくちゃシンプルなやつ
```javascript:マクロ.gs
function myFunction() {
  var spreadsheet = SpreadsheetApp.getActive();
  var range = spreadsheet.getActiveRange();
  
  range.splitTextToColumns(SpreadsheetApp.TextToColumnsDelimiter.SEMICOLON);
}
```

## 分析する
技術スタックは、適当に整形してCOUNTIFすれば何の求人が多いかわかります。普通にTSが多かったです。次いでJava,Python。  
蓄積した情報は目視で確認でも十分だったりしますが、情報量が多いのでAIを使っちゃうと手っ取り早いです。

次はGoogleのNotebook LMを使います。  
https://notebooklm.google.com

1. ChatGPTにスプシの内容を全て投げ、マークダウンで整理してください的な指示をします
1. 出力された内容をNotebookLMにテキストでソースに追加します
1. 特に加えたい情報がある場合はURLやPDFをソースに追加
    1. 今回は自社と他社の違いを機械的に出してみたかったので、自社のサービスURLと営業資料をソースに追加しました
    1. あとは適当に他社のサービスURLも追加
1. 質問する

## 以上

やっぱりフォーマットが違うものを眺めて整理するというのは負荷が高いもの。AIに整理させるのは手っ取り早いですね。  
そのあとは煮るなり焼くなり好きにできます。採用頑張るぞー。  
なお目視での確認をせずAIへの質問だけで済ませるなら情報を集めて整理するの整理は飛ばしてもいいですね。

というわけで、よければユートラ繋がったり応募したりしてくれると嬉しいです！

https://youtrust.jp/recruitment_posts/f131d4f674f47a6cfca6aba9950c8feb
【Outsystems】ServerActionからTimerをScheduleする

# 初めに
非同期のAPIを実行し、一定時間後その結果を問い合わせ、後続の処理を行う必要がある。
Timerで後続の処理をするため動的なTimerのScheduleについて調査したので備忘録代わりに書き留めておく。

# 環境
Service Studio Version 11.54.37

# ServerActionからTimerをScheduleする

## Schedule方法
スケジュールしたい時間を```HH:mm```形式で```Timer.{対象のTimer}.Schedule```変数にAssignすればよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/7e61c35d-f4ff-4efd-9bfa-51ca7d1106ea.png)
複数の時間をスケジュールする場合はSapceで区切って複数指定することができる。

## 結果
OccursがDailyに変更される。
他にScheduleの設定がある場合、上書きされる。
指定されたTimerがDeactiveの場合でも、指定の時間に動作するようにActive化される。
そのため、Timerが指定の時間に実行された後、**次の日の同時刻にScheduleされる**。
指定の時間に一度だけ実行したい場合は注意が必要である。

# 最後に
要望は実現できそうだが、Timerの実行時間制限と合わせてベストプラクティスに沿った形で適切に実装する必要がある。
Timerの同期設定を書き換えてしまうため、正常終了を含めTimerの終了時の再Scheduleを不足なく設計しておく必要がある。
【AWS SysOps Administrator - Associate】エラーまとめ

AWS SOAの問題を解いてると、「〇〇エラーの対処法は？」みたいなのをよく見かける気がするので、勉強中に出てきたエラーをまとめてみることにする。
個人用かつ、随時更新なのでご承知おきを。

# I

## InstanceLimitExceededエラー
リージョンで起動できるインスタンスの実行数の制限に達した場合に発生するエラー
対策としては、**EC2クォータ**(インスタンス制限の緩和)の引き上げを申請する

## Insufficient Instance Capacityエラー
EC2インスタンスを起動する際に、**必要なインスタンス容量**が不足している場合に発生するエラー
ここでいうインスタンス容量とは、EC2インスタンスを起動するための必要なリソース(CPUやメモリ)のこと。
対策としては、**EC2インスタンスを起動するAZを変える**か、**インスタンスタイプを変更する**。
Insufficientとは、「不十分」という意味である。

# 追記
4/4 AWS SOA合格しました。
結局エラーらしいエラーは上記2つと、4xxエラーとか5xxエラーくらいしかなかった。
【ExcelVBA】レコードデータが全て「0」判定を配列で行い、レコード1件(行)削除する処理

# はじめに
無駄な変数を定義するより、配列を使ってレコードデータが全て「0」判定を実施する処理を実装することにしました。

## 用意したデータ
用意したデータは下記のとおりです。

![before.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/23ad5053-621c-4361-a77a-91fcb3f48c35.jpeg)

## 実装したソースコード
実装したソースコードは下記になります。

```VB
'配列を使い、配列の要素が全て0のデータを削除する処理
Sub arraytest()
    'ワークシート変数の定義
    Dim ws1 As Worksheet
    '範囲変数の定義
    Dim r As range
    '配列の定義
    Dim array1 As Variant
    'カウント計算の変数
    Dim count As Long
    'カウント変数
    Dim i As Long
    '配列の要素データの変数
    Dim data As Variant
    '最終行変数
    Dim last_row_num As Long
    
    'ws1変数をセット
    Set ws1 = ThisWorkbook.Worksheets("Sheet1")
    '最終行を取得
    last_row_num = ws1.Cells(Rows.count, 2).End(xlUp).Row
    'カウント変数(開始行の行数)をセット
    i = 3
    'カウント変数が最終行の行数を超えるまでループする
    While i <= last_row_num
        count = 0
        Set r = ws1.range("C" & i & ":" & "E" & i)
        array1 = r
        '配列の要素を取り出し、要素が0の個数を計算する
        For Each data In array1
            If data = 0 Then
                count = count + 1
            End If
        Next
        '0の個数が3の時、行削除する
        If count = 3 Then
            ws1.Rows(i).Delete
            
        Else
        '違う場合はカウント変数を1足す
            i = i + 1
        End If
        
        '最終行を取得する
        last_row_num = ws1.Cells(Rows.count, 2).End(xlUp).Row
        
    Wend
    
End Sub
    
```

## 実行した結果
実行した結果は下記になります。

![after.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/64922fd0-f6f5-4a98-9f6b-3b69902e9b72.jpeg)


# 最後に
配列を使った判定を使うと、コーディングが楽ですね。
【ハッカソン】技育CAMP2024 Vol.22で優秀賞を受賞しました！

## はじめに

2024年2月に株式会社サポーターズ主催のハッカソンに参加した話です。

https://talent.supporterz.jp/events/21ff01e0-4e23-4758-9e08-b50c29c51860/

このハッカソンの日程はこんな感じでした。

- 2月7日: キックオフミーティング
- 2月7日〜2月14日: 事前開発
- 2月15日: メイン開発
- 2月16日: 開発&発表

友達の計3人のチームで参加し、今回は合計で19チーム参加していました。

## 開発したもの

**SnapNoteClip**というChrome拡張機能を開発しました。

![screenshot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2906464/7fc043a1-4967-470e-a891-42e6dd7eb070.gif)

https://github.com/MRyutaro/SnapNoteClip

スクショやメモを保存しておける拡張機能で、画像をクリックすることでタブを移動したりできます。

![move-tabs.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2906464/a6ec4c7d-b777-43f7-8bc5-c7ff39dd64bb.gif)

これを使うことでタブが増え過ぎてどのタブにどのページがあるか分からない問題を解決できます。

## 発表

3分間の発表を行いました。

こちらが発表で使ったスライドです。

https://speakerdeck.com/ryutarom/ji-yu-camp2024-vol-dot-22-snapnoteclip

## 結果

優秀賞を頂くことができました！

https://x.com/geek_pjt/status/1891055828339188045?s=46&t=Ex5vntQcGQIgrYGDDKluwg

このプロダクトを通して解決しようとした問題を審査している人に共感してもらえたことが優秀賞を頂けた1番の要因かなと思っています。

## ハッカソン後

2月17日の深夜2時ごろにChromeウェブストアへの申請を行いました。
拡張機能に与える権限の個数によって審査の時間が変わるらしく、今回は5個くらい書いていました。

審査が通り次第追記します。

:::note info
追記
2月19日の21時ごろに無事審査が通りました。（3日かからないくらい。）
:::


## さいごに

最後まで読んでいただきありがとうございました。

これを読んだ人はハッカソンにぜひ参加してみてください。

また、**SnapNoteClip**もぜひ使ってみてください！

https://chromewebstore.google.com/detail/snap-note-clip/jgplanmhjkhipfenhmcnklafelgfpdge?pli=1
Apple純正メモアプリ計算一覧

今更だけど、Apple純正メモアプリで何が計算できるのか検証してみた


```
・足し算
　86+39‎ = 125

・引き算
　39-86‎ = -47

・掛け算
　38*74‎ = 2,812

・割り算
　84/9‎ = 9.333

・小数の計算
　12.2+52.9‎ = 65.1
　12.298+52.9‎ = 65.198
　0.002*45‎ = 0.09

・円周率
6*π‎ = 18.85

・割合の計算方法
❌2:x = 1:5 

・速さ
　60km/h*0.5h‎ = 30 km
　30km/0.5h‎ = 60 km/h
　30km/60km/h‎ = 0.5/時間

・日付
　2025/02/18+10日‎ = 66日 6時間 ←なんか計算できたけど表示がおかしい

・三角関数
　sin60°‎ = 0.866
　cos90°‎ = 0
　tan30°‎ = 0.577

・平方根
　√2‎ = 1.414

・指数
　10^2‎ = 100

・対数
　log2‎ = 0.301
　3log2‎ = 0.903

・異なる単位同士の計算（全て足し算）

　・長さ
　　10cm+1m‎ = 110 cm
　　1mm+1km‎ = 1,000,001 mm
　　※単位の規模が小さい方に合わせて出力される
　
　・水の量
　　10mL+1L‎ = 1.01 L
　　❌10dL+10dL=
　　※単位dL(dl)は使えない

　・時間
　　60s+1m‎ = 120 s
　　60s+1h‎ = 3,660 s
　　1h+60s‎ = 1時間 1 m ←日本語「時間」と英語「m」が混入してる。バグ？
　　1時間+60s‎ = 1時間 1 m
　　1h+60秒‎ = 1時間 1 m
　　1時間+60秒‎ = 1時間 1 m
　　1時間+1分‎ = 1時間 1 m


・微分
❌F’(x) = (2x^3)’=

・不定積分
❌∫(x^2)dx=

・絶対値
❌|-2|+4=
```
【DNS】nslookupの「権限のない回答（Non-authoritative answer）」とは？

`nslookup` コマンドを使ってDNSクエリを行うと、時々 **「権限のない回答（Non-authoritative answer）」** という表示が出ることがあります。

本記事では、
- **「権限のない回答」とは何か？**
- **なぜ「権限のない回答」が表示されるのか？**
- **「権限のある回答」との違いは？**
- **どうすれば「権限のある回答」を取得できるのか？**

これらの疑問を深掘りしていきます。


## 🔹 「権限のない回答（Non-authoritative answer）」とは？

DNSサーバーには、大きく分けて2種類の役割があります。

### 1. **権威DNSサーバー（Authoritative DNS Server）**
特定のドメインに関する正式な情報を保持し、DNSレコードを管理するサーバーです。
- 例えば、`example.com` のドメイン所有者が設定したDNSサーバーが該当。

### 2. **キャッシュDNSサーバー（Recursive Resolver / Caching DNS Server）**
ユーザーのDNSクエリを処理し、過去に取得したDNS情報をキャッシュして素早く返すサーバーです。
- ISPのDNSサーバーやGoogle Public DNS (`8.8.8.8`) などが該当。

### 🔽 「権限のない回答」が表示される理由
`nslookup` で「権限のない回答」と表示されるのは、**キャッシュDNSサーバーが過去の問い合わせ結果を返しているため** です。

```sh
nslookup example.com
```
🔽 結果
```sh
Server:  8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
Name:    example.com
Address: 93.184.216.34
```
ここで `8.8.8.8`（Google Public DNS）がキャッシュしていた結果を返しており、**「Non-authoritative answer」** と表示されています。



## 🔹 「権限のある回答（Authoritative answer）」との違い

| 項目 | 権限のある回答（Authoritative） | 権限のない回答（Non-authoritative） |
|------|---------------------------------|----------------------------------|
| **回答元** | 権威DNSサーバー | キャッシュDNSサーバー |
| **情報の正式性** | 公式な最新情報 | 過去に取得されたキャッシュ情報 |
| **nslookup時の表示** | `Non-authoritative answer` の記載なし | `Non-authoritative answer` が表示される |


## 🔹 **どうすれば「権限のある回答」を取得できるのか？**

「権限のある回答」を取得するには、**権威DNSサーバーを直接指定して問い合わせる** 必要があります。

### ① `nslookup` で権威DNSサーバーを指定
```sh
nslookup example.com ns1.icann.org
```
🔽 結果
```sh
Server:  ns1.icann.org
Address: 192.0.32.1#53

Name:    example.com
Address: 93.184.216.34
```
→ **「Non-authoritative answer」 の表示がなくなり、権威DNSサーバーからの公式な回答になっている！**

### ② `dig` コマンドを使う（Linux / macOS）
```sh
dig example.com +trace
```
このコマンドを実行すると、ルートDNSサーバーから順に問い合わせを行い、最終的な権威DNSサーバーの情報を取得できます。

## 🔹 **なぜ「権限のない回答」が必要なのか？**

キャッシュDNSサーバーを利用することで、以下のメリットがあります。

✅ **DNSクエリの応答速度向上** → キャッシュから取得することで問い合わせ時間を短縮。

✅ **DNSの負荷軽減** → 毎回権威DNSサーバーに問い合わせると負担がかかるため、キャッシュを活用。

✅ **ネットワークトラフィックの削減** → 余計な通信を減らし、インターネット全体のパフォーマンス向上。

しかし、キャッシュのデメリットとして、DNSレコードが変更されても**すぐには反映されない可能性がある**点には注意が必要です。

## 🔹 **まとめ**

- **「権限のない回答」は、キャッシュDNSサーバーから返された過去の情報。**
- **「権限のある回答」は、権威DNSサーバーから直接取得した情報。**
- `nslookup` ではデフォルトで「権限のない回答」が表示される。
- **権威DNSサーバーを指定すると「権限のある回答」が取得できる！**
- `dig +trace` を使うと、DNSの問い合わせの流れを詳細に確認できる。

DNSの動作を理解しておくと、ネットワークトラブルの調査やドメイン設定の確認に役立ちます！💡


## 🔹 **参考リンク**
- [nslookup コマンドの使い方（公式ドキュメント）](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/nslookup)
- [dig コマンドの使い方（Linux manページ）](https://linux.die.net/man/1/dig)
Cloudfrontのコンテンツ圧縮機能でハマった

# はじめに

こんにちは、Gakken LEAPインフラエンジニアの丹羽です。
今回はCloudfrontのコンテンツ圧縮を検証していた際の失敗談をご紹介したいと思います。

# 前提

Webサーバーからレスポンスを返す際、コンテンツを圧縮することで転送量を減らしたりレスポンスを高速化したりするテクニックは広く知られていると思います。

AWS Cloudfrontにも[コンテンツ圧縮機能](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html)があり、S3オリジンの場合は例えば次のような条件下で圧縮されます。

- ビヘイビアで`オブジェクトを自動的に圧縮する`が有効化されている
- キャッシュポリシーで`Gzip`または`Brotli`の圧縮サポートが有効化されている
- キャッシュポリシーのTTL値が0より大きい値に設定されている
- ビューアーリクエストに`Accept-Encoding`ヘッダーがあり、値に`gzip`または`br`が含まれている
- 非圧縮のコンテンツがすでにキャッシュされていない
- オリジンからのレスポンスに`Content-Encoding`ヘッダーがない
- オリジンからのレスポンスで`Content-Type`ヘッダーの値がCloudfrontの圧縮する[ファイルタイプ](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html#compressed-content-cloudfront-file-types)に含まれている
- オブジェクトのサイズが1KB~10MBの範囲内
- オリジンからのレスポンスに`Content-Length`ヘッダーが含まれている
- オリジンからのレスポンスに本文がある

# 起きたこと

ある日、サービスで使用しているCloudfrontディストリビューションのビヘイビアを確認したところ圧縮の設定が有効化されていないものがあり、有効化することで転送量を節約できるのではないかと思い、検証を始めました。

前項で挙げた条件を設定後、curlコマンドで圧縮状況を確認します（Cloudfrontのドメインやファイル名は仮のものです）。

```sh
curl -I -H 'Accept-Encoding:gzip,br' https://cf.example.com/example.file
```

ところが、返ってきたレスポンスに`Content-Encoding`ヘッダーがありません。サイズもS3オリジンにあるものと変わりないように見えます。つまり圧縮が効いていない…？

先の条件を1個ずつ再確認したり、キャッシュ削除を行なったりしましたが状況は変わらず、その日は進展なく終わりました。

# 解決

翌日も動作に変化はなかったのですが、ふと思いついて実際にファイルにダウンロードしてみました。

```sh
curl -v -H 'Accept-Encoding:gzip,br' -o example.file https://cf.example.com/example.file
```

すると、レスポンスに`Content-Encoding`ヘッダーが付いているではないですか！

何が起きたのでしょう？

これまでの確認では、curlの`-I(--head)`オプションを指定していました。このオプションはHEADメソッドでリクエストを送信して、GETメソッドでリクエストした場合に返されるヘッダーのみを取得します。本文は無視されます。

ここで前項のCloudfrontが圧縮を行う条件を思い返しましょう。

> オリジンからのレスポンスに本文がある

そうです、HEADメソッドでリクエストした際にはオリジンからのレスポンスにも本文が存在せず、したがって圧縮も行われないのです。

筆者は本文がないというのをうっかりサイズ0のファイルをS3に置いたようなケースを想定していましたが、なんのことはない、うっかり者は筆者の方でした。

ちなみに一度Cloudfrontのエッジに圧縮されたコンテンツがキャッシュされると、それ以降に実行した`curl -I`には`Content-Encoding`ヘッダーが返ってくるようになります。

# 教訓

今回はcurlでレスポンスヘッダーを取得するには`-I`オプションと思い込んでおり、それが実際にはどのようなリクエストを送信しているかということに思い至らなかったのが失敗でした。

期待した結果が返ってこない時にはどうしても焦りがちですが、そういう時こそ冷静に自分の環境を根本から見直したいものです。

# エンジニア募集

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！
ぜひお気軽にカジュアル面談へお越しください！！

https://gakken-leap.co.jp/recruit/
Salesforceレポートに使えるURLハック

最近使ったので、備忘的に。
Salesforceのレポートは公式にURLパラメータが利用可能です。
https://help.salesforce.com/s/articleView?id=sf.reports_filter_url.htm&type=5

今回は、検索条件のURLパラメータとエクスポートのURLパラメータを使った使用例をいくつ共有します。

## 検索条件を指定する場合のURLパラメータ
```
https://<DOMIAN NAME>.lightning.force.com/lightning/r/Report/<SFDC ID OF REPORT>/view?queryScope=userFolders&fv0=<Filter Value>
```

fv0, fv1, fv2...という形で、レポートに指定する条件の上から順に指定してくことができます。

## CSVをダウンロードする場合のURLパラメータ
```
https://<DOMIAN NAME>.lightning.force.com/<SFDC ID OF REPORT>?csv=1&exp=1&enc=Shift_JIS&isdtp=p1
```
条件指定とDLを同時に指定することは不可でした。
encで「UTF-8」など指定の文字コードを指定可能です。

## カスタムリンクでの相対URLでの式
```
/lightning/r/Report/<SFDC ID OF REPORT>/view?queryScope=userFolders&fv0={!<OBJECT_API_NAME>.Id}
```
数式やカスタムリンクの場合は、相対URLで用意するのがベターですね。

## 画面フローや数式でURLを可変的に使う場合の式
```
HYPERLINK(
	LEFT({!$Api.Enterprise_Server_URL_630}, FIND('/services', {!$Api.Enterprise_Server_URL_630}))+ CASESAFEID({!C_GetReportID.Id}) + "?csv=1&exp=1&enc=Shift_JIS&isdtp=p1",
	"指定した一覧レポートをDL", 
	"_blank"
)
```
こちらは画面フローで利用した数式です。
C_GetReportID：あらかじめレポートを検索しレポートIDを取得しています

## Record Hunterの検索結果をレポートの条件に設定する場合
```
HYPERLINK(
	LEFT({!$Api.Enterprise_Server_URL_630}, FIND('/services', {!$Api.Enterprise_Server_URL_630}))+"lightning/r/Report/"+ CASESAFEID({!C_GetReportID.Id}) + "/view?queryScope=userFolders&fv0="+{!contextId}+"&fv1="+{!selectIdsText} ,
	"検索結果に応じた一覧レポートを表示", 
	"_blank"
)
```
こちらも画面フローで利用した数式です。
C_GetReportID：あらかじめレポートを検索しレポートIDを取得しています
selectIdsText：Record Hunterで選択したレコード一覧を保持しています

## 特記事項
DL指定と検索条件指定は同時に機能しませんでした。
もしDL指定と検索条件指定の両方を同時指定が可能な方法を見つけられた方はご連絡お待ちしております！
OACビジュアライゼーションで列を非表示にする

# はじめに
OAC（**Oracle Analytis Cloud**）でビジュアライゼーションを作成する際に、属性列で並べ替えをしたいことがあると思います。
昇順や降順で並べ替えることができますが、並べ替え用のコードがあれば、その列を使って並べ替えができます。
この記事では、並べ替え用の列の値を使って属性を並べ替えて、並べ替え用の列の値は非表示にする方法を紹介します。

# ワークブックの作成
こんなデータセットで新規のワークブックを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8520e316-d46e-a8e3-3485-6827250169a2.png)

Autonomous Data Warehouse（**ADW**）のSHサンプルスキーマのPRODUCTSとSALESを結合したデータセットです。

# ビジュアライゼーションの作成
製品カテゴリと顧客数で簡単なビジュアライゼーション（棒グラフ）を作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/379453c7-e59d-43cc-3c3a-098f65003b07.png)

X軸に製品カテゴリが表示されていますが、文字コード順に並んでいます。

## 並べ替えと列の非表示
文字コード順ではなく、製品カテゴリIDで並ぶようにしたいと思います。
製品カテゴリIDをX軸の製品カテゴリの上にドラッグ＆ドロップします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/f0bdc421-4a8c-ec4c-868f-06cb63a84be6.png)

希望する順番に並び替わりましたが、本来製品カテゴリID自体は必要ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/2881b2ff-66d8-da2c-d762-216062afb486.png)

そこで、製品カテゴリをクリックして非表示（Hide）に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/7c04a2a7-079c-859e-90a2-fce8a46607c2.png)

不要な列のデータが非表示になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/657189ae-82dd-56ee-796b-97911d77ea67.png)
【Unity】シーン切り替え時のエフェクトを無料で簡単に実装する

シーン切り替え時のエフェクトを
無料で簡単に実装するにはどうすれば良いか
考えてみました。

考えた結果シーン切り替え時の
エフェクト用のアセットを作成する事にしました。

成果物は下記の URL からダウンロードできます。
無料で使用できます。

[Unity Asset Store でダウンロード](https://assetstore.unity.com/packages/tools/utilities/sephiroth-scene-switching-effects-311262)
[Google Drive でダウンロード](https://drive.google.com/file/d/1bspLY8YjXkYPkQDxVyVErsJlP50RP_ni/view?usp=sharing)
[BOOTH でダウンロード](https://giftedstyle.booth.pm/items/6607944)

BOOTH のページに飛ぶと
紹介動画があります。

紹介動画を見ると
どんなアセットか分かりやすいと思います

容量が大きいように見えますが
ほとんどがサンプルグレースケール画像の容量です。
サンプルグレースケール画像と HowToUse.pdf を削除すれば
unitypackage で 600KB 程度です。

***

説明

アプリケーションにおけるシーン遷移エフェクトは、ユーザー体験に大きな影響を与える重要な要素です。

SephirothSceneSwitchingEffects は、以下の 4 種類の遷移エフェクトを提供します：
- 最後にタッチした地点から円が広がるようにシーン遷移
- 任意の一点から円が広がるようにシーン遷移
- シンプルなフェードによるシーン遷移
- グレースケール画像に基づくカスタムシーン遷移

これらはすべて、黒い画面を挟まずシームレスに画面遷移します。

＜グレースケール画像によるカスタム遷移＞
グレースケール画像を使用することで、自分だけの遷移エフェクトを簡単に作成できます。
画像を作成できるスキルがある方は、自由にオリジナルエフェクトを追加できます。
スキルがなくてもご安心ください。多数のサンプル画像が付属しており、それだけでも豊富な演出が可能です。

＜使用方法の概要＞
基本的な使用方法は非常にシンプルです。例えば、最後にタッチした位置から円状に広がる遷移を行いたい場合は、以下のメソッドを使用します：
SephirothTools.SephirothSceneSwitchingEffects.CircleWipeSceneSwitchAtLastTouchPoint(string sceneName);

Unity の SceneManager.LoadScene の代わりに上記メソッドを使用してください。

speed パラメータを調整すれば、遷移速度も自由に変更可能です：
SephirothTools.SephirothSceneSwitchingEffects.CircleWipeSceneSwitchAtLastTouchPoint(string sceneName, float speed = 1f);

＜グレースケール画像を使用したフェード＞
「グレースケール画像に基づくフェード」エフェクトを使用するには、グレースケール画像を以下のフォルダに保存してください：
Assets/SephirothSceneSwitchingEffects/GrayScale/GrayScaleImage

ここに保存された画像は、StreamingAssets フォルダに配置され、実行時に参照されます。

画像の回転が必要な場合は、以下のメニューコマンドを実行できます：
Tools > SephirothSceneSwitchingEffects > ExecSephirothGrayScaleRotateFunction

＜メモリ効率にも配慮＞
このアセットは、前後のシーンを同時に読み込むことがありません。
そのため、メモリの使用量が多いシーン間の遷移でも問題なく動作します。

例えば円が広がるシーン遷移の処理は、以下の手順で行われます：
step1: 現在の画面を Texture2D に変換します
step2: 現在のシーンをアンロードします
step3: 次のシーンをロードします
step4: step1 で用意した Texture2D を画面全体に表示し、指定した地点から円が広がるように徐々に非表示にします

＜カスタマイズオプション＞
境界線を暗くしたい場合は、参考動画をご覧ください。
シェーダーのコメントアウトを解除することで、暗い枠線を表示できます。

＜推奨・補足事項＞
このアセットをインポートすると SephirothSceneSwitchingEffects フォルダが Assets 直下に配置されますが、このフォルダは他の場所へ移動しても正常に動作します。

フェード処理の重複は自動的に制御されます。
フェード中に新たなフェードを実行した場合は、1 回のみ予約され、先行するフェードが完了した後に実行されます。
この仕様は、「自動で 1 回だけフェードを実行する」ようなケースで、フェード中に処理がスキップされてしまい、アプリがフリーズする問題を回避するために、本アセットの設計段階で導入されました。

グレースケール画像のサンプルは以下のフォルダにあります：
Assets/SephirothSceneSwitchingEffects/RecommendedImages

必要なものだけをコピーし、不要なファイルは削除してプロジェクトを軽量化してください。

グレースケール画像は引き伸ばされて使用されます。
違和感のないデザインの画像を使用してください。
縦画面で使用する場合は、縦長の画像を用意することを推奨します。

グレースケール画像生成ツールも付属しています。詳細は以下を参照してください：
Assets/SephirothSceneSwitchingEffects/RecommendImages/Generator/Memo.txt

＜セットアップ手順＞
アセットを使用するには、UseScene フォルダ内のシーンを Build Settings > Scenes In Build に追加してください。
インポート時に自動で設定されますが、削除してしまった場合は再追加をお願いします。

サンプルの DemoScene を試す場合も、Build Settings に含める必要があります。

＜動作環境＞
Android および iOS にて動作確認済み。

***

以上シーン切り替え時のエフェクトを
簡単に実装する方法について紹介しました。

シーン切り替え時にエフェクトがあると
見栄えが良くなるハズなので
是非取り入れて頂けると嬉しいです。

皆さんの開発の助けになれますように
閲覧ありがとうございました。
【備忘録】ラズパイ初期化時に行うこと

## 環境

Raspberry Pi Imagerでラズパイ4にUbuntu Serverをインストールしている環境。

Imager側でSSH設定やWi-Fi設定をしておく。

## （キーボード配列）

| JIS | US |
|:-:|:-:|
| `Shift + 2` | `@` |
| `;` | `;` |
| `Shift + ;` | `:` |
| `@` | `[` |
| `[` | `]` |
| `Shift + @` | `{` |
| `Shift + [` | `}` |


## パッケージマネージャの設定

```bash
sudo apt update && sudo apt upgrade -y
```

## SSH接続の設定

```bash
～いつも使っているPC側の設定～
ssh-keygen -t rsa -b 4096
scp <ローカルの公開鍵のパス> <サーバーのユーザー名>@<サーバーのIPアドレス>:~/.ssh/

～一旦パスワードでサーバーに接続～

cat <サーバーの公開鍵のパス> >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```

https://qiita.com/ryutarom128/items/895105a8b413a9e8775b

```bash
sudo vi /etc/ssh/sshd_config
～変更～
sudo systemctl stop ssh
sudo systemctl start ssh  # なぜかrestartだと反映されなかｔｔ
```

## プライベートIPアドレスを固定

```bash
sudo vi /etc/netplan/50-cloud-init.yaml
```

```/etc/netplan/50-cloud-init.yaml
network:
  version: 2
  renderer: networkd  # なぜかデフォルトだとwifisの中に入っていたから修正
  wifi:
    wlan0:  # デフォルトで入っている
      access-points:
        hogehoge:  # デフォルトで入っている
          password: hogehoge  # デフォルトで入っている
      dhcp4: false
      dhcp6: false
      addresses:
        - 192.168.aaa.bbb/24
      routes:
        - to: default
          via: 192.168.aaa.ccc
      nameservers:
        addresses:
          - 192.168.aaa.ccc
          - 8.8.8.8
          - 8.8.4.4
```

```bash
sudo netplan apply
```

## ファイアウォールの設定
```bash
sudo ufw enable
sudo ufw allow <port-id>
(sudo ufw delete allow <port-id>)
```

## Nginxの設定

```bash
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
```

## Let's Encryptの設定
```bash
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run
```

## USBメモリのマウント