OmniAICreator/Qiita-1.07M huggingface dataset:
Worldcoin / World IDを自作アプリと統合する

本記事では、World IDを用いた認証を自作アプリに組み込む方法について解説します。公式のガイドラインは下記にあります。

https://docs.worldcoin.org/id/sign-in

# World IDの認証連携

World IDは、OpenID Connect（OIDC）に準拠した認証プロバイダであるため、OIDCをサポートする任意の認証ライブラリやフレームワークを使用してWorld IDと統合することが可能です。

使用できる典型的な互換の認証エンジンには、Auth0、AWS Cognito、CloudFlare Access、OneLoginなどがあります。ほとんどの言語とフレームワークには、これに対応するシンプルなオープンソースパッケージがあります。

本記事ではWorld ID認証をAuth0と連携させる方法について解説します。

## 前準備
まずは、Auth0のアカウントとテナントを作成します。
https://auth0.com/signup

次にWorldcoin Developer Portalのアカウントを作成します。
https://developer.worldcoin.org
サインインするためには、World Appをダウンロードし、電話番号の確認を完了する必要があります。

## World IDの設定
Worldcoin Developer Portalに移動し、新しいアプリを作成します。
作成方法は下記に記載していますのでご参照ください。

https://qiita.com/trickstar03/items/06e827d6738101a8c6b0#1-developer-portal%E3%81%B8%E3%81%AE%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%A4%E3%83%B3

アプリを作成し終えたら、Developer PortalのSign In設定セクションに移動し、Redirect URIに``https://{domain}/login/callback``を追加します。``{domain}``はAuth0のテナントドメイン(``dev-xxxxxx.auth0.com``)です。
Client IDとClient Secretは後で使用するのでメモしておきます。Secretは更新したときにだけ表示されるので、一度resetする必要があります。これらの値はAuth0での接続設定時に使います。

## 接続の追加

https://marketplace.auth0.com/integrations/worldcoin

上記リンクにアクセス後、``Add Integration``を選択し、必要なアクセス要件を読んで、Continueを選択します。
Client ID, Client Secret, アプリケーションに必要な権限を入力し、Createします。

![Screenshot 2023-07-30 at 1.58.48.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466824/21aebe4f-d5d3-e6ed-7921-08467eefd25e.jpeg)

Applicationsビューで、この接続を使用してログインするアプリケーションを選択します。
![Screenshot 2023-07-30 at 8.47.31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466824/21f462c0-d397-5623-7b7e-81c79ccaed2a.jpeg)


## 認証テスト

Try Connectionを押すと、World ID認証用のQRコードが表示されます。World AppシミュレーターにQRを読み込ませ、認証します。![Screenshot 2023-07-30 at 2.02.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466824/82fa2800-b4e8-4b5b-4af1-12f57b39f9ac.jpeg)

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466824/6054684f-2a0b-28b3-9df7-870178a2306d.jpeg">

認証成功すると、下記のような画面が表示されるはずです。
![Screenshot 2023-07-30 at 2.03.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466824/70bbaf09-386e-e3e5-18fc-248e1f21ce81.jpeg)

以上で設定は完了です。これで自作アプリの認証プロバイダをAuth0にすることで、World IDを用いた認証管理ができるようになります。

Auth0連携のサンプルアプリは[こちら](https://github.com/auth0-samples/auth0-nextjs-samples/tree/main/Sample-01)が参考になります。

# その他
公式のサインインチュートリアルにあるNext.jsと連携させるNextAuth Templateがあるのですが、Developer Portalでredirect先URLを設定するところでエラーとなり、断念しました。プロトコルがhttpのリダイレクト先は設定できないのかもしれないです。サンプルもあまり更新されていないです。

![Screenshot 2023-07-30 at 8.51.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466824/6763eb24-27ee-9c47-e6f0-e0cd1f68ad3a.jpeg)

# P.S.
関連記事を貼っておきます。

https://qiita.com/trickstar03/items/1202554b80c114c00d8b

https://qiita.com/trickstar03/items/06e827d6738101a8c6b0
【超基礎】Salesforce × DataSpider

## はじめに
最近、Salesforce案件の他チームでよく使用されている、DataSpiderというデータ連携ツール。自分は使ったことはないので、少し調べてまとめてみようと思います。

## DataSpiderとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1025346/89d2cd60-0409-4ac9-568b-33b8d0246b72.png)
https://www.hulft.com/software/dataspidercloud

システム間のデータ連携を、ノーコーディングで実現するクラウドサービス。
Salesforceとの連携は、国内最多クラスとのこと。
Salesforce専用アダプタがあるため、システム間連携が容易に設定可能。 

DataSpiderで社内システムと連携する方法には、大きく2つある。
1. データベース連携
    - 社内のデータベースに対し、DataSpider Cloudが直接データを読み書きする連携方法。
    - 例えば、salesforce上で操作ユーザがボタンを押下すると、社内システムから必要なデータを取得し表示するといった使い方が可能。
1. ファイル連携
    - 社内システムから出力されたファイルを、DataSpider Cloudが取得しSalesforceに連携する方法。
    - 逆にSalesforceから取得したデータをファイル形式にして、社内システムに連携することも可能。


## DataSpiderの開発の進め方
1. トリガのタイミングとI/F形式の決定
    - DataSpiderが提供するトリガ機能
        - ファイルが配置されたタイミング、定期実行、他のアプリケーションからのCall、etc...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1025346/76a83f5b-bfa8-10b1-9199-52027a730977.png)
    - 連携の方向（Salesforce → DataSpider、DataSpider → Salesforce）
    - I/F形式：JSON、XML、SOAP、csvなど
   
1. 疎通確認
    - salesforceとの連携に関しては、次章でまとめる。
1. データの加工
    - https://www.hulft.com/help/ja-jp/DataSpiderCloud/index.htm

## DataSpiderとSalesforceの連携
SalesforceとDataSpiderの相性は非常に良いため、設定も簡易に行えます。
1. 事前準備(API接続のためのセキュリティ設定)
    - セキュリティトークンを発行する。
    - 接続元IPアドレスを許可する。
2. Salesforceアダプタでの接続
    - グローバルリソース接続設定の新規作成で[Salesforce接続設定 API34.0]を選択する。
    - 認証方式は複数あるが、一番簡易に設定できるのはID/パスワードによる認証方法。

3. SalesforceからDataSpiderの処理を起動
    - DataSpider側ではHTTP/Webサービストリガーを使用する。
    - Salesforceからトリガーへリクエストを送信するには下記のような方法があります。
        - 画面のリンクやボタンをカスタマイズしてブラウザからHTTPリクエストを送信する。
        - Apexコールアウトリクエストを送信する。
        - アウトバウンドメッセージアクションでWebサービスリクエストを送信する。


## まとめ

DataSpiderとsalesforceの連携は、GUIから容易に設定が可能。どういうタイミングでデータを連携するか、どういう種別のデータを連携するかを事前に検討が必要。
DataSpiderの詳細な使い方はマニュアルを使いながら、インプットする。
QwikCityの`server$`で`RequestEvent`にアクセスする方法

`server$`の関数シグネチャは

```ts
const serverAction = server$((...args) => {
  // ...
});
```
という感じで`routeAction$`のように引数に`RequestEvent`オブジェクトが渡ってこないのですが、これにアクセスするにはアロー関数を使わずに

```ts
const serverAction = server$(function(...args){
  this; // <- RequestEvent object
});
```

という感じで`this`にバインドされて渡ってきます。
Reactで混乱することのない useRef と createRef の理解と適用



こんにちは、Reactを使った開発で遭遇するかもしれない問題について解説します。今日は、`useRef` と `createRef` の違いとそれぞれの使用例について詳しく見ていきましょう。



## useRef と createRef の基本

Reactでは、`useRef`と`createRef`という2つの異なるrefの作成方法が存在します。これらは主にDOM要素への参照を取得するために使用されますが、それぞれ異なる目的と状況で使用されます。

`createRef`は主にclass componentで使用され、毎回新しいrefインスタンスを作成します。つまり、React componentが再レンダリングされるたびに新しいrefが作成されます。

一方、`useRef`はReact Hooksの一部であり、function componentで使用されます。最初の呼び出し時に引数として与えられた値で初期化された`mutable`なrefオブジェクトを返します。そのオブジェクトは`.current`プロパティを持ち、このプロパティは参照の対象となる値を変更できます。そして、コンポーネントが再レンダリングされるたびに同じrefオブジェクトが返されます。

---

##  createRef の使用例

以下に、Reactのclass componentで`createRef`を使用する基本的な例を示します。

```jsx
import React from 'react';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  componentDidMount() {
    this.myRef.current.focus();
  }

  render() {
    return <input ref={this.myRef} />;
  }
}

export default MyComponent;
```

ここでは、`createRef`を使用してinput要素への参照を作成し、componentがマウントされた時点でそのinput要素にフォーカスを当てています。

---

##  useRef の使用例

次に、Reactのfunction componentで`useRef`を使用する基本的な例を示します。

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

function MyComponent() {
  const myRef = useRef();

  useEffect(() => {
    myRef.current.focus();
  }, []);

  return <input ref={myRef} />;
}

export default MyComponent;
```

この例では、`useRef`を使用してinput要素への参照を作成し、componentがマウントされた時点でそのinput要素にフォーカスを当てています。`useRef`は最初に作成したrefを再利用するため、同じrefオブジェクトが返される点に注意してください。

---

##  useRef と createRef の違い

`createRef`と`useRef`の主な違いは、再レンダリング時に新しいrefインスタンスを作成するかどうかです。`createRef`は毎回新しいrefを作成しますが、`useRef`は最初に作成したrefを再利用します。

したがって、refの値を追跡する必要がある場合や、refの値が変更されてもコンポーネントを再レンダリングしたくない場合は`useRef`を使用します。また、`useRef`はReact Hooksの一部であり、function componentで使用されます。

---

## まとめ

この記事では、Reactの`useRef`と`createRef`の違いとそれぞれの使用例を見てきました。適切に使用することで、Reactアプリケーションのパフォーマンスを改善し、コードの可読性を高めることができます。


---

最後に、この記事が役立つと感じたら、ぜひ「いいね」を押してください。あなたのサポートが私たちの励みになります。ありがとう！
Pythonで非同期処理

TypeScriptでフロントエンドの開発していた頃に非同期処理をゴリゴリ書いていましたが
今はPythonで同期処理ばかりで、Pythonで非同期処理が作成できないか調べてみました

Python3.11からasyncioというライブラリを使用して非同期処理が作成できるようになりました

https://docs.python.org/ja/3/library/asyncio.html

# 1.asyncioについて

>asyncio は async/await 構文を使い 並行処理の コードを書くためのライブラリです。
>
>asyncio は、高性能なネットワークとウェブサーバ、データベース接続ライブラリ、分散タスクキューなどの複数の非同期Pythonフレームワークの基盤として使われています。
>
>asyncio は多くの場合、 IOバウンドだったり高レベルの 構造化された ネットワークコードに完璧に適しています。
>
>asyncio は次の目的で 高レベル API を提供しています:
>・並行に Python コルーチンを起動 し、実行全体を管理する
>・ネットワーク IO と IPC を執り行う
>・subprocesses を管理する
>・キュー を使ってタスクを分散する
>・並列処理のコードを 同期 させる
>
>これに加えて、ライブラリやフレームワークの開発者が次のことをするための低レベルAPIがあります:
>・ネットワーク通信、サブプロセスの実行、OSシグナルの取り扱いなどのための非同期APIを提供するイベントループの作成と管理を行う
>・Transportを使った効率的なprotocolを実装します
>・コールバックを用いたライブラリとasync/await構文を使ったコードの橋渡し
>(本文引用)

公式サイトの非同期処理のサンプルコードです

```Python
import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

asyncio.run(main())
```

# 2.非同期処理が役立つ業界
+ Webアプリ
 リクエストを並行して処理することができ、アプリのケーラビリティを向上させることができる
+ DBアクセス(I/O)
 I/Oが時間がかかる場合があるため、並列処理させることで他の処理を待たずにI/Oできます
+ バッチ処理
 大量のデータを処理するバッチジョブで並列処理させることができるので効率が上がります。
+ メッセージキュー
 一度に多量のメッセージを受信した場合に同時に処理することができる
+ IoT
 デバイスから送られてきたデータをリアルタイムに処理する必要があるため非同期処理が便利です
+ イベント処理
 ユーザの画面クリックなどの処理を受けつつ他の処理をすることができます
+ ネットワーク通信
 APIやプロトコルの通信では、レスポンスを待つ間に他の処理をすることができます


# サンプルコード
ネットワーク通信を例に非同期処理をコードで紹介します

```python
import asyncio
import aiohttp

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def download_pages(urls):
    tasks = [fetch(url) for url in urls]
    # 複数の非同期タスクを並行して実行
    return await asyncio.gather(*tasks)

if __name__ == "__main__":
    urls = [
        "https://qiita.com/",
        "https://qiita.com/timeline",
        "https://qiita.com/trend"
    ]

    # 非同期で複数のウェブページをダウンロード
    results = asyncio.run(download_pages(urls))

    # 結果を表示
    for i, result in enumerate(results, 1):
        print(f"Page {i}:\n{result[:200]}...\n")
```

fetch関数でページをダウンロードしています。
download_pages関数のreturn await asyncio.gather(*tasks)
asyncio.gather(*tasks)で前のページのダウンロードを待たずに、今回だと3ページ分を同時並行でダウンロードしています。
gatherは全てのtask、今回の場合はダウンロード処理が終わるまで待ちます。

また、1つのtask実行時にエラーが発生すると処理が続行されませんが、asyncio.gather(*tasks, return_exceptions=True)とすることで1つのtaskのエラー時に他のtaskは続行されます。

GitHubで公開しているのでダウンロードできます

https://github.com/takuya-wooooo/sample-async


# おわりに
光通信、4G、5Gの到来でネットワーキングや通信に関するアプリは普及してきています。現代のアプリは多くのユーザから一度に多くのリクエストを受けることがあります。そのため効率的な処理が求められます。そこで、今回のasyncioのような非同期処理の重要になってきます。
React+TypeScriptでフォーム作成にトライ

TypeScriptでReactのフォーム作成にトライしたので、メモを残す。

完成形のコードは下記になる。
```typescript:TestForm.tsx
import { useState,FC } from "react";

export const TestForm :FC =()=> {

    interface Value {
        num: number;
        title: string;
        sentence: string;
    }


    const[value,setValue] = useState<Value>({
        num: 0,
        title: "",
        sentence: "",
    });

    const handleInput = (e: React.ChangeEvent<HTMLInputElement>) =>{
        setValue({...value,[e.target.name]: e.target.value });
        //console.log(value);
    }

    const handleTextArea = (e: React.ChangeEvent<HTMLTextAreaElement>) =>{
        setValue({...value,[e.target.name]: e.target.value });
        console.log(value);
    }

    const formSubmit = (e:any) =>{
        e.preventDefault();
        alert(value.num + '\n' + value.title + '\n' + value.sentence);

    }

    return(
        <form className="w-96 ml-auto mr-auto mt-10 p-5 border border-slate-400 rounded-lg" onSubmit={formSubmit}>
            <h1 className="text-4xl text-blue-600">Typescriptのフォーム</h1>

            <div>No:</div>
            <input 
                type="number" 
                name="num" 
                className="block w-full border border-slate-400 rounded-lg"
                onChange={handleInput} 
            />

            <div>タイトル</div>
            <input 
                type="text" 
                name="title" 
                className="block w-full border border-slate-400 rounded-lg"
                onChange={handleInput} 
            />

            <div>本文</div>
            <textarea 
                name="sentence" 
                className="block w-full border border-slate-400 rounded-lg"
                onChange={handleTextArea} 
            ></textarea>

            <button 
                type="submit" 
                className="block mt-10 bg-gray-800 w-full h-10 text-white ml-auto mr-auto rounded-lg shadow-lg font-medium text-1xl"
            >
                送信
            </button>

        </form>
    );
}
```

レンダリング結果はこんな感じ(cssはtailwindowを使ってます)
![type.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332453/8d024095-884a-e306-267f-784408189cd9.png)

各項目に名入力して送信ボタンを押すとその内容がアラートで出力されます。
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332453/60b43e90-bc3b-1942-ff42-d59b7308956e.png)
エンジニア歴3ヶ月、新しい現場にて学んだこと

## 新しい現場のタスク
結合テストを行っていました。
特に自分が担当しているのは、データを入れるデータベースに様々なデータを格納し、テストを実行していました。

## 学んだこと
### ①何の為に仕様書やテストがあるのか考えてみる
「どんなデータをDBに格納すると良いのか」、「資料のどこを見たら良いのか」という不安を持ちつつ、テストを消化していました。そこで、テストする意味や仕様書が作成される理由を考え見ると、目的が見え、自分が見るべきポイントや適切なテスト用のデータを知るきっかけに繋がりました。

### ②入力値と出力値を通じてDBの関係性を理解できる

### ③ポジティブ思考を持つ
タスクが消化出来ていないことを報告することや分からないことを質問することは、億劫になる行動です。私は叱責されるイメージがあるからだと思っています。また、SES事業を展開する企業に雇用されている私のようなエンジニアにとっては、動き続けることが大切だと思っています。そこで、報告や相談しても、受け入れてもらえるというイメージを持ったことで、より気持ちを楽にできるようになりました。

### 準備の重要性
テストする際、証跡として様々なファイルを取得したり、SQL文を発行したりする必要があります。そこで、円滑に進めるために、事前にSQL文や適切なデータを用意することが適切になることを気づきました。
秋月の1.3インチカラー液晶で遊ぶ(ST7789V2)(Arduino UNO)K-15560 ATM0130B3


ＡＴＭ０１３０Ｂ３使用フルカラー液晶コントロールキット
[AE-ATM0130B3]
通販コード　K-15560
発売日　2020/11/12

ST7789 ST7789V ST7789V2

ATM0130B3


https://akizukidenshi.com/catalog/g/gK-15560/


https://qiita.com/caa45040/items/3c57c159be0fd0f7a718


https://qiita.com/caa45040/items/8935036eab45af3b08d0





目的
ST7789その互換機の標準的なライブラリになっている
Adafruit ST7735　+ Adafruit GFXのインストール で
文字列を表示して遊ぶ


![o_cop632.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5299c2ff-8f75-1e11-a3aa-0c313f092916.jpeg)


![o_cop634.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e3a6c10b-64fb-8d8f-5bf7-89c837ebc754.jpeg)



接続

3.3V-3.3V(VDD(1))
5V-5V(VDDIO(2))
GND-GND(3)

13 sck- SCK(4)
12
11 mosi-MOSI(5)
10 cs-CS(6)
9 res-RES(8)
8 dc-D_C(7)

リセットとコマンドデータ切り替えが逆なので注意　何の事?


プログラム


```c++



//spi_st7789_UNO_uno_1


//ヘッダーファイル
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>


//定義
#define TFT_CS        10
#define TFT_RST        9 // Or set to -1 and connect to Arduino RESET pin
#define TFT_DC         8
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);


//初期化
void setup() {

  //240x240の液晶を使用する。
  tft.init(240, 240);           // Init ST7789 240x240

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  tft.fillScreen(ST77XX_BLACK);

  // テキストサイズを設定
  tft.setTextSize(3);
  // テキスト色を設定
  tft.setTextColor(ST77XX_WHITE);
  // テキストの開始位置を設定
  tft.setCursor(0, 10);


  // 1行目に46を表示
  tft.println("UNO");


  delay(1000); //1秒待つ

}//loop




```
ReactをTypescriptでビルドする

## ビルド方法
下記コマンドで、typescriptでのreactのプロジェクトが作成できる。


```
npx create-react-app (プロジェクト名) --template typescript
```

## プロジェクトを起動
まずは下記を実行
```
npm run build
```

完了したら、下記を実行するとサーバーが立ち上がる
```
npm start
```
以上です。
seeed studio aws用iotボタンを使って扉が開閉するのを検知してメールを送信する方法

seeed studio aws用iotボタンは[digikeyのこちら](https://www.digikey.jp/ja/products/detail/seeed-technology-co-ltd/102991334/12093283)で購入
購入後4日位で届きました。

本体センサーは0.1秒だけ通電するとクリックと認識するようである。
磁石センサーはノーマルクローズの[こちら](https://www.amazon.co.jp/E3-82-A8-E3-83-BC-E3-83-A2-E3-83-B3-amon-E9-96-8B-E9-96-89-E9-80-A3-E5-8B-95-E3-82-B9-E3-82-A4-E3/dp/B09FL4VNXJ/ref=dp_ob_title_auto?th=1)を使用する
扉が開き続けるとずっと電流が流れるので、電子部品をつける。

iotと磁石センサーの間に、ワンショット装置をかませる


コンデンサー 10μF（CT4-0805Y106M）と30kΩの抵抗を並列につないだ物をかませる
【React】デフォルトで生成されるファイルの単体テスト内容をまとめてみた。

# 背景
Reactでの開発において、単体テストのやり方をアウトプットとしてまとめました。
規模間の大きなReactでの開発になるにつれ、単体テストのコードを作成する必要性が大きくなってくると思います。
また、テストコードを作成しないといけないのでめんどくさく思ってしまいますが、単体テストを実施する事で後々の作業も楽になると考えています。

# 環境構築

### ■ React version：react@18.2.0

次のコマンドで開発するReactのひな形フォルダを作成します。
フォルダの作成が完了したら`cd`コマンドでそのフォルダに移動します。
```
npx create-react-app sampletest
```

# デフォルトで作成されているファイルについて

## ■ setupTests.js

作成されたひな形のうち、`setupTests.js`ファイルには以下の記述があり、デフォルトでテストに使用するライブラリがインポートされています。


```javascript:setupTests.js
import '@testing-library/jest-dom';
```
## ■ App.test.js
実施するテストの内容を`renders learn react link`のように記述し、Appコンポーネントをテストの対象としています。
テストを実施した際にこの`renders learn react link`の文字は出力されます。


```javascript:App.test.js
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});
```
上記の`/learn react/i`に関しては、下記`App.js`ファイルの**aタグ**内における`Learn React`の文字を指しています。


```javascript:App.js
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```
また、`/i`を記述する事で**大文字と小文字を無視**し、下記のコード部分でLearn ReactがApp.js内に**記載があるのか**を確かめています。
デフォルトではApp.jsのAppコンポーネント内にlearn reactの記載があるので、テスト結果としてはエラーなく成功します。

```javascript
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
```
実際に以下のコマンドでテストを行ってみます。
```
npm test
```

:::note info
補足：npm test について
以下画像のpackage.jsonの`scripts`部分にデフォルトで`test`の記載があるので、`npm test`でテストを実行する事ができます。
:::
![pckc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/b57f4e36-ba1e-671e-950e-0bd32a84755d.png)


このコマンドを実行すると下記画像の**Watch Usage**が表示されるかと思うので`a`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/7aab99f2-97a1-761e-8b61-f26511aad358.png)

以下のように問題なくテストが成功しました！
![reacttestimg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/bb3f38c4-7ba2-8ca7-501c-01729d71f8ec.png)
Windows11にて右クリックのメニューをWindows10版に変更する方法

# はじめに
最近、パソコンをWindows10からWindows11にアップグレードしました。新しいシステムでの仕様変更は、既存のシステムを使い慣れている者からすると少しストレスに感じます。本記事では、Windows11にてWindows10の右クリックメニューを復活させる方法を調査したものをまとめました。

# Step.1 レジストリのバックアップ
今回の記事ではレジストリを管理するファイルを編集して、右クリックのメニュー表示を変更します。ファイルの編集にあたって、問題が生じた際に元の状態へ戻れるようにバックアップ作業を行います。

## 1. 復元ポイントの作成
タスクバーにある検索欄にて「復元ポイントの作成」と入力して、[復元ポイントの作成]をクリックします。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/d30d4590-c632-5522-6a3d-b7f348e2d5a6.png">

そうすると、[システムのプロパティ]ウィンドウが表示されます。ここで、[Windows (C:)(システム)]を選択して、「作成」を選択します。[システムの保護]ウィンドウで復元ポイントに関するコメントを記述することができます。作成に成功すると、「復元ポイントは正常に作成されました。」と表示されたウィンドウが出現します。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/b2c7be10-f2a6-d19c-bae1-f0b3d2776a0a.png">

## 補足:「作成」を選択をできない
[システムのプロパティ > システムの保護 > 保護設定]にて[Windows (C:)(システム)]が「無効」となっている場合は「構成」をクリックして、[システム保護対象 Windows (C:)]ウィンドウから[設定の復元]にて「システムの保護を有効にする」を選択して「OK」にて確定します。

# Step.2 レジストリの編集
## 1.レジストリエディタの起動
タスクバーにある検索欄にて「regedit」と入力して、[レジストリエディター]をクリックします。
<img width=50% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/27e49a28-ec94-008c-1d98-f4b81ddb4902.png">

## 2.ディレクトリの移動
[レジストリエディター]ウィンドウにて、画面上部のアドレスバーに次を入力します。

    コンピューター\HKEY_CURRENT_USER\Software\Classes\CLSID

<img width=50%
src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/6e0cee01-bd4f-3f2b-4f24-be3065a03382.png">

## 3.キーの作成
[CLSID]を右クリックして[新規 > キー]を選択して次のキーを作成します。

    {86ca1aa0-34aa-4e8b-a509-50c905bae2a2}

<img width=50%
src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/6bd8ce36-a436-badc-2e11-1c7859aaf1f9.png">

作成した{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}キーに対して、先ほどと同様の手順で次のキーをさらに作成します。

    InprocServer32

作成したキーを選択して「(既定)」をダブルクリックして、[文字列の編集]ウィンドウ
で[値のデータ(V):]が空であることを確認して、「OK」をクリックします。再起動後、右クリックでWindows10仕様のメニューを表示できるようになっているかと思われます。

# おわりに
ご閲覧いただきありがとうございました。現在、私は新しいパソコンで開発環境を整えるために様々なツールを導入している状況です。今後、同様の作業をする際の忘備録として記事を投稿させていただいております。拙い点や誤っている点がいくつかあるかと思いますが、コメントにてご指摘、ご教授いただけると幸いです。

# 参考文献
- [Windows 11 - 右クリックメニューを旧仕様に戻す方法 - PC設定のカルマ](https://pc-karuma.net/right-click-context-menu-back-on-windows-11/)
- [Windows 11 - レジストリをバックアップする/復元する方法 - PC設定のカルマ](https://pc-karuma.net/backup-restore-registry-windows-11/)
Webhookを活用したMicrosoft Teamsへのメッセージ投稿方法

## はじめに
今回の記事ではWebhookを用いたMicrosoft Teamsへのメッセージ投稿の方法について記述する。
## Webhookとは
Webhookとは、あるシステムに何か特定のイベントが起きた時にサーバーからクライアントに通知するための手法の一つ。APIはユーザーからのリクエストに基づいて情報を提供するのに対し、Webhookは特定のイベントが発生した際に自動的に情報を送信する。

## Microsoft TeamsでWebhookを設定する
- Teamsアプリの右上の三点リーダーをクリック
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook1.png?raw=true)
- コネクタをクリック
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook2.png?raw=true)
- Incoming Webhookを追加する
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook3.png?raw=true)
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook4.png?raw=true)
- Incoming Webhookの構成をクリック
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook5.png?raw=true)
- Incoming Webhookの名前を入力して作成する
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook6.png?raw=true)
- WebhookのURLを取得する
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook7.png?raw=true)

## Railsプロジェクトの設定
今回はSidekiqを使って非同期にメッセージ送信処理をするworkerを定義する。
```Ruby
require 'net/http'
require 'uri'
require 'json'

class ReminderWebhookWorker
  include Sidekiq::Worker

  def perform(notification_id)
    notification = Notification.find(notification_id)
    vehicle = notification.vehicle
    user = notification.user

    # TeamsのWebhook URLを用意
    url = URI(user.webhook_url)

    # メッセージの内容
    message = {
      "@type" => "MessageCard",
      "@context" => "http://schema.org/extensions",
      "summary" => "Sample",
      "title" => "こんにちは",
      "sections" => [{
        "text" => "junpei314です"
      }]
    }

    # HTTPクライアントを作成
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    # POSTリクエストを作成
    request = Net::HTTP::Post.new(url.request_uri, {'Content-Type' => 'application/json'})
    request.body = message.to_json

    # POSTリクエストを送信
    response = http.request(request)

    # レスポンスのステータスコードを表示
    puts response.code
  end
end
```
以下実行結果。
![](https://github.com/junpei314/Apprentice/blob/main/blog/Webhook8.png?raw=true)

## まとめ
今回はWebhookを使ったMicrosoft Teamsへのメッセージの送り方を紹介した。
Microsoft Teams以外にもLINEやSlackなどでもWebhookを用いてメッセージを送れるとのこと。
今度試していきたい。


## 参考
[受信 Webhook を作成する](https://learn.microsoft.com/ja-jp/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet)
[Microsoft Teams連携機能を実装する](https://tech.stmn.co.jp/entry/2020/09/23/162142)
.net6 MAUI でApplicationDisplayVersion に1.0.0または1.0以外を指定するとBuild時にNuGetパッケージの復元エラーになる

.net6 MAUI でApplicationDisplayVersion に1.0.0または1.0以外を指定するとBuild時にNuGetパッケージの復元エラーになる。

テストプロジェクトを作成したいので、MAUIのテスト対象のプロジェクトのTargetframeworks にnet6.0を追加し、ApplicationDisplayVersion に2.0.0 や2.0を指定するとNuGetパッケージの復元エラーになる。

よく分からないがnet8では解消される模様。

多分現状ではnet6.0の不具合のようである。


github のissue 内で言及されている以下のタグをApplicationDisplayVersionの下に加えても解消しなかった。

```
<Version>$(ApplicationDisplayVersion)</Version>
```

または

```
<Version>$(ApplicationVersion)</Version>
```


Ref.

https://github.com/dotnet/maui/issues/12859

https://github.com/dotnet/maui/issues/10579
仮想マシンツールVirtualBoxのインストール

# 仮想マシン
仮想マシンとは、コンピュータ上で仮想的なコンピュータ環境を作り出すソフトウェアや技術のことです。今回インストールするVirtualBoxについても、軽くまとめておりますので、過去に記事を記述しましたので、ご興味があればご参考ください。

[仮想マシンについて - Qiita](https://qiita.com/banana_bancho/items/cc70c77b6875ff2fb976)

# 検証環境
検証日: 2023/07/29

- ハードウェア情報

|CPU | Core i7 8550U|
|---|---|
|物理メモリ|16GB |
|GPU|UHD Graphics 620|
|ストレージ|512 GB|

- ソフトウェア情報

|ホストOS  |Windows11|
|---|---|
|ソフトウェア  |VirtualBox 7.0.10|

## Step.1 インストーラのダウンロード
以下のサイトにて、[Download VirtualBox > VirtualBox binaries > VirtualBox x.x.x platform packages > ​Windows hosts] からインストーラをダウンロードできます。「VirtualBox-x.x.x-yyyyyy-Win.exe」というファイルが確認できるかと思われます。「x.x.x」はソフトウェアのバージョンを示しており、私が導入した際は「7.0.10」でした。

[Downloads – Oracle VM VirtualBox](https://www.virtualbox.org/wiki/Downloads)

## Step.2 インストールの実行
「VirtualBox-x.x.x-yyyyyy-Win.exe」をダブルクリックして、インストーラを起動します。次のウィンドウで[Next >]をクリックします。後に出現する設定画面は、特にこだわりがない場合はデフォルトで問題がないかと思われます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/850202dd-bab1-ecea-50ed-7bff0358ee45.png" width=50%>

無事にインストールが完了すると、次のウィンドウが表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/1584294d-1e2b-c800-6701-5bf9ce8853d6.png" width=50%>




### ※ 補足
次のウィンドウが表示される場合、Microsoft Visual C++ 2019 Redistributable Packageをインストールする必要があります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/3d4ddc32-124b-ba9e-39d1-854f38e4a5ce.png" width=50%>

次のサイトにある[Visual Studio 2015, 2017, 2019, and 2022]から、このパッケージは入手が可能です。

[Latest supported Visual C++ Redistributable downloads | Microsoft Learn](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)

# おわりに
ご閲覧いただきありがとうございました。現在、私は新しいパソコンで開発環境を整えるために様々なツールを導入している状況です。今後、同様の作業をする際の忘備録として記事を投稿させていただいております。拙い点や誤っている点がいくつかあるかと思いますが、コメントにてご指摘、ご教授いただけると幸いです。
私のKeyball61セットアップ

工事中、現在パーツリストとURLのみ

### 完成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45682/e0f513a3-bd0b-5e3d-f7ea-969c2b5dcfe8.png)

### パーツ


https://shirogane-lab.com/products/keyball61


| パーツ名称 | 固有名  | URL |  値段 |
| -------- | -------- | -------- | ------ |
| キット本体 | Keyball61 | https://shirogane-lab.com/products/keyball61 | 25,300 |
| Pro Micro | Pro Micro Type-c | https://shop.yushakobo.jp/products/3905 | 4,400 |
| LED | SK6812MINI-E |https://shop.yushakobo.jp/products/sk6812mini-e-10 |3,080 |
| キースイッチ | TECSEE tactile | https://shop.yushakobo.jp/products/7046 | 5,400 |
| スプリング | 35g金メッキスプリング | www.amazon.co.jp/dp/B071SLW5XH | 1,600 |
| ルブ | シリコンルブスプレー | www.amazon.co.jp/dp/B07H82T1PR | 700 |
| キーキャップ | XVX WoB | www.amazon.co.jp/dp/B0BXWTXMV5 | 3,380 |
| ケース | マットブラック | https://training-kbd.booth.pm/items/4921741 | 6,000 |
| トラックボール | ペリックス黒玉 | www.amazon.co.jp/dp/B08DD6GQRV | 1,500 |
| バッテリ | cheero Slim 5000mAh IoT機器対応 |www.amazon.co.jp/dp/B07W3Q8K6Z | 6,160 |
| スチールシート | シンワ測定スチールシート| www.amazon.co.jp/dp/B003479F2K | 340 |
| ラッピングフィルム | マットブラック | www.amazon.co.jp/dp/B00J94MPQ0 | 1,100 |
| 磁気プレート | VRIG 三脚マウント MagSafe用 |www.amazon.co.jp/dp/B0BNPVXC1L | 4,160 | 
| Z型雲台 | Neewer 折り畳み式Z型雲台 | www.amazon.co.jp/dp/B07GF9C2SY | 6,200 |
| USB2BT+ | USB2BT+ | www.amazon.co.jp/dp/B07DFY1ZQ9 | 12,400 |
| ケーブル | TypeA to TypeC L字 0.2m | www.amazon.co.jp/dp/B0B4JQ41SW | 1,000 |
| ケーブル | TypeA to microB L字 12cm | www.amazon.co.jp/dp/B07KZS8JDT | 1,400 | 
| アクリルプレート | グレースモーク アウタープレート | https://shop.yushakobo.jp/products/keyboard_acrylic_plate | 3,500 |
| アクリルプレート | 不透明ブラック ミドルプレート | https://shop.yushakobo.jp/products/keyboard_acrylic_plate |3,400 | 
|計|||9,1020 |
Tailwind CSSでフッターを固定する

## はじめに
こんにちは、エンジニア転職を目指してRailsを学習中のJintaと申します。
現在、ポートフォリオを作成中で、CSSのフレームワークにTailwindを使用しています。
そこで、コンテンツ量の少ないページ（ログインなど）を作成していた際に、フッターが下部に固定されず、フッターの下に余白ができて違和感を感じていました。

## どういう状況か？
今回はログイン画面で説明します。
修正する前のビューのコードとブラウザでの表示は以下のような状況です。
```html:application.html.erb
<html>
.
.
  <body>
      <%= render 'shared/header' %>
      <%= render 'shared/flash' %>
    <div class="bg-yellow-50">
      <%= yield %>
    </div>
      <%= render 'shared/footer' %>
  </body>
</html>
```
```html: sessions/new.html.erb
<div class="container mx-auto">
  <div class="px-5 border-opacity-50">
    <div class="grid place-items-center">
      <h2 class="place-items-centeer my-6 text-2xl text-bold">ログイン</h2>
    </div>
    <div class="grid place-items-center">     
      <%= form_with model: resource, url: session_path(resource_name), class: 'w-full px-5 md:w-3/5 md:px-0', local: true do |f| %>
        <div class="form-control">
          <%= f.label :email, class: 'label-text text-xl' %>
          <%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'input input-warning border-gray-800 border-opacity-50 bg-yellow-50', placeholder: 'sample@samplecom' %>
        </div>

        <div class="form-control mt-5">
          <%= f.label :password, class: 'text-label text-xl' %>
          <%= f.password_field :password, autocomplete: "current-password", class: 'input input-warning border-gray-800 border-opacity-50 bg-yellow-50', placeholder: 'パスワード（6文字以上）' %>
        </div>

        <% if devise_mapping.rememberable? %>
          <div class="field">
            <%= f.check_box :remember_me %>
            <%= f.label :remember_me %>
          </div>
        <% end %>

        <div class="actions">
          <%= f.submit "ログイン", class: 'btn btn-wide btn-neutral w-full mt-10' %>
        </div>
      <% end %>
    </div>
    <div class="grid place-items-center mt-10">
      <%= render "users/shared/links" %>
    </div>
  </div>
</div>

```
![スクリーンショット 2023-07-29 23.54.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600084/ec7729e5-9d16-7c08-1e3d-19103c1e481d.png)
コンテンツが少ないので、フッターの下に余白ができています。
かなり違和感を覚えますよね。

## 解決方法
```html: application.html.erb
<html>
.
.
  <body class="flex flex-col min-h-screen">
      <%= render 'shared/header' %>
      <%= render 'shared/flash' %>
    <div class="flex-grow bg-yellow-50">
      <%= yield %>
    </div>
      <%= render 'shared/footer' %>
  </body>
</html>
```
上記のように、bodyに「class="flex flex-col min-h-screen"」、コンテンツ部分に「div class="flex"」を適用することで、以下のとおり解決しました。
![スクリーンショット 2023-07-30 0.01.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600084/86ed22ba-f0ee-4e10-ee92-526b63431e6b.png)

解説としては、
・flex flex-colで、ページのコンテンツ（ヘッダー、コンテンツ、フッター）を縦方向に配置
・min-h-screenで、ページの最小の高さを画面の高さ（ビューポートの高さ）に合わせる。
・flex-growはデフォルト値が0で、余分なスペースは受け取らないみたいなので、コンテンツ量に合わせてサイズ調整される（コンテンツ量が少ない場合は、フッターが画面の下部に固定される形）。

## 最後に
これまでCSSに触れる機会があまりなかったので、勉強になりました。
ポートフォリオ作成を始めてまだまだ序盤ですが、作成の中で発見したことは、記事にして発信していきたいと思います！
ChatGPTの新機能 "Custom instructions"とは？

## 新機能 "Custom instructions"
[7/20にOpenAIはChatGPTに新機能のカスタム指示（Custom instructions）を追加しました。](https://openai.com/blog/custom-instructions-for-chatgpt)
これにより今まで質問をするたびに書いていた条件を再度入力する手間が省けることになりました。
8/1現在、この新機能は月額20ドルのChatGPT Plusに加入しているユーザーのみ使用することができます。

## 有効化手順
有効化の手順は以下の通り
#### ①Web版
　アカウント情報（ユーザー名部分）→設定→ベータ版機能→オプション内のカスタム指示のトグルをオン
#### ②アプリ版
　設定→新規機能→カスタム指示のトグルをオン

## 具体例
以下に具体的な"Custom instructions"を利用している例を提示します。
　※ChatGPTへの質問は画像内の人アイコン部分のみ
#### <details><summary>case1　3年生の理科教師として月についての重要項目を3つ挙げてもらう</summary>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2792638/631957ba-618f-a7d7-b461-c4ad26ff34e1.png)

</details>



#### <details><summary>case2　ソフトウェアエンジニアとしてGo言語を使用してコードを書いてもらう</summary>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2792638/24705417-bae9-c8a9-8081-4a3df75865d6.png)

</details>

このようにして"Custom instructions"を使用することで、加味してほしい前提条件を毎回質問に含める事なく意図した回答が得られるようになります。

## さいごに
これにより益々適切な条件付けを行いAIから最適な結果を得るプロンプトエンジニアリングの有用性が高まると個人的には思いました。
次回はそのChatGPTにおけるプロンプトについて調べまとめようかと思います。
PDF viewer で見ると問題無く、プログラムで読むと回転してしまうPDFに出会った話

# はじめに
PDFファイルに色々追記するプログラムを作っていた時の話です。  
いくつかの手持ちのPDFに文字やら何やらを追記していたところ、一部のPDFに期待の角度から90°、270°回転して文字が書き込まれていました。さらに詳しく調べると、どうやら通常は左下にある始点(プログラムによって異なる)の位置がPDFによってはずれてしまっていることが分かりました。

![変なPDF.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110482/c8a60cc5-406f-1dfe-3299-e8af5ae5486b.jpeg)

AdobeのPDF readerやMacOSX のプレビューアプリでメタデータを覗いたが分からず、"PDFの仕様は難しいので各種アプリが仕様通りに実装されていない場合もある"とブログに書く人もいるので、何を信じて良いかが分からなくなりました。結局、PDFをエディタで開いてみて、原因を見つけることができたので備忘録として残します。

# 結論: Page object に /Rotate が設定されている。

問題のPDFのページにはRotateが設定されていました。

> << /Type /Page /Parent <省略> /Resources <省略> /Contents <省略> /MediaBox [0 0 842.04 595.44]
/Rotate 270 >>

pypdf の transfer_rotation_to_content 関数(Apply the rotation of the page to the content and the media/crop/… boxes.) を実行することで、始点をページの左下に設定し直すことができました。

ちなみに、複合機が作成したPDFにRotateが設定されていることが多かったです。

以上です。
変数更新によるレイアウト反映のやり方


## やりたいこと
ボタンを押下したら、変数を更新させて、更新された変数に合わせて画面を反映させる（useStateは使わない(!?)）

## useState使いたくなかった理由
useStateを使うと、再レンダリングされてしまう為、上位コンポーネントの再レンダリングをした場合、再レンダリングする必要がない下位コンポーネントまでレンダリングされてしまうから、使いたくなかった

### 処理イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011212/4201ca3d-fdaf-7ed8-3365-d0eacaf43273.png)

## 結果：無理
正確には、propsに渡して再レンダリングさせれば可能ではあるが、今回やりたいことではなかった為、ノーカン

やっぱりsetStateで再レンダリングさせる必要がある

失敗したソースコード
```javascript:App.tsx
function App(){
  const v = [];
  for(let i=0; i<5; i++){
    v.push("test: " + i);
  }
  const [testReturn, setTestReturn] = useState(v);
  console.log(testReturn);
  const t = testReturn;


  function onClickEventHandler(){
    const newItem = "add" + testReturn.length;
    // setTestReturn([...testReturn,newItem]);
    t.push(newItem);
    console.log(t);
  }
return (
    <div className="App">
      <div>
        <button type="button" onClick={onClickEventHandler}>add</button>
        {
          t.map(
            text =>(
              <p key={text}>{text}</p>
            )
          )
        }
      </div>
    </div>
  );
}
}
```

上記だと、内部処理的にはDOMが増えていることになっているが、レイアウトに反映されていない為、失敗となる
（上記のような実装で表示できたら有難かった）

最終的なソースコード
```javascript:App.tsx
function App(){
  const v = [];
  for(let i=0; i<5; i++){
    v.push("test: " + i);
  }
  const [testReturn, setTestReturn] = useState(v);
  console.log(testReturn);
  const t = testReturn;


  function onClickEventHandler(){
    const newItem = "add" + testReturn.length;
    setTestReturn([...testReturn,newItem]);
    console.log(t);
  }
return (
    <div className="App">
      <div>
        <button type="button" onClick={onClickEventHandler}>add</button>
        {
          setTestReturn.map(
            text =>(
              <p key={text}>{text}</p>
            )
          )
        }
      </div>
    </div>
  );
}
}
```

## まとめ
変数更新によるレイアウト更新をしたい場合は、useStateを使ってレンダリング更新させる必要があると思い知らされた

## 最後に
Reactにちょっとだけ慣れたけど、コンポーネント設計間違えたら不要なレンダリングをいっぱいするから、気を付けた方が良い
1コンポーネントの再レンダリングにかかる時間みたいなものが分かれば、ユーザー操作によりレイアウト更新時間が大体見積れると思った
【iTerm2】単語単位の移動や削除をする方法

## 単語単位の移動
単語単位の移動は`Esc + b`や`Esc + y`で可能ですが、連続で移動しようとすると`b`や`y`が入力されます。  
任意のキーかつ連続で移動できる設定方法を以下に記載します。

### 設定画面を開く
iTerm2を開いて`cmd + ,`で`Preferences`を開きます。  
そして`Preferences`の`Keys`を開きます。
![image220427_003532.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/db56ab7a-24ef-e29b-1a26-2f40049ca8f5.png)


### 設定する
`Keys`の中の`Key Bindings`を開き、右下の`+`をクリックします。
![image220427_003907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/f0a5a062-5a8a-9228-0bc0-20da16120075.png)


`Keyboard Shortcut`に任意のキー、`Action`に`Send Escape Sequence`を選択、`Esc +`に`b`を入力し、`OK`をクリックします。
![image220427_004414.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/3cf3b380-5cf1-ecfb-5cfc-a3fb2754c529.png)


すると、任意のキー（上記の例では`cmd + ←`）で単語単位の移動ができるようになります。  
`Esc + f`は上記の`Esc +`の箇所に`y`を入力することで設定可能です。

### コマンドの先頭、末尾に移動する
コマンドの先頭、末尾に移動するにはデフォルトでは`ctl + a`、`ctl + e`です。
これも単語移動と同様に設定することで任意のキーで実行できます。

`Keyboard Shortcut`に任意のキー、`Action`に`Send Hex Code`を選択、入力欄に`0x01`を入力し、`OK`をクリックします。
![image220427_010727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7b9e33cf-bdce-47bd-0008-3eb4af9fba5f.png)


これで任意のキーでコマンドの先頭に移動できます。  
`ctl + e`は上記の入力欄に`0x05`を入力することで設定可能です。

## 単語単位の削除
デフォルトでは`Ctr + w`で単語削除ができますが、以下のように設定することで任意のキーで単語単位の削除ができます。  

### 設定方法
「設定画面を開く」までは移動と同様です。  
`Keyboard Shortcut`に任意のキー、`Action`に`Send Hex Code`を選択、入力欄に`0x1b 0x08`を入力し、`OK`をクリックします。
![image220427_012849.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/85e0c419-06e5-f81a-0e40-e38ed7d9f7a0.png)


上記の設定をすると任意のキーで単語単位の削除ができます。
スクレイピングを実際にやってみて初心者が感じたことや必要だと思ったことを共有したい

今回ある目的のためにとあるサイトをスクレイピングすることにしました。
スクレイピングに関する情報はネット上にも多くあり調べやすくはありましたが、なかなか自分が実装したいことと関係しているのか判別ができるほどの知識がないことで苦労しました。
スクレイピングは初心者が挑戦するには難易度が高いものだと素直に感じました。なぜならネット上で転がっている初心者向けの記事は理解するのも難しいし、その知識を使って自分が対象としているサイトでそれを実行できるとは限らないからです。特にスクレイピングに関して自分が実現したい理想的なことと自分の知識量のなさによる現実の制約との間でギャップがかなりあります。



実際にやってみたことでスクレイピングを実行する上で知っておいてほしい必要なことを自分みたいな初心者の人のためにも共有したいと思います。

1. Pythonの文法知識を抑える：
　スクレイピングを行う上でいろいろな言語がありますが、解説の情報量からパイソンをお勧めします。そのうえでパイソンに関する基本的な文法知識に関してはmustで抑えてほしいです。これができないと正直何も手を付けることができません。

2. requestsを使えるようになる：
　スクレイピングを行う上でこのrequestsは非常に重要なものとなっております。スクレイピングしたい対象のデータを取得する必要がありますが、そのときにこのrequestsを使うことでhtmlからエンコードとデコードの作業をします。これをしないと実際に使える情報にならないのですが、その理由を詳しく知るにはバイト列といった知識も必要となっていますが、これはあくまで補足的なものです。とにかくまずこのrequestsを最初に行うということを認識してくれたらいいです。

3. html、cssに関する基本書を読む：
　個人的にはこのhtml,cssの勉強もしてほしいと考えています。なぜなら自分が抽出したいと思っている情報がなんなのかによって取りうるスクレイピングの手段が変わってくるからです。今回自分が抽出したい情報のタグがtdでした。当初はseleniumやbs4を使う予定でしたが、このタグで調べてみるとpandasを使う方法が一番楽だと知ることができました。このように自分が実現したいものによって何を勉強すべきかが変わってきます。それらを判断するためにも基本書を読んでおくといいと思います。

4. スクレイピングの対象サイトが静的か：
　動的の場合seleniumやbs4に関する勉強をする必要があります。しかしもし静的ならこれらを勉強しなくてもスクレイピングを実行できる可能性はあります。



初心者の場合は簡単な静的なサイトで、かつ１ページと限られたページから特定の情報を抽出してみるというスクレイピングを経験してみるといいと思います。そこから複数ページにまたがる動的なサイトから抽出するというように難易度を上げていくのがいいと個人的に思いました。

スクレイピングは難しいと思いますが、最終的に実装できたので自信をつけることができてよかったです。
Twitter（X）で自動でいいねするコンソールスクリプト

仕様上あんまり使う機会は無いと思うけど、こんなこともできるよっていうコンソールスクリプトの例です。
## Twitterで自動いいねするjavascript
```javascript
// data-testid="like" を持つ要素を取得
const likeButton = document.querySelector('[data-testid="like"]');

// もし要素が見つかった場合は、クリックする
if (likeButton) {
  likeButton.click();
} else {
  console.log("要素が見つかりませんでした。");
}
```
一番初めの投稿に対して1回「いいね」します。
## ワンライナー
```javascript
document.querySelector('[data-testid="like"]').click();
```
## 10回自動いいねする
```Javascript
for (let i = 0; i < 10; i++) { document.querySelector('[data-testid="like"]').click(); }
```
これは単純に10回ループしてるだけです。
PRにもいいねするし使い過ぎればすぐに制限食らうのであまり使えるスクリプトではないかもしれません。
aws-cliでCloudWatch Alarmをタグベースでフィルタしたい

`CloudWatch Alarm`は登録したアラームにタグをつける事ができます。

タグ付けできるので、`aws-cli`でアラーム一覧を取得してタグでフィルタすることも簡単にできるかと思いきや……

なんとaws-cliの`aws cloudwatch describe-alarms`では`CloudWatch Alarm`の一覧は取得できますが、ここにタグ情報はふくまれてない事に気が付きました。

この事に気がつく前は、`aws ec2 describe-instances`のように、一覧とタグ情報が一度に引けて簡単にフィルタ処理できるかと考えていましたが、`Cloud Watch Alarm`だとそうはできなかったので本記事で紹介します。

## ドキュメント

[describe-alarms](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/describe-alarms.html)

[get-resources](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/resourcegroupstaggingapi/get-resources.html)

[AWS リソースのタグ管理 〜タグ付けと統制〜（後編）](https://aws.amazon.com/jp/blogs/news/aws-tagging-and-governance-part2/)

## aws cloudwatch describe-alarms にはタグ情報がない！

[describe-alarms](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/describe-alarms.html)

[list-tags-for-resource](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/list-tags-for-resource.html)

2023年7月現在コマンドのドキュメントを確認すると、最初に気が付きますがアラームの一覧を取得できる`describe-alarms`の`output`に`Tags`がありません。

当然のようにタグ情報を取得できると考えてしまいますが、これがないのは`CloudWatch Alarm`自体へのタグ付けが最初からサポートされていたわけではなかった歴的な背景がありそうです。

[Amazon CloudWatch アラームにリソースレベルポリシーを使用できるようになりました](https://aws.amazon.com/jp/about-aws/whats-new/2019/04/you-can-now-use-resource-level-permissions-for-amazon-cloudwatch/)

## でもタグフィルタしたい

そもそも`CloudWatch Alarm`のタグ情報は`describe-alarms`では取得できず、`list-tags-for-resource`で取得できます。

[list-tags-for-resource](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/list-tags-for-resource.html)

ただし、`list-tags-for-resource`は必須引数として`--resource-arn`を指定する形となり、アラーム一覧をタグでフィルタしたいといった用途に使うためには。

`describe-alarms`で`CloudWatch Alarm`の一覧を取得し、それをベースに一アラームずつ`list-tags-for-resource`でタグ情報を取得する必要があります。

この方式だと、`CloudWatch Alarm`の登録された個数回、`list-tags-for-resource`を実行する必要があり残念な感じです。

## resourcegroupstaggingapiからせめてみる

`aws-cli`ではタグを取り扱う、`resourcegroupstaggingapi`もあるのでこちらからせめてみます。

`aws resourcegroupstaggingapi get-resources`でAWSリソースのタグを取得できます。

このコマンドのオプションに`resource-type-filters`があり、このオプションでサポートされているサービスは下記の一覧となります。

[Services that support the Resource Groups Tagging API](https://docs.aws.amazon.com/ja_jp/resourcegroupstagging/latest/APIReference/supported-services.html)

[AWS Resource Groupsとタグエディタで使用できるリソースタイプ Amazon CloudWatch](https://docs.aws.amazon.com/ja_jp/ARG/latest/userguide/supported-resources.html#services-cloudwatch)

この中に、`Amazon CloudWatch (alarms only)`と記載されており、アラームの情報だけ取得できます。

```powershell
aws resourcegroupstaggingapi get-resources --resource-type-filters cloudwatch:alarm --tag-filters Key=Name,Values=qiita
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/5c84616b-98f8-63de-373a-022048ac9ddf.png)

`aws resourcegroupstaggingapi get-resources`からせめたとによって、CloudWatch Alarmをタグでフィルタし,CloudWatch AlarmのARNを取得できました。

## 総評

過去の経緯？　から`describe-alarms`にタグ情報が含まれていないのは残念でしたが、リソースタグの方向からなんとかフィルタできました。

ただしタグで取得したアラームに対して、変更操作をしたい場合。

`delete-alarms`等は必須パラメータが`alarm-names`となっており、`arn`ではないので取得した`arn`をそのまま使えず、ひと手間追加で必要となる点はやっぱうまくいかない感があります。
20230729_自主学習MVVM_データレイヤ勉強編_DI完敗

## やったこと
* 公式のデータレイヤの研修
https://developer.android.com/courses/pathways/android-basics-compose-unit-5-pathway-2?hl=ja


## わかったこと
* データリソースの勉強も必要
* DIの箇所の理解不足
丁寧に勉強せねば。


## わからないこと
* サンプルアプリの画面レイアウトとしての、xmlファイルで存在しない。（別のやり方があるんだろう・・・）
＝＞　いろいろ調べているとこれであると推測。ChatGPTにも聞いてみました。

ChatGPT君が言うには・・・
>Jetpack Composeファイル：もしリポジトリがJetpack Composeを使用している場合、Jetpack Composeファイルが含まれている可能性があります。Jetpack Composeでは、UIコンポーネントがKotlinコードで直接記述されるため、XMLレイアウトファイルを使用しないことがあります。

## これからやること
完了まで行えていないので、続きやってみよう～。

## 偉大なる参考様
なし

いつもありがとうございます。

2023/07/30　追記
以下でかみ砕いて説明している動画を発見しました。
どの部分の何が問題か？を図で説明してくれていて、勉強になりました。
（文章を読むと理解した気にはなれますが、実際解説してもらうとよりイメージがわきました。）

https://youtu.be/SmiyWwP9Q1E
ローカル開発用にmemfsでOPFSを使用したファイルストレージを作ると便利

[OPFS(Origin Private File System)](https://developer.mozilla.org/ja/docs/Web/API/File_System_Access_API#%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)を使うとブラウザの中だけでストレージを利用でき、ローカルの開発環境でのみ実際に画像のアップロードをしたくないケースなどでいい感じに使える。

実装には[memfs](https://github.com/streamich/memfs)を使う。memfsには[crudfs](https://github.com/streamich/memfs/blob/master/docs/crudfs/index.md)というOPFS(a.k.a [File System Access API](https://developer.mozilla.org/ja/docs/Web/API/File_System_Access_API))のCRUDラッパーが実装されている。さらに、それをget/putだけに抽象化した[casfs](https://github.com/streamich/memfs/blob/master/docs/casfs/index.md)というラッパーも用意されており、これを使うとファイルストレージ的にOPFSを扱うにあたっては非常に便利。

以下が実装例。

```ts
import { FsaCrud } from "memfs/lib/fsa-to-crud";
import { CrudCas } from "memfs/lib/crud-to-cas";
import { IFileSystemDirectoryHandle } from "memfs/lib/fsa/types";
import uuid4 from "uuid4";

class InBrowserImageStorage {
  async uploadImage(file: File): Promise<string> {
    const buffer = await file.arrayBuffer();
    const manager = await this.getOPFSManager();
    return await manager.put(Buffer.from(buffer));

  }

  async getImage(fileName: string): Promise<string> {
    const manager = await this.getOPFSManager();
    const file = await manager.get(fileName);
    const blob = new Blob([file]);
    return URL.createObjectURL(blob);
  }

  private async getOPFSManager() {
    // ここの型はいい感じにできないものか...
    const dir =
      (await navigator.storage.getDirectory()) as unknown as IFileSystemDirectoryHandle;
    const crud = new FsaCrud(dir);
    return new CrudCas(crud, {
      async hash(blob: Uint8Array): Promise<string> {
        return createHash("sha1").update(blob).digest("hex");
      },
    });
  }
}
```

あとはinterfaceで抽象化して、実際のアップロードを行う実装と `NODE_ENV` かなんかで切り替えればよさそう。

```ts
interface ImageStorage {
  uploadImage(file: File): Promise<string>;
  getImage(fileName: string): Promise<string>;
}

class InBrowserImageStorage implements ImageStorage {
  // ...
}

class RemoteImageStorage implements ImageStorage {
  // ...
}

export const imageStorage: ImageStorage =
  NODE_ENV === "production"
    ? new RemoteImageStorage()
    : new InBrowserImageStorage()
```
GitHub に草が生えない (結論: フォークしたリポジトリだから)

# 目次
[1. Push しても草が生えない](#1-push-しても草が生えない)
[2. Fork したリポジトリだったから](#2-fork-したリポジトリだったから)
[3. Fork リポジトリをスタンドアローンリポジトリに変換する方法](#3-fork-リポジトリをスタンドアローンリポジトリに変換する方法)
[4. まとめ](#4-まとめ)
[参考文献](#参考文献)

# 1. Push しても草が生えない
ここ数日，GitHub に Push しても草が生えないという状態になってました．草を求めて日々 GitHub に Push しているわけではないですが，ひとつのモチベーションになっているのは確かです．
軽く調べると，メールアドレスの設定が原因で草が生えない人が多いみたいです．自分はコミットログに個人のメールアドレスを残したくなかったため，**@users.noreply.github.com** のアドレスを使えるように GitHub の設定をしていたので，もしかしたらそれが悪いのかなと思いました．しかし，**.gitconfig** には正しく設定できているし，自分のメールアドレスを表示させるように設定を変えても草は生えませんでした．

# 2. Fork したリポジトリだったから
結論，Push しても草が生えなかったのはメールアドレスの問題ではなく，そのリポジトリが 同僚のリポジトリから Fork したリポジトリだったからです．Fork したリポジトリに Push しても草は生えないみたい......
そもそも草が生えることをコントリビューションっていうみたいで，[コントリビューションの条件](https://docs.github.com/ja/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-contributions-on-your-profile)ってのがあるみたいです．コントリビューションとは GitHub への貢献を意味しているので，[Fork したリポジトリは Fork もとに Pull Request を送って Merge されないと貢献として認めて貰えない](https://qiita.com/Sakuya_wd/items/f50fbaba81bbf98eace5)みたいです．なんじゃそりゃ．
まあ草を生やすことが目的であれば，Clone して自分のリポジトリに Push するのが良さそうですね．一応手順を書いておきます，[いい感じにまとめてくれている記事もありました](https://kitigai.hatenablog.com/entry/2019/08/06/003834)が．
1. remote URL の確認．
`$ git remote -v`
1. 空のリモートリポジトリ作成．
1. remote URL の変更．
`$ git remote set-url origin [YOUR REPOSITORY URL]`
1. remote URL の確認．

# 3. Fork リポジトリをスタンドアローンリポジトリに変換する方法
[Github Support に連絡する](https://aloerina01.github.io/tip/2018-05-21-1)ことで Fork もとと切り離してくれるみたいなのですが，めんどくさそう．適当にやってみたら自分でも切り離せて草も復活したので，やり方を共有します．
1. GitHub 上で Fork したリモートリポジトリを削除．
1. 同じ名前のリモートリポジトリを新規作成．
1. ローカルのリポジトリから Push する (リモートリポジトリの URL は変わっていないので URL 変更の必要はない．リポジトリ名を変えるなら URL を変更する必要あり．)．

# 4. まとめ
今回は，GitHub の Fork についていい勉強になりました．単純に他人のリモートリポジトリをコピーする機能ってくらいの理解でした．OSS 開発などで本格的に貢献したい人用の機能のようですね．
それにしても，GitHubへの貢献とか言われてもよくわからないですね．金もらって働くように，草を生やすためにプログラムを書くのもいいのではないでしょうか．

# 参考文献
- プロフィールでコントリビューションを表示する, https://docs.github.com/ja/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-contributions-on-your-profile, 2023-07-29 確認
- git clone したリポジトリを別リポジトリに PUSH する，https://kitigai.hatenablog.com/entry/2019/08/06/003834, 2023-07-29 確認
- GitHub で草が生えなくなった時の対処法, https://qiita.com/Sakuya_wd/items/f50fbaba81bbf98eace5, 2023-07-29 確認
- ForkリポジトリをFork元から切り離してスタンドアローンなリポジトリにする, https://aloerina01.github.io/tip/2018-05-21-1, 2023-07-29 確認
逆三角関数の和の公式

あまりエンジニア向きの記事ではないかもしれませんが、求める機会がありどこにも載っていなかったので自力で導出してメモとして残しておきます。むしろ大学数学の記事かも。
今回は逆三角関数の中でも、逆正接関数の和の公式の証明していきます。

# 逆正接関数と和の公式
高校数学でお馴染み正接関数は、いわゆるタンジェント。
$x=tan\theta$ $(-\dfrac{\pi}{2}<\theta<\dfrac{\pi}{2}, -\infty<x<\infty)$
その逆関数を逆正接関数といい、アークタンジェントと呼びます。定義は以下。
$\theta=Arctanx$ $(-\dfrac{\pi}{2}<\theta<\dfrac{\pi}{2}, -\infty<x<\infty)$
定義域は実数全体ですが、値域が限られていることに注意してください。

そんな逆正接関数ですが、以下のような和の公式が成り立ちます（wikipedia[^1]にも載っていますがこちらには証明がありません）。初見では場合分けがよくわかりませんね。今回はこれを証明していきましょう（数学科の人間ではないので細かい点に関してはご容赦ください）。

| $Arctanx + Arctany =$  | $Arctan\(\dfrac{x+y}{1-xt}\)$ | $xy<1$ |
| ---- | ---- | ---- |
|  | $\pi+Arctan\(\dfrac{x+y}{1-xt}\)$ | $xy>1,x>0$ |
|  | $-\pi+Arctan\(\dfrac{x+y}{1-xt}\)$ | $xy>1,x<0$ |

# 証明
$x = tan\alpha,$ $y = tan \beta$ $(-\dfrac{\pi}{2}< \alpha, \beta < \dfrac{\pi}{2})$とおく。

すると、タンジェントの加法定理から
$tan(\alpha + \beta) = \dfrac{tan \alpha + tan \beta}{1 - tan \alpha tan \beta}$
$tan(\alpha + \beta) = \dfrac{x+y}{1-xy}$
となる。このとき、逆正接関数の値域と、$-\pi <\alpha + \beta < \pi$であることに気をつけると、
$Arctanx + Arctany = \alpha + \beta = \begin{cases} 
Arctan\(\dfrac{x+y}{1-xy}\) (-\dfrac{\pi}{2}< \alpha + \beta < \dfrac{\pi}{2}), \\
\pi + Arctan\(\dfrac{x+y}{1-xy}\) (\dfrac{\pi}{2}< \alpha + \beta),\\
-\pi + Arctan\(\dfrac{x+y}{1-xy}\) (\alpha + \beta < -\dfrac{\pi}{2})
\end{cases}$
となる。あとは、$\alpha+\beta$が$(-\dfrac{\pi}{2},\dfrac{\pi}{2})$に収まるか否かを判定すれば良い。

[$x>0$のとき]
$0 < \alpha < \dfrac{\pi}{2}$である。
さらに$y<0$とすると$-\dfrac{\pi}{2} < \beta < 0$より明らかに$-\dfrac{\pi}{2}< \alpha + \beta < \dfrac{\pi}{2}$となる。
$y>0$のとき、すなわち$0 < \alpha, \beta < \dfrac{\pi}{2}$のときに、$\alpha+\beta>\dfrac{\pi}{2}$となるのは
$\alpha+\beta>\dfrac{\pi}{2} \Leftrightarrow 
cos(\alpha+\beta)<0 \Leftrightarrow
cos\alpha cos\beta < sin\alpha sin\beta \Leftrightarrow
\dfrac{sin\alpha}{cos\alpha}\dfrac{sin\beta}{cos\beta}>1 \Leftrightarrow
tan\alpha tan\beta > 1 \Leftrightarrow
xy>1$

[$x<0$のとき]
$-\dfrac{\pi}{2} < \alpha < 0$である。$x>0$のときと同様にして$y>0$のときは$-\dfrac{\pi}{2}< \alpha + \beta < \dfrac{\pi}{2}$が保証される。
$y<0$のときは$-\dfrac{\pi}{2} < \alpha,\beta < 0$であり、
$\alpha+\beta<-\dfrac{\pi}{2} \Leftrightarrow
cos(\alpha+\beta)<0 \Leftrightarrow
cos\alpha cos\beta < sin\alpha sin\beta \Leftrightarrow
\dfrac{sin\alpha}{cos\alpha}\dfrac{sin\beta}{cos\beta}>1 \Leftrightarrow
tan\alpha tan\beta > 1 \Leftrightarrow
xy>1$

証明完了。

# 参考文献
[^1]: wikipedia「三角関数の公式の一覧　逆三角関数に関する公式」（2023年7月29日閲覧）（https://ja.wikipedia.org/wiki/%E4%B8%89%E8%A7%92%E9%96%A2%E6%95%B0%E3%81%AE%E5%85%AC%E5%BC%8F%E3%81%AE%E4%B8%80%E8%A6%A7#%E9%80%86%E4%B8%89%E8%A7%92%E9%96%A2%E6%95%B0%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E5%85%AC%E5%BC%8F）