OmniAICreator/Qiita-1.07M huggingface dataset:
301リダイレクトでアクセスが激減、3か月かけて回復

前回の記事から気が付けば、5か月経過してました。
経過やSEO上の変化が見えてきたので記事にしたいと思います。

前回の記事はこちらです。


https://qiita.com/damayasan/items/94c9c9ea64540938fe7e


この検証はサブディレクトリからサブドメインにURLを乗せ換えたものです。
最初はサブディレクトリで作成したサイト。

サイト間の関連性が低いと感じたのでサブドメインに変更しました。


ttps://kyoka-ok.com/marriage-visa/


↓↓↓↓↓↓↓↓↓↓


https://marriage.kyoka-ok.com/


結果を発表します。
検索結果のURLが全部入れ替わるまでに1か月ほどかかりました。

大半のURLは早い段階で変わりました。
しかし数記事は入れかわるまでに1か月要する結果に。

![2023y03m07d_202340312.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2897693/c5e6cfb4-4878-5d80-2142-ffd398b550a7.jpeg)


次にアクセス数ですが…
リダイレクト前の数字になるのに3か月かかりました。

301リダイレクト直後から2か月間はほぼゼロ。
2か月後の12月に入るころに徐々にアクセスが回復。；
それでも以前の20％あるか無いかの数字。

2か月経ってもアクセスが回復しないので、このサイトは使えないかなと思っていました。

正月明けの1月6日前後からPV数が急激に上昇しました。
なんとか以前のアクセス数まで回復することに成功しました。

ここで得た教訓は、必要が無いなら301リダイレクトは止めとけです。
数か月間はアクセスが消えます。

またサーチコンソールから、リダイレクトエラーの通知が複数回。
（来たところで何も出来なかった…）

エラーの内容はURLの重複です。
新しいURLがコピーコンテンツ扱いに。
その結果、新しいURLで順位が大幅に下落していました。

いい勉強にはなりましたが…
Googleのアプデでもないのに、順位もアクセスも爆死は心臓に悪いですね。

何かの参考になれば幸いです。

今気が付いたのですが、URLを貼るとカードタイプで表示されるようになったんでですね。
UbuntuでWebサーバー構築を試したときに参考になって記事まとめ

 ## 【図解】Ubuntu Desktop 22.04 LTS：Google Chromeインストール手順 
https://inab818.site/ubuntu-desktop/22-04-lts-google-chrome-download-install/



## Ubuntu 20.04にApache Webサーバーをインストールする方法
https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-ubuntu-20-04-ja

## Ubuntu、Apacheを用いて自宅webサーバー構築
https://qiita.com/m-m-mame/items/a8ca30058e7a2a9a24f1

## Ubuntuでcurlを使えるようにする
https://blackbird-blog.com/ubuntu-curl-setup

## [Sy] MySQL5.7 にて root のパスワード変更などの初期設定をする（mysql_secure_installation 使用）
https://utano.jp/entry/2017/10/mysql57-mysql-secure-installation/

## Ubuntu 20.04 LTSの自宅サーバーを建てた時のメモ
https://blog.tsukumijima.net/article/ubuntu-homeserver-setup/

## Ubuntuにifconfigをインストールする
https://kaworu.jpn.org/ubuntu/Ubuntu%E3%81%ABifconfig%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B
Javaを基本からまとめてみた【オーバーロード・コンストラクタ】

## オーバーロード
- クラス内に同じ名前で引数の型や数が違うメソッドを複数定義することを『オーバーロード』 
- 呼び出すメソッドは名前と引数の組み合わせで決めている

```
//メソッドを作る側   

class Student {
   void setData(String n){
}
　 void setData(String n, int e, int n){
 }
}
```
```
//メソッドを呼び出す側
main (){
  Student stu = new Student();
  stu.setData("Maickel");
```
```Sample1.java
class Student1 {
//メンバ変数(属性)
	String name;
	int engScore;
	int mathScore;

void setData(String n){
    name = n;
}
void setData(String n, int e, int m){
    name = n;
    engScore = e;
    mathScore = m;
}
void setScore(int e, int m){
    name = n;
    engScore = e;
    mathScore = m;
}
void display(){
    System.out.println(name + "さん");
    System.out.println("英語" + engScore + "点・数学"  + mathScore + "点");
	}
}
```
```Sample2.java
public class StuSample2 {
	public static void main(String[] args) {
		Student2 stu1 = new Student2();
        Student2 stu2 = new Student2();

		stu1.setData = ("Michael");
		stu1.setScore = (80,92);
	　　 stu1.display ();
         
         stu1.setData ("Michael",80,92);
         stu2.display ();
	}
}
```
## コンストラクタ
- オブジェクトの初期化のために使われる特殊なメソッドをコンストラクタと呼ぶ

ルール①　名前を『クラス名』と同じにする
ルール②『戻り値』を持たない
ルール③ new クラス名(コンストラクタへの引数)

```Rule①②.java
class Student {
//『戻り値』を持たない 大文字にする　※voidがいらない
   Student(String n){
}
　 Student (String n, int e, int n){
 }
}
```

ルール③ new クラス名(コンストラクタへの引数)
- コンストラクタを定義していない場合は、自動でデフォルトコンストラクタ（引数・処理なし）が生成される
例)Student(){}

```Rule③.java
main (){
  Student stu1 = new Student("Michael");
  Student stu2 = new Student("Kenny",80,92);
```
```Sample2.java
//Sample1.javaをコンストラクタを使用したらどのようになるかを作成

class Student2 {
//メンバ変数(属性)
	String name;
	int engScore;
	int mathScore;

//オーバーロード　
//オーバーロードとは引数の型や数が違わなければ同じ名前で複数定義できる

『void setData(String n){
    name = n;
}
void setData(String n, int e, int m){
    name = n;
    engScore = e;
    mathScore = m;
}』
//『』をコンストラクタに変換

『Student2(String n){
    name = n;
}
　Student2(String n, int e, int m){
    name = n;
    engScore = e;
    mathScore = m;
}』


void setScore(int e, int m){
    name = n;
    engScore = e;
    mathScore = m;
}
void display(){
    System.out.println(name + "さん");
    System.out.println("英語" + engScore + "点・数学"  + mathScore + "点");
	}
}
```
```Sample2.java
//実行用クラス

class StuSample2 {
	public static void main(String[] args) {
		Student3 stu1 = new Student3("Michael");
        Student3 stu2 = new Student3("Kenny",80,92);

		stu1.setScore = (80,92);
	　　 stu1.display ();
         stu2.display ();
	}
}
```



## 参考サイト
[オーバーロードのメリット（作る側・呼び出す側）を解説します！【Java入門講座】3-5 オーバーロード](https://www.youtube.com/watch?v=F31uBm7T8k4)
[コンストラクタを作る３つのコツと使うメリットとは？【Java入門講座】3-6 コンストラクタ](https://www.youtube.com/watch?v=WoCfOOpFc6A)
Amazon Cognito OAuth2.0 Client Credentials Grant 利用方法メモ

* Amazon CognitoでOAuth2.0 Client Credentials Grantを利用する方法をメモする

## Client Credentials Grantとは

![cognito_cc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/f8852b55-6540-4c0f-01ba-c12e5cb6b709.png)


* OAuth2.0で定義されている認可フローの１つ
* トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受けとるフロー
  * ユーザー認証を行わず、クライアントアプリケーションの認証のみが行われる

## Amazon Cognitoでの設定方法

ユーザープール、リソースサーバー、クライアント設定を行う

1. Cognito ユーザープールを作成する
2. アプリケーションの統合 -> リソースサーバーを作成する
   * リソースサーバー名
   * リソースサーバー識別子
   * カスタムスコープ
3. アプリケーションの統合 -> ドメインを設定する
4. アプリケーションの統合 -> アプリケーションクライアントを作成する
   * アプリケーションタイプ：秘密クライアント
   * クライアントのシークレット：クライアントシークレットを生成する
   * OAuth2.0許可タイプ：クライアント認証情報



## 動作確認

* トークンリクエスト

  ```http
  POST /oauth2/token HTTP/1.1
  Host: {ユーザープールドメイン}.auth.ap-northeast-1.amazoncognito.com
  Authorization: Basic Base64(アプリケーションクライアントID:アプリケーションクライアントシークレット)
  Content-Type: application/x-www-form-urlencoded
  Content-Length: 66
  
  grant_type=client_credentials&client_id={アプリケーションクライアントID}
  ```

* トークンレスポンス

  ```json
  {
      "access_token":"...",
      "expires_in":3600,
      "token_type":"Bearer"
  }
  ```

* アクセストークンの構造

  ヘッダー部

  ```json
  {
      "kid": "...",
      "alg": "RS256"
  }
  ```

  

  ペイロード部

  ```json
  {
      "sub":"{アプリケーションクライアントID}",
      "token_use":"access",
      "scope":"{クライアントに指定されたカスタムスコープ}",
      "auth_time":1678174231,
      "iss":"{ユーザープールドメイン}/ap-northeast-1_...",
      "exp":"1678177831",
      "iat":"1678174231",
      "version":2,
      "jti":"....",
      "client_id":"{アプリケーションクライアントID}"
  }
  ```

  ※`sub`と`client_id`にはアプリケーションクライアントIDが指定される

  ※`scope`にはクライアントに設定したスコープが設定される
[ React ] プルダウンメニュー作成する方法

初投稿！selectタグを使ってプルダウンメニューを実装しました。

## 完成コード
以下、コードの解説していきます。
```react:sample.jsx
const colors = ["red", "blue", "yellow"];

const PulldownMenu = () => {
  return (
    <>
      <select>
        {colors.map((color) => {
          return <option key={color}>{color}</option>;
        })}
      </select>
    </>
  );
};
export default PulldownMenu;
```



## １. プルダウン内で選択する値を定義する。

```react:sample.jsx
const colors = ["red", "blue", "yellow"];
```


## ２. mapメソッドを使用してプルダウンメニューを表示させる。
配列（colors）に定義されている値をoptionタグに入れてループさせます。
mapメソッドは配列に格納されている値を一つずつ取り出してループさせてくれます。
```react:sample.jsx
const colors = ["red", "blue", "yellow"];
const PulldownMenu = () => {
  return (
    <>
      <select>
        {colors.map((color) => {
          return <option key={color}>{color}</option>;
        })}
      </select>
    </>
  );
};
export default PulldownMenu;
```

:::note warn
注意
optionタグには、一意なkey属性を設定しなければなりません。
:::
以上、Reactでプルダウンメニューを実装する方法でした。
OSのディスククローンした際にBCDファイルを読み込めなくなったので備忘録

# OSのディスクをより大きい記憶域のものに換装したときにエラーが出た。
![DSC_0114.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3088998/febd6482-871a-ad0b-d50b-3f3257d66630.jpeg)

クローン作成したときに使用したソフトはMacrium　Reflectというソフト。

エラー内容としては「Windowsを起動する際のBCDファイルが読み込めなかったからインストールディスク突っ込んで修復してね」という
よくある内容。

何度か修復を実行してみたけどずっと同じエラーで読み込めない。

# そもそもでエラーを出さない方法
①クローンディスクを作成している途中に新しくOSを入れるドライブの記号を確認しておく。（私はF:でした）
②クローンディスクを作成完了したらすぐにコマンドプロンプトを開く。
③以下を実行。
```
cd /d F:\
bcdboot F:\Windows
```

そもそもでエラー起こす前にブートローダーをシステムディスクを元に復元しておけばエラー起きないよねって話。
ブート修復について参考

https://mo.kerosoft.com/0219
InfluxQL: 過去 24 時間からレコードを選択しますか?

あるクエリは:

SELECT mean("value") FROM "autogen"."°C" WHERE ("entity_id" = 'shelly_1l_our_room_device_temperature') AND $timeFilter GROUP BY time($__interval) fill(null)

同じデータを使用して 2 番目のクエリを追加しようとしていますが、24 時間遅れています

私は多くのことを試しましたが、うまくいかないようです:

SELECT mean("value") FROM "autogen"."°C" WHERE ("entity_id" = 'shelly_1l_our_room_device_temperature') AND DATE_SUB(NOW(), INTERVAL 24 HOUR) GROUP BY time(20s) fill(null)

SELECT mean("value") FROM "autogen"."°C" WHERE ("entity_id" = 'shelly_1l_our_room_device_temperature') AND time >= now() - 48h and time <= now() - 24h GROUP BY time($__interval) fill(null)

以上の構文は私には良さそうです。いくつかの問題があるのはデータ自体である可能性があります。

確認のため、以下をお試しいただけますでしょう：

1. 過去 24 時間のデータがあるかどうかを確認する

SELECT "value" FROM "autogen"."°C" WHERE ("entity_id" = 'shelly_1l_our_room_device_temperature') AND time >= now() - 24h

2.　集計を適用する

SELECT mean("value") FROM "autogen"."°C" WHERE ("entity_id" = 'shelly_1l_our_room_device_temperature') AND time >= now() - 24h GROUP BY time(20s) FILL(null)
SonarQubeを実行したときに出会ったエラー

https://docs.sonarsource.com/sonarqube/9.9/try-out-sonarqube/
を参照して、ローカルにソナーキューブを構築・実行した。

>C:\Program Files\sonarqube-9.9.7.96285\bin\windows-x86-64>StartSonar.bat
>Starting SonarQube...
>Unrecognized option: --add-exports=java.base/jdk.internal.ref=ALL-UNNAMED
>Error: Could not create the Java Virtual Machine.
>Error: A fatal exception has occurred. Program will exit.

Java17はインストール済みのはずと思っていたが、Pathの環境変数の順番でJava8が優先されていて、起動できていなかった。
Java17が通るように修正して、解決。

---
https://docs.sonarqube.org/9.6/try-out-sonarqube/
を参照して、ローカルにソナーキューブを構築・実行した。

> Execute the Scanner 
> Running a SonarQube analiysis is straighforward. You just need to execute the following commands in your project's folder.
> sonar-scanner.bat -D"sonar.projectKey=My_Trial" -D"sonar.sources=." -D"sonar.host.url=http://localhost:9000" -D"sonar.login=xxxxx"

とのことだったので、表示されているコマンドをプロジェクトのディレクトリ配下から実行したところ下記のエラーが発生。

> ERROR: Error during SonarScanner execution
> org.sonar.java.AnalysisException: Your project contains .java files, please provide compiled classes with sonar.java.binaries property, or exclude them from the analysis with sonar.exclusions property.

classファイルよこせや。ということの様なので、classファイルが出力されているディレクトリ直下に移動してから再実行。
コマンド自体は成功したものの、結果を確認すると何も出力されていなかった。

> The main branch has no lines of code.

classファイルが出力されているディレクトリに移動して実行ではなく、
classファイルが出力されているディレクトリ「sonar.java.binaries」で指定し実行して解決。

以下の様な感じで、引数に追加
```
sonar-scanner.bat -D"sonar.projectKey=My_Trial" -D"sonar.sources=." -D"sonar.host.url=http://localhost:9000" -D"sonar.login=xxxxx" -D"sonar.java.binaries=bin" 
```
Bashでif節をNOPにするとエラーになる

## 背景
最近Bashでシェルを学習＆作成するようになり、後述のエラーで少しハマったので備忘録として記載。

## 事象
以下のような判定を書いたところ「予期しないトークン `elif' 周辺に構文エラーがあります」のエラーが発生。
見返してもそれっぽい構文ミスが見当たらない。
~~~bash
if [ $? -ne 0 ]; then
  #NOP
elif [ -z "hoge" ]; then
  touch /fuga/fuga.csv
fi
~~~
## 原因
if節の中が処理を書いていなかったことが原因。

## 対処法
処理なしとなっている箇所にコロンを書くことでエラーとならなくなる。
~~~bash
if [ $? -ne 0 ]; then
  :#NOP
elif [ -z "hoge" ]; then
  touch /fuga/fuga.csv
fi
~~~

メインで使用している言語のJavaやJavaScriptだと処理なしを許容しているので、盲点だった…
Requestクラスのauthorizeメソッドを使ってのリクエストの認可について学んでみる

## はじめに
laravelでバリデーションを設定する際に使用するクラスでRequestクラスがある。
その中にauthorizeメソッドがあるのだが、普段あまり触ることがなく、何をしてくれるメソッドなのか気になったので少しまとめてみる。

## authorizeとは
Laravel 9のRequestのauthorizeメソッドは、アクションが実行される前に、リクエストを認可するために使用される。
authorizeメソッドは、trueまたはfalseを返す必要がある。
trueを返すと、リクエストが認可されます。falseを返すと、リクエストは拒否される。
リクエストが拒否されると、403 Forbiddenエラーが自動的に送信される。

## もう少し細かく
authorizeメソッドには、いくつかの方法でリクエストを認可するかどうかを決定することができる。

### ログインしているユーザーの権限をチェックする
ログインしているユーザーが、リクエストに必要な権限を持っているかどうかをチェックすることができる。
たとえば、管理者だけが投稿を編集できるようにする場合、authorizeメソッドで管理者であるかどうかをチェックすることができる。

```test.php
public function authorize()
{
    return $this->user()->isAdmin();
}
```

### 特定の条件をチェックする
リクエストの内容に応じて、特定の条件をチェックすることができる。
たとえば、あるリソースが更新可能かどうかを判断する場合、更新しようとしているリソースが存在するかどうかを確認することができる。

```test.php
public function authorize()
{
    return Post::where('id', $this->id)
               ->where('user_id', $this->user()->id)
               ->exists();
}
```

### ポリシーを使用する
ポリシーを使用して、リクエストが認可されるかどうかを判断することができる。ポリシーを使用すると、より複雑な権限のチェックを行うことができる。
ポリシーのupdateメソッドを使用して、リクエストが認可されるかどうかを判断している。

```test.php
public function authorize()
{
    $post = Post::findOrFail($this->route('post'));

    return $this->authorize('update', $post);
}
```

### 具体的な条件に基づいて認可を行う
リクエストに含まれるデータや、リクエストを送信するユーザーに基づいて、認可を行うことができる。
たとえば、あるユーザーが自分の投稿だけを編集できるようにする場合、リクエストに含まれる投稿のIDと、リクエストを送信するユーザーのIDを比較することができる。

```test.php
public function authorize()
{
    $post = Post::findOrFail($this->route('post'));

    return $this->user()->id === $post->user_id;
}
```

以上
Private Endpoint が有効な(パブリックネットワークアクセスが無効な) App Service に デプロイを行う方法　その 4

# はじめに

https://qiita.com/georgeOsdDev@github/items/1827c2a5bc15db214cff

に対する回避策 4 となります。
この記事では、カスタムコンテナーを利用する場合の考慮事項について記載します。

https://learn.microsoft.com/ja-jp/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux

https://learn.microsoft.com/ja-jp/azure/app-service/deploy-ci-cd-custom-container?tabs=acr&pivots=container-linux

# カスタムコンテナー利用時のデプロイフローについて

カスタムコンテナーを利用するアプリケーションのデプロイにおいては、zip デプロイ等は必要ないため、Kudu のデプロイメント API を利用することはありません。
基本的にはアプリケーション側が、ACR や DockerHub 等のレジストリから Pull を行うことになるため、アプリケーション側からのアウトバウンド通信となる動作は Private Endpoint や、パブリックネットワークアクセスの制御の対象外となります。

なお、Pull 実行時に VNet を経由させる方法については本記事では言及しません。以下の記事を参考にしてください。
[ネットワークで保護されたレジストリからイメージを使用する](https://learn.microsoft.com/ja-jp/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux#use-an-image-from-a-network-protected-registry)

ただし、アプリケーションに pull を実行させる契機となる、webhook エンドポイントについては注意が必要となります。

## webhook エンドポイントについて

App Service for Container の webhook エンドポイントは [デプロイセンター]ブレードや、az cli で確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/0960d9ae-1b04-364e-d008-0f5ed28bf289.png)

```bash
az webapp deployment container config --name <app-name> --resource-group <group-name> --enable-cd true --query CI_CD_URL --output tsv
```

実際の値は以下のようなアプリケーションスコープのBasic認証情報込の Kudu のエンドポイントの URL となっています。

`https://$<app名>:<認証パスワード>@<app名>.scm.azurewebsites.net/api/registry/webhook`

または、

`https://$<app名>:<認証パスワード>@<app名>.scm.azurewebsites.net/api/docker/hook`

のような値が得られます。

Kudu の Basic 認証については下記の Wiki を参照してください。

https://github.com/projectkudu/kudu/wiki/Accessing-the-kudu-service#authentication--authorization

これらの API が呼び出されるとアプリケーションは、再起動および指定されているイメージを pull することになりますが、Kudu によって提供されるエンドポイントとなるため、Private Endpoint や、パブリックネットワークアクセスの制御の対象となります。

例えば、ACR からこのエンドポイントに通知を行う場合、パブリックにアクセスできる必要があり、パブリックネットワークアクセスが行なえない状態では Webhook は到達しません。

https://learn.microsoft.com/ja-jp/azure/container-registry/container-registry-webhook

> Webhook のエンドポイントはレジストリからパブリックにアクセスできる必要があります。

## 回避策

アプリケーションが利用するイメージのタグを `latest` に固定している場合などは、webhook をきっかけに再起動およびイメージの取得を行う方法は有効ではありますが、同一のタグを更新する運用を行う場合、スケールアウトしているインスタンスによって取得したイメージの内容が異なる可能性がでてきます。
また、イメージのリリースと、アプリケーションが提供するウェブサービスの更新のライフサイクルが同一とも限りません。

そのため、App Service においては、アプリケーションが利用するイメージのタグは明示的にユニークな値として運用することが適していると考えます。

その場合そもそも webhook は必要なく、イメージを随時異なるタグで更新した後に、任意のタイミングでアプリケーションが利用するイメージはアプリケーションの属性として更新することが良いと考えます。

アプリケーションの属性の更新には、Azure Management API が用いられるため、Private Endpoint や、パブリックネットワークアクセスの制御の対象外となります。
Rails SassC::SyntaxError Error: no mixin named prefix 解決法

# no mixin named prefixという謎のエラー
そう、それは突然現れる謎のエラー
```
SassC::SyntaxError at /users/sign_in
Error: no mixin named prefix
        on line 3:12 of app/assets/stylesheets/common.scss
>>   @include prefix(user-select, none, moz ms webkit);
   -----------^
```

Rubyのバージョンが原因なのか、出る人と出ない人がいたりもする。
治し方はもしかしたら色々あるのかもしれないが、一つ方法をメモとして残しておく。

# 解決法: scssファイルの階層を整える

例えば今回の場合階層はこう
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147005/1b7d6799-a64b-5aa6-dc7c-939530d96b86.png">

aplication.scssはこう

```aplication.scss
@import 'bootstrap';
@import 'switch';
@import 'variables';
@import 'mixins';
@import 'layout';
@import 'common';

@import 'flash';
@import 'forms';
@import 'tables';
@import 'search';
@import 'framework/**/*';
```

これを
階層はこう
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147005/36c62f7d-fc84-bdad-ebee-7320aec02973.png">

aplication.scssはこうするのです。

```aplication.scss
@import 'bootstrap';
@import 'variables';
@import 'mixins';

@import 'main/**/*';
@import 'framework/**/*';
```

数ヶ月前くらいにググった結果こうなったんやけどソースを忘れてしまった。
しかも今ググってもそれっぽい解決法が見つからないので信頼度70%くらいで活用してください！
他に方法があったらぜひ教えてください。
【Poetry】Poetryのチートシート

## Installation [#](https://python-poetry.org/docs/#installation)

- Linux, macOS, Windows (WSL)

  ```shell
  curl -sSL <https://install.python-poetry.org> | python3 -
  ```

- Windows (Powershell)

  ```shell
  (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
  ```

## Commands

- プロジェクトの新規作成 [#](https://python-poetry.org/docs/cli/#new)
  - `poetry new [project-name]`

- 既存プロジェクトの初期化
  - `poetry init`

- パッケージのインストール [#](https://python-poetry.org/docs/cli/#install)
  - `poetry install`

- パッケージのアップデート [#](https://python-poetry.org/docs/cli/#update)
  - `poetry update`

- パッケージの追加 [#](https://python-poetry.org/docs/cli/#add)
  - `poetry add [package-name]`
  - オプション
    - --group -G: 依存関係を追加するグループを指定
    - --dev -D: (非推奨 代わりに `-G dev` を推奨) 開発環境の依存関係としてパッケージを追加
    - --look: poetry.lockファイルを更新 (インストールは行わない)

- パッケージの削除 [#](https://python-poetry.org/docs/cli/#remove)
  - `poetry remove [package-name]`

- 実行 [#](https://python-poetry.org/docs/cli/#run)
  - `poetry run [command]`

- poetryのアップデート [#](https://python-poetry.org/docs/cli/#self-update)
  - `poetry self update`

## Configuration

- 設定の一覧表示 [#](https://python-poetry.org/docs/configuration/#listing-the-current-configuration)
  - `poetry config --list`

- 設定値を初期化する [#](https://python-poetry.org/docs/cli/#usage)
  - `poetry config [setting-key] --unset`

- 仮想環境を構築しない [#](https://python-poetry.org/docs/configuration/#virtualenvscreate)
  - `poetry config virtualenvs.create false`

- 仮想環境をプロジェクトと同一フォルダに構成する [#](https://python-poetry.org/docs/configuration/#virtualenvsin-project)
  - `poetry config virtualenvs.in-project true`

## Managing environments

- 仮想環境に関する基本情報を表示
  - `poetry env info`


## 参考文献

- [Poetry 公式](https://python-poetry.org/)
Ruby CGI::Session(CGI::Cookie)をSameSite属性対応する

# Ruby CGI::Session(CGI::Cookie)をSameSite属性対応する
ruby標準ライブラリ [CGI](https://docs.ruby-lang.org/ja/3.2/library/cgi.html) でセッション(やCookie)を利用していて、なおかつCookieにSameSite属性を付けたい人向けの記事です。

Railsなんかでは対応されているようですが、標準の CGI::Cookie や CGI::Session クラスではSameSite属性に対応していないんですね。自力でなんとかしてみます

## 過去の対応方法(ruby-2.7.7では無効)

今までは単純に `path` などの末尾に `; SameSite=xxx` 付けてしまえば大丈夫でした。

```ruby:sample.cgi
#!ruby
#-*- coding:utf-8 -*-
require 'cgi'
require 'cgi/session'
cgi = CGI.new
path = ENV['SCRIPT_NAME'] ? File.dirname(ENV['SCRIPT_NAME']) : '/'
path += '; SameSite=Strict'
session = CGI::Session.new(cgi, {"session_path" => path})
session['counter'] ||= 0
session['counter'] = session['counter'].to_i + 1
cgi.out("type" => "text/plain") do
  "counter: #{session['counter']}"
end
```

ただしこの方法は ruby 2.7.7 で CGI::Cookie に脆弱性の対応が入り使えなくなりました。
`path` は正規表現でチェックされるようになり、`;` などが含まれているとエラーです。

https://blog.tokumaru.org/2022/12/CVE-2021-3362.html


## ruby-2.7.7以降の対応方法

CGI::Cookie, CGI::Sessionクラスを改造することにしました

```ruby:cgisamesite.rb
#-*- coding:utf-8 -*-
require 'cgi'
require 'cgi/session'

class CGI::Cookie
  attr_accessor :samesite
  
  SAMESITE_VALUE_RE = %r"\A(Lax|Strict|None)\z"i
  
  alias :initialize_original :initialize
  alias :to_s_original :to_s
  
  def initialize(name = "", *value)
    @samesite = nil
    initialize_original(name, *value)
    if !name.kind_of?(String) && name.has_key?('samesite')
      self.samesite = name['samesite']
    end
  end
  
  def samesite=(str)
    if str and !SAMESITE_VALUE_RE.match?(str)
      raise ArgumentError, "invalid samesite: #{str.dump}"
    end
    @samesite = str
  end
  
  def to_s
    buf = to_s_original
    buf << "; SameSite=#{@samesite}" if @samesite
    buf
  end
end

class CGI::Session
  alias :initialize_original :initialize
  
  def initialize(request, option={})
    initialize_original(request, option)
    session_key = option['session_key'] || '_session_id'
    session_id = @session_id
    request.instance_eval do
      @output_cookies =  [
        ::CGI::Cookie::new(
          "name" => session_key,
          "value" => session_id,
          "expires" => option['session_expires'],
          "domain" => option['session_domain'],
          "secure" => option['session_secure'],
          "path" => option['session_path'] || (ENV["SCRIPT_NAME"] ? File::dirname(ENV["SCRIPT_NAME"]) : ""),
          "samesite" => option['session_samesite']
        )
      ] unless option['no_cookies']
    end
  end
end
```

これを require して以下のように使います

```ruby:sample2.cgi
#!ruby
#-*- coding:utf-8 -*-
require 'cgi'
require 'cgi/session'
require './cgisamesite.rb'
cgi = CGI.new
session = CGI::Session.new(cgi, {"session_samesite" => "Strict"})
session['counter'] ||= 0
session['counter'] = session['counter'].to_i + 1
cgi.out("type" => "text/plain") do
  "counter: #{session['counter']}"
end
```

CGI::Session.new の第2引数に `session_samesite` オプションを渡すだけでよくなりました。

CGI::Cookie や CGI::Session の構造が変わらない限りは使えると思います
Webpackの設定で @をプレフィックスとしたimportが可能にする

webpack.mix.jsはLaravel Mixで使用されるWebpackの設定ファイルです。WebpackはReactのビルド時に使用されるツールであり、importのパス解決を担っています。

Webpackで絶対パスを使うには、Webpackの設定ファイルにてresolve.aliasを指定します。Laravel Mixではwebpack.mix.jsでこれを設定することができます。

例えば、resources/jsにあるファイルを絶対パスで読み込む場合は、以下のように記述します。

```
const mix = require('laravel-mix');
const path = require('path');

mix.webpackConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'resources/js'),
    },
  },
});
```

このように設定することで、@をプレフィックスとしたimportが可能になります。

```
import App from '@/components/App';
```

上記の例ではresources/js/components/App.jsを読み込むことができます。
Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「BLOBライフサイクル管理規則」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「BLOBライフサイクル管理規則」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure でのストレージの実装と管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-storage/)
◇対応するモジュール
[BLOB ライフサイクル管理規則を追加する](https://learn.microsoft.com/ja-jp/training/modules/configure-blob-storage/5-add-blob-lifecycle-management-rules)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「BLOBアクセス層」](https://qiita.com/fsd-jume/items/fbb890c5802d71a98066)

## BLOBライフサイクル管理規則
### データセットのライフサイクル
・すべてのデータセットには一意のライフサイクルがある
・ライフサイクルの例と適したアクセス層
　-初期段階：頻繁にアクセス → ホットアクセス層
　-2週間後：たまにしかアクセスされない → クールアクセス層
　-1か月後：ほとんどアクセスされない → アーカイブアクセス層

### Azure Blob Storageのライフサイクル管理ポリシー
**◆ライフサイクル管理ポリシーの構成**
・ストレージアカウントレベルでルールベースの条件(1日1回実行)を定義
・ルールベースの条件をコンテナ/BLOBのサブセットに適用

**◆ライフサイクル管理ポリシーで可能なタスク**
・BLOBを下記のように切り替え、パフォーマンスとコストを最適化可能
　-ホットアクセス層 → クールアクセス層
　-ホットアクセス層 → アーカイブアクセス層
　-クールアクセス層 → アーカイブアクセス層
・ライフサイクル終了時にBLOBを削除可能

### ライフサイクル管理ポリシールールの構成
・If句がtrueと評価 → Then句が実行

**◆条件(If)**
・ポリシールールの評価句を設定
　-BLOBデータに適用する期間を設定
　-指定された期間におけるアクセスや作成/更新有無の確認
※次の日数より前：評価条件で使用する日数を指定

**◆その場合(Then)**
・ポリシールールのアクション句を設定
　-クールストレージに移動
　-アーカイブストレージに移動
　-BLOBを削除

## 次の学習内容
**◆BLOBオブジェクトレプリケーション**

https://qiita.com/fsd-jume/items/3c1e6e32bf9971de0fd7

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
ThinkPad E420 を再生

自分の facebook の書き込みによると、2011年に ThinkPad E420 を購入していました。もはや古過ぎて使っていなかったのですが、別のコンピュータが故障したので、こいつを復活させて、自宅で Kubernetes の練習をしようと思います。
![326356_2339683024765_1369917761_o.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/a79d3489-4b82-e207-59c3-a0a114e8df05.jpeg)

ハードディスクだと動作がもっさりするので、SSD に換装しよう思いました。すると以下の素敵な情報を見つけたので、早速 mSATA SSD を購入してインストールしました。
* [Thinkpad E420 mSATA SSD化とCloudreadyの起動時間](https://www.bchari.com/2021/02/cloudready-e420-2.html)
![1678180064307.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/912033d9-8dc6-d903-b72b-203114b5c98b.jpeg)
![1678180041411.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/7352ce3c-923b-0f35-08d4-1eadf655a176.jpeg)

何の問題もなく動作しております。実に素晴らしい。ちなみに、2023年3月6日に購入した 256GB の SSD は、2,780円。お安くなりましたね。

なお、メモリは約一年前に換装していて、16GB 積んでいます。メイカーの仕様上は 8GB までの対応となっていますが、この PC に載っているチップは 16GB でも対応しているらしく、こちらも普通に使えております。
透過型レーザー回転数測定器

# 回転数計測器が欲しい
何かとあると便利な回転数計測器・・・
本当は反射型が欲しいですが、難しかったため透過型を今回は作りました。

![IMG_20230307_173636481.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/09edc58a-4c05-fac9-ad68-a871cd4cd596.jpeg)

![IMG_20230307_173733844.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/fde93746-22da-1113-9776-9e78529de3c5.jpeg)


## 構成

+ レーザーモジュール(波長550nm)
+ フォトトランジスタ（波長900nm）
+ LM358N
    + 微分器
    + 比較器

まず、レーザーモジュールの波長帯域とフォトトランジスタの波長帯域があっていない。
よって、反応が悪い。

装置としては、レーザのとフォトトランジスタの間にものが通るとフォトトランジスタの出力が変化することで回転数が測れるというものである。On,OFFの二値で現れれば簡単だが、微妙な反応しかしない。手で遮ると1Vほど電圧が落ちるが、プロペラが間に通るのは一瞬すぎて電圧の変化量が小さ過ぎる。そのままではマイコンで反応が拾えないという問題がある。フォトトランジスタの反応の悪さはマイクロマウス関連で重要になる。



## 回路図
反応が悪いのと、どの電圧からONかOFFかは微妙な話になるため、微分器をまず通す。
そのあと比較器を通す

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/26362fde-52dc-4535-fb22-35066ad1a65f.png)

http://www.nteku.com/opamp/opamp-differential.aspx

によれば、今回の微分機は

```math
V_out = -0.136 \frac{dV}{dt}
```
になる。

## プログラム
外部割り込みがあるとカウンタが回り、タイマー割り込みで1秒あたりのカウント数に変換する。
センサにノイズが載っているため、外部割り込みで誤反応が何度かあった。割り込み後に何us経過したか確認して1.5ms以内だったら無視することにしている（つまり、$666count/s=40000count/s$以上は計測できないことになる）。

```C++
/*
 * プロペラ回転速度測定
 * 
 */
#include <MsTimer2.h>

volatile int count = 0;
volatile int w_count[10] = {0,0,0,0,0  ,0,0,0,0,0};
volatile unsigned long b_time;

void setup() {
  Serial.begin(115200);
  pinMode(2,INPUT);
  attachInterrupt(digitalPinToInterrupt(2),sensor_ditected,RISING);
  MsTimer2::set(100, time_fun);
  MsTimer2::start(); 
  b_time = micros();
}

void sensor_ditected(){
  unsigned long n_time = micros();
  if(n_time - b_time >1500){
    count ++;
    b_time = n_time;
  }
}
void time_fun(){
  for(int i = 9;i>0;i--){
    w_count[i] = w_count[i-1];
  }
  w_count[0] = count;
  count = 0;  
}
void loop() {
  int sum = 0;
  for(int i = 0;i<10;i++){
    sum += w_count[i];
  }
  Serial.println(sum);
  delay(200);
}
```


# 開発過程
作っていく過程と失敗の記録

## 素のセンサー出力
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/bdc0e279-c366-a609-c620-1b90df2fbc45.png)
プロペラを間に挟んで回転させた。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/e73588e8-4a54-048b-fcd8-61519ff7f104.png)

0.5Vほどで上下している。5ms間隔ほどの一定の間隔で振動している。

## 微分器を通したあと

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/632c6a8e-234e-f7f1-5e96-0548163ad932.png)

3Vマックスで、1.5Vぐらいまで落ちている。
立ち下がりより立ち上がりが遅い


## 比較器を通したあと

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/94dc71d2-4c28-1feb-46d0-1417dc57ff24.png)

比較器を通すときれいになるね。
比較対象電圧が決め打ち担ってしまっているのが少し残念。今は、2.452Vになっている。

# まとめ
ひとまず、回転速度の測定がし易い測定器が作れた。反射型にもチャレンジしたい。そのためには、光散乱テープがいるなぁ。
Crystal言語から、OpenAI APIを呼ぶ

Crystal言語から、OpenAI APIを呼ぶ。
ChatGPTをやりたかったけど、少し面倒くさそうなので、まずは、text-davinci-003 から。

次のようなコードを使えばいいみたい。（OpenAI APIを呼ぶためには、有料のAPI KEYが必要です）
`ENV["OPENAI_ACCESS_TOKEN"]` が動くように、環境変数を設定しておく。

```crystal
require "option_parser"
require "http/client"
require "json"

data = {
  "model"       => "text-davinci-003",
  "prompt"      => "Hi!",
  "max_tokens"  => 10,
  "temperature" => 0,
}

OptionParser.parse do |parser|
  parser.on("-m INT", "--max-tokens INT") { |v| data["max_tokens"] = v.to_i }
end

data["prompt"] = ARGV.join(" ")

url = "https://api.openai.com/v1/completions"
api_key = ENV["OPENAI_ACCESS_TOKEN"]
headers = HTTP::Headers{
  "Authorization" => "Bearer #{api_key}",
  "Content-Type"  => "application/json",
}
response = HTTP::Client.post(url, body: data.to_json, headers: headers)

if response.status.success?
  response_data = JSON.parse(response.body)
  puts response_data["choices"][0]["text"]
else
  puts "Error: #{response.status_code} #{response.status}"
end
```

## 使い方

```sh
crystal run ファイルの名前.cr -- Are you fine?
crystal run ファイルの名前.cr -- -m 20 Are you fine?
```

もしくはちゃんと `build` して

```sh
実行ファイル Are you fine?
実行ファイル -m 20 Are you fine?
```

みたいな感じ。

この記事は以上です。
【Swift】XcodeGenを使用している場合のFirebaseCrashlyticsのRunScriptの設定

# はじめに
FirebaseCrashlyticsを導入したらエラーが出るようになりました。
原因がXcodeGenだったので記録しておきます。

# エラー
![スクリーンショット 2023-03-07 18.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/0b60b811-ef12-9524-94f3-4a8da21f1494.png)

# 原因
XcodeGenでBuildScriptを設定する方法が複数ありました。
- `preBuildScripts`
- `postCompileScripts`
- `postBuildScripts`

実行される順番が違うようです
今回の場合は`GOOGLE_APP_ID`が読み込まれる前にFirebaseCrashlyticsが実行されていました。

# 解決方法
```project.yml
postBuildScripts:
  - name: Run FirebaseCrashlytics
    script: '"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run"'
    inputFiles:
        - ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
        - $(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)
```

# おわり
こんな落とし穴があるとは。。。
[Pandas] DataFrameの複数列を使って新しい列を作る方法

# 環境
python3.8.10
pandas 1.3.5

# やりたいこと

![スクリーンショット 2023-03-07 18.16.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131671/cb219c15-afdb-828c-998a-824d2d042255.png)
これを
![スクリーンショット 2023-03-07 18.17.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131671/1cb40da7-cf94-d7d1-8dc2-220b31f4aed0.png)

どのような関数を使うかは別として、複数列使って新しい列を作りたい。

# やり方
まず、簡単にテーブルを作る。
```python
import pandas as pd

def test(c1, c2):
    return c1 + c2

df = pd.DataFrame([['a', 'b'], ['c', 'd']], columns=['char1', 'char2'])
```

![スクリーンショット 2023-03-07 18.16.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131671/cb219c15-afdb-828c-998a-824d2d042255.png)


以下のやり方で複数列を使用できる。
```python
df['concat_text'] = df[['char1', 'char2']].apply(lambda text: test(text[0], text[1]), axis=1)
```
![スクリーンショット 2023-03-07 18.17.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131671/1cb40da7-cf94-d7d1-8dc2-220b31f4aed0.png)

- `apply()`は関数をDataFrameに対して適用するメソッドであり、内部のlambda式は簡単に関数を作ることができるものである。
- lambda式で定義した変数を他の関数に引数として渡し、その結果を新しい列に格納する。
- 元となるDataFrameのカラムの順番通りに0オリジンでオフセットを指定する。
- axisで行方向と列方向のどちらに関数を適用するかを決める。デフォルトは0なので明示的に指定する。
Unity 実機端末でのCPU/GPU使用率確認

# 目次　
1.使うサービス　
2.方法
3.備考　

# 1.使うサービス　
・Unity
・プロファイラー（Unity内に備え付けのサービス）
・実機端末

# 2.方法 
1.Unityのウィンドウ>分析>プロファイラーを開く　
　
2.下記のようにビルド設定項目で「開発ビルド」と「プロファイラーを自動接続」をオンにする　
![スクリーンショット 2023-03-07 18.05.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2362827/869f555f-33ed-aff8-ef9d-60c4b56eafc3.png)

3.実機端末とUnity開発端末で同じWi-Fiに接続する

4.ビルドし、実機端末で動作確認する

5.プロファイラー画面でCPU/GPU使用率を確認する
※VSyncとOtherは動作の重さに関係ないので無視してOK

参考サイト　

https://light11.hatenadiary.com/entry/2019/12/23/222233

https://blog.qs-grct.com/2020/09/30/030755/unity-ios-slow-cause-stupid/

# 3.備考
Unityでの動きをより軽くする方法はこちら

https://note.com/unityjapan/n/n2bb1917aee50

https://creator.cluster.mu/2020/10/21/world-weight-saving/

https://kurokumasoft.com/2022/01/06/unity-optimization-summary/

https://kan-kikuchi.hatenablog.com/entry/Unity_App_Size
M1 Macでboostを使う

# 概要
M1搭載のMacでboostライブラリを使おうとしたら, Error や Warningが多数でました. ここでは次の形でコンパイルが通ったので, 備忘録的に書いておきます. 
# 開発環境
- macOS Ventura 13.2.1
- g++ : Apple clang version 14.0.0 (clang-1400.0.29.202), Target: arm64-apple-darwin22.3.0
- Boost : boost_1_18_0

# エラーメッセージ
> error: unknown type name 'constexpr'
> error: a space is required between consecutive right angle brackets (use '> >')
> #error "This library now requires a C++11 or later compiler - this message was generated as a result of BOOST_NO_CXX11_RVALUE_REFERENCES being set"

エラーを見ていると, boost内部でのコンパイルエラーのようです. 
g++は, Apple自身が提供しているものです. バージョンを見る限り, C++11には対応済みです. 

# 解決策
コンパイルオプションとして, 次を指定します.
> -std=c++11

これにより, C++11の拡張やライブラリを使用することが可能となります. Boost.Math は, C++14以降でしか使えないという Warninもあります. 次の指定すると, このWarningも消えます.
> -std=c++14

まだ sprintfのWarning もありますが, 気にしないことにします. エラーは消えましたので, コンパイルは通るようになりました. 

# 追記
今回は, Boost　を　https://www.boost.org/  からダウンロードして, コンパイルするところからはじめましたが, Homebrew を使うと簡単にインストールできます. こちらのライブラリでもコンパイルは通りました. 
なお, コンパイル時には, 
> -I(インクルードファイルのディレクトリ)
> -L(ライブラリのディレクトリ)

を付けることを忘れないようにしましょう.
PyQt5勉強①

# はじめに

本記事から、PyQt5のチュートリアルを動かしていきます。

https://www.tutorialspoint.com/pyqt5/index.htm

# Hello World

https://www.tutorialspoint.com/pyqt5/pyqt5_hello_world.htm

こちらのチュートリアルを進めます。


### 1. Pycharmのインストール
以下のリンク等を参考に、PyCharmをインストールします。
(Intellijなどの使用経験があり)JetBrainsのアカウントをすでに持っている場合は、Professional版でも問題ありません。

https://sukkiri.jp/technologies/ides/pycharm/pycharm-win.html

### 2. 新規プロジェクトの作成
PyCharmを開き、メニューから「File」->「New Project」を選択します。
その後プロジェクトの名前と保存先を指定し、「Create」ボタンをクリックします。

### 3. PyQt5ライブラリのインストール
プロジェクトが作成されたら、PyQt5ライブラリをインストールする必要があります。
PyCharmのTerminalを開き、「pip install pyqt5」と入力して、PyQt5ライブラリをインストールします。

![PyQt5ライブラリのインストール](https://imgur.com/mSgBTYd.png)

### 4. pyファイルの記述と実行
PyCharmで新しいPythonファイルを作成します。ファイル名は自由に決めます。
その後、以下のようなコードを記述します。

```python:sample1.py
# 必要なモジュールをインポートする
# QApplication, QWidget, QLabel　は、PyQt5でGUIアプリケーションを作成するために必要なクラス
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel

# アプリケーションウィンドウを定義するためのクラスを作成
class App(QWidget):

    # アプリケーションウィンドウの初期設定を定義
    def __init__(self):
        super().__init__()  # QWidgetクラスのメソッドを継承
        self.title = 'Hello, World!'  # アプリケーションウィンドウのタイトル
        self.left = 100  # 左上隅のX座標
        self.top = 100  # 左上隅のY座標
        self.width = 200  # ウィンドウの幅
        self.height = 150  # ウィンドウの高さ
        self.initUI()  # アプリケーションウィンドウのレイアウトを作成

    # アプリケーションウィンドウのレイアウトを作成
    def initUI(self):
        self.setWindowTitle(self.title)  # ウィンドウのタイトルを設定
        # ウィンドウの位置とサイズを設定
        self.setGeometry(self.left, self.top, self.width, self.height)
        # ウィンドウ上にテキストを表示するための QLabel オブジェクトを作成
        # 最初の引数は表示するテキスト、2番目の引数は QLabel オブジェクトを親ウィジェットとして設定する
        # self に設定しているため、ウィンドウ上にラベルが表示される
        label = QLabel('Hello, World!', self)
        # QLabel オブジェクトをウィンドウ上で移動させる
        # 最初の引数は x 座標、2番目の引数は y 座標を表す
        label.move(50, 20)

        # ウィンドウを表示
        self.show()

# アプリケーションの開始
# モジュールがインポートされたときは実行されない
if __name__ == '__main__':
    # QApplication オブジェクトの作成
    app = QApplication(sys.argv)
    # App オブジェクトのインスタンス化
    ex = App()
    # Qtアプリケーションのメインループ（イベントループ）を実行
    # GUIイベントを受信して処理し、ウィンドウやウィジェットなどのGUIオブジェクトを描画するために使用される
    # Qtアプリケーションが終了したときに、Pythonプログラムも終了する
    sys.exit(app.exec_())

```

このファイルを保存した後、実行します
以下のようなウィンドウが表示されるはずです

![sample1.pyの実行結果](https://imgur.com/1s0xRHH.png)



# 最後に

これでHello Worldは終了です。
次回はQt Designer を使ってGUIの画面を作成します。

https://qiita.com/kiryu-3/items/6b45db42daa59941e93f
【MariaDB/MySQL】phpMyAdminインストール【PHP7.1.28】

```bash
wget --no-check-certificate https://files.phpmyadmin.net/phpMyAdmin/4.9.11/phpMyAdmin-4.9.11-all-languages.tar.gz \
  && tar xf phpMyAdmin-4.9.11-all-languages.tar.gz \
  && cd phpMyAdmin-4.9.11-all-languages \
  && cp config.sample.inc.php config.inc.php \
  && echo '$i++;' >> config.inc.php \
  && echo '$cfg["Servers"][$i]["host"] = "example.com";' >> config.inc.php
```

下記からサーバーを追加してましょう
http://localhost/phpMyAdmin-4.9.11-all-languages/setup

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127414/cf37d7a4-8e14-f997-411b-7191a8d7bb2a.png)
Salesforce_オムニチャネルの基礎

# オムニチャネルとは
ServiceCloudで提供されている機能の一つ。
チャットや電話、あるいはサービス独自の対応(例えば予約の調整や商品購入の後追いなど）といった様々な作業を自動でエージェントに割り振ってくれるのがオムニチャネル。

以下オブジェクトを作業の対象とすることができる。


- ケース
- チャット
- 請求
- 請求範囲
- 請求の復元
- 連絡要求
- インシデント
- リード 
- メッセージング (Lightning Experience のみ)
- 注文
- 支払要求
- ソーシャル投稿
- SOS ビデオ通話 (Salesforce Classic のみ)
- スウォームメンバー
- 主オブジェクトがないカスタムオブジェクト

# オムニチャネルの設定に関する基礎知識
オムニチャネルの設定を開始すると見慣れない用語がいくつか出てくるので、まずはそれについてまとめていく。
次の記事で実際の設定方法を書いていこうと思う。

## プレゼンス状況
- エージェントの状況のこと
    - オンライン（受け入れられる）かオフライン（受け入れられない）かの選択肢を作ることができる
- プレゼンス状況ごとに受け入れられるサービスチャネルを決めれる
    - 例えば「メール受け入れ化（オンライン）」ていうプレゼンス状況を作ってメールのキューだけ受け入れられる、電話は受け入れられないといった設定が可能
- プレゼンス状況はプロファイルか権限セットでエージェントへ紐付けることができる

## プレゼンス設定
- 上で作ったプレゼンス状況の設定ではない
- エージェントが受け入れ可能な作業量やエージェントが作業を拒否できるかどうかとかを設定する
    - この設定はユーザ単位かプロファイル単位で紐づけられる
- １エージェントに対して１プレゼンス設定しかできない
    - 複数設定した場合はあと勝ち
    - エージェントの作業量の定義とかがされてるから１エージェントに対して1つしか指定できないのは確かに納得

## サービスチャネル
- 作業を受信する方法を定義するためのもの
- どのオブジェクトを対象とするか
- そのオブジェクトがどうなったら作業完了とみなすかなどが定義できる

## ルーティング
- エージェントへの作業の割り振りルールの定義
- ルーティングには3種類ある
    - キューベースルーティング
        - まずオムニチャネルはキューに作業を割り当てる
        - 作業の優先度を基準にして、そのキューに属しているエージェントに作業が転送される
    - スキルベースルーティング
        - 事前にスキルの定義をしておいて、スキルに応じたエージェントに作業が転送される
        - スキルは例えば
            - 英語・日本語・スペイン語といった対応可能言語
            - 経理知識・会計知識・システム知識といった専門知識
    - 外部ルーティング
        - Salesforce外にあるルーティングをAPI経由で使うことができる


# まとめ
オムニチャネルは説明を始めて説明を読んだ時には「チャット・電話・メールの転送しかできない」と思っていましたが、作業として転送できるオブジェクトの範囲は広く、様々な場面で活用できると感じました。
どんどん作業が自動で転送されるということは、エージェントは作業を選ぶことに頭を使わず、作業の内容に対して頭を使うことができるようになるのでとてもいいなと思います。積極的に使っていきたいので、また設定方法についてもまとめていきます。
Vuetifyのv-time-pickerを複数個設置する

## はじめに
よくありがちなFrom-Toの入力フォームを作成する際、安易に2個設置すると動かなくて調べてみました。
## 環境
- windows 10
- Vue.js 2.7.14
- vuetify 2.5.5
## はまった点
実装は以下のように行いました。
```vue:index.vue
<template>
  <v-menu
    ref="menu"
    v-model="fromDialog"
    :close-on-content-click="false"
    :nudge-right="40"
    :return-value.sync="startTime"
    transition="scale-transition"
    offset-y
    max-width="290px"
    min-width="290px"
  >
    <template #activator="{ on, attrs }">
      <v-text-field
        v-model="startTime"
        label="開始時刻"
        prepend-icon="mdi-clock-time-four-outline"
        readonly
        v-bind="attrs"
        v-on="on"
      ></v-text-field>
    </template>
    <v-time-picker
      v-if="fromDialog"
      v-model="startTime"
      full-width
      @click:minute="$refs.menu.save(startTime)"
    ></v-time-picker>
  </v-menu>
  <v-menu
    ref="menu"
    v-model="toDialog"
    :close-on-content-click="false"
    :nudge-right="40"
    :return-value.sync="endTime"
    transition="scale-transition"
    offset-y
    max-width="290px"
    min-width="290px"
  >
    <template #activator="{ on, attrs }">
      <v-text-field
        v-model="endTime"
        label="終了時刻"
        prepend-icon="mdi-clock-time-four-outline"
        readonly
        v-bind="attrs"
        v-on="on"
      ></v-text-field>
    </template>
    <v-time-picker
      v-if="toDialog"
      v-model="endTime"
      full-width
      @click:minute="$refs.menu.save(endTime)"
    ></v-time-picker>
  </v-menu>
</template>
<script>
export default {
  data() {
    return {
      fromDialog: false,
      toDialog: false,
    }
  },
</script>
```
これで動かすとFrom、ToどちらもTimePicker表示されるのですがfromのtextfieldだけ値が戻せないという事態に。
propsのv-ifやv-modelは変えてあげないとそもそも値を取得できないしなというところは修正していたのですが。

## 修正後
to側だけ直しました。
``` vue:index.vue
  <v-menu
    ref="menu2"
    v-model="toDialog"
    :close-on-content-click="false"
    :nudge-right="40"
    :return-value.sync="endTime"
    transition="scale-transition"
    offset-y
    max-width="290px"
    min-width="290px"
  >
    <template #activator="{ on, attrs }">
      <v-text-field
        v-model="endTime"
        label="終了時刻"
        prepend-icon="mdi-clock-time-four-outline"
        readonly
        v-bind="attrs"
        v-on="on"
      ></v-text-field>
    </template>
    <v-time-picker
      v-if="toDialog"
      v-model="endTime"
      full-width
      @click:minute="$refs.menu2.save(endTime)"
    ></v-time-picker>
  </v-menu>
```
menuも分けないと動かない、という内容でした。
そもそもcompornent化して別出しにすれば良い気がしますが、その辺りは次回挑戦してみます。
参考URL：
[公式：v-time-picker](https://v2.vuetifyjs.com/ja/api/v-time-picker/)
[Vuetifyのv-time-pickerをループ内に実装する](https://qiita.com/unclecat/items/a611f2e4272b405c988b)
【git reflog】gitでやらかしてもgitなら大丈夫

## やらかし内容
 - ```git rebase --hard``` で必要な変更も消してしまった。
     - Source Treeだと```現在のブランチをこのコミットまでリセット```、```(ブランチ名)をこのコミットまで戻す```をHardで実行

- 必要なブランチを削除してしまった
- など。。。

## git reflogとは？
```git reflog```とは、Gitの操作履歴を見ることができるコマンド


```
$ git reflog
c2344c123 (HEAD -> develop, origin/develop, origin/HEAD) HEAD@{0}: pull origin develop: Fast-forward
b452355c0 HEAD@{1}: checkout: moving from master to develop
d52edfc46 HEAD@{2}: checkout: moving from develop to master
b153446c9 HEAD@{3}: reset: moving to b953044c833ad515f06be9ba9c32111a353b65f3
```

上記のログだと↓のようにGit操作が行われている。
 - b953044c833ad515f06be9ba9c32111a353b65f3のコミットにリセット
 - developブランチからmasterブランチにチェックアウト
 - masterブランチからdevelopブランチにチェックアウト
 - developブランチでpull

## やらかした操作をリセットする
先ほどの```git reflog```で操作履歴を確認後、```git reset --hard```を使いやらかした操作の一つ前に戻ることでやらかしの前に状態を戻すことができる。

```
git reset --hard HEAD@{1}
```


## まとめ
 - 追加したファイルをプッシュする前に```git reset```で消してしまった
 - プッシュ前にブランチを削除してしまった

など、Gitでやらかしてしまった場合でも、Gitなら大体復元することができます。
困った時は```git reflog```を使ってみてください。
SetUIDについて

## 環境
Ubuntu20.4

## パーミッション
ユーザーのパスワードを管理しているファイル（**/etc/shadow**）のパーミッションを表示すると、次のように表示されます。
```
$ls -l /etc/shadow
-rw-r----- 1 root shadow
```

このファイルの所有者は**root**で、グループが**shadow**になっています。所有者の権限が、**rw**であるため、rootはこのファイルに読み書きすることができます。グループの権限が**r**であるため、shadowグループはこのファイルを読み込むことはできるが、書き込むことはできません。その他のユーザーには権限が設定されていないため、読み込むことも書き込むこともできません。

現に、自分は、vagrantユーザーでログインしているのですが、つぎのコマンドを実行するとエラーになります。
```
$cat /etc/shadow
$vi /etc/shadow
```

## SetUID
**/usr/bin/passwd**のパーミッションを表示すると、次のように表示されます。passwdはパスワードを設定するためのコマンドです。
```
$ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root
```

パーミッションを確認すると、root以外のユーザーにも実行権限がありますが、パスワードを書き込む、shadowファイルに、読み込み書き込み権限がありませんでした。しかし、rootユーザーでない自分でも、passwdコマンドを実行して、hadowファイルを書き換えることができてしまいます。

なぜでしょうか？:thinking:

passwdの所有者のパーミッションの実行権限の設定にsがついていることが原因です。このsのことを、**SetUID**と呼びます。SetUIDが設定されているプログラムのことを、SetUIDされたプログラムといういい方もします。

SetUIDがついていると、所有者以外のユーザーであっても、所有者が持っている権限と同じ権限で実行できるようになります。つまり、root以外のユーザーが実行しても、shadowファイルの読み書きができるようになるということです。

## sudo
sudoを使うと、どのユーザーでもroot権限でコマンドが実行できるようになります。これは、sudoコマンドにSetUIDが設定されているためです。sudoのパーミッションを確認します。
```
$ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root
```

確かに、SetUIDが設定されています。

このように、SetUIDが設定されているプログラムは、passwd、sudoコマンド以外にもいくつかあります。SetUIDが設定されているプログラムは、次のコマンドで調べることができます。

```
sudo find / -type f -perm -u+s -ls
```

SetUIDが設定されていると、他ユーザーでもsudoなしで実行できる便利さがある反面、悪意のあるユーザーにログインされた場合、実行されてはいけないコマンドが実行されてしまうといった脅威が発生することになります。セキュリティ的には要注意な設定です。
AndroidからWifiNetworkSpecifierを使ってTHETAへ接続する方法

# 目的
Androidアプリ(kotlin)でTHETAへダイレクトモード接続して、WebApiアクセスを行う。
ユーザー入力負担を減らすために、[WifiNetworkSpecifier](https://developer.android.com/guide/topics/connectivity/wifi-bootstrap?hl=ja)を利用する。

# 問題
WifiNetworkSpecifierから接続した場合、WebApiアクセスに失敗する。

```error
Caused by: java.net.ConnectException: failed to connect to /192.168.1.1 (port 80) from /:: (port 0) after 10000ms: connect failed: ENETUNREACH (Network is unreachable)
```

AndroidOS設定からTHETAに接続すると、WebApiアクセスが正常に行えた。
そのため、WebApiやhttpアクセスが問題ではないことが分かった。


# 解決方法

[THETAフォーラムQA](https://community.theta360.guide/t/solved-ricoh-theta-connection-issue-using-android-api-29/6127/2)で解決方法が見つかった。
Android公式サンプルには記述されていない2行を追加すればOK。

```kotlin

    override fun onAvailable(network: Network?) {
        //下記2行を追加する。
        super.onAvailable(network)
        connectivityManager.bindProcessToNetwork(network);
    }
```

# 追記
THETA切断時は下記コードが必要だった。
[Android公式](https://developer.android.com/training/wearables/data-layer/network-access?hl=ja#releasing-the-network)
[stackoverflow](https://stackoverflow.com/questions/64913185/after-called-bindprocesstonetworknetwork-app-never-connect-to-internet-throug)

```kotlin
connectivityManager.bindProcessToNetwork(null) //これを忘れるとTHETA切断後にWiFi接続しても、インターネットにアクセスできない。
connectivityManager.unregisterNetworkCallback(networkCallback)
```
SSOと拡張ドメイン

+ [拡張ドメインのまとめ2](https://qiita.com/Keiji_otsubo/items/8f55a16543e3f789afcc)

私の認識としては、以下の内容です。

**[私のドメイン] ログイン URL ( MyDomain.my.salesforce.comの形式)を使用して Salesforce 組織にログインする SSO/AD 接続 は影響を受けません**が、Experience Cloud サイトおよび Salesforce サイトへの SSO/AD 接続 は影響を受けます。 拡張ドメインではサイトの URL が変わるためです。

SSO/AD connections that log into your Salesforce org with your My Domain login URL (in the format MyDomain.my.salesforce.com) aren't impacted in that case, but SSO/AD connections to Experience Cloud sites and Salesforce Sites are impacted, because site URLs change with enhanced domains.

しかし、拡張ドメインを有効にするとSSOが失敗するとのことです。

+ [Communities redirect broken via SSO after enhanced domain deploy](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000O6ay2)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d570e24f-f8e0-924f-aef1-40feaf69b34c.png)
SSO は Salesforce にログインしますが、この新しいドメイン URL にリダイレクトしません。 


We also reviewed with the support team the Saml logs and it seems that the SSO tool (One login) cannot apply the redirecting to the My.site domain.
Also the Metadata xml cannot be updated in the SSO unless you create a seperate one.

また、サポート チームと一緒に Saml ログを確認したところ、SSO ツール (One login) は My.site ドメインへのリダイレクトを適用できないようです。
また、個別に作成しない限り、SSO でメタデータ xml を更新することはできません。


You were wondering if the SSO flow would still work without updating the config on OneLogin identity provider side to use the enhanced my.site.com domain. As you discovered, it does not...but in order to change that config you had to create a separate Service Provider entry (additional dedicated App) within OneLogin

強化された my.site.com ドメインを使用するように OneLogin ID プロバイダー側​​の構成を更新しなくても、SSO フローが引き続き機能するかどうか疑問に思っていました。あなたが発見したように、そうではありません...しかし、その構成を変更するには、OneLogin内に別のサービスプロバイダーエントリ（追加の専用アプリ）を作成する必要がありました
SQL 100本ノック　知識の整理(-33)

SQL100本ノックの前半(WITHが出てくるまで)の基礎的な問題に対する個人的な備忘録です。

---
Q9 13ではない場合(not equal to)
```sql
prefecture_cd != '13'
```

Q10 S14で始まるもの
```sql
WHERE store_cd LIKE 'S14%'
```

Q11 末尾が1のもの
```sql
WHERE customer_id LIKE '%1'
```

Q12 '横浜市'が含まれるもの
```sql
WHERE address LIKE '%横浜市%'
```

Q13 先頭がアルファベットのA-Fで始まるもの
```sql
WHERE status_cd ~ '^[A-F]'
```

Q14 末尾が数字の1-9で終わるもの
```sql
WHERE status_cd ~ '[1-9]$'
```

Q15 先頭A-F、末尾1-9で終わるもの
```sql
WHERE status_cd ~ '^[A-F].*[1-9]$'
```

Q16 電話番号が3桁-3桁-4桁のデータを参照
```sql
WHERE tel_no ~'[0-9]{3}-[0-9]{3}-[0-9]{4}$'
``` 

---
### -ランクの付け方-
Q19 amountのランクを表示、等しい場合は同一順位を付与
```sql
SELECT RANK() OVER(ORDER BY amount DESC) AS ranking
```

Q20 amountのランクを表示、等しい場合でも別順位を付与
```sql
SELECT ROW_NUMBER() OVER(ORDER BY amount DESC) AS ranking
```
---
---
### -count-
Q21 receiptデータの件数をカウント
```sql
SELECT COUNT(*)
```

Q22 重複を排除したcustomer_idをカウント
```sql
SELECT COUNT(DISTINCT customer_id)
```
---


Q23 店舗ごとの売上金額の合計
``` sql
SELECT
    store_id,
    SUM(amount) AS amount
```

Q24 最も新しい or 古い売上年月日
```sql
SELECT 
    MAX(sales_ymd),
    MIN(sales_ymd)
```

---
### -WHERE/HAVING-
Q26 HAVING句

HAVING
GROUP BY句と一緒に使われる条件式で、グループ化された結果に対して条件を適用する。グループ化された結果を制限する。集約関数(SUM,COUNT,AVG...)を使用する場合に用いる。
```sql
SELECT
    customer_id,
    MAX(sales_ymd),
    MIN(sales_ymd)
FROM
    receipt
GROUP BY
    customer_id
HAVING
    MAX(sales_ymd) != MIN(sales_ymd)
LIMIT 10
;
```

WHERE
FROM句で指定されたテーブルからデータを取得する際に、条件を適用するために使用される。データの集合を制限する。
```sql
SELECT
    customer_id
FROM
    receipt
WHERE
    customer_id = 'CS018205000001'
;
```

---
Q28 amountの中央値の計算 
```sql
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY amount) AS med_amount
```
WITHIN GROUP は定型的な記述。ORDER BYでは値を取る対象列の指定とデータの並び順を指定する。


---
Q29 商品コード(product_cd)ごとの最頻値
```sql
SELECT MODE() WITHIN GROUP(ORDER BY product_cd)
```

Q30 amountの分散
```sql
SELECT VAR_POP(amount) AS var_amount
```

Q31 amountの標準偏差
```sql
SELECT STDDEV_POP(amount) AS std_amount
```

Q33 店舗ごとに売上金額の平均を計算し、330以上のものを抽出
```sql
SELECT
    store_id,
    AVG(amount) AS avg_amount
FROM
    receipt
GROUP BY
    store_id
HAVING
    AVG(amount) >= 330
;
```