OmniAICreator/Qiita-1.07M huggingface dataset:
BlenderのShaderグラフで動くラインを描画する

この記事は[海洋大の技術系サークルのアドベントカレンダー](https://qiita.com/advent-calendar/2023/kaiyo-tech)の18日目です
# はじめに
ここ最近はずっとUnityで[個人開発](https://qiita.com/YSnami/items/152474788a64173d2fa3)をしていたのですがたまには息抜きでblenderで遊んでいきます。

# 今回作っていくもの
以下のような線が下から上に動いていくようなアニメーションを作っていきます
![Line.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/f7fc641c-5560-2966-2f1f-114c4ee09abf.gif)

# Step1 線の描画
![スクリーンショット 2023-12-20 003808.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/21e94e00-2397-3094-3996-3ce49a7cad46.png)

まずは上の画像のような線をShaderでPlaneに描画します。

Planeを作成し新規マテリアルを作成したら以下のようにノードを接続してください
![スクリーンショット 2023-12-20 005340.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/ba5dcf1c-3454-bba2-ad2e-4db78e7aa9e5.png)

SeparateXYZでPlaneのYの値を取得して0.5以上0.6以下の部分を描画しています。これは僕のイメージなのですがMultiplyで2つの値を接続するとその共通部分が現れる、という感じです。

# Step2 フレームで線が移動するようにする、線の太さの調節をできるようにする
![スクリーンショット 2023-12-20 010723.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/aeb2c676-d172-b3bf-f96e-16b4122f6282.png)
![スクリーンショット 2023-12-20 010732.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/738ce6e7-5512-e76e-5cd1-92166c2790ce.png)
Step1からの変更点は黄色で囲んだ部分です。Thresholdから線の位置が変更でき、Thicknessから線の太さが変えられます。
![スクリーンショット 2023-12-20 011144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/3e6a7796-b0a3-f649-a0e6-096de71d85ad.png)
ここでThresholdに"#frame"と打ちこみます。こうすると現在のフレーム数に応じて値が変化するようになります。
ただこのまま再生するとあまりにも動きが速すぎて一瞬でいなくなってしまうのでThresholdにmathノードのdivideを接続して下の値を100くらいに設定してください（下図）
![スクリーンショット 2023-12-20 011429.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/9c5be6e4-75e7-c1d5-7a13-976537ee5a28.png)
ここで一度再生してみると下のようになります
![Line2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/0338725f-fdff-d935-2a21-ebd24b2d7b01.gif)

# Step3 線をぐちゃぐちゃにする
![スクリーンショット 2023-12-20 012031.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/6de0caa5-5d81-1065-fda4-c41ddf3b402c.png)
![スクリーンショット 2023-12-20 012043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/5a878d43-6d1a-1b2e-3a15-b2746d5053e4.png)

黄色い線で囲んだ部分がStep2からの変更点です。SeparateXYZとLess than／Greater thanの間にミックスカラーノードを挟みノイズテクスチャとミックスさせることで線がぐちゃぐちゃになっていい感じになります。
![Line3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/24c9c181-ce6d-930a-625a-aff268b2836e.gif)
冒頭の動画の物はこれのThicknessを0.010に設定したものになります

# 終わりに
　線を動かす表現は色々なところで使えます。個人的に気に入ってる表現です。Z座標を取得して３Dモデルにこのシェーダーを適用すれば下の動画のようなものも作れます
 ![Grass_and_Line.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620913/e441f599-b304-1643-a63a-384dbb780682.gif)

　シェーダ―はUnityの方でも気になっている部分で、ちゃんとゲームエンジン内部のとこまで理解して自分の思っている画を自由に出力できるようになりたいなあなんて思ってます。
PHP ぼやき日記 2023-12-19

- [次回](https://qiita.com/sj-i/items/c41f72009d8036b2c43b)
- [前回](https://qiita.com/sj-i/items/bda185bfd574d3cbb89d)

不定期に誰に向けるでもなく PHP に関する雑な殴り書きをしている。日付が変わってから変わる前の日付の奴だと言い張って投稿するくらいの雑さ加減。

# Reli 0.11.0 をリリースした
- https://github.com/reliforp/reli-prof/releases/tag/0.11.0
- PHP の `memory_limit` 超過で `Allowed memory size of 〜 bytes exhausted` が出た時にメモリ内容の内訳を吐ける奴
- [メモリ解析機能のドキュメント](https://github.com/reliforp/reli-prof/blob/0.11.0/docs/memory-profiler.md) をわりと充実させたりした

# OSS で `memory_limit` 超過の issue を見つけては[急にメモリ計測をとって去っていく PHP 界の妖怪](https://twitter.com/sji_ch/status/1733215354166661183)としての活動もちょっとした
- https://github.com/PHPOffice/PhpSpreadsheet/issues/3814#issuecomment-1862367771
- "A possible optimization" として挙げていて [PR](https://github.com/PHPOffice/PhpSpreadsheet/pull/3834) で実装してるのはいわゆる [zero page optimization](https://stackoverflow.com/questions/35547665/linux-kernel-role-of-zero-page-allocation-at-paging-init-time/35550384#35550384) 的な dedupe の仕組みを念頭に置いてる
- PHP の配列は CoW なので、ほぼ同じ発想でいけるな、みたいな
- OS や libc のメモリ管理と同じだなと考えると、CoW のコピーを実際に発生させないために PHP の配列を直接書き換えず配列内の要素と何らかの形で関連付けた mutable なデータを別で書き換える、とかの ELF の PIC 的な発想もどこかで活きることがあるのかもしれない

# PHP の readonly クラスは諸事情により簡単にモックできない
- PHPUnit には[できない](https://github.com/sebastianbergmann/phpunit/pull/5113)
- Mockery にも[できない](https://github.com/mockery/mockery/pull/1319)
- 個人的にはなんでできないのかよく分からない
- `readonly` クラスは `readonly` クラスでしか継承できず、よくあるモックライブラリはモック対象の子クラスのコードを動的に生成して読み込むような形で元クラスと互換性のある型を作って機能しているので、生成コードを非 `readonly` クラスと共通化できないのは分かる
- ただ状態は別クラスへ分離してメンバで持てばよいだけで（PHP の readonly は中身まで immutable になるわけではない）、readonly クラスの子は通常クラスと別の形で生成しないといけない制約も元々あるわけなので、特に困らないような気もする
- [それっぽいのを試してみて](https://3v4l.org/bivtj)もふつうに動くので、全然やればできそうな気するけど、皆単に時間がないのか技術的な制約があるのか
- とりあえず readonly 対応のモックライブラリみたいなの作るなら今がチャンスな気がするので、暇なひとは作ってみるのがよいです
Clusterの会場アップロードを楽にしたい

この記事はクラスター [Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cluster) シリーズ2の19日目の記事です

テクニカルアーティストをしているMSA_iです
詳しくは以下を

https://note.com/cluster_official/n/n8c8fbb9ebd8a?fbclid=IwAR3REMqVA6xxWijxNZdWVN-FxrN_K4QQ3FZqdE3JEttHnJ1rdIPYt3deC0g


前回はTAAT626さんの[クラスターに入社してもうすぐ１年](https://note.com/taatn0te/n/n77ef1426a69a)でした
あっという間に一年経ちますよね！実際弊社はスペシャリストだらけだと思います
しかし、ガリガリ黙々とやっていて話しかけづらいなんてことはありません
僕も日々助けられつつ、刺激を受けながら働いています！

# はじめに
Clusterで催しやろうと思うと会場が複数にまたがることがありますよね？
負荷の問題だったり、イベント進行の都合だったりなど理由は様々ですが会場を分けざるを得ないことがあります
また、自分が管理しているワールドに一斉に変更を入れたいとか、場合によってはアップデートによって会場の見た目が変わってしまったり…

そういう時にCCKのアップローダーからポチポチ会場をひとつずつアップロードするの大変ですよね？
アップロードを待っている間、PCを使えないのもつらい…
しかも、アップロードボタンを押して、数分待って、アップロードボタンを押して、待っての繰り返し…
つらい

そこで自動化してみようというのが今回の企画です

# そうだ自動化しよう
流行りの自動化の波に乗って会場アップロードも自動化しよう！
…どのように？？？

# CIツール
世には会場アップロードに限らず、アセットをすぐに使える状態にまとめてパッケージングする作業がたくさんあります
つまりビルドですね
そして、このビルドを自動化したい！という需要がたくさんあります
それらを実行するツールはCIツールと呼ばれています
Unity Build AutomationやCircleCI、Jenkinsなどなど

これ会場アップロードにも使えるんじゃない？

# Let's Try!
実際にやってみようと思いますが、注意点があります
それは、Clusterの会場のビルドが通常の実行ファイルを生成するものではなく、AssetBundleを生成するものだということ
つまりは独自のビルドパイプラインだということになります
さらに言えばCCKによってアップロードまで半自動化されているのでそこに載っかるのが筋がよさそうです

Jenkinsは個人でシュッとやるには環境構築に時間がかかりすぎ、Unity Build AutomationだとUnityの既定のBuildフロー以外は実行できなさそうでしたので、今回はCircleCIを使ってみたいと思います

GameCIも利用します
1. 基本的には以下の通りまずはセットアップしていきます
https://game.ci/docs/circleci/getting-started/

2. ライセンス形態によってUnityのアクティベーション方法が変わるので注意です
CircleCI向けのPersonalライセンスの方は古そうでしたので以下を
https://game.ci/docs/github/activation/#personal-license
Proは以下
https://game.ci/docs/circleci/activation/#professional-license
Windowsでは
`certutil -encodehex -f "Unity_lic.ulf" "Unity_lic_base64.txt" 0x40000001 1>nul`
とかやってBase64にエンコードするのが良さそうです

3. そしてStaticなMethodが実行できるbuild-methodパラメータを使います
https://game.ci/docs/circleci/build/#build-method
config.ymlはこんな感じになりました
```
version: 2.1

orbs:
  unity: game-ci/unity@1.7

workflows:
  build-unity-project:
    jobs:
      - unity/build:
          executor:
            name: 'unity/ubuntu'
            target_platform: 'linux-il2cpp'
            editor_version: '2021.3.4f1'
            resource_class: 'large'
          build-target: 'StandaloneLinux64'
          build-method: 'Editor.Uploader.Upload'
          context: unity # UNITY_ENCODED_LICENSEやらUNITY_USERNAMEやらUNITY_PASSWORD 
```

ここまで来たらあとは簡単です
UnityプロジェクトにStaticな会場アップロード用のMethodを用意してあげましょう
`ClusterVR.CreatorKit.Editor.Window.View.UploadVenueView`
あたりを参考にするのが良いかもしれません

※あくまでもハック的なものだと思ってください
※当然ですが公式でサポートされているものではありませんし、今後こんなことはできなくなるかもしれません

# 最後に

https://amanatsu-knit.hatenablog.com/entry/2023/12/16/000000

「人が足りません」
切実ですね
お力添えいただける方、ぜひお待ちしております
料理は楽しいゲームになる！キッチンでの冒険

料理は、誰もが楽しめる身近なアクティビティですが、料理が苦手な人や、面倒だと感じる人も少なくありません。そこで、ゲーミフィケーションの力を活用して、料理をもっと楽しく、魅力的なものに変えてみませんか？

ゲーミフィケーションとは、ゲームの要素をゲーム以外の分野に応用する手法です。料理にゲーミフィケーションを取り入れることで、新しい楽しさや面白さを引き出すことが可能です。

# ゲーミフィケーションを取り入れた料理の3つの魅力

## 目標や達成感：
ゲームのように、料理にもクリアすべき目標や達成すべきスコアを設定します。新しいレシピへの挑戦や料理の写真をSNSに投稿することで、達成感を味わうことができます。

### アプリ：
[Paprika Recipe Manager](https://www.paprikaapp.com/)：レシピ管理や食事計画の作成で目標達成感をサポート。

### SNS：Instagram：料理の写真を共有し、コミュニティからのフィードバックで達成感を得る。

## 継続性の向上：
ゲームの目標やスコアによって、料理の継続性が高まります。料理の記録をつけたり、オンラインレッスンを受けたりすることで、料理への関心を持続させることができます。

### アプリ：

[Yummly](https://www.yummly.com/)：個々の好みに合わせたレシピで料理の継続を促進。

### オンライン教室：

[MasterClass](https://www.masterclass.com/)：料理のスキルアップを目指すオンラインレッスン。

## 新たな発見や成長：
ゲームのように、新しい食材や調味料に挑戦したり、料理のスキルをアップさせることで、新たな発見や成長を促します。

### アプリ：

[Habitica](https://habitica.com/static/home)：日常の料理タスクをゲーム化し、新しい発見や成長を促進。

# ゲーミフィケーションを取り入れた料理の実例

## 料理のレベルアップ：
新しいレシピに挑戦するたびに、料理のスキルや知識をレベルアップさせます。

## 料理のコンテスト：
料理の腕前を競うコンテストや大会を開催し、モチベーションを高めます。

## 料理のオンラインレッスン：
プロから直接指導を受けることで、スキルアップと新しい発見を促します。

## SNSへの投稿：
料理の記録や写真を共有し、他のユーザーと交流を深めます。

# 最新のゲーミフィケーショントレンドの活用

## アバターやマイルストーン：
料理の進捗をアバターやマイルストーンで視覚化し、継続性を高めます。

### アプリ：
[Habitica](https://habitica.com/static/home)：進捗をアバターやマイルストーンで可視化。


## AIやVRの活用：
AIを活用したレシピ提案や、VRを使ったバーチャル料理体験が新しいトレンドです。これらは、料理の新たな発見や学習に役立ちます。

### VR体験：

[Tastemade](https://www.tastemade.com/)：VRを活用したバーチャル料理体験。

### AIレシピ提案：

[Yummly](https://www.yummly.com/)：AIを活用した個別レシピ提案。

## コミュニティの活用：
料理のコミュニティを通じて、同じ趣味を持つ人々との交流が可能です。

### レシピ共有サイト：

[Allrecipes](https://www.allrecipes.com/)：レシピの共有とコミュニティとの交流。

# まとめ
ゲーミフィケーションを取り入れた料理は、誰もが楽しめる身近なアクティビティを、より楽しく、魅力的なものに変えてくれます。最新のトレンドを取り入れながら、キッチンでの冒険を楽しんでみてはいかがでしょうか。
Djangoでテンプレートを作成する方法

Djangoでは好きなようにビューのテンプレートを作成できる。
作り方の簡単なメモ。

## テンプレートの作り方

### 1.urls.pyにパスを追加
urlpatternsに下記部分を追記します。
```python:urls.py
from .views import MyClass #追記

urlpatterns = [
    path('XXXurl/', MyClass.as_view(), #追記
]
```

### 2.ビュー用のファイルを作成
下記の通り、ビューファイルを作ってTemplateViewをインポートし、テンプレートとしてhello.htmlを指定します（後ほど作成）。
```python:views.py
from django.views.generic import TemplateView #追記

class MyClass(TemplateView): #追記
    template_name = 'hello.html' #追記
```

### 3.テンプレートファイルを作成
まずはプロジェクト直下にtemplatesディレクトリを作成し、その中にhello.htmlという名前のファイルを作ります。
```zsh
cd /your/project/path
mkdir templates
touch templates/hello.html
```

```html:hello.html
Hello World!
```

### 4.setting.pyを修正
デフォルトだとテンプレートファイルのディレクトリが登録されていないので、下記の通りファイルを修正します。
```python:settings.py
TEMPLATES = [
    'DIRS' = [BASE_DIR / 'templates'], #修正
```

### 確認
そして下記を実行すると、ブラウザにhello.htmlの内容が表示されるはずです。
```zsh
python3 manage.py runserver
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522867/323adf1d-e0b6-3187-bf8c-a68ff401a1c0.png)



## TemplateDoesNotExist エラーの対処方法
テンプレートをいじっていると、おそらく遭遇するであろうエラー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522867/02801e62-0d27-eec3-ca84-60817bdb6e89.png)


「テンプレートが存在しない」と言われているので、下記の点をチェックしましょう。

* settings.pyのTEMPLATESのDIRSの内容は合っているか
* ビュー用のファイル名とviews.pyで登録したテンプレート名は一致しているか
* views.pyで定義したクラス名とurls.pyでインポートしたクラス名は一致しているか

以上です。
苦手克服したい「JSXの{}にはJavaScriptの式書く！！」

## はじめに
エンジニアになって3ヶ月経ち、それなりにコードを書いて気づいたのですが…
苦手なところってありませんか？？
いつも間違えてエラーが出たり、なかなか覚えられない文法など…

今日エラーが出たところが私の苦手ポイントでした。
もう流石に引っかかりたくないので、戒めのためにまとめたいと思います。

## 私の苦手ポイント
私の苦手ポイントは、**JSXの{}の中に何を書けばいいのかわからない**ことです。
JavaScriptの式を書くと知識として知っていても使いこなせておらず、同じようなエラーを出してしまいます。
以下、まさに今日出たエラーを具体例として紹介します。

## 具体例
### 背景
クリックすると画面遷移をするボタンがすでに実装されています。
どの画面に遷移するか？によって遷移先とボタンのラベルが異なります。
これまでは、ボタンの種類は2種類だけでしたが、もう１つボタンの種類を増やすことになりました。

### 方針
こちらが元のコードです。
元は三項演算子で書かれてました。ここに、`toPlanC`という分岐を入れることになりました。
```react
<div className="button">
    {toPlanA ? (
        <Button onClick={redirectPlanA}>プランAを選択</Button>
      ) : (
        <Button onClick={redirectPlanB}>プランBを選択</Button>
      )}
</div>
```
分岐が3つになると三項演算子で書くのは難しいので、別で分岐した方が良いだろうと考えました。
if文はJSXの中には書けないので関数としてJSXの外に書きます。

### 実装
```react
const onClickButton = () => {
    if (toPlanA) {
      return (
        <Button onClick={redirectPlanA}>プランAを選択</Button>
      );
    }
    if (toPlanB) {
      return (
        <Button onClick={redirectPlanB}>プランBを選択</Button>
      );
    }
    return (
       <Button onClick={redirectPlanC}>プランCを選択</Button>
    );
  };
```
良さそうですね。
switch文で書いてもいいかもしれません。むしろそっちの方がわかりやすかったかも…
今回はif文で書きました。

さああとはこれをJSXで呼ぶだけです。
### 苦手ポイント
```react
// 型 '() => JSX.Element' を型 'ReactI18NextChildren' に割り当てることはできません。

<div className="button">
	{onClickButton} 
</div>
```
エラーが出ました😭
なぜーーー！！！！

**関数実行してないからだよ！！！**
どうして気づかないの！！！！！

これが私が何回も繰り返してしまう苦手ポイントです…
これでは関数を渡しているだけですね。呼び出せていません。

### 解決
シンプルです。
`{}`の中で関数実行しましょう。
```react
<div className="button">
	{onClickButton()} 
</div>
```
JSX内では`{}`でくくるとJavaScriptの式を埋め込めます。
関数を実行して、式として結果を返してあげましょう。

## 終わりに
何回同じミスをしているんだというぐらい繰り返している気がします。
なんか引っかかってしまうんですよね。
これを機に減らしたいです😢
Google Apps Scriptの設定

GoogleAppsScriptより↓下記を入力して設定を行いました。


var lineToken = "xxxxxxxxxxxxxx"; //LINE notify token
var get_interval = 5; //●分前～現在の新着メールを取得 #--トリガーの時間間隔をこれに合わせる


function send_line(Me){
 var payload = {'message' :   Me};
 var options ={
   "method"  : "post",
   "payload" : payload,
   "headers" : {"Authorization" : "Bearer "+ lineToken}  
 };
 UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}


function fetchContactMail() {
 //取得間隔
 var now_time= Math.floor(new Date().getTime() / 1000) ;//現在時刻を変換
 var time_term = now_time - ((60 * get_interval) + 3); //秒にして+3秒しておく
 
 //検索条件指定
 var strTerms = '(is:unread after:'+ time_term + ')';
 
 //取得
 var myThreads = GmailApp.search(strTerms);
 var myMsgs = GmailApp.getMessagesForThreads(myThreads);
 var valMsgs = [];
 for(var i = 0; i < myMsgs.length;i++){
  valMsgs[i] = " " + myMsgs[i].slice(-1)[0].getDate().getMonth() + "/"+ myMsgs[i].slice(-1)[0].getDate().getDate()
  + " " + myMsgs[i].slice(-1)[0].getDate().getHours() + ":" + myMsgs[i].slice(-1)[0].getDate().getMinutes()
  + "\n[from]" + myMsgs[i].slice(-1)[0].getFrom()
  + "\n\n[subject]" + myMsgs[i].slice(-1)[0].getSubject()
  + "\n\n[Message]\n"+ myMsgs[i].slice(-1)[0].getPlainBody();
 }

 return valMsgs;
}

function main() {
 new_Me = fetchContactMail()
 if(new_Me.length > 0){
   for(var i = new_Me.length-1; i >= 0; i--){
     send_line(new_Me[i])
   }
 }
}




このような記述を行いgmailからLINE　notify tokenを使用し受信したメッサー時をLINEに送信しておりますが
トリガー設定で、新着メッセージが時間（1分ごと）などの通知を行うと永遠に送信されてしまします。
１回きりの送信で良いのですが、受信メールをいちいち既読にしなくてもよい方法などはございますでしょうか？

またLINEに外部の文字データを送信する際にmailを介して行なおうと思うのですが、
良い方法などがあれば教えてください。
よろしく願いいたします。
約十年ぶりにVBAマクロの改修をやってみた

　今年(2023/01-09)の間に携わっていた運用業務で、久々にExcel VBAマクロの改修を行いました。
　技術経歴書を見返したところ、仕事としてマクロをいじったのが社会人一年目の2014年以来でした(世代がばれる)。
　その運用業務は既に終息済でマクロをもう利用しなくなったかつ内部資料作成目的のマクロであり直接運用業務部分に関わらない内容の為、備忘録として今年のアドベントカレンダーネタにさせて頂きます。


 # 改修箇所
1. 図形削除基準変更
2. Copyメソッド行エラー解消
3. 2の改修に伴う新規事象発生の防止
:::note warn
記事作成にあたり、適宜不必要な行の省略やファイル名の変更を行っております。
予めご了承ください。
:::

## 1. 図形削除基準変更
<改修前>

```vb
    'スライド内の図形を検索し、Hogehogeグラフという名前の図形があれば削除
    For Each ShName In pptSld.Shapes
        If ShName.Name = "Hogehogeグラフ" Then
	    ShName.Delete
        End If
    Next ShName
```

<改修後>

```vb
    'スライド内の図形を検索し、グラフが含まれていれば削除
    For Each ShName In pptSld.Shapes
        If ShName.Type = msoChart Then
	    ShName.Delete
        End If
    Next ShName
```

<改修ポイント>
　改修前は「PowerPointスライド内の図形を検索し、特定の名前の図形(グラフ)があれば削除する処理」。
　エラーは出ていませんでしたが、週に一回資料を更新する際前のグラフが消えずに重複する事象が度々発生。
　該当のスライドにはグラフが一枚しか貼られてないのをいいことに、グラフの有無で判定する処理に変更しました。
　改修後の判定に使った「msoChat」は、VBAで図形の種類や範囲を指定する為に使用するShape.Typeプロパティ定数のひとつで、「グラフ」を表しています。画像や吹き出し等、他の定数は[Microsoft公式ドキュメント](https://learn.microsoft.com/ja-jp/office/vba/api/office.msoshapetype)をご覧ください。
 

## 2. Copyメソッド行エラー解消
<改修前>

```vb
    '表修正
    'カウントした値をインデックス番号として修正対象の表を指定
	'表に記載されている直近8日間の値を週始めのセルから順に転記
    With pptSld.Shapes(Table).Table
    For j = 1 To 7
        For CopyCol = 10 To 17
            .Cell(j, CopyCol).Shape.TextFrame.TextRange.Copy
        PasteCol = CopyCol - 7
            .Cell(j, PasteCol).Shape.TextFrame.TextRange.Paste
        Next CopyCol
    Next j
    End With
```

<改修後>

```vb
    '表修正
    'カウントした値をインデックス番号として修正対象の表を指定
	'表に記載されている直近8日間の値を週始めのセルから順に転記
    With pptSld.Shapes(Table).Table
    For j = 1 To 7
        For CopyCol = 10 To 17
            .Cell(j, CopyCol).Shape.TextFrame.TextRange.Copy
        PasteCol = CopyCol - 7
            .Cell(j, PasteCol).Shape.TextFrame.TextRange.Text = .Cell(j, CopyCol).Shape.TextFrame.TextRange.Text)
        Next CopyCol
    Next j
    End With
```

<改修ポイント>
　改修前はクリップボードが他のアプリケーションによって使用されている為か、Copyメソッドの行でほぼ毎回失敗。
　一旦DataObjectによりクリップボードを操作してCopyメソッド行を通したものの、以降のクリップボード操作で引っかかり修正が難航。
　最終的に「クリップボードを使用せず、直接貼り付け先のテキスト内容をコピー元に値を転記させる処理」に変更する事で無事エラー解消。


 ## 3. 2の改修に伴う新規事象発生の防止

 <追加内容>
 
```vb
    '内部資料作成に使用したExcelファイルを保存せずに閉じる
    Application.DisplayAlerts = False
    (中略)
    End Sub
```
 <追加ポイント>
　改修前はWorkbook.Closeメソッドを引数なしで使用。
 　既存の処理では「○○.xlsxを保存しますか？」と尋ねられる事はありませんでした。
　Copyメソッド行の処理内容を変更した事で、マクロ終了直前に保存するかどうかのポップアップが出る様になってしまいました。ここは重要な処理ではない為、ポップアップ表示させない処理を最後に追加して改修完了！ 


# マクロ改修裏話
　ふたつ目の改修途中、下記の内容を記載しました。
 > 一旦DataObjectによりクリップボードを操作してCopyメソッド行を通したものの、以降のクリップボード操作で引っかかり修正が難航。

　ボツになってしまったDataObjectの記述を勧めてくれたのは……実はBing AIでした。
  IT技術者もそうでない人もChatGPTで遊び倒していた間、私はびびってこの手のAIを使う事を躊躇っていました。
  ところが限られた期間でExcel VBAのマクロを修正しなくてはならない状況に陥り、とうとうAIに助けてもらうという選択をしました……そう、現CopilotことBing AIちゃんです。
　この改修をやっていた頃(2023/03-04)と比べて、今は名前も変わり五回までのやり取りならMicrosoftアカウントでログオンする必要さえもなくなりました。あっという間に便利になりましたね。
　まぁ今回に限っては「残念ながら最適な解決方法はご提案してもらえなかった」もとい「先方のご提案は不採用になってしまった」のですが。。。


# おわりに
　毎年恒例になってきた(?)ひいきバンドマン(草野マサムネ)と推しウクレリアン(関口和之)の誕生日お祝いシリーズ、三年目にして遂にポエムを脱出！……出来ましたよね？？？
 
　そしてマサムネさん&ムクちゃんさん、お誕生日(12/21)おめでとうございます！

 (12/22追記)
　Qiita投稿が年一ペースなもので、マクロ本文の可読性に気が回っておりませんでした。
　編集リクエストを送ってくださった方のお陰で、見栄えが向上しました。この場をお借りして感謝申し上げます。
情シスよ、Power BIをさわるんだ！

# はじめに

**M365を管理している情シスへ捧げます。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/1f90d9a0-c675-2b49-3d2e-58a8b38a6218.png)
DALL-E作成

# 姉妹記事

https://qiita.com/akihiro_suto/private/725031627d4f1844b210

# 情シスしかさわれないデータソース

Power BIがさわれれば、組織の状況を簡単に可視化してユーザーや経営層に伝えることができる。

さらに情シスには、**情シスしかさわれないデータソースがある**んです。

- Entra ID関係
- Log Analytics、Sentinelなどのセキュリティ関係

こちらを可視化すれば、組織内での**情シスとしての価値**もあがるはず。

# Entra IDを可視化

Entra IDの診断設定からLog Analyticsにデータを吐き出し、それを可視化する。認証に失敗した人の数や、日々のサインイン数、危険なユーザー数、など様々な分析が可能。

診断設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/d2efb597-a1b3-f058-f08c-2cb38e562b7a.png)


Log AnalyticsやSentinelからは、クエリを書いたらそれをMクエリやデータセット（現在はセマンティックモデル）にエクスポートが可能。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/f621425a-1326-715e-efdc-87b118bc5c05.png)

# Logic Apps からSharaPointリストに出力

Logic Appsを利用してGraph API経由で取得した、例えばEntra IDにしばらくログインしていないゲストユーザーをSharaPointリストに出力しておく。

何人いるのか、どのドメインに多いのか、ログインしていない期間はどのくらいかなど、可視化したいと思った場合でも、Power BIで簡単ですよね。


# Intune も簡単可視化

デバイスの準拠状況をチームで共有したいよね。でもIntune管理者を渡すのは怖い。

それ、Power BIで解決しましょう。

Intuneも、データウェアハウス機能が提供されており、テナントのデバイス状況をPower BIで簡単に可視化できる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/b6c841cc-50f7-78cf-532d-6fd139be13bb.png)

# Email関連も簡単可視化

**上司** 「危険なメールってどのくらいきてるのかなー？」

2秒後

**私** 「こちらですっ！」

Email関連のログもSentinelにためておけば、サクッと提出。高い評価とIT予算をゲット！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/4930fd7a-2db9-6e81-c008-85dbfdb6cca6.png)

# 終わりに

情シスに異動して、さわっていてよかったなと思ったものが、

- **Logic Apps**

と

- **Power BI**

でした。

ログだけ見せても誰も理解できないけど、可視化して見せればみんなが理解できる。次のアクションが決まる。データ加工に最初は時間がかかるけど、慣れればサクサクっとデータができるはず😁Power BIやExcelをうまく使って、組織の状態を周囲に伝えてみましょう。

# 姉妹記事

https://qiita.com/akihiro_suto/private/725031627d4f1844b210
技育アドバンス Vol.4 Graphqlの仕様理解が甘くて転けた話

# はじめに
技育CampアドバンスVol.4にて、Graphqlを使用してリアルタイムでスキーマの共同編集を行えるアプリの開発を行いました。

そこで得た気づきや失敗談について書いていきます。
間違いがあればご指摘いただけると幸いです。

# Graphqlの特徴
初めにGraphqlの特徴について軽く触れておきます

### リクエストの柔軟性
GraphQLでは、クライアントが必要なデータの構造を指定でき、サーバーは正確にその要求に応じたデータを返します。
これにより、過剰または不足なデータの取得を防ぐことができます。

### 単一エンドポイント
伝統的なREST APIとは異なり、GraphQL APIは通常単一のエンドポイントを使用します。これによりAPIの設計がシンプルになり、エンドポイントの管理が容易になります。

### 型システム
GraphQLは強力な型システムを持っており、スキーマ定義によりAPIで利用可能な型やクエリを事前に定義できます。
これにより、APIの使用がより明確かつ安全になります。

### リアルタイム通信
GraphQLのサブスクリプションを使用すると、リアルタイムでデータの変更を購読することができます。

### パフォーマンスの最適化
必要なデータのみを取得することにより、ネットワーク使用量を減らし、パフォーマンスを最適化することができます。

参考記事

https://zenn.dev/nameless_sn/articles/graphql_tutorial


# 今回作ったもの
今回作成したものの詳細です。
その共同編集部分だけ抜粋して紹介します。

エディター部分に独自のマークアップ言語を記述していくことでデータベースを定義できます。

これをもとにオブジェクトを出力したり、さまざまなsqlでのインポート、エクスポートが行えます
これらを共同編集でリアルタイムに行えるようにしました

((字句解析が死んでます....

![スクリーンショット 2023-12-18 22.52.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527736/b4388790-c99f-fd05-4233-a3f33a94d4e4.png)


発表時に使用したスライド🔽

https://docs.google.com/presentation/d/11c_d8L0afDumXIkq_I7PaLniuNadmEG8ORD0o8wZ3Lg/edit?usp=sharing


### 共同編集部分の仕様
 
今回、共同編集部分はこのような構成になっていました

![gfrghbgfghb.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527736/7e03b3eb-8335-cc5c-e3d7-c70a3f257e3b.png)


PostEditor(Mutation)
dataが書きかわった時にバックエンドの情報を送信する

Save(Subscription)
dataの変更を検知して変更された際にdataを返す

このような通信を行なってリアルタイム共同編集を実現しています

# どのような問題が発生したのか
当初私が考えていたフローは以下のような感じでした。
```
フロントエンドからeditorのデータを送信　
-> バックエンドで字句解析を行いjsonに整形して返す
-> 受け取ったjsonをそのまま使用してオブジェクトを生成
```
## 問題1　json型での通信が不可能だった
オブジェクト部分の定義
GraphQLは型の厳密さを重視しているため、標準スキーマ定義には、JSON型は含まれていません。

これに関しては、byte型での通信を行いそれをstring型にキャストしたりjsonに直すなどして対応しました。


## 問題2　字句解析はフロントで行う想定だった。

大前提として、バックエンドとの話し合いがしっかりできいませんでした。

私が「字句解析はバックがやってくれる」と思い込んだまま進めてしまっていたのです...

これらが発覚したのがアドバンスの前日、朝方でした...
手の震えがとまらなかったです...


# まとめ
どちらの問題もコミュニケーション不足が原因ですね...
**話合いは大事！！！**
今後もう一度仕様を見直し、今度こそ完成させます。
Mbed OS 5をPlatformIOでビルドしたときにdarwin_arm64で怒られる時の対処法

## 問題

https://qiita.com/TomiXRM/items/4478dc63301c9919cfc2

こちらの記事を参考にMbed OS 5のコードをやろうと思ったが、このようなエラーが出て動かない。

```zsh:
/Users/shirokuma89dev/.platformio/penv/lib/python3.9/site-packages/urllib3/__init__.py:34: NotOpenSSLWarning: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: https://github.com/urllib3/urllib3/issues/3020
  warnings.warn(

Resolving nucleo_f446re dependencies...
Tool Manager: Installing platformio/framework-mbed @ 6.51504.200716
UnknownPackageError: Could not find the package with 'platformio/framework-mbed @ 6.51504.200716' requirements for your system 'darwin_arm64'
```

## 私の環境

```
shirokuma89dev@shiro89dev.local 
------------------------------- 
OS: macOS 14.2 23C64 arm64 
Host: Mac14,2 
Kernel: 23.2.0 
Uptime: 4 days, 6 hours, 28 mins 
Packages: 57 (brew) 
Shell: zsh 5.9 
Resolution: 2560x1440 
DE: Aqua 
WM: Quartz Compositor 
WM Theme: Blue (Dark) 
Terminal: vscode 
CPU: Apple M2 
GPU: Apple M2 
Memory: 4918MiB / 24576MiB 
```

``` zsh
% pio --version                             
PlatformIO Core, version 6.1.11
```

```
% python3 --version
Python 3.12.0
```

## 解決策

`platformio.ini`に以下を追記する。すでに`platform_packages`が書いてある人は消してこれに上書きする。

```
platform_packages =
   	framework-mbed@~6.51506.231105
```

## 原因

あまり詳しくはわかっていないが6.51504.200716がレガシーすぎてarmに対応していないっぽい？Rosetta入れたりしたけどダメでした。

## これにたどり着いた経緯

こちらのにあるMbed OS 5の最新版が6.51506.231105で先月(2023/12/20現在)だったので、書き換えたらなんかうまくいきました。

https://registry.platformio.org/tools/platformio/framework-mbed/versions

## 終わりに

Apple SiliconのMacBookでロボカップとかの競技をやる人がだんだん増えてきたと思うので、レガシーコードを動かすときに役に立てば嬉しいです。

これはどちらかというと暫定的措置なので、現在メインのプロジェクトをMbed OS 5でやってる人は面倒かもしれませんが6に移行することを検討した方がいいと思います。
phpのfile_get_contentsを利用して、APIを実行しようとしたら403が帰ってきた

## 現象が発生した背景
開発を進めているアプリにて、API実行先仕様が変化した模様。
極力ソースコードをいじらないよう進めようとしたら、403エラーが発生した

## 確認内容
Postman・Curlにては正常に動くけど何故か、PHPのfile_get_contentsにて処理実行時は403が発生した

## 修正内容など
file_get_contentsではなく、curl_execにする事により200が返ってきて正常に動作するようになった

## 補足
リクエスト時のヘッダー・レスポンスなどからAWSにてAPIサーバーを立てていることまでは理解できた
余裕があれば自信で環境構築して原因について追求してゆきたい
Tailwind CSSにフォームプラグインを導入する

## 記事を書くきっかけ
TailWindを使用してラジオボタンのスタイルを記述しようした際に躓いたので本記事を書きました。

## インストール
```
npm install -D @tailwindcss/forms
```
※form関係のスタイルを簡単にリセットするプラグインを提供してくれます。

```:tailwind.config.js
module.exports = {
  theme: {
    // ...
  },
  plugins: [
    require('@tailwindcss/forms'),
    // ...
  ],
}
```
require部分を追記する。

これでselect要素やinput要素のデフォルトスタイルをリセットしてくれます。

## 基本的な使い方
基本的なフォーム要素はユーティリティで簡単に上書き可能なシンプル要素が設定されています。要するにTailWindのユーティリティクラスを簡単に使えますということです。
- input[type='text']
- input[type='password']
- input[type='email']
- input[type='number']
- input[type='url']
- input[type='date']
- input[type='datetime-local']
- input[type='month']
- input[type='week']
- input[type='time']
- input[type='search']
- input[type='tel']
- input[type='checkbox']
- input[type='radio']
- select
- select[multiple]
- textarea

## 参考文献

https://github.com/tailwindlabs/tailwindcss-forms

## さいごに
Reactの学習と並行してTailWindも学習しているのですが、
いまのところTailWindの旨味を実感できない状況です。
（ユーティリティクラスで記述するのにすごく違和感を感じる）
しかし、コンポーネントごとにスタイルを書いていくReactとは相性がいいと思っているので立ち止まらず学習を続けます。

意見コメント等ありましたら気軽にコンタクトしていただけると嬉しいです。
Docker Hubから取得したimageをECR上に設置してみた

## はじめに
(当時)Docker HubのPull数制限に引っ掛かることが原因で、テスト用環境へのデプロイに失敗するという事象に遭遇しました

## 問題点
- 制限に引っかかるとデプロイが出来なくなる等様々な不都合が生じる(特に本番デプロイであれば致命的)
- Pull数制限について今後どうなっていくかも当時不明瞭という状況であった

## 今回の対処法
必要なimageを都度Docker Hubから取得するのではなく、ECR上のプライベートリポジトリ上に設置しておき、そちらを参照するという形をとりました。

### ECR上にプライベートリポジトリを作成する
今回は例として`node`というリポジトリをあげてみます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/973e2a7c-1bf3-cd70-f00b-b26ab6922d13.png)

### Docker Hubからのpull及びECRへのpush
AWS CLIを利用して、以下のような流れで実施することが出来ました。
```sh
# Docker Hubからローカルにimageを持ってくる
docker pull node:18.18.0

# ECRにログインする
aws ecr get-login-password --region ap-northeast-1 --profile test_aws_profile | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com

# Docker Hubから持ってきたimageに、ECR用のタグをつける
docker tag node:18.18.0 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/node:18.18.0

# ECRにpushする
docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/node:18.18.0
```
ECRを確認したところ...お目当ての`18.18.0`が出現しています🍀
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/33112c47-50c8-37bf-2001-b9a64dbe750a.png)

## おわりに
ECRへのログインやpush手順などは他の場面でも活用出来ていますので、この機に学べてよかったと感じています。

## 参考にさせていただいた記事など
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/docker-push-ecr-image.html 

https://matsuand.github.io/docs.docker.jp.onthefly/docker-hub/download-rate-limit/#:~:text=Docker%20Hub%20%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E7%8E%87%E5%88%B6%E9%99%90%E3%81%A8%E3%81%AF&text=%E5%8C%BF%E5%90%8D%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E3%83%97%E3%83%AB,%E3%81%AB%E3%81%AF%E5%88%B6%E9%99%90%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82
さくらのオブジェクトストレージにRubyからaws-sdk-s3を用いてアクセスする

この記事では凡そAWS S3互換であるとされるさくらのオブジェクトストレージに対し、Rubyのaws-sdk-s3パッケージを用いてアクセスする方法を記載します。

どのAPIが互換であるのかは以下の公式マニュアルをご確認下さい。

https://manual.sakura.ad.jp/cloud/objectstorage/api.html

## Gemfile

記事記載時点でのパッケージのバージョンは `1.141` です。

```bash
gem "aws-sdk-s3", '1.141'
```

## Clientの初期化

クライアントは `Aws::S3::Client` です。

```ruby
client = Aws::S3::Client.new(
    region: 'jp-north-1',
    endpoint: "https://s3.isk01.sakurastorage.jp",
    access_key_id: "01234567-89ab-cdef-0123-456789abcdef",
    secret_access_key: "SAMPLETOKENSAMPLETOKENSAMPLETOKENSAM"
)
```

**region**は現在さくらのオブジェクトストレージは石狩第1ゾーンにしか存在しないため `jp-north-1` 固定となります。

**endpoint**は[公式のAWS SDK 利用時の設定パラメータを参照](https://manual.sakura.ad.jp/cloud/objectstorage/about.html#id6)すると `isk01.sakurastorage.jp` とあるのですが、実際にエンドポイントとして設定する場合は `https://s3.isk01.sakurastorage.jp` にする必要があるようです（同ページ下部の[エンドポイントを指定して実行](https://manual.sakura.ad.jp/cloud/objectstorage/about.html#id20)のところには同様のURLの記載があります）。

**access_key_id**、**secret_access_key**にはさくらのオブジェクトストレージのサイト画面で発行したもの、またはパーミッションからパーミッションの追加を行い発行されたものを用います。ただし、サービス側はパーミッションの追加から生成されたアクセスキーの利用を推奨しています（パーミッションの追加から生成されたものはバケットそのものに対する直接的な操作は出来なくなります）。

## Resourceの生成

この記事はClientオブジェクトから直接的にAPIを呼ぶのではなく、よりリソース指向的に扱えるとされるResourceオブジェクトを用いてアクセスします。

```ruby
resource = Aws::S3::Resource.new(client: client)
```

ResourceオブジェクトのコンストラクタはClientと同様のオプションを受け付けます。ここではclientをベースとして作成しています。

例えばバケットの特定フォルダのファイル一覧を表示する場合、Clientで

```ruby
client.list_objects({bucket: "bucket_name", prefix: "folder_name/"})
```

のようにアクセスするか、Resourceで

```ruby
bucket = resource.bucket("bucket_name")
bucket.objects(prefix: "folder_name/")
```

とするかはお好みで使い分けて下さい。

## バケット内のオブジェクトに対するアクセス

基本的なアクセス方法を以下に示します。各APIには様々なオプションがありますので、AWSの公式ドキュメントを参照してください（さくらのオブジェクトストレージに互換がないものは扱えませんが）。

https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html

https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Resource.html

### アップロード

```ruby
bucket.put_object(body: file_path, key: "path/to/name")
```

単一で5GBを超えるオブジェクトは`put_object()`ではアップロード出来ないので、マルチパートアップロードにより対応する必要があります。RubyのAWS SDKには`upload_file()`が用意されておりこれが複雑なマルチパートアップロードを内部的にやってくれるので、`put_object()`よりこちらを呼び出すと良さそうです。

https://aws.amazon.com/jp/blogs/developer/uploading-files-to-amazon-s3/

```ruby
bucket.object("path/to/name").upload_file(file_path)
```

アップロード先に既に同名のオブジェクトが存在する場合はそのオブジェクトは上書きされます。

### 削除

```ruby
bucket.delete_objects({
	delete: {
		objects: objects
	},
})
```

### 列挙

```ruby
found_objects = bucket.objects(prefix: "path/to/folder")
```
NuPhy Air60 V2とusevia.appで解決：iPadとmacOSのIME関連の悩みを一掃

![DALL·E wide blog header.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/98030cf1-3758-378c-538a-20e6775c8abc.png)

## はじめに：USキーボードとiPad、そしてmacOSのIMEに関する困りごと

USキーボードを愛用しているのですが、iPadでの使用に際し、IMEの切り替えがきわめて不便と感じていました。もちろん、[地球儀キーやctrl+spaceでIMEのオン/オフをトグルする方法はあります](https://sumahosupportline.com/ipados-bluetooth-keyboard/#i)が、もっと明確に操作したかったのです。具体的には、「特定のキーでIMEオフ、別のキーでIMEオン」という操作です。最適なのは、macOSと同様に、左cmd短押しでIMEオフ、右cmd短押しでIMEオンになること。これまで様々な手法を試してきましたが、AppleのiPad入力システムの制限により、願い通りの設定を実現することができませんでした。

一方、macOSでも別の問題がありました。[Karabiner-Elementsという神ユーティリティ](https://karabiner-elements.pqrs.org)を使っていますが、キーのタイミングによっては、誤ってcmdキーと認識される事態がしばしば。たとえば、短く左cmdキーを押し、IME OFFにしたつもりが、実際にはcmd+wと解釈されてしまい、ウィンドウが閉じるなどの誤操作が頻発していました。

しかし最近、[NuPhy Air60 V2](https://nuphy.com/collections/keyboards/products/air60-v2)を導入したことで、これらの長年の悩みが一挙に解決しました。VIAというツールでキーマップをカスタマイズすることで、長年の悩みを払拭できたのです。この解決策に大変満足しており、その手順を皆さんにも紹介したいと思います。

### 環境

- NuPhy Air60 V2
- macOS Sonoma 14.1.2（23B92）
- MacBook Pro (14-inch, 2021)

今回はNuPhy Air60 V2ですが、VIAが使えるなら同じことができるはずです（未検証）。

## VIAを使えるようにする

[VIA Usage Guide for NuPhy Keyboards](https://nuphy.com/pages/via-usage-guide-for-nuphy-keyboards)ページに沿って準備します。

- JSONファイルを取得：[JSON files for NuPhy keyboards](https://nuphy.com/pages/json-files-for-nuphy-keyboards)
- [usevia.app](https://usevia.app)ページをブラウザで開く
- Settingsタブで、`Show Design Tab`を`ON`にする
- DesignタブでJSONファイルを読ませる
- キーボードをUSBで接続し、Configureタブで、キーボードを選ぶ

## キーを設定する

- Layer 0で、左Commandキーを選択（ゆっくり点滅する）。
- Keymap > Special > Any を押下
- `MT(MOD_LGUI,KC_HANJ)`と入力
- 同様に、右Commandキーに対して`MT(MOD_RGUI,KC_HAEN)`と入力
    - なぜか勝手に`MT(MOD_LGUI | MOD_RGUI,KC_HAEN)`に書き換えられてしまいます

![SS 2023-12-19 19.12.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/8c1e55ae-8f59-489d-4943-e1a92940f59d.png)

MTとはMod-Tapのことで、QMKのタップダンス機能を使っているとのこと。MT(A,B)で、長押しならA、短押しならBと判定されます。

KC_HANJは漢字キー、KC_HAENはハングルキーです。ほんとうはキーコードを直接指定したほうが明確なのだろうと思いますが、動いているので追究していません。

## おわりに：VIAによるIMEトラブル解消

この記事では、USキーボードとiPad、あるいはUSキーボードとmacOSにおける、IMEの困りごとについて、対応策を紹介しました。NuPhy Air60 V2の導入とVIAツールを活用することで、長年の悩みを解決することができました。

わたしが困っていたのは、iPadでのIMEの不便な切り替えと、macOSでの誤操作の多発でした。これらの問題を解決するために、NuPhy Air60 V2のカスタマイズ機能を利用しました。VIAを用いることで、左右のCommandキーの短押しをそれぞれIMEのON/OFFに割り当てることが可能になり、スムーズな操作を実現しました。これにより、iPadはもちろん、macOSにおいても快適なキーボード操作が可能になりました。

この記事ではNuPhy Air60 V2を扱っていますが、VIA対応のキーボードなら同じことができるはずです。また、Mod-Tap機能で、キーの長押しと短押しで異なるキーを割り当てることは、多くのケースで役立つテクニックではないでしょうか。

### 謝辞

[@taroleo](https://twitter.com/taroleo)さんの下記ツイートが突破口となりました。深く感謝申し上げます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">NuPhy Air60 v2の短い右シフトキーの誤爆を防ぐには、VIAで↑キーをMT(MOD_RSFT, KC_UP) に設定すると安心。押している間だけシフトキーとして動作し、単体で押すと↑キーになるようにできる。 <a href="https://t.co/miSxG5Y3dQ">pic.twitter.com/miSxG5Y3dQ</a></p>&mdash; Taro L. Saito (@taroleo) <a href="https://twitter.com/taroleo/status/1732537993154728306?ref_src=twsrc%5Etfw">December 6, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
ハードコードとは？

:::note
「ハードコード（Hardcode）」とは、プログラミングにおいて、データや設定値をプログラムのコード内に直接書き込むことを指す。ハードコードされた値は、プログラムの実行時には変更することができない。これは、特にプログラムの柔軟性や再利用性に影響を与えることがある。
:::

## ハードコードの特徴と影響
#### 変更の困難さ
ハードコードされた値を変更するには、プログラムのソースコードを直接編集し、プログラムを再コンパイルまたは再デプロイする必要があります。

#### 再利用性の低下
ハードコードされた値が含まれているプログラムは、異なる状況や環境で再利用するのが難しくなります。たとえば、データベースの接続設定がハードコードされている場合、異なるデータベースサーバーでプログラムを実行するのが困難になります。

#### メンテナンスの問題
ハードコードされた値は、メンテナンスを困難にします。変更が必要になった場合、どこにどのような値がハードコードされているかを把握し、それぞれを修正する必要があります。

## ハードコードの例
#### 設定値
データベースの接続文字列やAPIキーなどをコード内に直接記述する。
#### マジックナンバー
コード内に説明なしで直接数値（例：if (x > 10) {...}）を使用する。
#### ファイルパス
アプリケーション内で使用するファイルのパスをコード内に直接記述する。

:::note
ハードコードの代わりに、設定ファイル、環境変数、データベース、または外部の設定管理システムを使用して、プログラムの設定や変更が頻繁に必要な値を管理することが推奨されます。これにより、プログラムを変更することなく、外部から設定を調整することが可能になります。
:::
【競技プログラミング】Nimで割る数が64bit整数でも動作するpowmodを作る

# 前提
この記事は`Nim 1.6.14`で`C++(gcc)`にトランスコンパイルすることを前提に書かれています。

# modpowって？
aをn乗したものをmで割った余りを求めるものです。繰り返し二乗法というアルゴリズムを用いることで、$O(\log(n))$で計算ができます。
計算途中の結果が最大で$(m-1)^2$となるので、mが32bit整数を超えるような値の場合はオーバーフローに気を付けて実装する必要があります。

# 作り方
C++の128bit整数を呼ぶことで、簡単に作成することができます。
```nim
proc mul128(a, b, m: int): int {.importcpp: "(__int128)(#) * (#) % (#)", nodecl.}
proc powmod(a, n, m: int): int =
  result = 1 mod m
  var
    a = a
    n = n
  while n > 0:
    if n mod 2 != 0: result = mul128(result, a, m)
    if n > 1: a = mul128(a, a, m)
    n = n shr 1
  return result
```

# 使用例
64bit整数について確定的に判定できるミラーラビン素数判定を作成するときに、内部で用いる。
```nim
proc mul128(a, b, m: int): int {.importcpp: "(__int128)(#) * (#) % (#)", nodecl.}
proc powmod(a, n, m: int): int =
  result = 1
  var
    a = a
    n = n
  while n > 0:
    if n mod 2 != 0: result = mul128(result, a, m)
    if n > 1: a = mul128(a, a, m)
    n = n shr 1
proc isprime(N: int): bool =
  let bases = [2, 325, 9375, 28178, 450775, 9780504, 1795265022]
  if N == 2:
    return true
  if N < 2 or (N and 1) == 0:
    return false
  let N1 = N-1
  var d = N1
  var s = 0
  while (d and 1) == 0:
    d = d shr 1
    s += 1
  for a in bases:
    var t: int
    if a mod N == 0:
      continue
    t = powmod(a, d, N)
    if t == 1 or t == N1:
      continue
    block test:
      for _ in 0..<(s-1):
        t = powmod(t, 2, N)
        if t == N1:
          break test
      return false
  return true
  ```

  # 参考文献
  [64bit数の素数判定 - Mizar/みざー](https://zenn.dev/mizar/articles/791698ea860581)
HerokuのEco dynoプランで実現する、なるべく安くて立派な個人開発

## 前書き

Freeプランがなくなって、ちょっとした個人開発物の置き場をHerokuから他のサービスに移した方はいらっしゃいますか？いらっしゃいますね？
私も一度はHerokuに置いていた自分用ツールをLightSailに移してHerokuの個人利用から離れたのですが、結局Eco dynoプランに出戻って参りました。
Eco Planは月額5ドルです。5ドルでどれだけのことができるのでしょうか。

## そもそもHerokuって何？
> HerokuはSalesforce社の提供するコンテナベールのクラウド型PaaS（サービスとしてのプラットフォーム）です。

https://jp.heroku.com/about

Herokuを利用することで、ミドルウェアを意識せずともWebアプリを実行、公開することができます。

## Eco dynoプランの概要
月額5ドルで1アカウントにつき月1000時間、HerokuのDynoを利用できるプランです。
複数のアプリを跨いだ利用も可能で、残時間は全てのEco dynoで共有されます。（全アプリで月1000時間を共有する形）
また、Eco dynoは30分アクセスがないと自動的にスリープされるためアプリが使用されていない無駄な時間はカウントされないようになっています。
1000時間を使い切った場合は翌月までEco dynoの利用が停止されるようです（使い切ったことがないた未確認）。

https://devcenter.heroku.com/ja/articles/eco-dyno-hours

かつてのFreeプランと同じようなルールですね。
1アプリを常時起動していたとしても10日分ほどのDyno時間が残ります。
私はアシスタント用のDiscordアプリを一つ常時起動、その他のお試し開発用のアプリは都度起動/停止しながら利用しています。

## 結局何が便利なの？
### 実行環境構築がラク
ここに尽きます。とにかく楽なのです。
開発言語に応じたBuildpacksを指定するだけで、標準的な実行環境の構築が完了します。
Python, Node.js, PHP, Ruby, Go, Java等主要な開発言語は公式サポートされており、特殊な構成でなければコードだけ書いていれば良いようになっています。

### GitHub連携でデプロイがラク
Heroku Pipelinesを使用するとmainブランチにプルリクエストを出したタイミングで変更内容が反映されたReview Appsが自動起動、マージを行うとmainブランチの内容がStaging環境に反映され、PromoteボタンでPromote、といったキチンとしたCI/CDが実現でき便利なのですが、App単体でもGitHubと連携して、指定ブランチに変更があったタイミングで自動デプロイを走らせることができます。これが地味に有用です。

### One-off Dyno(heroku run)が便利
アプリ(Web Dyno)とは別に、heroku runで立ち上がるOne-off Dynoでスクリプト等の実行が可能です。
実行時間分しかカウントされないので、軽いスクリプトであればほとんどDyno時間を消費しません。

### Heroku Schedulerも便利
heroku runをスケジュール実行するためのアドオンです。
予定や天気のDiscordへの通知等、Pythonで書いたスクリプト群を定時実行しています。

## Eco Dynoプラン、おすすめです。

これだけのことが5ドルで実現できるなら、かなりお得なのではないでしょうか。
なんだか夏に書いたnoteの焼き直しのような記事になってしまいましたが、Herokuの賑わいの一助となれば幸いです。

https://note.com/shown_it/n/na6c06c0df93a
【AWS】開発用環境にてFargate Spotへの乗り換えをしてみた

## はじめに
Fargate SpotについてAWS SAAの学習中にその存在を知り、どこかで利用してみたいと考えていました。
とある案件においてピッタリな開発用環境に遭遇しましたので、節約効果を期待して実際に数か月間試してみた際の記録となります。

## 対象の環境について
- 社内の小規模な開発用環境であり、落ちても特に構わないという状況である(重要)
- 既にFargateを利用している
- 開発チーム内に、余りにも落ちすぎて鬱陶しかったりしたら考えようぜ、一旦試してから考えよう的な温かい雰囲気が漂っていました(これも重要)

## 注意点
Fargate SpotではAWS上の余剰リソースを安く(7割引！)利用できる反面、予告なくインスタンスが停止する可能性があります。(※正確には終了2分前に警告を通知してくれます)
その為、本番環境などで利用される際は耐障害性、特に中断への耐性といった観点から本当に問題が無いのか事前に十分検討する必要があります。

## 乗り換え方
既にFargateを利用されている場合であれば、ECSサービスの更新時にCompute options⇒Capacity providerから`FARGATE_SPOT`を選択する事で利用を開始出来るかと思います。
私が設定を試みた際には当初Fargate Spotが選択肢として表示されない状態だったのですが、[こちらの記事](https://qiita.com/hisayuki/items/a84f9f35a4dd8bb17a8f)を参考にさせていただきクラスタの設定を更新したところ、`FARGATE_SPOT`が選択可能となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/fb18cfab-8ce5-0fd7-9b93-7b3fd08944a3.png)

## 乗り換えてみた結果
約5か月前に乗り換えたところ導入直後から目に見えて料金が下がり、単位時間辺りの料金を改めて計算したところ綺麗に7割引となっていました！！
懸念していた停止頻度については様々な要因が絡んでくるかと思いますので一概には言えないとは思うのですが、当環境においては**導入後に落ちたところを見た者がいない**という状況になっており、良い意味で逆に不安になってくるレベルとなっています~~1回落ちるところを見て安心したい~~

### 利用料金
乗り換えは7月下旬に実施しました（赤青が混ざっているタイミング）8月から目に見えて料金が下がっているかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/7b574991-52a1-eb3c-1632-c46090c5dc75.png)


### 利用CPU時間
メモリとほぼ同様の傾向にありますが、料金と見比べることで単位時間当たりのコストが目に見えて落ちていることが分かるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/12123e0f-33ec-4060-f806-627a9dc1624b.png)


### 利用メモリ時間

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/796055af-5056-7ea3-a11c-ebf9a08ddd19.png)

## おわりに
気になっていたFargate Spotを実際に試してみたところ、設定が容易で節約効果が非常に大きく、懸念されていた停止頻度も小さいと大満足の結果となりました！
効果が想像以上でしたので現在は本番利用の検討を進めています🍀
特に以下のような要素を持つ環境であれば導入が容易かと感じましたので、検討してみる価値は大いにあるかと思います！

- 開発用といった理由から落ちても特に構わない(or 耐障害性バッチリな)環境である
- 既にFargateを利用している

## 今回参考にさせていただいた記事
https://qiita.com/hisayuki/items/a84f9f35a4dd8bb17a8f  

https://repost.aws/ja/knowledge-center/fargate-spot-termination-notice
CSSのtransformを使うとスマホで要素が消える件

## はじめに

[CSS Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cascading_style_sheets) 23日目の記事です。

釣り気味のタイトルです。ごめんなさい。
もう少し詳しく書くと、transform等の高負荷になりがちなプロパティを使ったときに、スマホのような非力な環境では要素が消えたり、ブラウザが落ちることがあるよという内容です。

※主にMacを使って開発をされている方向けの情報になります。

### 先に解決方法

1. スマホでの閲覧が想定されている場合は、実装時にちゃんと実機確認をする
2. もし不具合が出ていそうであれば Xcode の Simulator の Debug > Color Blended Layers で確認しながら負荷を減らす

が、主な対処方法になると思います。

## よくありがちなこと

普段、ウェブサイトやウェブアプリの実装時に、検証スピードを上げるために、PC用ブラウザの開発ツールのスマホビューを使用したり、ちょっと頑張った際にはXcode等にある検証ツールを使って、表示の確認をしていることが多いと思います。

ただ、ここには罠があります。

PC用ブラウザの開発ツールや、開発環境の検証ツールでは完璧に表示されているのに、特定環境で一部の要素が表示されない場合やブラウザが落ちるという現象が発生することがあります。

はじめてこれに出会った際には、まさに「おま環」という感じがして、手元の開発ツールや検証ツールで確認して「再現できず」と返答してしまう可能性があるのですが、一呼吸おいて実機で確認してみましょう。

## Color Blended Layersを使ってみよう

怪しげな挙動を見かけたら Xcode の Simulator の Debug > Color Blended Layers を使って確認してみてください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620149/7512f0bf-cd2c-8087-2097-2986c2d0ccd2.png" width="200" alt="Color Blended LayersをOFFにしたサンプル画面">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620149/b7c60149-f3a7-c382-5c66-3f338f7174fa.png" width="200" alt="Color Blended LayersをONにしたサンプル画面">

1枚目はColor Blended LayersがOFFの状態、2枚目はONの状態になります。ONの際には画面に緑と赤の色がついていると思います。

この赤い箇所が負荷の高いところで、赤い箇所が増えすぎると表示に不具合のでる可能性が高くなります。

## どういうことをしたら赤い状態になるのか？

要素が静止している場合と、アニメーションしている場合で若干の違いはありますが、基本的には transform 等を使って下の要素との重なりがあるときに赤い状態となります。

例えば静止している状態だと`transform:translate3d`だったり`transform:rotateX`を使用すると赤い状態が発生しますが、`transform:translateX`や`transform:rotate`では緑のままです。

アニメーションしている場合では`transform:translate3d`や`transform:rotateX`に加えて、`transform:translateX`や`transform:rotate`でも赤い状態になります。

## どのように赤から緑にするのか？

アニメーションでいうと`transform:translateX`ではなく`position`と`left`の組み合わせを検討してみるという手はあります。たしかに`transform:translateX`の方が動きはなめらかで、`position`と`left`の組み合わせは若干劣ります。環境や場合によってはカクつくということもあるかもしれません。ただし赤い状態から緑の状態にはなります。

3D関係のプロパティを使っているときは、他の代替手段があまり思いつかないということもありそうです。

滑らかさや3D関係のプロパティが必要な箇所のみを残し、位置（leftやtop）、大きさ(widthやheight)は目立たない範囲で置き換えていく、場合によっては変形する箇所やアニメーションする場所を絞る等の判断が必要になってくるかもしれません。

## とはいえ……

ブラウザ側の処理が上手くなったのか赤くなるプロパティ等々が減っていたり、ハードウェアのスペックが向上しているのもあり、以前より気にしなくても大丈夫な範囲は増えていると今回の記事を書いていて感じました。

ご参考になれば🙏🏻
Nimでセマンティックバージョン比較

phpのversion_compare関数のような関数を作りたかった。


```Nim
import strutils

proc compareVersions(version1, version2: string): int =
  var parts1 = version1.split('.')
  var parts2 = version2.split('.')

  # メジャー、マイナー、パッチと順に確認する。
  for i in 0 .. min(parts1.len, parts2.len) - 1:
    let num1 = parseInt(parts1[i])
    let num2 = parseInt(parts2[i])
    
    if num1 < num2:
      return -1
    elif num1 > num2:
      return 1

  # 桁数が多い方が大きいとする
  if parts1.len < parts2.len:
    return -1
  elif parts1.len > parts2.len:
    return 1

  return 0
```

## 試しに実行してみよう

```Nim:test.nim
# ここはさっきと同じ。
import strutils

proc compareVersions(version1, version2: string): int =
  var parts1 = version1.split('.')
  var parts2 = version2.split('.')
  
  for i in 0 .. min(parts1.len, parts2.len) - 1:
    let num1 = parseInt(parts1[i])
    let num2 = parseInt(parts2[i])
    
    if num1 < num2:
      return -1
    elif num1 > num2:
      return 1

  if parts1.len < parts2.len:
    return -1
  elif parts1.len > parts2.len:
    return 1

  return 0


# 使用例
let storedVersion = "2.3.1"
let currentVersion = "2.3.0"

let result = compareVersions(storedVersion, currentVersion)

if result > 0:
  echo "アップデートが必要です."
elif result < 0:
  echo "アップデートは不要です."
else:
  echo "バージョンは同じです."
```

test.nimを作ったら下記で実行

```Shell
$ nim c -r test.nim
```
【UTF-8-SIG】ChatGPTがお好きなエンコーディングの正体

### はじめに

※この記事は「[LTSグループAdvent Calendar 2023](https://qiita.com/advent-calendar/2023/ltsgroup)」に参加しています。

はじめまして！[株式会社エル・ティー・エス](https://lt-s.jp/)のSakuragiiと申します。

私がChatGPTにPythonのコード生成を依頼した際、csvファイルの出力におけるエンコーディングとして、しばしばUTF-8-SIGの使用が推奨されます。UTF-8を使用するとExcelで開いた際に文字化けが起こることがありますが、UTF-8-SIGを使うとその問題が解消されることに気づきました。この経験から、UTF-8-SIGの信頼性とその利点について、備忘録としてまとめてみることにしました。

---
### 当たり障りのない結論
UTF-8-SIGは、特定の環境とニーズに非常に合致するエンコーディング方式ですが、その特性を深く理解し、適切な状況で使い分けることが重要です。

---
### そもそもエンコーディングとは何か？
エンコーディングとは、人間が理解する文字や記号をコンピュータが処理できるバイナリ形式に変換する方法です。世界には多様な言語があり、それぞれの文字をデジタル化するために様々なエンコーディング方式が開発されています。ASCII、ISO-8859-1、UTF-8、UTF-16など、さまざまな方式があり、それぞれに利点と制限があります。

---
### UTF-8とは何か？
UTF-8は、国際的な文字エンコーディング標準の一つで、世界中のほぼ全ての文字を表現できます。この柔軟性と拡張性により、UTF-8はウェブ開発やソフトウェアの国際化において非常に人気があるようです（実際私の入っている開発PJでも標準エンコーディングとなっています）。UTF-8は可変長エンコーディング方式を採用しており、一般的なASCII文字に対しては1バイトを使用し、それ以外の文字に対しては最大4バイトを使用します。

---
### UTF-8-SIGとは何か？
UTF-8-SIGは、通常のUTF-8エンコーディングの一種で、ファイルの最初にBOMと呼ばれる特別なシーケンスが含まれています。

---
### BOMとは何か？
BOM（Byte Order Mark）とは、テキストファイルの先頭に配置される特定のバイトシーケンスで、主にファイルのエンコーディング形式とバイト順（エンディアン）を識別するために使われます。UTF-8のBOMは、16進数で **`EF BB BF`** と表されます。これは、バイナリ形式では **`11101111 10111011 10111111`** となります。これらのバイトは、テキストファイルの最初に配置され、ファイルがUTF-8でエンコードされていることを示します。

---
### BOM付きとBOM無しの違い
BOM付きUTF-8（すなわちUTF-8-SIG）は、ファイルの先頭にBOMを含むことで、そのファイルがUTF-8であることを示します。これに対し、BOM無しUTF-8はファイルの先頭にBOMを含まず、よりシンプルで広く普及している形式です。BOMの有無は、特にファイルを開くソフトウェアによって、異なる動作を引き起こす可能性があります。

---
### BOM付きが有用な場合
BOM付きのUTF-8-SIGは、特にMicrosoftの製品、例えばExcelでの使用に適しています。Excelなどの一部のソフトウェアは、BOMを使用してテキストファイルがUTF-8でエンコードされていることを認識し、適切に表示します。これは、文字化けを防ぐのに特に効果的です。

---
### BOMなしが有用な場合
一方で、ウェブ開発やUNIX系のシステムでは、BOMなしのUTF-8が一般的に推奨されます。BOMがあると、ウェブブラウザや一部のテキストエディタ、プログラミング言語のコンパイラなどがファイルの内容を正しく解釈できないことがあります。特に、HTMLやCSSファイルでBOMが存在すると、ページの表示に影響を及ぼす可能性があります。

---
### おまけ
- Windowsのメモ帳でテキストファイルを保存すると、自動的にBOMが付加されます。

---
### 参考
https://qiita.com/mitsutoyo32104/items/76335bb6e783d55f311c
https://qiita.com/showmurai/items/60d32006d13512ffeaff
WINGサービスが、誰を対象としたサービスか探ってみる

# この記事の趣旨
独自ドメインを持つ知り合いがWebサーバー（ヒアリングしたらWordPressで十分）を更新したいと言っていたので、**ConoHaのVPNをお勧め**したが、難色示してきたので **「素人にも楽なサービスねーかな」** さがしてみたらConoHaにあった。

$\tiny{私が、転職をしてまでこの仕事を引き継ぐつもりでいたのですが、}$
$\tiny{給与が院卒同水準からやり直しになると知って、やる気が失せた。手取りは少なくても年６本無いと出て行けない。}$
$\tiny{やりたい仕事だったけど。}$

# ConoHaのサービス 


ConoHaのサービスと言えば、**VPN** だと思います。
VPNでWebサーバーも用意できるし、WordPressもKUSANAGIを使えば楽に構築も可能なので、WINGを契約するのは意味があるのかなと思っていました。
VPNとWINGの大まかな違いは知っているものの、使わずに評価するのもね。

# ConoHaの WING 
主な特徴は次の通りっぽい
+ 初めからWordPressが搭載
+ 独自ドメインも使える（もちろんDNS変更は必要だけど）
+ Webメールも使える

私にとってのWINGの印象は、このはちゃんが、エナジードリンクを届けてくれるサービス。

# 今回の目的
よく相談をいただく内容を抜粋してまとめる

+WordPressを利用できる環境を作ること
+Webメールを使えるようにすること
+メールアドレスを使えること。通常使うメールアドレスとは別で良い。

# いざ契約してみる

1.ConoHaのコントロールパネルからWINGを選択
2.サーバ追加を選択
3.プランを選択（ベーシックで十分）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212894/7ecc1c26-ffcf-ab31-51a7-b533cf73f4b1.png)

30秒でこの画面までたどり着く。
ここでは、「今は利用しない」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212894/93ed2810-53b3-8b74-ed9d-5e7330ea3c66.png)

続いてメールアドレスを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212894/7fbee5a5-4582-212d-6600-6c75a7636ca4.png)

次にWordPressの要「サイト管理」
メールアドレスは作成したものを入力可能
ユーザー名とパスワードは管理用のものなので任意のものを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212894/2416f3f8-98aa-a3ef-3f77-81ce80bb4e22.png)

とりあえずWordPress設置
WordPressの設定方法はどこも同じだよね。省略。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212894/212f15a5-471d-a474-6ecf-fb564dc53eb7.png)

Webメール
普通に便利。VPNになんでこのサービスないの？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212894/088fef95-dc35-60b6-4c86-202fe5ce3e26.png)

とりあえず、ここまでConoHaな画面を操作している時間だけは20分かからずに完了です。

便利。

目的は完了です。

# 企業などで使う事を考えると
DNSの設定変更は必要だと思いますが、外向けのがわだけはConoHaで作ってしまい、リバースプロキシかなにかで
ConoHaに流す方法もありですね。
企業で使うメールアドレスを流用するのは難しいかもだけど。
ごく小さな団体で使うにはWingは便利だと思います。メールとWordPressだけを使いたいなら。

月額2000円切って、これだけ使えるならWINGで良い。設定も簡単。


# 来年の記事
どうにかしてVPNでWebMailを使える記事を書きたい。


ConoHa事務局さんへ。連絡先は別に送ります。
【rails】rspecでENVをスタブ化した際に詰まった話

# はじめに
あるシステムの自動テストをrspecで作成していた際に、`Please stub a default value first if message might be received with other args as well.`というエラーが表示され詰まった時のお話です。

# 問題
下記を含んだテストコード実行した際にエラーが表示されました。
~~~
allow(ENV).to receive(:[]).with('HOGE').and_return('111')
~~~
エラーについて、chatgptに聞いてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3382528/286bed48-1b00-2638-ca3f-8a2bcb2e7409.png)
ENVの[ ]メソッドが`HOGE`以外の引数で呼び出されている箇所が存在することが問題のようです。

# 解決策
chatgptの回答のように、allow(ENV).to receive(:[]).and_call_originalを追加しました。
~~~ruby
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:[]).with('HOGE').and_return('111')
~~~

# おまけ
chatgpt以外にも調べたところ、[こちら](https://qiita.com/vivid_muimui/items/5e0bc229a688afefbce2)にも記載されていますが、環境変数は様々な箇所で呼びされることが多いため、ENVのスタブ化は今回のような問題が発生しやすいみたいですね。

# おわりに
以前rspec実装した際にもallowを使用して外部へのAPI通信をスタブ化した経験はありましたが、今回初めて見たエラーだったので詰まってしまいました。エラーに関して調査し解決できたので、スタブ化に関する理解が少しは深まった気がしました！

# 参考
https://qiita.com/vivid_muimui/items/5e0bc229a688afefbce2
外部データを購読するuseSyncExternalStore

## useSyncExternalStore
`useSyncExternalStore`はReactが提供するブラウザAPIなどの外部の状態ストアと同期するためのhooksです。
型情報はシンプルで以下のようになっています。
```ts
export function useSyncExternalStore<Snapshot>(
    subscribe: (onStoreChange: () => void) => () => void,
    getSnapshot: () => Snapshot,
    getServerSnapshot?: () => Snapshot,
): Snapshot;
```
`subscribe`が外部の状態ストアを購読する関数、`getSnapshot`が現在の外部の状態ストアから値を取得する関数、`getServerSnapshot`はサーバー上で実行された時に初期値を返すような関数です。
`subscribe`に渡す関数がレンダリング間で異なっている場合は、再購読することになるのでコンポーネント外で宣言するか、`useCallback`で宣言するようにしてください。
`subscribe`が引数に持つ`onStoreChange`が呼び出されると、Reactは対象のコンポーネントを再レンダリングします。

## 例: 状態ストアを自作する
値がアプリケーション全体で共有され、その変化によって利用するコンポーネントが再レンダリングされるような仕組みを`useSyncExternalStore`を作成します。
簡単な条件としてカウンターを考えていきます。まずは、値を定義します。アプリケーション全体で利用するために、グローバルに定義します。
```tsx
let count = 0;
const getSnapshot = () => {
  return count;
};

export default function App() {
...
```
SnapShotとしてコンポーネントから読み取るための関数も定義しています。
そして、`count`に対する変更を定義します。今回は+1だけする`increment`を定義します。
```ts
const increment = () => {
  count++;
};
```
このままでは`count`の更新が伝わらないため、`subscribe`を定義してReactに更新を伝えられるように準備します。
```ts
let listeners: (() => void)[] = [];

const increment = () => {
  count++;
  emitChange();
};

const subscribe = (listener: () => void) => {
  listeners = [...listeners, listener];
  return () => {
    listeners = listeners.filter((l) => l !== listener);
  };
};

function emitChange() {
  for (let listener of listeners) {
    listener();
  }
}
```
`listeners`変数を定義して、`subscribe`が呼び出された時に、引数の`onStoreChange`を詰め込むようにしました。さらに、`listeners`が全て実行される`emitChange`を定義して、`count`が更新される(今回だと`increment`が呼ばれる)度に`listener`を発火して変更毎にレンダリングを起こして画面へ反映を試みるようにします。

それらを用いて`useSyncExternalStore`を使えばアプリケーション全体で値が共通され、値の更新ごとにレンダリングが走るようになります。
```tsx
export default function App() {
  const snapshot = useSyncExternalStore(subscribe, getSnapshot);

  return <button onClick={increment}>{snapshot}</button>;
}
```

https://codesandbox.io/embed/vyr5yd?view=Editor+%2B+Preview&module=%2Fsrc%2FApp.tsx

今回の仕組みに限らず、基本的には`useSyncExternalStore`ではなく、`useState`や`useReducer`、`useContext`やその他状態管理ライブラリなどを利用して記述するようにしましょう。
【Zod】前後のスペースを削除する方法

## `trim`を使用する

`trim`を以下のように使用することで、文字列の前後のスペースが削除されます。

```js
const sampleSchema = z.object({
  name: z
    .string()
    .trim()
    .nonempty('名前を入力してください')
})
```