OmniAICreator/Qiita-1.07M huggingface dataset:
【Unity】ShadowCaster2DのShapeを自動で作るEditor拡張

# はじめに
https://x.com/ayaha__401/status/1715611322111734226?s=20

動画のように1クリックでShadowCaster2Dの影の範囲を作ってくれるEditor拡張を作りました。

# ソースコード
https://github.com/ayaha401/AutoCreateShadowCaster2DShape

# 作ったわけ
2Dゲーム作ってる友達が『毎回チマチマ設定するのめんどくさいな～』と嘆いていたので作りました。
機能は
* `SpriteRenderer`のMeshに対応した形でShapeを作る
* `CompositeCollider2D`からTilemapの形でShapeを作る
* 作った形をまとめて消す

があります。

# 解説
## 既存のShadowCaster2Dを拡張する
今回は既存のインスペクターの見た目の下に自分の追加項目を付け足すのが目標です。
`ShadowCaster2D`は最初からUnityにあるComponentで、これをEditor拡張するには
```C#
[CustomEditor(typeof(ShadowCaster2D))]
public class ShadowCaster2DAutoShapeEditor : Editor
{
    var loadAssembly = Assembly.Load("Unity.RenderPipelines.Universal.Editor");
    var type = loadAssembly.GetType("UnityEditor.Rendering.Universal.ShadowCaster2DEditor");
    if (type == null)
    {
        return;
    }
    var editor = CreateEditor(target, type);
    editor?.OnInspectorGUI();

    // この下に自分で付け足したいEditor拡張内容を書く
}

```
とします。
```C#
var loadAssembly = Assembly.Load("Unity.RenderPipelines.Universal.Editor");
```
をアセンブリが違うのでこうしないと`type`は`null`になります。

```C#
public override void OnInspectorGUI()
{
    base.OnInspectorGUI();
}
```
にすると標準のインスペクターの見た目ではなく、Debugモードでの見た目になるので使いません。

## SpriteRendererのMeshに沿ってShapeを作る
```C#
// 重心を使って頂点を時計回りにソートする
Vector2 center = Vector2.zero;
foreach (Vector2 vertex in vertices)
{
    center += vertex;
}
center /= vertices.Length;

Array.Sort(vertices, (v1, v2) =>
{
    float angle1 = Mathf.Atan2(v1.y - center.y, v1.x - center.x);
    float angle2 = Mathf.Atan2(v2.y - center.y, v2.x - center.x);
    return angle2.CompareTo(angle1);
});
```
ここが一番重要です。`SpriteRenderer`のクラスから簡単に頂点情報は手に入れれますが、これをそのまま`ShadowCaster2D`に代入するとShapeの形が変になります。
これは頂点情報の格納されてる順番がぐちゃぐちゃなので起きます。

ぐちゃぐちゃな並び順を一周回るようにソートします。

重心を求めて、重心から頂点の角度を計算し、それでソートします。
凸型だったり、特殊形状だとこの方法はおそらくうまくいきません。

```C#
Vector3[] hogePath = new Vector3[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
    hogePath[i] = vertices[i];
}
shapePathField.SetValue(shadowCaster2d, hogePath);
shapePathHashField.SetValue(shadowCaster2d, UnityEngine.Random.Range(int.MinValue, int.MaxValue));
meshField.SetValue(shadowCaster2d, new Mesh());
```
あとは`ShadowCaster2D`にSetして完了です。`Vecter3`じゃないとうまくSetできなかったので`Vecter3`にしてます。

## CompositeCollider2DからShapeを作る
`SpriteRenderer`の時ほど難しくないです。
```C#
for (int i = 0; i < tilemapCollider.pathCount; i++)
{
}
```
最初の`For`はPathの分だけ繰り返します。これはタイルマップは宙に浮いているマスなどがあるので、浮いているマスの分だけ別々にGameObjectを作って処理するからです。
`CompositeCollider2D`から頂点情報をGetすると並び順に問題はないのでさっきのようにソートする必要性は無いです。
Getして`ShadowCaster2D`にSetして完了です。

## 保存できるようにする
折角Shapeを作ったのに保存できなかったら意味が無いです。
```C#
EditorUtility.SetDirty((ShadowCaster2D)target);
```
これを書いて保存できるようにします。
WordPressの固定ページで抜粋・カテゴリ・タグを使えるようにする方法

WordPressのカテゴリとタグは、初期状態では投稿のみで利用できるようになっています。
固定ページでもカテゴリやタグを設定できるようにしたい場合には、
有効化しているテーマのfunctions.phpに、
または、プラグイン「my-plugin/my-plugin.php 」に
以下のコードを記述することで、設定できるようになります。


```php
/**
 * ↓追加
 */

/*
 *  固定ページで抜粋を有効化
 */
add_post_type_support('page','excerpt');

/*
 *  固定ページでカテゴリを使えるようにする方法
 */
/*
 *  固定ページでカテゴリーを有効化
 */
function add_category_to_page() {
	register_taxonomy_for_object_type('category','page');
}
add_action('init','add_category_to_page');

/*
 *  カテゴリアーカイブに固定ページを含める
 */
function add_page_to_category_archive($query) {
	if ($query->is_category== true && $query->is_main_query()) {
		$query->set('post_type', array('post','page'));
	}
}
add_action('pre_get_posts','add_page_to_category_archive');

/*
 *  固定ページでタグを使えるようにする方法
 */
/*
 *  固定ページでタグを有効化
 */
function add_tag_to_page() {
	register_taxonomy_for_object_type('post_tag','page');
}
add_action('init','add_tag_to_page');

/*
 *  タグアーカイブに固定ページを含める
 */
function add_page_to_tag_archive($obj) {
	if (is_tag()) {
		$obj->query_vars['post_type'] = array('post','page');
	}
}
add_action('pre_get_posts','add_page_to_tag_archive');
```

追加前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592268/312fe822-2a63-9f2e-0d77-09f8efd1b8a5.png)
追加後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592268/177a44a4-9cf3-b5da-878f-55126044c5ac.png)
【Jenkins】 slaveサーバ（ノード）を指定する方法

```groovy
node('ノード名') {
    '''作業内容'''
}
```
例：ノード名が`slave100`の場合
```groovy
node('slave100') {
    '''作業内容'''
}
```
`node`の内側で書かれた作業は指定したノードを使って行われる。
何も指定しない場合はランダムにノードが選ばれる。
【AWS】Next.js×Rails API ホストベースルーティングの設定

# 概要
- Railsのみで構成していたアプリケーションを、Next.js×Rails APIのSPA構成に変更した
- SPA化に伴い、AWS本番環境の設定を変更した
- その中の一部として、ALBにホストベースルーティングの設定を追加し、Frontendのドメインをwww.example.com、Backendのドメインをback.example.comとした
- その際、ALB以外にも設定が必要な箇所があったためまとめ

> 参考）ホストベースルーティング設定

https://www.clara.jp/media/?p=6155

ホストベースルーティングの基本的な設定はこちらを参考に実施した。

# 環境
- Backend
    - ruby 3.0.2
    - rails 6.1.4 (APIモード)
- Frontend
    - react 18.2.0
    - next 13.1.6

# インフラ構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/e39246e4-8deb-892f-c13c-6f82fef0babe.png)


# 必要な設定について
## 証明書、DNSの設定
- Rails単体構成で使用していたこれまでの証明書
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/30d41137-e6f4-a907-5ff0-43d2ca093062.png)

back.example.comへの通信もSSL化するため、「*.example.com」を追加する。

### 設定手順
1. リクエスト
2. 証明書をリクエスト
    証明書タイプ：パブリック証明書をリクエスト
3. 完全修飾ドメイン名　に、下記の２つを追加
    - `www.example.com`　（既存のドメイン名と同様）
    - `*.example.com`　　（新しく追加するドメイン名）
   検証方法：DNS検証、キーアルゴリズム：RSA2048
4. Route 53でレコードを作成

- 以上の手順で作成された証明書
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948830/adb5ef17-5428-30d4-4d67-48973d1ca431.png)


## ALBへの紐付け
### 設定手順
1. ロードバランサ→HTTPS:443リスナ→リスナーの編集
2. セキュアリスナーの設定
3. デフォルトのSSL/TLS証明書
    - `ACMから`
    - `www.example.com`(新しく追加した方の証明書 IDを選択)

新しく追加した証明書の`関連付けられたリソース`として、このALBが設定できていればOK。

# 動作確認
ここまでの設定で、

- `https://www.example.com`へのアクセスで、
    - Frontendアプリケーションのみで構成される静的な画面が表示されることを確認
    - FrontendからBackend(`https://back.example.com`)へのAPIリクエストが動作し、動的なコンテンツが表示されることを確認

でき、ホストベースルーティングが正常に機能することが確認できた。

# ここまでの設定で正常に動作しない機能について
大部分の機能は正常な動作が確認できたが、`ログイン関連処理`で一部異常が見られた。詳細は下記記事に記載。

https://qiita.com/jibirian999/items/222b2d01e687e1b1c016

# 最後に
より良い方法や間違い等ありましたらご指摘いただけますと幸いです！
Cloudflare Pages上で動かすRemixからAPIリクエストを送ると「Application Error」と表示されたときの対処法

# 結論

- Cloudflare Pagesから直接IPアドレスを指定してリクエストを送ることはできない
    - [https://developers.cloudflare.com/support/other-languages/日本語/cloudflare-1xxx-エラーのトラブルシューティング/#error-1003-アクセス拒否直接ipアクセスが拒否されました](https://developers.cloudflare.com/support/other-languages/%E6%97%A5%E6%9C%AC%E8%AA%9E/cloudflare-1xxx-%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E3%83%88%E3%83%A9%E3%83%96%E3%83%AB%E3%82%B7%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0/#error-1003-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E6%8B%92%E5%90%A6%E7%9B%B4%E6%8E%A5ip%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%8C%E6%8B%92%E5%90%A6%E3%81%95%E3%82%8C%E3%81%BE%E3%81%97%E3%81%9F)

## 起こった事象
![CleanShot 2023-10-21 at 15.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26043/32e44923-bf15-027d-d243-ea34d868089b.png)

- Cloudflare PagesからKagoya vpsのIPアドレスに対してGETリクエストを送ったところWebページに「Application Error」と表示された
    - ```リクエスト先の例　http://123.45.67.891/api/getPost ```
    - Cloudflare PagesではRemixを使っておりサーバーサイドレンダリングを用いていた。なのでサーバ側（Cloudflare Pages）からリクエストを送っていた
    - 「Application Error」とだけでは原因がわからないのでいろいろ試したところ結局、Cloudflare Pages上で「**403 Forbidden**」が起こっていたことがわかった
    - 「Error: Unexpected Server Error」とChrome Dev Toolsで表示されることもあった
- ローカルの開発環境ではリクエストは成功していた
    - ローカルで成功していたのでサーバ側（Cloudflare Pages）に何かしらの問題や制約があると予想
- 試しに阿部寛のホームページに対してfetchリクエストを送ると成功した
    - http://abehiroshi.la.coocan.jp/
- Kagoya vpsのrootのipアドレスに対してfetchリクエストを送ると「**error code: 1003**」が返ってきた
    - これはcloudflare固有のエラーステータスである
        - [https://developers.cloudflare.com/support/other-languages/日本語/cloudflare-1xxx-エラーのトラブルシューティング/#error-1003-アクセス拒否直接ipアクセスが拒否されました](https://developers.cloudflare.com/support/other-languages/%E6%97%A5%E6%9C%AC%E8%AA%9E/cloudflare-1xxx-%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E3%83%88%E3%83%A9%E3%83%96%E3%83%AB%E3%82%B7%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0/#error-1003-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E6%8B%92%E5%90%A6%E7%9B%B4%E6%8E%A5ip%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%8C%E6%8B%92%E5%90%A6%E3%81%95%E3%82%8C%E3%81%BE%E3%81%97%E3%81%9F)
エンジニアからみたフルリモート、ハイブリッド、オフィスワーク

コロナ禍でリモートワークになり、多くのエンジニアがその恩恵を受けてきたと思います。海外ではいち早く規制が無くなり、日本でもほぼコロナ禍前のような状態になり、リモートワークに関してもだいぶ変化が出てきたように見えます。

エンジニアから見てフルリモート、ハイブリッド、オフィスワークについての考察をしてみたいと思います。

# 現状について
以前別の記事でも書きましたが、現在ドイツ在住でかれこれ合計15年以上海外で仕事をしています。そのため日本の働き方やオフィスの環境などについては、あまり詳しくありません。日本のことについては、以前に東京で勤めていたことのことをベースに考えていきます。

https://qiita.com/dg4101/items/1e7c2f1c7fa4fcc2f41d

現状ですが、ドイツの中部の町で勤め先はハイブリッドということで通勤はそれぞれの自由といった感じで行われています。所属する部署などでも違うようですが、週に何日か曜日を決めて出社するところもあれば、特別なミーティングでもない限り出社することもないチームもあります。

自分は後者で、今年になって出社したのは数回です。それもハイブリッドということで出社したから丸１日会社にいなければならないと言わけでもなく、ミーティングが終われば即帰宅する人も大勢います。


# フルリモート
## メリット
フルリモートの最大のメリットは通勤に時間を割く必要がないということに尽きると思います。これは実際の通勤時間だけでなく、起床してからの準備や帰宅してからのこと、着ていく服とそれのクリーニングも含めてかなりのものを省くことができます。猛暑の中、歩いて駅に行く必要もないし、自宅で軽装で仕事ができます。

さらフルリモートで通勤が無くなると、居住地の選択の幅がかなり大きくなります。通う必要がないので、通勤圏内に住む必要もないし、極端に言ったら安定したネットワークさえあれば山奥でも仕事はできます。

会社によったらフルリモートと共に勤務時間にも幅をもたせて以前のようなフレックスタイムを導入しているところもあります。例えば、勤務は午前11時から午後6時までと午後9時からさらに2時間とかにすると、空いた時間を有効的に使えます。家庭事情によって異なった働き方が求められることもあるので、それらに対応できると思われます。

また、フルリモートが増えれば通勤する人が減るので、仕事上通勤しないといけないような職業の人にとっても電車がすいていたりとメリットも出てくるはずです。

エンジニアとしてはフルリモートの最大の利点の一つは集中して仕事する時間を取りやすいということかと考えています。コーディングするにしてもトラブルシューティングするにしても数時間集中して邪魔をされずに仕事をする必要があるとき、オフィスではほぼ無理です。リモートの場合、隣の席の人に話しかけられたり、上司から突然呼ばれて何か頼まれる的なことも少なくなります。

## デメリット
やはり、同僚たちと話す機会が極端に減ることでしょうか。雑談レベルの会話の中からいいアイデアが出てきたりすることもあり、それらの機会が減ることはマイナス点といえます。

また、オフィスに集まって行ったほうが効率がよくなるような仕事（例えばワークショップ）など、フルリモートをデフォルトで行っている場合は日付の調整などが以前よりは難しくなると思われます。

プライベートでは、通勤しないことで運動不足とかになりがちですが、これは普段からそうならないようにフルリモートでも運動をする習慣を取り入れれば回避できます。

# フルリモートとほぼフルリモートの違い
最近たまに見かけるのが、”ほぼフルリモート”といった感じで紹介されている働き方です。一見これはフルリモートっぽくていいですが、”ほぼ”がついているだけでたまには通勤しなくてはならず、それによって通勤圏内に住む必要もあります。

また”ほぼフルリモート”なので出社したとしても、普段一緒に仕事をしている人が同じ日に出社しているとも限りません。出社する曜日、日時をきめて行うとその日に都合の会わない社員も出てきたりします。

これでは中途半端にマイナス面があり、あまりメリットはないかと思われます。

# ハイブリッド
## メリット
ハイブリッドの場合、チームやプロジェクトで出社する曜日など決めて行っていたりします。この場合、チーム内のコラボレーションや普段の雑談からアイデアを出したりなど、出社することによるメリットもあると思われます。
また、毎日出社するわけでもないのでコーディングなど集中して時間が必要な場合も、その時間を取りやすいでしょう。

## デメリット
フルリモートの時のように同僚たちと話す機会が極端に減ると言ことはなさそうです。少なくとも定期的に会って、話す機会も取れると思われます。
ただ、定期的に曜日等を決めるにしても、非定期で出社するにしても全員の都合がいいとは限らないのでそれなりの調整が必要になります。

以前の毎日出社のころから見れば贅沢なように見えますが、いったんハイブリッドと会社の方針で決まった場合は、出社日に関してもある程度の配慮が必要で、強制的に毎週水曜日とかにすると都合の悪い社員にとってはより負担になってしまうかもしれません。

また、ハイブリッドは時々出社することが前提なので、フルリモートと違い通勤圏内に住む必要もあります。

# オフィスワーク
エンジニア的には正直毎日出社することにメリットは感じられません。通勤時間は無駄な時間で、オフィスで周りに同僚たちがいって電話会議なんかしているところでは、集中して時間をとってエンジニアリングの仕事をするのは精神的にも負担になると思います。

よくオフィスワークのメリットとして聞くのが”ミーティングでみんなで顔を合わせて話もできて、コラボレーションできていいアイデアが出て・・・”といったことを聞きます。

ミーティングやワークショップを多く行う必要がある管理者、マネージャーにとっては当てはまるかもしれません。ただ、エンジニアとしては特にミーティングは不稼働な時間となることが多く、それに時間を取られるほど実際の技術的な仕事に費やす時間が減っていきます。管理者がこなす１日数回のミーティングのうち、その一つにしか参加しないにもかかわらず出社するのは、管理者の満足度は上がってもエンジニアとしてはストレスがたまるだけになるかもしれません。


# 終わりに
それぞれの働き方ごとのメリットとデメリットを並べてみました。いかがでしたでしょうか？年齢、キャリア、家庭環境などの違いで必ずしも当てはまるとは限りませんが、共感していただけることもあるかと思います。
個人的には物理的なものを扱う必要がない場合は、基本的にリモートで仕事ができると思っています。いずれにしても以前のように毎日全員出社っていうのは、そのうちなくなるのではと思っています。
🚀 Reactのマウントとレンダリングを🖼️ アートギャラリー🎨🖌️🏞️というアナロジーで

Reactを学ぶ過程で、「マウント」と「レンダリング」を理解するのは非常に大切です。これらの概念をアートギャラリーというアナロジーを使って、もっと直感的に理解しましょう。

1. **🎨 絵を描くアーティスト = レンダリング**:
   Reactのコンポーネントはアーティストのようなものです。新しい情報や変化があるたびに絵を描きます🎨。これがレンダリングのプロセスです。しかし、すべての絵が自動的にギャラリーの壁に飾られるわけではありません。

2. **🖼️ 絵を壁に飾る = マウント**:
   コンポーネントが初めてギャラリーの壁(DOM)に絵を飾るとき、それを「マウント」と言います🏞️。この特別な瞬間は、コンポーネントの一生の中で一度だけ起こります🌟。

3. **🔽 絵を壁から取り外す = アンマウント**:
   展示が終了したときや、何らかの理由で絵を壁から取り外す必要が生じたとき、そのアクションを「アンマウント」と言います🔽。この瞬間が来ると、絵は再びギャラリーの壁から取り外されます。

🔄 もしギャラリー全体をリフレッシュ（ページリロード）する場合、展示中のすべての絵は一旦壁から取り外され、アーティストが再び絵を描き、ギャラリースタッフが新しい展示として壁に飾ります。

> DOMや仮想DOMについては[こちら](https://qiita.com/TakanoriVega/items/174da20f64af9a13ccf4)

### 🎣 useEffectの魅力

`useEffect`はReactのHooksの一つで、アクションの後に実行したい副作用を設定する際に使います。副作用は、データの取得、購読、DOMの変更などの操作を含むことができ、コンポーネントのライフサイクルと連動して実行されます。

```jsx
import React, { useState, useEffect } from 'react';

function ExampleComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;

    return () => {
      console.log('Component will unmount');
    };
  }, [count]);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
```

この例では、`useEffect`の効果は、`count`が変わる度に発動🔥！


## 🖼️ アンマウントについて具体例を見ていこう

### 1. 🖼️ ルーティングによるアートギャラリーの部屋の変更:

考えてみてください。あなたが大きなアートギャラリーにいて、「風景画の部屋」から「肖像画の部屋」に移動することにしました。移動すると、「風景画の部屋」の絵🏞️はもう見えなくなり、代わりに新しい「肖像画の部屋」の絵👩‍🎨が目に入ってきます。

```jsx
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>

        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

```

このReactのコードは、アートギャラリーの部屋を変えるようなものです。`Home`から`About`に移動すると、前のページのコンポーネント（絵🎨）はアンマウントされ、新しいページのコンポーネントがマウントされます。

### 2. 🎨 条件的なレンダリングによる絵の取り外し:

アートギャラリーで、特定の絵を見たいお客様だけのために、カーテン🖼️で覆われた特別な展示があると想像してみてください。お客様がボタン🔘を押すと、カーテンが開き、その特別な絵が現れる。再度ボタンを押すと、絵は隠れてしまう。

```jsx
import React, { useState } from 'react';

function App() {
  const [showComponent, setShowComponent] = useState(true);

  return (
    <div>
      {showComponent && <MyComponent />}
      <button onClick={() => setShowComponent(!showComponent)}>
        Toggle Component
      </button>
    </div>
  );
}

function MyComponent() {
  return <h2>Hello World</h2>;
}

```

このコードは、上記の特別な展示のようなものです。ボタンをクリックすることで絵🎨（`MyComponent`）の表示・非表示を切り替えることができ、非表示にすると、絵はギャラリーの壁から取り外される（アンマウント）のです。




## （まとめ）🤔 マウントとレンダリングの関係

- **レンダリングのみ🎨**: stateやpropsが変わると、コンポーネントは新しい絵を描きますが、再度壁に飾ることはしません。
  
- **両方🎨🏔️**: コンポーネントが初めて部屋に飾られるとき、絵を描いて壁に飾ります。

結局のところ、マウントは絵を描くことを含むけど、絵を描く度に壁に飾るわけじゃない🎨🚫🏔️。
【オンボーディング中】さあ、更新を再開だ！

# ごあいさつ
みなさんこんにちは。いかがお過ごしですか？
お久しぶりです。husuiです。
UiPath（ユーアイパス）[^0]というRPA[^1]の会社で、若干業務よりの人として働いて **いました。**
[^0]: https://www.uipath.com/ja
[^1]: Robotic Process Automationの略です。

前回、いきなりの衝撃発言からスタートした 
**「【余談】これからの「わたし」の話をしよう。」** 
の記事ですが、
なんとなんと気がついたら**自分史上最高のビュー数**になっているではありませんか！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329659/77d8d92f-c2d6-a20f-c308-38c36f736b0c.png)
(；ﾟдﾟ) ・・・
(つд⊂)ｺﾞｼｺﾞｼｺﾞｼ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329659/13a5b836-c4e3-f965-9769-cd4adc5213d6.png)
　　_, ._
（；ﾟ Дﾟ） …！？　ｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴｴ！！！！
この記事のどこがそんなに良かったのか？面白かったのか？全くわからないのですが、とりあえず誰かの書いた本のようなタイトルに似せた[^2][^3]のが成功要因だったのかなと勝手に分析しております偉そうにしてしまってほんとごめんなさい。
まだ読んで無いよ！という方はこちらをどうぞ、ほんとどうでもいい記事です。
[^2]: 「これからの「正義」の話をしよう」　https://www.amazon.co.jp/dp/4152091312
[^3]: 実はこちらの題名に似せようか迷った。ちと前だからやめた。→「桐島、部活やめるってよ」　https://www.amazon.co.jp/dp/4087468178

https://qiita.com/husui/items/b047615d56f0a0cfe014

# 更新を再開します
前回の記事で、
>まだまだ「私見的RPA展開メソドロジー」は続けるし、これから自分が会得した技術的・マネジメント的なメモみたいなものも執筆していく予定です。

って**何カッコつけてんだコイツは**的な発言をしてしまっているんですが、きちんと宣言通りに更新を再開したいと思います。

ただ#01-#10までは退職前のちょっとした有給休暇消化期間中の時間で書いたのでほぼ毎日更新できたのですが、今は絶賛`新会社でオンボーディング中`なので同じペースをキープすることは難しそうです。

なので`週一`で記事を書いてみようと思います。日曜更新目標。

あっ！！！！！！！！！！！！！！！1
そこのアナタ！　今明らかにガッカリしたでしょ！？　幻滅したでしょ！？
安心してください。大した記事は書きませんから！

何かコメントやhusuiにアクセスしたいかたは…QiitaにDM機能はないようなので記事に直接コメントよろしくお願いします。
もし他のSNSで私と繋がっている方はそちらからお願いしますね！

ということで今後ともよろしくお願いいたします。
まずは明日10/22に#11を発射しますよ！
（さて、#10まで何を話していたか思い出そう…）

husui
屋内用ロボットの絶対位置推定方法について調べてみる

屋内のどこに自分がいるのか知るための手法を調査

環境が変わる場合はLidar SLAMだと怪しいし...

以下，調査した製品ごとの位置推定手法について記載していきます．

# 配膳ロボット

https://servingrobot-ranking.com/robot/driving.html

## DINEBOT (KEENON Robotics 株式会社)

`エンコーダ`,`IMU`,`LiDAR`,`RGBD`,`UWB`によって位置推定をしているとのこと

https://www.keenonrobot.com/jp/

## SERVI (SONY)

- SERVI 仕様

https://www.softbankrobotics.com/jp/product/servi/spec/

位置推定には`SLAM`を使用とのこと

## BellaBot（KAIYO ROBOTICS)

`SLAM`を使用とのこと.頭上を主にみてるのかな？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/73405981-cdcb-7d33-36c5-79ad54029100.png)

# 手法整理
## UWB

長広帯域無線通信のこと（日本国内では8.5GHz～9.5GHz程度の周波数帯域を利用）


https://www.ichimie.com/method/uwb.html

精度は数十センチらしい，移動体への使用は不可？（下記資料より）

https://www.apptec.co.jp/technical_report/pdf/vol22/treport_vol_22-09.pdf
Python環境構築(IKD )


```shell
conda create --name agama_202307 python=3.7

$ conda activate agama_202307
conda install -c conda-forge numpy
```


```shell
# [1]
$ conda create --name py37_gaia_dr3_try1 --clone agama_202307
$ conda activate      py37_gaia_dr3_try1
$ conda install -c conda-forge ***

*** のリスト（上から順番に入れた）
scipy
matplotlib
jupyter (遅いので飛ばす) 
astropy
astroquery
corner (遅いので飛ばす) 
mpi4py
schwimmbad

conda update -n base conda -c defaults

pandas # already installed
wget
cython
scikit-learn
seaborn
pytest

corner (遅いので最後に回した) 
jupyter (遅いので回していない) 

```
FlutterでOpacityウィジェットを使わずに半透明にさせる方法

# やりたいこと
Flutterでは、OpacityWidgetを使うことでウィジェットを透明にすることができます。
しかし以下のような状態で、赤色のContainerのみを半透明にしたい場合は別の方法を使わないといけません。

![スクリーンショット 2023-10-21 14.47.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/59e56178-d0a6-42e0-7416-da8b1459fffc.png)
↑青い部分まで透明化してしまっている

# 解決法
Colorプロパティの.withOpacityを使う

```dart
Container(
    height : 100,
    width : 100,

    color: Colors.red.withOpacity(0.5),
                      ^^^^^^^^^^^^^^^^

    alignment: Alignment.center,
    child : Container(
        height : 50,
        width : 50,
        color : Colors.blueAccent,
    ),
),
```

こうすることで以下のように.withOpacityを使ったウィジェットのみ、半透明にさせることができます。

![スクリーンショット 2023-10-21 14.59.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/9c9e364c-5d8f-5f42-2923-d445f0abec91.png)

お役に立てば幸いです。
ラズパイでセンサーの値を表示しよう

こんなの作りました。
![PXL_20231101_094705841.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29493/9afa702f-56a9-d66e-3f08-6c2c90fdcc7c.jpeg)


# ハード構成

・Raspberry Pi 3a (今回のお題を実現するためなら Wi-Fi に対応したラズパイならなんでも良い)
・HDMIディスプレイ、今回はAmazonでこれを購入 ([OSOYOO (オソヨー) HDMI 3.5 インチ LCD ディスプレイ モニター タッチスクリーン 1920x1280ハイビジョン Raspberry Pi 4 3 2 Model B に対応](https://www.amazon.co.jp/OSOYOO-%E3%82%AA%E3%82%BD%E3%83%A8%E3%83%BC-IPS%E3%82%BF%E3%83%83%E3%83%81%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3-1920x1280%E3%83%8F%E3%82%A4%E3%83%93%E3%82%B8%E3%83%A7%E3%83%B3-Raspberry/dp/B077PTBB8N/ref=sr_1_7?keywords=%E3%83%A9%E3%82%BA%E3%83%99%E3%83%AA%E3%83%BC%E3%83%91%E3%82%A4+%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4&qid=1687565706&sr=8-7))
・iRemocon Wi-Fi (温度・湿度・照度センサーとして以前入手したものを利用)
・Wi-Fiルーター

# センサから温度など読み込むスクリプト作成
別記事で投稿済み

https://qiita.com/yujimny/items/57813ec8cd608895818b

・上記で作成したスクリプトをcronで1分置きとかで定期実行しファイルに保存する。cronの設定については検索すればどこにでもあるので省略。


## 表示UI作成

Pythonで書くのが慣れていて楽だったのでPython用のGUIToolKitから以下を選定

### KIVY

https://qiita.com/yujimny/items/c00785ed6d192a281e94

### tkinter

https://qiita.com/yujimny/items/6870c09810229de03d9b

以前はKIVYを使用していたが、ラズパイOSを最新に入れ直した際によりシンプルそうなtkinterに変更した。
GUIでセンサー値を保存したファイルを読み込んで表示する。

### ディスプレイ付けっ放し設定
ラズパイでセンサから取得した値を表示する場合、ディスプレイに省電力モードに入って欲しくないので設定する。
下記の記事の画面スリープ停止を参考にした。

https://qiita.com/god19/items/3e67ce9ad6849afd9547

自分の記事も以前書いたが最新のOSでは役に立たなくなっていた…
https://yujimny.hatenadiary.org/entry/20150318/1426672867

以下、すでに実現しているが記事にはしていないため、後日投稿する予定。
・センサー情報をIoTサーバに送りグラフ表示
・屋外の温湿度気圧をラズパイで表示＆グラフ表示する（Switchbot防水温湿度計を使用）
・iRemoconではなくSwitchbot Hub 2の温湿度センサーの値を使用する
・WattCheckerでTVの消費電力を取得しテレビの電源ON/OFF状態を判別する
ワークシート関数をコピペで利用する方法

#
[ここをクリックすると他の技術投稿の目次に行きます](https://qiita.com/FUKUTAKA7938/items/2312362e44dbcecd11ca)

# ワークシート関数をコピペで利用する方法
（基礎？応用？どっちだろう？見直してみたら高度技術だったみたい）

長くなるのでご覚悟を\(_ _)(笑)

　Excel 、google スプレッドシート、Libre Offe Calc など、対応・・・だと思う・・・（T T）

※ 文字入力の日本語入力モードと直接モードに注意してください

↓サンプルダウンロード
[sample0001.xls](https://drive.google.com/u/4/uc?id=1crqnchoGwGtUjYPYP79I02S2Q0QDw-PS&export=download)
[sample0002.xls](https://drive.google.com/u/4/uc?id=1T3fkf-DW1MiZmFGFkFMpc8jSGQeIHWLk&export=download)

これは、あくまでサンプルです。今回は、sample0002.xlsx については投稿してません。

セルA1 に 
=IF(B1 < C1, ”真”, ”偽”)　という 題材で作っていきたいと思います。

このようなものを作る場合の理論をまずは、お伝えします。

セルA2 に まずは、B1 < C1 だけを作っていきます。

セルB1 に 1 、 セルC1 に 2 を 入力しておいてください

※日本語入力を文字列以外入力しない時はオフにしたりする切り替えが必要です。
=を入力する時は、日本語オフです。

知ってる方もいらっしゃるでしょうが
セルA2 に 

=

 を挿入し、
B1をクリックしエンター
すると A2 に 1 が表示したと思います。

セルA2 を再度クリックし キーボードのF2 を押下してください。
するとセルの中の右端に | (カーソル) が表示されたと思います。

この状態で、< を 入力し そのまま 、セルC1 をクリックしてください。
そしてエンター

するとセルA2にTRUE が表示されたと思います。

この状態で、B1 に 2 、C1に1 を 入力して見てください。

するとセルA2にFALSE と表示されたと思います。

これのTRUEとFALSEとは何かですが、これセルA2に書かれた条件式の結果なんです。

つまり、B1 < C1 の条件が合えば、TRUE（真） 、違えば FLASE（偽）
 が表示されるということです。

条件式には < 、<=、> 、>=、 =、 <>(不等号)など　があります。

いろいろ試されてみてください。

では、
最初の頃に書いた
セルA1 に 
=IF(B1 < C1, ”真”, ”偽”)

と何が関係があるのかですが、大有りです。

=IF(B1 < C1, ”真”, ”偽”) の
IF関数は、ただ単純に条件式のB1 < C1 の部分の結果
つまり、TRUE （真）、FALSE（偽）の結果を表示させていただけなんです。

TRUEなら”真”の部分を処理、FALSEなら”偽”の部分の処理にしてただけみたいなんです。

さて、なぜ？上記で処理というふうに書いてるかなのですが、この”真”、”偽”の部分に
ワークシート関数を挿入できるのですが、
今は混乱する可能性がありますので、この説明は後々順をおって説明していきます。
（今回はいたしません）

では、戻って実際作っていきます。
ここからは、少し特殊なやり方です。

セルA2をクリックして、数式バーを見てください
セルA2 が

=B1<C1

とういう式になっていると思います。
これが、先程の説明したものの正体です。
では、この=B1<C1の
= の部分をキーボードのBS または DEL で削除してください

セルA2に
B1 < C1
と表示されたらOKです。

これは、=  が セルの先頭にあれば、関数式。
なければ、文字列、数値などのデータとExcelなどの表計算ソフトでは、認識されます。

そして、

セルA1 に 普通のIFの関数の作り方で

=IF(B1 = 1, ”真”, ”偽”)作っておいてください。ベースになるものを作ります。




そして、これの左の = を数式バーから削除して
IF(B1 = 1, ”真”, ”偽”)にしておいてください。
先程の説明の文字列にしておくということですね。

さらに、セルA1に表示されている
IF(B1 = 1, ”真”, ”偽”)のB1=1 の部分を数式バーで消し
IF（, ”真”, ”偽”）にしておきます。※  , は必ず残してください

※これは、現在、文字列のデータとなっており、数式ではありません。
あくまでも、SUMなどの数式の先頭に半角の= が入れば、数式になります。

では、先程のセルA2 をコピーします。
面倒なので、ショートカットのCtrl(⌘) + c でコピーしてください。
これは、=がある状態でコピーするとあとあとエラーなどで面倒なので、先に消しました。

そして数式バーで、|（カーソル）を
IF( の隣に挿入して、IF( | , ”真” ,”偽”)の状態

（セルA2をクリックして、数式バーのその場所をでクリック、
または、セルA2をクリックしてF2キーで入力状態にして、
キーボードの矢印キーの← →の左右を押していき移動）

にし、

Ctrl(⌘) + v で挿入 

セルA1に
IF(B1 < C1, ”真”, ”偽”)が表示されれば良いです。


あとは、= を数式バーの先頭に挿入してエンターするだけ
こんな感じです。

=IF(B1 < C1, ”真”, ”偽”)
 
もし、エラーが出たら、落ち着いて、また数式バーで 先頭の= を消し、よく眺めてください

修正したら、また、数式バーで、先頭に = をつける
※関数式は一度かならず、=(関数式) のやり方で雛形を作ってください。
= 無しの文字列状態で最初から作ってると、
わけわからない文字コードのエラーが出やすいです。

で、なんで、こんな面倒なやり方を伝えたかなのですが、

たとえば、
`=IF(AND(B6>=$D$3,C6>=$D$3,D6>=$D$3),IF(SUM($B6:$D6)>=$E$3,SUM($B6:$D6),"不合格"),"不合格")`
※ANDの部分は、ソフトによって少し関数式の使い方が違うかも\(_ _)

こういった複雑ものを作ろうとすると、さきほど説明したやり方のほうが、便利だと思います。

では、セルB1 と セルC1 にいろいろな数値を入れて試してみてください。

以上です。

お役に立てれば幸いです。

#

[ここをクリックすると他の技術投稿の目次に行きます](https://qiita.com/FUKUTAKA7938/items/2312362e44dbcecd11ca)
複数リンクのXの投稿への貼り付け方

# 

[ここをクリックすると他の技術投稿の目次に行きます](https://qiita.com/FUKUTAKA7938/items/2312362e44dbcecd11ca)

# 複数リンクのXの投稿への貼り付け方

使うもの（私は、PCでしかできませんでした）
　・ブラウザ(google chrome など)
　・テキストエディッタ関係（メモ帳、word、メールなど）
　・X

やり方の工程

※Macユーザーの方でCtrl(windows) を知らない方は、
　⌘(command) キーでされてください。
(すみません。私、Macユーザーではなので、詳しくは知りません)

１．　ブラウザでアドレスをコピーしたいwebページを開きます
　　
２　　開いたブラウザのアドレスバーで、
　　Ctrl (Macなら⌘)+ a を押し範囲選択（マウスのドラッグで範囲指定しても可能）

３．　範囲指定したらCtrl(Macなら⌘) + c（右クリックのコピーの項目は使えません。
ただし、最新版のUbuntu Linux版Google Chromeは使えます。確認済）
　　で メモリにコピー

４．　ブラウザを一旦、最小化し、テキストエディッタ関係を開きます

５．　貼り付けたい位置に移動して、Ctrl(Macなら⌘)  + ｖ（右クリックの貼り付けでも可能）
　　で貼り付けます

６．　また、ブラウザに戻り、次のWebページに移動し、別のページを開き
１〜５を貼り付けたい分だけ、繰り返します

７．　Xに投稿したい分のテキストエディッタのURLを範囲指定して
　　Ctrl(Macなら⌘)  + C（右クリックのコピーでも可能）でコピーします。

８.     X にそのままCtrl(Macなら⌘)  + ｖ（右クリックの貼り付けででも可能）
　   で移り貼り付けして、あとは投稿したら完了。

以上です。

お役に立てれば幸いです。

# 

[ここをクリックすると他の技術投稿の目次に行きます](https://qiita.com/FUKUTAKA7938/items/2312362e44dbcecd11ca)
モバイルアプリ開発フレームワークflutterとreact native、どっちが人気？

以下はそれぞれのフレームワークの特徴と人気の理由です。

1. **Flutter**:
   - **特徴**:
     - Googleが開発したUIフレームワークで、単一のコードベースでiOSとAndroidの両方に対応することができます。
     - ウィジェットベースのUI構築で、アプリケーションの外観や動作を豊富にカスタマイズできます。
     - Dart言語を使用し、高速なパフォーマンスを提供します。
   - **人気の理由**:
     - 一貫したUIとネイティブアプリ並みのパフォーマンスが求められるプロジェクトに適しています。
     - Dart言語の学習コストが低く、習得しやすいとされています。
2. **React Native**:
   - **特徴**:
     - Facebookによって開発されたフレームワークで、JavaScriptを使用してクロスプラットフォームのモバイルアプリを構築します。
     - Reactコンポーネントを利用し、iOSとAndroidの両方のプラットフォームでネイティブコードを生成します。
     - ネイティブモジュールを統合することで、必要に応じてネイティブの機能を利用できます。
   - **人気の理由**:
     - JavaScriptを用いるため、多くの開発者が既に知識を持っており、スムーズに始められます。
     - コミュニティが大きく、多くのリソースやサードパーティのライブラリが利用可能です。

どちらが人気があるかは、プロジェクトのニーズやチームの経験、コミュニティのサポート、開発速度など多くの要因によって異なります。最適な選択をするためには、プロジェクトの要件や開発環境に合わせて比較検討することが重要です。
[リサーチ・メモ] ナビゲーションガード

## ナビゲーションガードとは
リダイレクトもしくはキャンセルによって遷移をガードするために主に使用される
→画面遷移の際にデータのチェックを実施する機能

## ナビゲーションガードの種類と使い方
### ガード変数to, from, nextについて
|ガード変数|内容|
|:--:|:--:|
|to|遷移先のルートオブジェクト|
|from|遷移元のルートオブジェクト|
|next|ナビゲーションを続行または中止する関数  <br>※next(false) を呼び出すとナビゲーションが中止され、next('/') のようにパスを指定するとそのパスにリダイレクトする|


### beforeEach :画面遷移前に実行される
→会員作成画面から確認画面へ遷移する際にデータが格納されているか確認する時などに使用
```
router.beforeEach((to, from, next) => {
    if (to.name === 'ConfirmMemberRegistration' && !store.state.memberInfo) {
        alert('登録情報が失われました。もう一度登録をお願いします。');
    } else {
        next(); //画面遷移する
    }
});
```

### beforeResolve:すべてのナビゲーションガードが解決された後に実行される
→データの整合性が取れたログを出力する時などに使用
```
router.beforeResolve((to, from, next) => {
  // ...
  next()
})
```

### afterEach:画面遷移後に実行される
→会員登録完了後のメッセージ表示等に使用
※nextは使用できない
```
router.afterEach((to, from) => {
  if (to.path === '/success') {
    showMessage('Operation completed successfully!');
  }
});
```
【Jenkins】リモートホストのスクリプトを定期実行させたい

# やりたいこと
リモートホストに置いてあるシェルをJenkinsを使って毎時００分に実行させたい。
cronでできることだがあえてJenkinsを用いる。

# 設定
設定画面でチェックアウトさせたいリポジトリURLとブランチ、Script Pathを指定。
Jenkinsサーバから対象リポジトリにチェックアウトするために認証の設定を済ませておく。
リポジトリ側の設定でグループまたは個人にReadパーミッションを付与しておく。
![スクリーンショット 2023-10-22 14.24.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377231/89f58cfc-fe9c-a396-d5eb-091650272194.png)

# Jenkinsfile
以下Jenkinsfileをリポジトリに配置
```groovy:Jenkinsfile
pipeline {
    agent any
    
    triggers {
        cron('0 * * * *')
    }
 
    environment {
        USERNAME = 'リモートホストにおけるユーザ名'
        HOSTNAME = 'リモートホスト名'
    }
  
    stages { 
        stage('SSH and run shell') {
            steps {
                sshagent(credentials: ['Credentialに登録済みのID']) {
                    sh '''
                        ssh ${USERNAME}@${HOSTNAME} "cd /ディレクトリへのパス/ && bash シェル名"
                    '''
                  }
            }
        }
        
        stage('Clean Workspace') {
            steps {
                cleanWs()
            }
        }
    }
}
```

ちょっとだけ解説


```groovy
triggers {
        cron('0 * * * *')
}
```
毎時００分に実行させる

```groovy
environment {
        USERNAME = 'リモートホストにおけるユーザ名'
        HOSTNAME = 'リモートホスト名'
}
```
リモートホスト名とどのユーザを用いるかをここで指定

```groovy
stage('SSH and run shell')
```
何でもいい。どんな内容を実行中なのかが分かれば

```groovy
sshagent(credentials: ['Credentialに登録済みのIDを指定']) {
    sh '''実行させたい内容'''
}
```
`実行させたい内容`にリモートホストで叩かせたいコマンドを記載。
今回私はSSHしてcdしてシェルを実行させるコマンドを叩いた。
ちなみに`Credentialに登録済みのID`にはあらかじめJenkinsの認証情報で設定したIDを埋め込む。これによりJenkinsサーバとリモートホスト間のノンパス設定が完了するのでパスワードを聞かれることがない。認証情報の設定は認証情報->認証情報の追加から行う。
![スクリーンショット 2023-10-21 13.36.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377231/e028c7fe-d48f-0293-0bb8-c54f28886616.png)

**種類**：SSHユーザー名と秘密鍵
**ID**：何でもいい（"ユーザ名-ホスト名"とかにすれば分かり易い）
**説明**：何でもいい
**ユーザー名**：リモートホストのユーザ名
**秘密鍵**：リモートホストから鍵をコピってペースト
**パスフレーズ**：指定なし


```groovy
stage('Clean Workspace') {
            steps {
                cleanWs()
            }
}
```
最後に使ったJenkinsサーバ内のワークスペースをクリーンに



※おまけ
```groovy
triggers {
        cron('0 * * * *')
}
```
の代わりに
![スクリーンショット 2023-10-22 14.39.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377231/a1efd344-ebf6-170a-bd15-6e06926fdc65.png)
で設定する方が簡単で運用が楽です。


他にもhttps://qiita.com/miyasakura_/items/9d9a8873c333cb9e9f43
にいろんなこと載ってたので参考になりそうです。
circleciをさっくり導入してslackに通知を投げる

# TL;DR
- circleCIとslackの連携はOrbを利用する
  - slack側ではオリジナルのアプリを作成する要領で構築する
- Pythonの単体テストの成功失敗有無の通知を行うconfigを記述した
  - slackへのメッセージは[Block Kit Builder](https://app.slack.com/block-kit-builder)が使える
  - 今回は面倒なのでtemplateをそのまま利用した


## 背景
- CI/CDツールを利用した経験が無いので何かしら導入してみたい。
- Jenkinsを導入するか悩んだが、そのうち触る機会がありそうなので今回はcircleCIを採用。
- githubと同じでslackにアプリがあるから紐づけるだけでいいだろうと思っていたが、どうやら主流なやり方では無いよう。

## 手順

基本的に公式に従う。
[circleciサイト](https://circleci.com/docs/ja/slack-orb-tutorial/)
ぼさっとしてるとハマったのでそこだけmemo。

### circleCI側Contextに設定する値でミス

config.ymlは公式のものをまずは採用。

circleCIのContextに
```
SLACK_ACCESS_TOKEN
SLACK_DEFAULT_CHANNEL
```
を環境変数として設定する必要がある。
SLACK_ACCESS_TOKENはSlack側で生成したものをそのまま張り付ければよい。

SLACK_DEFAULT_CHANNELはslackのチャンネルのリンクの値を張ればよい
![スクリーンショット 2023-10-18 010101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367227/5904659b-b2cd-be7c-f2fa-bde2388474d3.jpeg)
ここで取得したリンクをそのまま宛てるのではなく、このリンク中
```bash
https://example.slack.com/archives/C12ABCDE123 #<=C12ABCDE123の部分
```
C12ABCDE123の部分をSLACK_DEFAULT_CHANNELの値として設定する。
ここで間違うとinvalid_authとなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367227/e204e059-eb7b-efcf-bd91-65348f741d98.png)
成功するとリクエストに成功した旨がcircleCI側からも確認できる。


## 単体テストを自動で行う

自分以外の人も今回プロジェクトに関わっているためレビューを簡素化したり、バグを手早く発見したりしたいので今回は自動テスト化を目指す。

## 作りたいもの
- masterにマージされたら、単体テストを実行。
    - 成功したらコメントをチャンネルに流す
    - 失敗した場合もチャンネルに流す

今回はpytestによるテストがpassしたか否かの通知を行ってもらう。

## 完成形

```yaml
version: 2.1
orbs:
  slack: circleci/slack@4.12.5
jobs:
  build:
    shell: /bin/bash
    docker:
      - image: "cimg/python:3.12.0"
    steps:
      - checkout # ~/project dir
      - run:
          name: install pytest
          command: |
            python -m venv venv
            source venv/bin/activate
            pip install -r requirements.txt
      - run:
          name: run unittest
          command: |
            source venv/bin/activate
            cd backend
            python -m pytest
      - slack/notify:
          template: basic_fail_1
          event: fail
      - slack/notify:
          template: basic_success_1
          event: pass
workflows:
  unit_test:
    jobs:
      - build:
          context: slack-secrets

```


### 補足

失敗成功による通知はslackのorbが用意してくれたものを利用する
この辺を読むとわかる。
https://circleci.com/developer/ja/orbs/orb/circleci/slack#usage-notify_on_fail_with_template

#### slackで送信するメッセージについて
今回は以下の通りに設定した。
```
event: fail
template: basic_fail_1
```
templateではなく、customを用いれば自由に設定できる。
今回は簡便なもので構わないため、templateを利用した。

https://github.com/CircleCI-Public/slack-orb/wiki#templates



## ローカルcircleciで動作確認を実施
WSLを利用しているが、Dockerが利用できる環境であれば検証可能
https://circleci.com/docs/ja/local-cli/#alternative-installation-method
こちらを参照するとよい。

適当にローカルcircleciのコマンドを打つと一番初めは
「情報収集していいか？」と質問されるのでお好みで回答。

ローカルcircleCIで確認。
```bash
circleci local execute build #バージョンによってoptionの付け方が違うので公式サイト参照を推奨
```
dockerのimageをダウンロードするので、ネット帯域が細いとダウンロード時間が長すぎるために途中でコケるので注意。

無事に成功してればOK

## pushしてテストが走るか確認

![スクリーンショット 2023-10-21 134108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367227/f1e4a22d-3967-0acb-3324-d036b55bd29b.jpeg)

OK

## 今後の課題

- インフラを含めたデプロイ自動化
- フロントのデプロイ自動化
attr_accessorメソッドとinitializeメソッドの違いとは？

## なぜ調べたいと思ったか？
インスタンス変数を操作する時に、attr_accessorメソッドとinitializeメソッドを使ってきたが、使い分けが分からなくなり、調べてみたかった。


## attr_accessorメソッドの使い方を調べてみる

```sample.rb
class Menu
    @name
    @price
end

menu1 = Menu.new

menu1.name = "ピザ"
menu1.price = 1100
puts menu1.name
puts menu1.price
```
[実行結果]
```
sample.rb:8:in `<main>': undefined method `name=' for #<Menu:0x000000010e89a148> (NoMethodError)
```
**インスタンス変数を代入している様に見えるが、インスタンスメソッドとして扱われ、エラーが発生してしまう**



```sample.rb
class Menu
    # nameのセッタメソッド
    def name=(name)
      @name = name
    end

    # priceのセッタメソッド
    def price=(price)
      @price = price
    end

    # nameのゲッタメソッド
    def name
      @name
    end

    # priceのゲッタメソッド
    def price
      @price
    end
end

menu1 = Menu.new

menu1.name = "ピザ"
menu1.price = 1100
puts menu1.name
puts menu1.price
```
[実行結果]
```
ピザ
1100
```
**インスタンス変数を使って、変数の代入と取得を行なっているが、記述が多い**



```sample.rb
class Menu
    attr_accessor :name, :price
    @name
    @price
end

menu1 = Menu.new

menu1.name = "ピザ"
menu1.price = 1100
puts menu1.name
puts menu1.price
```
[実行結果]
```
ピザ
1100
```
attr_accessorメソッドを使って分かったのは、
**①インスタンス変数を、メソッド外から呼び出せる**
**②インスタンス変数の代入と取得の2つの機能がある**


・initializeメソッドの使い方を調べてみる
```sample.rb
class Menu
  attr_accessor :name, :price

  def initialize(name, price)
    @name = name
    @price = price
  end
end

menu1 = Menu.new("ピザ", 1100)

puts menu1.name
puts menu1.price
```
initializeメソッドを使って分かったのは、
**インスタンス化と同時に、インスタンス変数に値を代入できる**


## 調べてみて分かったこと
attr_accessorメソッドは、クラス外からインスタンス変数を参照する時に使う
initializeメソッドは、インスタンス化と同時にインスタンス変数に値を代入する時に使う
OdooをM2 Macで立ち上げる


## Dockerをインストール＆起動する
### DockerのサイトからDocker desktopをダウンロードしてインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/67cb3b6d-5f0c-e4c8-553a-92aa282e3fba.png)

### DockerDesktopを起動しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/2bb4c574-de6d-a25c-3d06-c3aec56e4990.png)

## DockerhubからのOdooインストール手順
### DockerhubからAMD版OdooをPullする
```
$ docker pull amd64/odoo
```

### Postgresを起動
```
$ docker run -d -e POSTGRES_USER=odoo -e POSTGRES_PASSWORD=odoo -e POSTGRES_DB=postgres --name db postgres:15
```

### Odooを起動
```
$ docker run -p 8069:8069 --name odoo --link db:db -t amd64/odoo
```
### 下記アドレスでページを開く
```
http://localhost:8069/
```

## 画面イメージ
最初に専用のDBと自分のアカウントを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/4445ef89-555c-7b4f-cbb2-d3d8c8665f25.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/4aa2b28b-4e6b-6101-b8bd-ae2e00af11bc.png)

作成したメアドとパスワードでログイン可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/6a90e7e4-c5ef-3ae3-0d2b-c720b4e8bf0c.png)

ポータルイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/e161f817-bbf0-8f94-4f9e-61e002e7dc25.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593/a4d1f7bd-4a4b-874b-d066-b1976e2a839d.png)

## 今後の展開
ここにはいろんなコンテンツが有り、Odooの開発の参考になりそうです。
https://www.odoo.com/documentation/16.0/developer.html
職場のコミュニケーションをサポートする業務連絡共有アプリ

みなさんこんにちは
スーパーで夜間の管理者として働くうっちーです。

前回に引き続き、デジタル未経験者の私がデジタル革命に挑戦し、
その内容を発信していきます！！前回の記事は↓

https://qiita.com/sh000ta/items/2bf176479e6dcd08e752

# Glideで業務連絡共有アプリを制作した背景
~~今回Glideで業務連絡共有アプリを制作したきっかけは
部門ごとに連絡ノートはありますが店舗全体での業務連絡ツールはなく、
ないことにより、連絡の伝達がスムーズに行えず、タスク管理や部門間の連携・引き継ぎ漏れという問題が起こったりします、
この問題を解決するために、Glideを使用して店舗全体の連絡ツールを制作しました。~~
### 修正
Glideで業務連絡共有アプリを制作した背景は、店舗全体への業務連絡や引継ぎ連絡のツールが存在しない点にあります。（現状の手段としてはノートやメモ書き）
この状況から発生する問題は、連絡の伝達が滞り、タスク管理や引き継ぎ漏れがあります。

こうした問題に対処するため、Glideを導入することで大きな改善が期待できます。
具体的には、アプリを通じて店舗全体の情報をリアルタイムで共有し、タスクや連絡事項を効果的に管理できるようになります。
ノートやメモ書きではなく、統一されたプラットフォームで情報が共有されることで、誤解や引き継ぎ漏れが大幅に減少し、業務プロセスがスムーズに進むと感じています。また、部門間の連携が促進され、業務の円滑な進行が期待されます。


# 完成動画

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Glideを使って店舗全体の業務連絡共有アプリを作成してみました。<br><br> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a><br> <a href="https://twitter.com/hashtag/%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8%E3%83%A3%E3%83%BC%E3%82%BA?src=hash&amp;ref_src=twsrc%5Etfw">#チャレンジャーズ</a> <a href="https://t.co/0xen5CowPD">pic.twitter.com/0xen5CowPD</a></p>&mdash; うっちー (@u_sh00ta) <a href="https://twitter.com/u_sh00ta/status/1715359074420928939?ref_src=twsrc%5Etfw">October 20, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 用意ツール


[Glide](https://www.glideapps.com/)
######  スプレッドシート

# 作成手順
①.[Glideにサインアップ](https://www.glideapps.com/)　　　

②.＋を押してアプリを作成

![スクリーンショット 2023-10-21 033820.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535733/0bb54a1c-41f1-979b-1cc2-661679f6265e.png)

スプレッドシートを選択

![スクリーンショット 2023-10-21 032413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535733/5e23e514-1032-f2c2-ca01-020d5f1aa7d0.png)

スプレッドシートはこんな感じにしました。

![スクリーンショット 2023-10-21 034356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535733/6e016f51-eb4a-f025-1821-64ade595b835.png)

ホーム画面はこちら
styleはlistを選択しました。
![スクリーンショット 2023-10-21 034807.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535733/34157f73-b679-a8ef-3084-44f7ad4b7e43.png)

投稿画面はこちら
![スクリーンショット 2023-10-21 120032.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535733/0b7ff537-3941-80e3-1bbc-334e077e3bea.png)
投稿内容確認する画面でこだわったポイント
![スクリーンショット 2023-10-21 121828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535733/3c1308ff-41ae-079d-5fcb-dcacc365998c.png)
３つシートを　追加担当者　ステータス　閉じる
・担当者はプルダウンで選択できるように
・ステータスは投稿者が進捗状況がわかるようにするため
・閉じるボタンは押すとアクション機能でホーム画面に戻れるようにしてます。

#  ﻿一緒に働く仲間たちからのレビュー
今回は、使い方となぜ制作したのかを説明し
ほしい機能・改善点のレビューを頂きました。

管理担当の方
ほしい機能
プッシュ通知機能をつけてほしい！
改善点
なんの用件なのか一覧でわかるといいですね
感想
実際に使ってみて、アプリで業務連絡できるのはすごく便利でした。
さらに使いやすくなるといいですね

日用品担当の方
ほしい機能
アプリを開かなくても新規投稿があったとわかるように通知機能がほしい。
使い方の説明ページもほしい
改善点
担当者の選択に「各部門名」・「全体」追加すると尚いい
感想
全体的に使いやすかった！

「使いやすい」という声を頂くことができました。
ただ改善点やほしい機能もいくつか頂いたのでバージョンアップしさらに使いやすいものにしていこうと思います。

# 最後に
今回は制作するだけでなく、実際に使用してもらうことで
自分では気づけなかったポイントをたくさん知ることができました。
これからもトライ＆エラーを繰り返し今よりもいい職場環境にできるよう頑張っていこうと思います！
最後まで読んでいただきありがとうございました！
[React]そもそもDOMとか仮想DOMって何よ？



Reactの勉強をする時、特にHooksを勉強する時とかよく「レンダリング」、「マウント」とか、useEffectだと「アンマウント」が出てきたりして「なんだっけ？」と思って何回も出てくるたびに調べ直した人は多いはず。
今回はその説明の大前提である「DOM」とか「仮想DOM」についてわかりやすく整理してみます。

## Webページを想像してみて下さい。
そこには文章や画像、ボタンなど、たくさんの要素が表示されています。これを一つ一つのブロックや箱と考えてみると、それぞれの箱には内容や位置、大きさなどの情報があります。

この各々の「箱」の情報や関係性をプログラムで扱うためのものが「DOM（Document Object Model）」です。

#### 可視化: DOM

想像してみてください。

📦  <- これがWebページ全体  
├ 📕 ← これがタイトル（例：`<h1>`タグ）  
├ 📗 ← これが段落（例：`<p>`タグ）  
└ 🖼  ← これが画像（例：`<img>`タグ）

これがとても単純化されたDOMの例です。実際のWebページにはもっとたくさんの箱（要素）が存在します。

ただ、このDOMを直接変更するのは重たい作業。毎回DOMを変更すると、ページの表示が遅くなったり、ちらつきが発生することも。そこで「仮想DOM」の出番です！

#### 仮想DOMって？

仮想DOMは、名前の通り「仮のDOM」。DOMの複製のようなもので、実際のDOMより軽量です。この仮想DOMでまず変更を行い、その変更を効率よく実際のDOMに反映させます。

#### 可視化: 仮想DOM

実際のDOM: 📦📕📗🖼  
変更したい内容: 📗を📘に変更したい！

1. 仮想DOMで変更を試みる。  
📦📕📘🖼

2. 実際のDOMとの違いを検出。  
📗と📘が異なる。

3. 実際のDOMに変更を適用。  
📦📕📘🖼

このように、仮想DOMを使うことでWebページの更新がスムーズに、そして高速に行えるのです。

次回はこれらの知識をもとにレンダリングとマウントについて、それらの発生時期？について整理してみます。
コードを最後まで終わらせるコード

# `brew upgrade`のダウンロードが途中で終了する
外出する直前に`brew upgrade`を走らせて家を出て、帰ってきたらターミナルプロンプトにエラーが表示されていてダウンロードが途中までしか終わっていなかったということが時々あります。 (ネットワークが貧弱なのでしょうか笑) 
これを回避するためにコマンドが無事終了するまで粘り強く実行し続けるコードが欲しいなということで備忘録です。
```sh
false; while [ $? = 1 ]; do "$@"; done
```
`$?`は直前に実行されたコマンドの終了ステータス、`$@`は全ての引数の意味ですので、例えば引数が`brew upgrade foobar`であった場合、途中でそのダウンロードが失敗すると`$?`は1となり、同じコマンドが続けて実行されて、ダウンロードが成功するまで終了しないという訳です。
(最初に`false`を実行するのは、繰り返しが始まる直前の`$?`はほとんどの場合0だからです。`exit 1`でもいいと思います。)
これを例えば`~/.zsh/functions/greedy`として関数登録しておけば
```sh
$ greedy brew upgrade foobar
```
を実行して安心して外出できます。
※関数の登録方法(`$FPATH`, `autoload` など)についての説明は割愛します、悪しからず。

内容に誤りがありましたらご指摘お願い致します。
【Image Creator】でのプロンプト手法について。画像あり。


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

　今回は、Microsoft BingのImage Creatorでのプロンプト手法についてです。ほかの画像生成AIで使えるかはわかりません。

:::note info
本記事は、Microsoft BingのImage
 Creatorで、画像を生成しています。
あしからず。
:::

　下記をやってから
　　いろいろとやっていました。
　　　正直ハマってますw
[【Bing＋ImageCreator 画像あり】女性の顔画像→町中に立つ女性を生成](https://qiita.com/kabumira/items/699d1ab57204d9c9aa8c)

　まずは、
　　こちらをごらんください。
![_a6362859-48ee-4e0a-b64b-9cd0ae1f63d5.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/7a26b7dc-7dd9-c306-71cd-d2481d5a8a50.jpeg)


　これは私の作品です。
　　「天音（Amane）」と
　　　命名しました。

　名前は、
　　ともかく、
　　　この画像では、
　　　　Amaneが
　　　　　ヘッドフォンと
　　　　　　VRゴーグルを
　　　　　　　かぶっていますね。

　プロンプトとしては、
　　ふつうに、こんな感じで
　　　特徴はこうで、と
　　　　書きました。

　でも、
　　修正を加えていくと、
　　　なんか複雑怪奇になっていく。

　ふと、思い付いたのが
　　オブジェクト指向です。

　GoogleSGEに
　　尋ねました。
>オブジェクト指向（OOP：Object Oriented Programming）とは、ソフトウェア開発の考え方の1つで、処理を部品化して、部品を組み合わせることで1つのプログラムを作る考え方です。

　はい、
　　人や物を
　　　オブジェクト化しようと
　　　　考えたわけです。﻿

　表記方法は、
　　なんとなく、
　　　こうしました。
```Text:日本語
VRゴーグル{白い。前面が黒く、青い文字で「Amane」と大きく表示}
```
　英文ならば
```Text:英語
VR goggles {white. Black front with big blue letters saying "Amane"}.
```
　まず、
　　物の種類（あるいは人）、
　　　「{}」の中に、詳細を記入。

　上記のプロンプトだけを
　　与えると
![Screenshot_20231019-124215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/4b62ff8d-86a2-4681-57b7-8c7bb1b4987b.png)


　となります。

　これを
　　Amaneや
　　　ヘッドフォンにも適応。

　最後に
　　描きたい状況を
　　　書きます。

　これで、
　　修正が楽になりました。

　この
　　オブジェクト指向プロンプトを
　　　使っていくと、
　　　　こんな感じになります。
![_ecab2d54-6b48-4e60-8390-e93cdb0a1766.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/fd278258-0d18-1104-140c-7d66947c77a9.jpeg)


　みなさんも
　　使ってみてください。

　今回は、ここまで。
Macでブラウジング：ショートカット集

## Command + キー (+ shift)の動作

| Command 　　　| キー | 動作 | +shift |
|-----------|-----------|-----------|-----------|
| Command   | A     | 全選択     |タブ検索|
| Command     | C     | クリップボードに保存    ||
| Command   | D     | ブックマークに保存     |すべてのタブをブックマークに保存|
| Command     | F     | ワード検索    |全画面|
| Command   | G     | 最後にcommand+Fで検索したものが*次に*出てくる場所検索|〃*前に*〃|
| Command     | L     | 現在のURL選択    ||
| Command   | N    | 新しいウィンドウを開く    |新ウィンドウでシークレットタブを開く|
| Command     | O     | ファイルを開く    ||
| Command   | P     | 印刷ダイアログを開く     |
| Command     | Q     | アプリケーションを終了する    |ログアウト|
| Command   | R     | リロード    |スーパーリロード|
| Command     | S     | 保存    |
| Command   | T     | 新しいタブを開く    |
| Command     | V     | クリップボードからペースト    |
| Command   | W     | 現在のタブを消去    |ウィンドウ消去|
| Command     | X     | 切り取り    ||
| Command   | Y     | 履歴を開く    |
| Command     | Z     | 元に戻す    |やり直す("元に戻す"をキャンセルする)|
| Command   | [     | 前のページに戻る    |1つ前(左)のタブに移動|
| Command     | ]     | 次のページに戻る    |1つ後ろ(右)のタブに移動|
| Command     | option + 矢印    |  タブ移動   ||
| Command     | 1~8    |  最左(1)から数値通りにタブ選択   ||
| Command     | 9    |  最右のタブ選択   ||
| Command     | control + F    |  フルスクリーン表示   ||
| Command     | tab    |  アプリケーション切替  ||
| Command     | スペース    |  Spotlight検索  ||


## 最後に
よくブラウジングで使うようなコマンドをまとめてみました。
もし他に便利なコマンドがあればぜひ教えてください！
カンマ区切りの文字列からテーブルを作成する方法

カンマ区切りの文字列からテーブルを生成し、
以下のデータから対象のIDのレコードを取得する方法を説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3247892/8a0c6b34-7f84-ea91-3f7a-a7d0e6ae06d9.png)

## コーディング例
``` SQL
WITH 対象ID AS (
	SELECT value AS ID FROM 
    string_split('0000000003,0000000004,0000000006', ',')
)

SELECT * FROM 商品マスタ 
INNER JOIN 対象ID ON ID = 商品ID
```

## 結果
商品IDが0000000003と0000000004と0000000006のレコードを取得できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3247892/41f920ab-e793-6308-2e94-69b7549202fd.png)

## ポイント
:pencil2: `STRING_SPLIT`は第一引数の文字列を、第二引数で指定した区切り文字で分割して、結果をテーブルとして返却する関数です。
`STRING_SPLIT([文字列], [区切り文字])`

:pencil2: `WITH句`を使用して、クエリ内でテーブルを新たに生成するこができます。
`WITH [作りたいテーブル名] AS ([作成したいテーブルを作るクエリ])`
3ヵ月間仕事の昼休みをタイピング練習に費やした結果

# はじめに
　新卒1年目の初夏、タイピングが趣味で、自分より圧倒的に速くコードを書く同期がいました。動画などで高速タイピングを見たことはありましたが、自分の目で見たのは初めてのことで、興味を持ちました。「あの速さでコーディングするのは、どんな感覚なんだろう」そんな思いで、タイピングに喜びタイピングに苦しむ昼休みを始めました。
　練習にあたって私が一番恐れていたことは、途中で飽きて辞めてしまうことでした。だから毎日の練習結果を記録に残すことにしてみました。練習を通して上達していることが可視化できれば、飽きずに続けられると思ったからです。

# やったこと

* 昼食が終わったら[e-typing](https://www.e-typing.ne.jp/english/words/business.asp)で英語タイピング(IT)を繰り返す
* 腕が疲れる、「もうやりたくない」と思ったらやめる
* 練習した日は最高WPM(タイピングの速さ)を記録する
* e-typingの最高スコアを更新したら同期に報告する

e-typingの英語タイピング(IT)はこんな感じです
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922519/847392c8-57d8-6803-ea0c-f9d9e7d6f591.png">

# 結果
　土日、忙しかった/やる気がなかった昼休みのWPMは記録していませんが、約3ヵ月でタイピングの速さが2倍以上になりました。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922519/f956e79a-e999-f333-47b4-0b7355478ff0.png">

# 感じたこと
### 6月
　一番成長を感じた時期でした。ほぼ毎日「昨日より速い」と感じながら練習していました。同期に最高スコアを報告できるタイミングも多く、楽しかったです。(彼が最高スコアを毎回讃えてくれたことがモチベーション維持に繋がりました。優しい人で良かったです)
　練習開始前はキーボードをチラチラ見ながらタイピングしていましたが、タッチタイピングははじめの3日くらいで「遅くてもなんとか」できるようになったので「タイピングの練習、割とすぐ結果出て面白いかも」と感じました。

### 7月
　6月と比べて伸び悩んでしまったため、モチベーションが下がらないよう「一週間前の自分よりも速くやろう」と考えながら練習していました。思うような最高WPMが出せなかった日は「(体感で)最低WPMが上がっている」ことに目を向けるようにしていました。7月後半になると、周囲から「なんかタイピングを頑張ってる人」として認識され始め、目標にしていた同期以外の方からタイピングについて話題を振られることが出てきました。
　また、言葉で表現するのは難しいのですが、7月は自分のタイピングが速くなったと感じたときの感覚が以下のように変化しました。
(「digital versatile disc」の場合)
　7月前半：「d、i、g、i、…」の「、」にかかる時間が短くなっていく
　7月後半：「digital」「versatile」「disc」の単語ごとにかかる時間が短くなっていく

### 8月
　思うようにスコアを伸ばすことができず、ついに8月に燃え尽きました。一週間練習しても最高WPMを更新できず、「こんな記録を残したくない」という思いから、WPMの記録を放棄するようになりました。6月～7月は昼休みに20分～30分練習していましたが、8月は10分も経たずに辞めてしまっていました。そんな中8月16日に久しぶりに最高スコアを更新し、「やっぱり今までの練習には意味があったんだ！！」と大喜びしました。しかしそれからも同じような喜びのために成長が実感できない練習を続ける気力は残っておらず、最高スコアを更新したタイミングで昼休みのタイピング練習を中止することにしました。
　8月は以下のような現象が起こるようになりました。
* タイピングの速さに脳が追い付かず、どの文字でミスしたのか分からない
　(=単語のどこかで不要な打鍵をしたが速すぎて自分でもよく分からない)
* 私が動かそうとする速さより速く指が勝手に動く

# まとめ

* チラ見タッチタイピングをしていたが、30分×3日でタッチタイピングを習得できた
    * 手元ではなくe-typingの画面を見てタイピングすることが重要
    * 上達するためには継続が必要
        * 10分でもいいから毎日練習した方がいい
* 練習の継続にはモチベーションの維持が重要
    * タイピングの練習は初めの1か月が最も成果が出て、楽しかった
    * 練習の成果が出なくなってからモチベーションの維持が重要になった
    * 褒めてくれる人の存在が大きかった
    * たぶん「タイピングたのし～！」という気持ちで練習できたらもっと継続できた
    * 「すき」「たのしい」の気持ちは重要
* 業務にも影響があった
    * コーディングが速くなった
        * 英語タイピングを練習していたので、コーディング高速化に直結した
    * 脳内のコードをさくさく出力できてストレスが減った
【個人開発】空耳クイズアプリ「空耳English」をリリースしました

## はじめに
こんにちは、りょうと申します！
私は現在、プログラミングスクールに通い、完全未経験からWebエンジニアへの転職を目指しています！
Webアプリを制作する機会がありましたので、その成果をご紹介させていただきます！
まだまだ学習中のため、内容に誤りがある場合がございます！
その際は、コメント等で教えていただけると幸いです！


## 作成したサービス
![SCR-20230913-ljyx.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514733/85783976-edbd-1a63-5524-9be93956e1ad.jpeg)
* サービス名：空耳English
* サービスURL：https://www.soramix2english.com
* Github：https://github.com/ryotaroinagaki/Soramix2English

## 開発の背景
私は昔から英語が好きで、勉強に励んでおりましたが、英語学習が継続的にできず思うように勉強したことが身につかないと感じることが何度もありました。
そのような課題を感じながら学習を進めている中で、“英語耳”という本に出会いました。その本では「リスニングができない人は英語の音を知らない。知らないから知っている音（日本語）に変換してしまう」という文章が書かれておりました。
この文章から、英語スキルを取得する上では知っている音を増やすことが大切だと深く実感し、英語の音を学べるサービスが作りたいと考えました！
また、学習を継続させるためには楽しさや面白さのある内容の方が良いと考えたため、空耳で日本語に聞こえる英語の洋楽を問題にして、英語の音について学べるアプリとして「空耳English」を開発いたしました！

## 実装機能

* ユーザー登録・退会機能
* ログイン・ログアウト機能
* Googleアカウントログイン・ログアウト機能
* パスワード再設定機能
* プロフィール表示・編集機能
* レベルアップ機能
* X（旧Twitter）共有機能
* クイズ一覧表示機能
* クイズ機能
* ランキング機能
* クイズいいね機能
* クイズブックマーク機能
* レコメンド機能
* 検索機能・オートコンプリート機能
* 音声認識機能
* 音声合成機能
* お試し体験(ゲストログイン)
* 管理ユーザー機能
* テスト機能（RSpec）

## 技術選定
* Ruby 3.2.2
* Rails 7.0.6
* Node.js 20.5.0
* CSS tailwind, daisyUI
* Webアプリケーションサーバ heroku
* データベース PostgreSQL
* ファイルサーバ AWS S3

## 主に使用したgem
* sorcery
* rails-i18n
* config
* googleauth
* meta-tags
* aws-sdk-s3
* kaminari
* ransack

## こだわりの機能
実装した機能の中で、特に拘った機能は以下の2つです！
* レコメンド機能
協調フィルタリングをベースにしており、ユーザーの嗜好に合わせたクイズを提供します。
具体的には、似た傾向のユーザーを特定し、それに基づいておすすめのクイズを提示します！

通常、クイズは難易度ごとに3問ずつ出題されますが、レコメンド機能を実装するために、クイズの難易度をランダムに選びたいと考えました。
そのため、セッションを使用してユーザーの回答数をトラッキングしています。
これより、もしもレコメンドできるクイズが2問しかない場合、3問目が存在しないことから生じるエラーや、過去に解答したことのあるクイズが出題されないようにしています。
その結果、2問しかない場合には2問しか出題しないようになります。セッションを使用して回答数を管理することで、システムを柔軟に調整できるようにしました！

* 音声認識・音声合成機能
ユーザーは音声を聞いた後、すぐに音声認識機能を使用して自分の発音を確認できるようにしました！
ユーザーが聞いた内容をすぐに実践し、アウトプットできるように設計しています。そのため、英語の音に関する課題を一貫して解決することに役立てるようにしました！

![Qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514733/ce5e71ed-9f24-ffe9-37b3-d4e4f9a59121.gif)


## 最後に
今回初めて、0からWebアプリを作成してみました！
クイズアプリを作成するに当たって、どのような流れで処理を行えばいいのかなどを考えなければいけない点が大変でしたが、自分で考えることによって非常に学びにつながりました！!
また、多くのユーザーさまに使っていただきたくお試しを押すだけで登録なしで本アプリをお楽しみいただけます！
ぜひ、遊んでいただけたら嬉しいです！
今後はさらに多くの技術を習得し、ユーザーに満足してしていただけるアプリを開発できるように頑張っていきたいと思います！
初めての記事で、読みにくい箇所が多々あったと思いますが、最後まで読んでいただきありがとうございました！
Qiita Markdown 書き方

Qiita記事の基本的な書き方。備忘録として。

# 見出し

＃スペース　⚪︎⚪︎

＊　＃は英数表記でないと正しく表示されないので注意


# コマンド
｀｀｀(バッククオート3つ)でコードをくくる

＊これも必ず英数表記にすること


```
aaaaaaaaa
```
Nuxt3で.envに環境変数置きたい備忘録

## Nuxt3でAPIを使いたい
コードにAPIキーベタ書きはアカンので.envファイルに書いてコンポーネントから読み込む

### 1 .envファイルを用意する
プロジェクトルートディレクトリに.envファイルを用意
``` .env
API_KEY_HOGE = HOGEHOGE
API_KEY_FUGA = FUGAFUGA
```
### 2 nuxt.config.tsに記述する
nuxtの設定ファイルでruntimeConfigプロパティを定義する
```nuxt.config.ts
  runtimeConfig: {
    apiKeyHoge: process.env.API_KEY_HOGE,
    public: {
      apiKeyFuga: process.env.API_KEY_FUGA,
    },
  },
```
runtimeConfig直下に記載すると、サーバーサイドのみで読み込み可能。
public下に記載すると、クライアントサイドからも読み込める。

### 3 コンポーネントから読み込む
```App.vue
<script lang="ts">
const runtimeConfig = useRuntimeConfig();
const apiKeyHoge = runtimeConfig.apiKeyHoge;
const apiKeyFuga = runtimeConfig.public.apiKeyFuga;
<script>
```

### 4 参考記事
https://qiita.com/A-Kira/items/ce784fede3faa8b62150

https://tyotto-good.com/nuxtjs/environment-variable

https://developer.mamezou-tech.com/nuxt/nuxt3-app-configuration/

https://www.kalium.net/image/2022/09/18/nuxt-config-js%E3%81%ABdotenv%E3%81%AE%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E5%8F%8D%E6%98%A0%E3%81%95%E3%81%9B%E3%82%8B/