OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonで「文字列の指定したインデックスの文字(要素)を取得する」の動作を確認してみた

# 概要

Pythonで「文字列の指定したインデックスの文字(要素)を取得する」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/string/index10.html

# 実装

以下のファイルを作成しました。
```sample.py
str1 = "Hello"
print(str1[1])   # e
print(str1[-1])  # o

str2 = "東京都"
print(str2[2])   # 都

str1 = "Hello"
print(str1[0])
print(str1[1])
print(str1[2])
print(str1[3])
print(str1[4])

str2 = "東京都"
print(str2[-3])
print(str2[-2])
print(str2[-1])
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
e
o
都
H
e
l
l
o
東
京
都
```

# まとめ

何かの役に立てばと。
.razor 内でディレクティブを書く順番

Blazor でコンポーネントを実装するには、普通は .razor ファイル、すなわち、Razor コンポーネントとしてソースコードを記述することでしょう。.razor ファイル内では、`@page` や `@namespace`、`@using`、`@inject`、`@inherits`、`@implements`、`@attribute` といったディレクティブを使用できます。基本的にこれらディレクティブは、**書く順番に制約はありません**。例えば次のように .razor ファイルを記述できます。

```csharp:MyComponent.razor
@inject IFizz Fizz
@implements IDisposable
@using Foo
@page "/"
@inherits Bar
@namespace Buzz
@attribute [Authorize]
...
```

しかしながら、"書く順番に制約はない" とはいうものの、どのディレクティブから順に書いたら良いか、一定のガイドラインがあったほうが気持が楽になりませんか? 自分は気持が楽になります。ということで、自分は下記の順番でこれらディレクティブを記述するようにしています。

```razor:MyComponent.razor
@page "/"
@namespace Buzz
@using Foo
@attribute [Authorize]
@inherits Bar
@implements IDisposable
@inject IFizz Fizz
...
```

どうしてこの順序にしているか、というと、それは、**".razor ファイルは、ある種の C# ソースコードである"** との認識からです。つまり、Razor コンポーネントとは `ComponentBase` から派生したクラスであり、.razor ファイルは C# コードに変換されて最終的にアセンブリファイルにコンパイルされる、ということです。詳しくは下記投稿を参照ください。

https://qiita.com/jsakamoto/items/bd5e1541f0524de40183#razor-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AF-c-%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B

そのため、上記ディレクティブを含むコードは、以下のような C# ソースコードに変換されます。

```cs:MyComponent.razor.g.cs
namespace Buzz
{
    using Foo;

    [Authorize]
    [Route("/")]
    public class MyComponent : Bar, IDisposable
    {
        [Inject]
        public IFizz Fizz { get; init; }
        ...
```

すなわち、

- `@namespace` はファイル先頭の名前空間宣言 `namespace` となり、
- `@using` は続く `using` となり、
- `@page` は、コンポーネントクラスを修飾する `Route` 属性となり、
- `@attribute` は指定された属性でコンポーネントクラスを修飾し、
- `@inherits` と `@implements` はクラス宣言に並記され、
- そして `@inject` は `[Inject]` 属性が付与されたプロパティ

になります。

このように、**.razor ファイルが C# ソースコードに変換された後の、各ディレクティブに対応する箇所の出現順を再現**するように、自分は .razor ファイル内でのディレクティブの出現順・記載順を決めています。

```cs:MyComponent.razor.g.cs
namespace Buzz   // ← @namespace Buzz
{
    using Foo;   // ← @using Foo

    [Authorize]  // ← @attribute [Authorize]
    [Route("/")] // ← @page "/"
    public class MyComponent : Bar, IDisposable // ← @inherits Bar, @inmplements IDisposable
    {
        [Inject]
        public IFizz Fizz { get; init; } // ← @inject IFizz Fizz
        ...
```


ただ、**ひとつ例外**があって、それは **`@page` ディレクティブ**です。これだけは自分のこのやり方の中での例外扱いで、**`@page` ディレクティブだけは常に、.razor の一番先頭行に記述**するようにしています。これには理論だった理由はなく、自分の直感的にそのほうが心地よかったためです。

繰り返しになますが、基本的に .razor ファイル内での各ディレクティブの出現順・記載順には制約はありません。ですがそれ故に、記載順をどうしたらいいかモヤッとしていた方に、この自分のやり方が参考になれば幸いです。

Happy Coding! :)
glm メモ

* glm::quat
  * glmのクォータニオンであるglm::quatのコンストラクタにはwから指定する必要がある
    * glTFからクォータニオンの四元数を取得してそのまま渡すことがあるので覚えておくと便利
```
glm::quat quat = glm::quat(w, x, y, z);
```
gkeepapi (Google Keep)をPythonで使うときにBadAuthenticationが出た時の対処法

# 概要
gkeepapiのBadAuthentication問題は、ちらほら起きているらしいが、解決のための情報が少なく、解決できず泣き寝入りしている人が大半のようである。解決できた人も、何が悪かったのかよくわかっていない人が多い。

gkeepapiの公式サイトのFAQにもBadAuthentiationについての説明はあるが、説明が甚だ不十分な上に、提示されている「解決に役立つリンク」がほとんどリンク切れしており、わずかに残っているリンク先にも泣き寝入りしている人が多かったりする。

以下に、現時点で見つけた解決方法についてShareする。

# 一番見つけにくい対処法

https://github.com/kiwiz/gkeepapi/issues/81#issuecomment-1744006474

Windows OS特有の問題、 Pythonのバージョンの問題、Pythonのライブラリ群のバージョンの問題、そもそもGoogle Keep APIが非公式の適当に管理されているAPIである、等が絡み合った問題らしい

このレスを書いたDon Sudduth氏(djsudduth)は、gkeepapiにおけるGoogle KeepのAuthenticationの失敗について、様々なコミュニティで言及しており、この問題について知り尽くしているスペシャリストであると思われる.

https://github.com/djsudduth

# 基本的な対処法
- 上記の質問スレッドの対処法を上から順に試す
- 「"gkeepapi" AND "BadAuthentication"」で検索する
- 認証パスワードに、普通のGoogleパスワードではなく「Google アプリパスワード」という特別なパスワードを生成して使用してみる
Thymeleaf Springのth:error="*{}"で混乱した話

# まとめ
Thymeleafにはオブジェクトのフィールド値が使える選択変数式:*{…}があるが
th:text="\*{…}"
th:error="\*{…}"
この２つの`"*{…}"`は右辺だけ見ると同じ内容を指していると思うが、左辺によって全く違う内容を指している。
th:textはオブジェクトのフィールドに入っている値が表示され
th:errorはオブジェクトのフィールドに対してValidateしたエラー内容が表示される。

## 何に混乱したのか
thymeleafでコントローラの@Validationを使った入力値チェックを表示する方法を探したところ、ビュー側でth:error="\*{…}"を使えば、…で指定したフィールドのチェック結果を表示できる事を知る。しかし、"*{…}"だけを見るとオブジェクトのフィールドの値を表示している式と読み取れる。コントローラー側でフィールドにエラーを代入している式も見つからず、なぜこれで表示できるのか分からなかった。

## 調べて分かった事
Thymeleafの公式ページや、ネットで調べても明記されている分が見つからなかったため、ChatGPTに聞いてみる事に。得られた回答が次の内容です。
>`th:text="*{...}"` と `th:error="*{...}"` は Thymeleaf テンプレート内で使用される異なる属性であり、出力される値は通常異なります。これらの属性は異なる目的を持ちます。
>
>1. `th:text="*{...}"`:
   この属性は、指定された変数の値を表示するために使用されます。バリデーションエラーの有無に関係なく、指定された変数の値が表示されます。
>
>2. `th:error="*{...}"`:
   この属性は、バリデーションエラーがある場合に、指定された変数に関連するエラーメッセージを表示するのに使用されます。バリデーションエラーの有無に依存してエラーメッセージが表示されます。バリデーションエラーがない場合、何も表示されません。
>
>したがって、出力される値は通常異なります。`th:text="*{...}"` は指定された変数の値を表示し、`th:error="*{...}"` はバリデーションエラーメッセージを表示します。どちらの属性も異なる目的に使用されます。

どうもth:textの"*{...}"とth:errorの"*{...}"は違い内容らしい

## 確認用のコード
~~~フォームクラス一部のみ記載 form.java
//~~省略~~
@Size(max = 5) 
private String name;
//~~省略~~
~~~
上記のようなnameフィールドを作成した。
5を超える名前を入力すると、エラー内容が表示されるはずである。
確認のために出力用のhtmlは次のようにしてみた。
~~~ビュー側の一部のみ記載.html
<!-- ~~省略~~ -->
<form th:object="${form}"  省略>
<!-- ~~省略~~ -->
<p th:text="*{name}">名前</p>
<p th:text="${form.name}">名前</p>
<p th:errors="*{name}"></p>
<p th:errors="${form.name}"></p>
<!-- ~~省略~~ -->
~~~

## 実行結果
テキスト欄に`あいうえおかきくけこ`と入力した出力結果が次の内容です
~~~ブラウザの出力結果
あいうえおかきくけこ

あいうえおかきくけこ

[名前] 5文字を超えています。

[名前] 5文字を超えています。
~~~
これより、`th:text`の`*{...}`と、`th:errors`の`*{...}`は違う結果が表示されており左辺の式によって出力される結果が変わることを確認できた。
また、`*`を使用しない`${form.name}`でも同じ結果になる事も確認できた。

## 参考
本記事では説明を全て省きましたが、@Validateを使った入力チェックと、結果の表示については、下記サイトがとても分かりやすく記載されていたので備忘録もかねて共有します。

https://kanda-it-school-kensyu.com/java-spring-contents/sb_ch07/sb_0703/
P#NP予想からAI,機械学習の実装の方向性を考える

# 実例
VSCodeにChatGPTの拡張機能を入れてコードレビューやバグを発見してもらう
https://qiita.com/tak001/items/c3000b3ce9b6e72b2ae5

# P&#8800;NPとは
https://ja.wikipedia.org/wiki/P%E2%89%A0NP%E4%BA%88%E6%83%B3
&nbsp;&nbsp;クラスPとクラスNPが等しくなる例は存在しない
&nbsp;&nbsp;これは証明自体は非常に困難でミレニアム懸賞問題になっています。ただし、この予想自体は正しいということは直感的には。。。わからないですね。

【ミレニアム懸賞問題】解けたら1億円!数学最大の難問「P≠NP予想」【ゆっくり解説】 
<iframe width="560" height="315" src="https://www.youtube.com/embed/XY4chs-VISI?si=URNw8rONhDSXIeUN&amp;controls=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

&nbsp;&nbsp;この動画の説明に曰く（というか確かにそうだ）$P&#8800;NP$予想とは「ある問題の答え合わせより、答えを求めるほうが難しい」という予想だといえる。

# ChatGPTの実装の記事はこの予想とどうかかわるのか
&nbsp;&nbsp;つまり、問題を解く、というところを「コードを書く」と言い換える。そして、答え合わせを「コードレビューやバグを発見する」とすると、コードを書くより、コードをチェックさせたほうがAI自体もうまく動くだろうといえることになる。コードレビューやバグの評価はYes/Noで答えてもよく、Yes-No問題といえるからだ。そうすると計算複雑性はードチェックのほうが多項式時間で可能となるだろう。速度も速く、間違える可能性も低くなるからだ。もしP=NPであり、コードを書くのとコードのチェックの計算複雑性が同じであり、多項式時間で解決可能なら、コードを書かせる実装とコードレビューをさせる実装がQiitaに同時に記事が出現し、同等に動くということになる。
&nbsp;&nbsp;しかし、こうはならない、ならないのは$P&#8800;NP$予想が正しいであろうからだ。
&nbsp;&nbsp;以上から、今回の記事のようなAI,機械学習の使い方、実装は最適であると判断される。

# NPであるがPではない、あるいはPであるか不明という方向から
&nbsp;&nbsp;上記動画で箱詰め問題が紹介されている。つまり効率的なものは（多項式時間では解決が）難しいが、効率的であるかどうかはチェック、レビューするほうは多項式時間で解決可能であることが多いといえる。
&nbsp;&nbsp;このことからも一般的にAIや機械学習は何かを生み出すのではなく結果を評価、検証させるほうが向いているという予想が成立する。

## P=NPは正しいか
&nbsp;&nbsp;少数ながらこのように予想している人たちもいるという。これは解釈によっては正しいであろう。なぜなら$P&#8800;NP$が「正しそう」なのは「答え合わせ」という表現のイメージにあらかじめ答えを知っているという前提があるからだ。しかし答え合わせをするとき、もう一度計算しなおしている場合には、答えを求めているのと変わらないケースが存在する。したがってP&#8800;NP予想が正しくても、現実にはPなのかNPなのかはあいまいな場合があることから、同時にP=NPも成立するだろう。つまり、一般的にはP&#8800;NPは正しいが、場合によっては$P=NP$も成立する。この予想が証明された場合、このような結果になるだろう。
&nbsp;&nbsp;そうると、ChatGPTのようなAIや機械学習は必ずしも検証、レビューに向かない場合が存在し、それは答えを求めているのと変わらないか、厳密過ぎて計算量が増える場合（いわゆるNP困難）だと予想できる。
&nbsp;&nbsp;また、現実には１つの関数を作動させると100時間もかかるようでは誰も使わない。現実のユーザーは時間と投資（お金）に見合うスピード、効率の上昇も求めているからだ。


# そうするとどうなるか
&nbsp;&nbsp;$P&#8800;NP$予想が正しいとすれば、この例のようにAIや機械学習でチェックやレビューに関する機能を開発、実装をしていくことが開発可能であり、開発速度が速く、動作速度が速く、実用的かつ効率的な使用方法となるだろう。引用記事がその最適な例といえる。ただし計算量や複雑さによって$P=NP$となる場合があり、この場合はAIや機械学習もあまり有効ではない。またユーザーの要求にこたえるものでなければ、予想に限らず適切な使用方法とはならない。

# 参考文献
## NP問題、あるいはNP困難問題
https://ja.wikipedia.org/wiki/NP%E5%9B%B0%E9%9B%A3

### [うさぎでもわかるP vs NP問題（NP完全、NP困難の違い）](https://www.momoyama-usagi.com/entry/info-p-np)
> クラスPとは、多項式時間以内で解くことができるアルゴリズムが存在するような問題のことを表します。
クラスNPは、多項式時間以内で、問題の解が本当に合っているかの検証を判定することができる問題のことを表します。

### 計算の複雑さと N P-完全問題
https://lecture.ecc.u-tokyo.ac.jp/~cnakamur/DVIOUT-NP-Complete.pdf
> 少なくとも NP-完全以上の難しさを持つ問題を NP-困難 (NP-hard) と呼ぶ。正確には、$P=NP$ でない限り、多項式時間のアルゴリズムが存在しないような問題で、NP に属するか否か問わないとき、NP-困難な問題であるという。

## ビンパッキング問題（動画の箱詰め問題）
https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%B3%E3%83%91%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E5%95%8F%E9%A1%8C
## 三彩色問題
グラフ彩色
https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%83%95%E5%BD%A9%E8%89%B2
3-彩色問題
http://www.r.dendai.ac.jp/~nakano/shoutestkaitou/Sotsukenslide.pdf
3-彩色問題は上記サイトでもアルゴリズムと関係があり、また、下記サイトのとおり、本人認証とも関係がある。
https://www.omoshiro-suugaku.com/entry/3saishokumonndai-honnninnkakuninn
[SAA-C03]AWS AppSync

# 更新日
- 2023/11/02 初回

# [AWS AppSync](https://aws.amazon.com/jp/appsync/)

## これ何？[^7]
サーバレスサービスの一つでGraphQL[^1]やPub/Sub API [^2],[^3]を利用してアプリをデータやイベントに接続する仕組み

### [補足] GraphQL
もともとウェブ/モバイルアプリ開発においてBackendから必要なデータ取得を正確に行うための規格でありREST　APIとのにqueryをPOSTする。複数のデータソースからデータを取得できるため、このあたり[^4],[^5]がよくまとまってそうなので時間があるときに読もう。

### [補足] Pub/Sub API
事前に関連付けるEventとQueryをマッピング(Subscription)し、イベントが発火されると登録しておいたQuer、Query変数,Payloadが実行される(Publish)。[^11]
Ref[^8],[^9]
## 何が便利？
- LambdaとDynamoDB間を直接つなげる[^6]ため、リアルタイム処理に向いている
- GraphQLで言えば、バックエンドの開発がRESTに比べて複雑化するがAppSyncを利用することで実装速度の向上が期待できる。キャッシュの実装など。[^7]
- 監視も容易
- Subscription処理を利用することでリアルタイム処理にデータのどの部分を利用するか指定可能。その際のSubscriptionの接続管理を自動的に処理できる点が便利[^11]

## 利用例
- 複数ユーザーが同時に扱うチャットサービス[^10]
- AmazonMusic. 複数のユーザーが同時にプレイリストを同期し、オフラインでの大規模アクセスに利用している[^12]
- 

# Ref
[^1]: [GraphQLとはなんでしょうか。](https://hasura.io/learn/ja/graphql/intro-graphql/what-is-graphql/)
[^2]: [Cloud Pub/Sub API](https://cloud.google.com/pubsub/docs/reference/rest)
[^3]: [Pub/Sub API](https://developer.salesforce.com/docs/platform/pub-sub-api/overview)
[^4]: [GraphQL とは](https://www.redhat.com/ja/topics/api/what-is-graphql)
[^5]: [GraphQLの全体像とWebApp開発のこれから](https://qiita.com/saboyutaka/items/171f7382cdf75b67d076)
[^6]: [Introduction to AppSync with CFN – Data Source: DynamoDB](https://awstut.com/en/2022/05/02/introduction-to-appsync-with-cloudformation-en/)
[^7]: [AWS AppSync の特徴](https://aws.amazon.com/jp/appsync/product-details/)
[^8]: [Pub/Sub とは](https://cloud.google.com/pubsub/docs/overview?hl=ja)
[^9]: [Pub/Sub メッセージングとは何ですか?](https://aws.amazon.com/jp/what-is/pub-sub-messaging/)
[^10]: [Amplify で Slack アプリつくってみた](https://qiita.com/HayatoW/items/e2ed24dcf54f352616ad)
[^11]: [GraphQLにおけるSubscription処理について(実装例: Amplify + AppSync)](https://qiita.com/yoshii0110/items/3d9ec03215537646b65c)
[^12]: [AWS AppSync のお客様](https://aws.amazon.com/jp/appsync/customers/)
非同期通信が機能しない？TurbolinksによるJavaScriptトラブルを解決！【フリマアプリ開発】

# はじめに

某プログラミングスクールでフリマアプリの商品出品機能を実装中、JavaScriptを用いた価格連動機能において直面した不具合とその解決策を共有します。

# 開発環境
> ruby 3.2.0
> Rails 7.0.8

# 前提
商品の出品価格入力に連動して販売手数料（10%）と販売利益を動的に表示するJavaScript機能を実装しました。しかし、出品ページにアクセスした際に機能が働かず、ページをリフレッシュ（F5）すると正常に動作する現象に直面しました。

```JavaScript:config\importmap.rb
pin "item_price", to: "item_price.js"
```

```JavaScript:app\javascript\application.js
import "item_price";
```

```JavaScript:app\javascript\item_price.js
const price = () => {
  const priceInput = document.getElementById("item-price");
  priceInput.addEventListener("input", () => {
    const inputValue = priceInput.value;
    const price = parseFloat(inputValue);
    if (!isNaN(price) && price >= 300 && price <= 9999999) {
      const fee = Math.floor(price * 0.1);
      const profit = Math.floor(price - fee);
      document.getElementById("add-tax-price").innerHTML = fee.toLocaleString();
      document.getElementById("profit").innerHTML = profit.toLocaleString();
    } else {
      document.getElementById("add-tax-price").innerHTML = "";
      document.getElementById("profit").innerHTML = "";
    }
  });
};
window.addEventListener("turbo:load", price);
```

# 何が原因？
Turbolinksが非同期通信がうまくいかない原因であることが判明しました。

# Turbolinksとは？
Turbolinksは、Ruby on Railsで広く使用されるJavaScriptライブラリで、ページの読み込み速度を向上させることを目的としています。

通常、ページ遷移は新しいページをサーバーから取得し、現在のページを破棄して新しいページを表示するプロセスを伴います。しかし、Turbolinksを使用すると、フルページの再読み込みを行わずに、サーバーから新しいページのHTMLのみを取得し、現在のページのbodyタグの中身を新しいHTMLで置き換えます。CSSやJavaScriptは再読み込みされずに保持されるため、ページの切り替えが非常に速くなります。

# どう解決したのか

Turbolinksを無効にするため、非同期通信を行いたいページへのリンクとフォームにdata: { turbo: false }を追加しました。

```ruby:app\views\items\index.html.erb
<%= link_to new_item_path, data: { turbo: false },class: 'purchase-btn' do %>
```

```ruby:app\views\items\new.html.erb
<%= form_with model: @item, data: { turbo: false }, local: true do |f| %>
```

# 原因についての詳細
Turbolinksは、ページ遷移を高速化するためにページを完全には再読み込みせず、bodyタグの中身とページのタイトルだけを交換する仕組みです。これにより、ページの遷移が速くなりますが、JavaScriptが正しく動作しない場合があります。

通常のウェブページでは、ページが読み込まれるときにwindowオブジェクトのloadイベントが発火し、これをトリガーにJavaScriptのコードが実行されます。しかし、Turbolinksを使用している場合、ページ遷移時にはwindowのloadイベントは発火しません。その代わりに、Turbolinksは独自のイベントturbo:loadが使用されるようです。

今回のケースは、Turbolinksが原因でloadイベントが発火しないため、JavaScriptが初期化されずに機能しないというものというふうに解釈しています。ページを更新（F5）すると機能するようになるのは、Turbolinksは使われずに通常のページ読み込みが行われるため、loadイベントが発火し、JavaScriptが期待通りに動作するからと推察できます。
Google Apps Script(GAS)の非同期のgoogle.script.run()関数にawaitを適用する


```javascript:サーバ側(GAS)の処理
function calculate(x, y) {
  if (typeof x !== 'number' || typeof x !== 'number') {
    throw new Error('数値ではありません');
  }
  return x + y;
}
```


```javascript:クライアント側の処理
async function btnClick() {
  try {
    const value = await getData(3, 5);
//  const value = await getData("a", "b"); //例外を発生させる
    console.log(value); // 3 + 5 -> 8
  } catch (error) { //Errorオブジェクト
    console.log(error.message); //数値以外を設定したとき、「数値ではありません」が出力される
  } finally {
    // 後処理
    // 砂時計のカーソルを元に戻すなど
  };
}

// データ取得関数を定義
function getData(x, y) {
  return new Promise((resolve, reject) => {
    google.script.run
      .withSuccessHandler(data => resolve(data))
      .withFailureHandler(error => reject(error)) //Errorオブジェクト
      // 2023-11-08 追記
      // よりシンプルに以下でもいけました
      //.withSuccessHandler(resolve)
      //.withFailureHandler(reject) //Errorオブジェクト
      .calculate(x, y); //ユーザ定義の任意の関数(GAS側の関数にあわせる)
  });
}
```


サンプルプログラム
```javascript:コード.gs
function doGet() {
  return HtmlService.createTemplateFromFile('index').evaluate();
}

function calculate(x, y) {
  Logger.log(`x:${x} y:${y}`);
  if (typeof x !== 'number' || typeof x !== 'number') {
    throw new Error('数値ではありません');
  }
  return x + y;
}
```

```html:index.html
<!DOCTYPE html>
<html>
<body>
<button type="button" onclick="btnClick()">計算</button>
<script>
async function btnClick() {
  try {
    const value = await getData(3, 5);
//  const value = await getData("a", "b"); //例外を発生させる
    console.log(value); // 3 + 5 -> 8
  } catch (error) { //Errorオブジェクト
    console.log(error.message); //数値以外を設定したとき、「数値ではありません」が出力される
  } finally {
    // 後処理
    // 砂時計のカーソルを元に戻すなど
  };
}

// データ取得関数を定義
function getData(x, y) {
  return new Promise((resolve, reject) => {
    google.script.run
      .withSuccessHandler(data => resolve(data))
      .withFailureHandler(error => reject(error)) //Errorオブジェクト
      .calculate(x, y); //ユーザ定義の任意の関数(GAS側の関数にあわせる)
  });
}
</script>
</body>
</html>
```
<br>

### Proxy を使う方法
2024/3/23 追記
Proxyオブジェクトを使えば、もっと汎用的に記述できます
```javascript:クライアント側の処理
async function btnClick() {
  try {
    const value = await googleScriptRun.calculate(3, 5);
//  const value = await googleScriptRun.calculate("a", "b"); //例外を発生させる
    console.log(value); // 3 + 5 -> 8
  } catch (error) { //Errorオブジェクト
    console.log(error.message); //数値以外を設定したとき、「数値ではありません」が出力される
  } finally {
    // 後処理
    // 砂時計のカーソルを元に戻すなど
  };
}

const googleScriptRun = new Proxy(google.script.run, {
  get(target, method) {
    return (...args) => new Promise((resolve, reject) => {
      target
        .withSuccessHandler(resolve)
        .withFailureHandler(reject)
        [method](...args);
    });
  }
});
```

参考記事

https://qiita.com/toratosoine/items/a1fa81b0c98da0e32490
MVCモデルについて

## はじめに
今回「MVCモデル」を取り上げたのは、Vue＋Laravelに関わり勉強することとなったためです。まず初学者ののためMVCについて問われましたが、全く理解わかりませんでした。調べたことをまとめたいと思います。なお、ソースコードを追いながら学習したため、この記事にはソースコードはありません。

## MVCモデルとは
プログラムを役割ごとにModel（モデル）・View（ビュー）・Controller（コントローラー）の3つの機能に分けて管理するソフトウェア設計モデルのこと。MVCは、アプリケーションフレームワークでよく使われているアーキテクチャです。
`MVCは、ユーザーインタフェースをもつアプリケーションソフトウェアを実装するためのデザインパターンである。 アプリケーションソフトウェアの内部データを、ユーザーが直接参照・編集する情報から分離する。そのためにアプリケーションソフトウェアを以下の3つの部分に分割する。Model、View、Controller。
`(Wikipedia)

### Model
データ処理全般を担当します。
- データベースとデータのやりとりを行う
- データを格納したり、取り出したりする
- データの取得、更新、削除、新規作成といったデータベースとのデータのやり取り
- 日付のフォーマットの指定などといった、アプリケーションが扱うデータの操作

モデルはデータベースとデータのやり取りを行う機能を実装したり、データベースから取得したデータをプログラムで扱いやすい形式でデータを変換するというような役割を担っています。
データベースとやり取りを行う場合は、データベース内のデータを取得したり、「更新」「削除」「新規作成」といった機能を実装します。


## View
- Webブラウザに表示するHTMLを動的に生成する
- ビューの役割は名前のとおり、Webページを画面に表示させるためのもの

## Controler
- ユーザーの入力に基づきモデルとビューを制御する
- データをModelに渡したり、データをViewに渡したりする処理関数を作る
Webページを表示させるためにはデータベースから必要な情報を取得し、その情報をもとに画面を生成しなければいけない。
その橋渡しとなるのがコントローラーの役割で、ユーザーの入力に基づきモデル・ビューが何の処理をすべきかコントロールする。



## ファイルの場所
### ルーティング
まずはルーティングから実装する。
ルーティングとはで受け取ったリクエストに対してどのような処理を行うかを定義する部分のこと。
◯◯◯にアクセスした時に、×××という処理を呼び出す、という関連付け、管理するの機能が「ルーティング」
Laravelでは`/rotes/web.php`というファイルにWebページとしてアクセスするためのルーティングを定義する。
`Route::get('アドレス', 'コントローラ名@アクション')`
のように設定する。

### コントローラ作成
コントローラは処理全体の制御を担当するものであり、プログラム本体部分といってもよい。
Webアプリケーションにアクセスをすると、コントローラが処理を行う。必要に応じてビューやモデルを利用し、画面表示やデータベースのデータなどを受け取る。
`app/Http/Contorollers/`配下に作成。

###　ビュー作成
Lalabelには「Blade」という独自のtんプレートエンジンが用意されている。
`resources/views`配下に設置していく。
Bladeでは「◯◯.blade.php」という名前でファイルを作成する。
Bladeでは`{{$変数}}`というようにして変数をテンプレート内に埋め込むことができる。
コントローラのアクションメソッドに変数を定義し、コントローラから値を受け取り、表示する。


## おわりに
まだまだ、途中ではありますがまずはフロントエンド側からある機能を持ったソースコードを追ってどのようにMVCがぞれぞれ機能しているのかを理解できるところまではできたのでここまでとします。

参考文献： PHPフレームワーク　Laravel入門　第２版　　掌田　津耶乃
【Python】FlaskでWEBアプリ作るぞ〜 #1 環境準備

# 開発環境
macOS
Python 3.9.6
pip 21.2.4
Flask 3.0.0

今回はflask-appというディレクトリで作っていきます。
```
mkdir flask-app
cd flask-app
```

# 仮想環境を作る
```
python3 -m venv venv
source venv/bin/activate
```

venvについてはこちら↓

https://www.manajob.jp/python/python-app/venv

仮想環境を無効化するときは下記
```
deactivate
```

# 仮想環境下にFlaskをインストール
```
(venv) $ pip install flask
```

# まずはブラウザに文字を表示させてみる
app.pyファイルを作成し下記のように記述
```app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!!!"

if __name__=="__main__":
    app.run()
```
```@app.route("/")```で、ルート（```http://127.0.0.1:5000/```）にアクセスしたときに表示するページの処理だよ〜っていうことを示しています。

# いざ実行!
```
(venv) $ python app.py
```

以下のように出力されたら正常に実行されています。
```
Running on http://127.0.0.1:5000
```

ブラウザで下記にアクセスすると...
http://127.0.0.1:5000/

![スクリーンショット 2023-11-03 15.10.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3598712/354a5d55-08cb-b868-76dc-33aa756befa4.png)

無事Hello Worldと表示されました:clap:
FastAPIにおける効率的なデータベースセッション管理

以下はFastAPIを使用したウェブアプリケーション開発におけるデータベースセッション管理に関する記事の構成例です。

---

## はじめに
現代のウェブアプリケーションでは、データベースとのやり取りは不可欠な部分です。PythonのFastAPIフレームワークを利用したアプリケーション開発において、SQLAlchemyを使用したデータベースセッションの効率的な管理方法を探ることは、アプリケーションの性能と信頼性を高めるために重要です。

## データベースセッションとは？
データベースセッションは、アプリケーションがデータベースとの間で行う一連の操作をカプセル化するコンテキストです。SQLAlchemyのセッションは、データの読み書きやトランザクションの管理を担当し、アプリケーションのデータベース操作の基盤となります。

## FastAPIと依存性注入
FastAPIでは、依存性注入システムを使用してデータベースセッションをエンドポイントに注入することができます。このパターンにより、コードの再利用性が向上し、テストや保守が容易になります。

## データベースセッションの生成と破棄
`dependencies.py` に定義された `get_db` 関数は、APIエンドポイントの実行前に新しいデータベースセッションを生成し、リクエストの処理が終了した後にそれを閉じる責務を担います。以下のコードはその一例です。

```python
# app/dependencies.py
from .database import SessionLocal

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
```

この関数は、リクエストのライフサイクルに沿ってセッションを適切に管理し、メモリリークやデータベースリソースのロックを防ぐために重要です。

## 結論
FastAPIとSQLAlchemyを用いたデータベースセッションの管理は、アプリケーションの効率性と信頼性を保つために欠かせない要素です。`get_db` 依存性関数を活用することで、各リクエストに対して独立したセッションを提供し、確実なデータベース操作を行うことが可能になります。

---

この記事は、FastAPIを使ったアプリケーション開発におけるデータベースセッションの管理に焦点を当てており、開発者が理解しやすいように基本的な概念から具体的なコードの実装までを網羅しています。
【Golang】配列の比較による新しい要素の抽出について

Golanfで2つの配列を比較し、一方の配列に存在しない要素を新しい配列に抽出することを実装したため、備忘録として残すもの。
この方法は、データのフィルタリングやデータの整理など、さまざまな応用分野で役立ちます。


### サンプルコード
```go
package main

import (
	"fmt"
)

func main() {
	// 配列を定義します
	existArray := []int{1, 2, 3, 4, 5}
	array := []int{3, 4, 5, 6, 7}

	// 新しい要素のみを追加するための空のスライスとして初期化します
	var newArray []int

	// arrayの要素を順番にチェックし、existArrayに存在しない要素をnewArrayに追加します
	for _, element := range array {
		found := false
		for _, existElement := range existArray {
			if existElement == element {
				found = true
				break
			}
		}
		if !found {
			newArray = append(newArray, element)
		}
	}

	// 結果を表示します
	fmt.Println("existArray:", existArray) // existArray: [1 2 3 4 5]
	fmt.Println("array:", array) // array: [3 4 5 6 7]
	fmt.Println("newArray:", newArray) // newArray: [6 7]
}
```

### 配列の要素比較について
実際に比較している箇所について、詳しくコメントを追加したものが下記
```go
// 最初にarrayを展開して、要素を一つ取り出す。
for _, element := range array {
        // array要素がexisstArrayの要素に含まれているかの制御文を追加
		found := false

        // existArrayを展開して、要素を一つずつ取り出す。
		for _, existElement := range existArray {
            // arrayとexistArrayの取り出した要素同士を比較する
            // 同じ要素があった場合は、制御文をtrueにしたループを抜ける
			if existElement == element {
				found = true
				break
			}
		}

        // existArrayとの比較が終了したループを抜けた際に、一致した要素がない場合に、下記処理が実行される。
		if !found {
			newArray = append(newArray, element)
		}
	}
```

:::note info
<font color="orange">**found変数**</font>は特定の条件（ここでは element が配列existArray内で見つかったかどうか）を追跡し、 <font color="orange">**「条件が満たされた場合」**</font>と<font color="orange">**「満たされなかった場合」**</font>の2つの状態を表現するのに役立つ。
:::

### まとめ
found変数（boolean）で状態を制御する方法について知ることができた。
PowerQueryで文字列から型を返す

例えば、通貨型を返す式の文字列から、通貨型そのものを得るには...
```Expression.Evaluate("Currency.Type", #shared)```
とすれば良い。

```#shared```が必要なことがわからなくてハマったのでメモ。

列名と型の組み合わせをExcelのテーブルに保存しておき、取得して利用したかったのだが、型を直接表現できないので、このようなことが必要になった。

|Name|TypeExpression|
|:-:|:-:|
|Id|Int64.Type|
|品名|Text.Type|
|単価|Currency.Type|

これを利用して、既存のテーブルから、[Table.TransformColumnTypes](https://learn.microsoft.com/ja-jp/powerquery-m/table-transformcolumntypes)関数の第2引数typeTransformationsに入力するリストを生成する関数を作ってみた。

```m
// TypeTransformationsFromTable
(table as table) =>
let
    schema = Table.Schema(table),
    transform = (document) => Expression.Evaluate(document, #shared)
in
    List.Zip({schema[Name], List.Transform(schema[TypeName], transform)})
```
Windows11のモバイルホットスポットをオフライン環境で無理矢理オンにする方法

国際線長距離フライトなどでインターネットに接続できない環境ではモバイルホットスポットを有効にできませんが、次のPowerShellで強制的にオンにできました。

登録済みWiFi名のところを「設定→ネットワークとインターネット→既知のネットワーク」一覧に出てくるもので置き換えてください。圏外であっても登録済みネットワークであれば何でもよさそうです。

```
$W="＜ここに登録済みWiFi名を書く＞"
$c = [Windows.Networking.Connectivity.NetworkInformation,Windows.Networking.Connectivity,ContentType=WindowsRuntime]::GetConnectionProfiles()|Where-Object{ $_.ProfileName -like "*"+$W+"*" }
[Windows.Networking.NetworkOperators.NetworkOperatorTetheringManager,Windows.Networking.NetworkOperators,ContentType=WindowsRuntime]::CreateFromConnectionProfile($c).StartTetheringAsync()

```

参考：https://stackoverflow.com/questions/45833873/enable-windows-10-built-in-hotspot-by-cmd-batch-powershell


※Windows11 22H2のみ検証済み。
Seleniumの環境構築のAttributeError: 'NoneType' object has no attribute 'split'に苦戦した

## 結論
Ubuntuにもchromeを入れよう。

## 経緯
・当初、BeautifulSoupだけでやろうと思ったが、ページ内遷移後のスクレイピングもしたいため、Seleniumも採用した
・できあがったら、Webサービスとして公開しようか悩んでいる

## 環境構成
wsl + Ubuntu(20.04)
Django 4.2.7
BeautifulSoup 4.12.2
Selenium 4.15.1

## ディレクトリ構成
```
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-38.pyc
│   ├── admin.cpython-38.pyc
│   ├── apps.cpython-38.pyc
│   ├── models.cpython-38.pyc
│   └── views.cpython-38.pyc
├── admin.py
├── apps.py
├── chromedriver.exe
├── chromedriver.exe:Zone.Identifier
├── migrations
│   ├── __init__.py
│   └── __pycache__
│       └── __init__.cpython-38.pyc
├── models.py
├── tests.py
└── views.py
```

## ソースコード
```views.py
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
def scraping(request):
　　# ③でだめだった書き方↓
    # service = Service(executable_path=r"C:\chromedriver-win64\chromedriver.exe")
    
    # ③でひとまずエラー解消された書き方↓
    driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
    return HttpResponse("Hello, World!")
```

## 対応
➀[ChromeDriver](https://chromedriver.chromium.org/downloads)をchromeと同じバージョンのものをダウンロード

➁最初、Cドライブ配下に設置してたが「**Chromeドライバーありません^^**」エラーが出続けるため、Djangoアプリ内に配置。ディレクトリ構成には見えてないが、```views.py```と同じ位置関係
→それでもエラー解消されず

➂書き方を変更
→```executable_path```はselenium4.6以降(?)使えないらしい。
参考URL➀：[Selenium4 WebDriver の executable_path 使用に伴う警告の回避方法](https://gammasoft.jp/blog/python-selenium-webdriver-deprecation-warning-by-executable_path/)

➃**本件のエラー発出**。下の参考3件で解決。
※ちなみに私は参考➁では解決しなかった。
参考URL➁：[kmeans.fitで AttributeError: 'NoneType' object has no attribute 'split'が出るとき](https://note.com/ino754/n/n7f9efe1a8c60)
参考URL➂：[UbuntuにChromeをインストールする](https://qiita.com/pyon_kiti_jp/items/e6032eb6061a4774aece)
参考URL➃：[webdriver_managerで自動的にSeleniumとChromeバージョンを一致させる](https://scr.marketing-wizard.biz/dev/webdriver-manager-selenium-chrome)

どうでもいい補足：python全然知見ないけど、すごそう(小並感)
以上
AWS公式アイコンのページが便利すぎた

## AWSのアーキテクチャ構成図を手軽に書きたい
パワポのアイコンないかなと探したら、
それ以上の収穫があった。

https://aws.amazon.com/jp/architecture/icons/

パワポのアイコンはもちろんのこと、
すぐに使える描画ツールも揃っている。

https://www.draw.io/?splash=0&libs=aws4

個人的には、職場でも使っている draw.io がすぐに使えて便利。![スクリーンショット 2023-11-03 13.51.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586577/1732f6a2-572e-8bb9-d6f9-eb147bc3c2cb.png)

これを機会に他の描画ツールも試してみたい。
Zabbix 5.0をphp8.1に対応させる

## php8.0までしかサポートしていない？ようなのでphp8.1に対応させる。

:::note warn
全機能を細かく検証したわけではないので、とりあえずエラーや警告を無くす程度の修正です。
:::

:::note info
rpmパッケージでアップデートがある度に直すのは面倒なのでパッチの作成を推奨。
:::

```
vi /usr/share/zabbix/include/classes/db/MysqlDbBackend.php
-------------------------
164	-$tls_mode = null;
164	+$tls_mode = 0;
-------------------------
```
※mysqli::real_connectのフラグでnullの使用が禁止

```
vi /usr/share/zabbix/include/func.inc.php
-------------------------
107 -setcookie($name, $value, isset($time) ? $time : 0, CSession::getDefaultCookiePath(), null, HTTPS, true);
107 +setcookie($name, !is_null($value) ? $value : "", isset($time) ? $time : 0, CSession::getDefaultCookiePath(), "", HTTPS, true);
-------------------------
```
※setcookieの引数でnullの使用が禁止

```
vi /usr/share/zabbix/include/classes/screens/CScreenProblem.php
-------------------------
// strftimeの箇所をdate("***", strtotime())に変換
-------------------------
```
※strftimeは非推奨
Webpackerを使っているときにJSを編集して画面をリロードしても変更が反映されない場合の対応

Rails6で開発をしてるときにJSに変更を加えて画面をリロードしても反映されないことがありました。
その時の対応方法です。

## 環境
`Rails 6.1.6`
`ruby 3.0.6`
`webpacker 5.4.3`

## Webpacker
`webpacker.yml`の`cache_manifest`の値にfalseを指定します。
もしくは削除します。
Cloud9で環境を作る(Github連携)

AWS ConsoleからCloud9を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/4197f9ad-2070-2226-125c-17da89ded104.png)

新しい環境を作成を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/3930e9f8-5db3-236d-ceaf-46a1055a194b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/2074483e-e5be-8a4b-2e89-c0f71e9a3eec.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/52e35687-90d6-0a93-a18c-49d5848639f0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/d1755dcc-865d-ca26-dacb-b5f9128f0a5d.png)

IDEを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/98a0501e-ef66-4014-b623-0842e64f7855.png)

ターミナルを開き、下記コマンドでssh keyを生成する
```
 $ ssh-keygen -t ed25519 -C 'your.email@example.com'
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_ed25519): langchainlambda-on-cloud9
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in langchainlambda-on-cloud9.
Your public key has been saved in langchainlambda-on-cloud9.pub.
The key fingerprint is:
SHA256:xxxxxxxx your.email@example.com
The key's randomart image is:
+--[ED25519 256]--+
|      .          |
|     = .         |
|    B o          |
|   . = .   o     |
|    = o S = o    |
|   * @   o o .   |
|  . % E .   .    |
|   BoBoo ..o     |
|   oO=B*=+o..    |
+----[SHA256]-----+
```

生成したpubキーの中身を確認する
 ```
 $ cat langchainlambda-on-cloud9.pub 
 ```

下記URLにアクセスし、[New SSH Key]にpubキーの中身を設定する
https://github.com/settings/keys

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/f6ce39e8-deae-7a51-b7bf-c5b72641ac56.png)

生成した鍵ファイルを移動
```
$ mv ./langchainlambda-on-cloud9* ~/.ssh/
```

ssh設定を行う
```
vim ~/.ssh/config 
```
下記をconfigファイルに張り付けるて、` :wq ` を入力
```
Host github.com
    User git
    IdentityFile ~/.ssh/langchainlambda-on-cloud9
```

接続確認
```
$ ssh -T git@github.com
The authenticity of host 'github.com (20.27.177.113)' can't be established.
ECDSA key fingerprint is SHA256:xxxxxxxxxxxxxxx
ECDSA key fingerprint is MD5:xxxxxxxxxxx
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,20.27.177.113' (ECDSA) to the list of known hosts.
Hi Hamanuma! You've successfully authenticated, but GitHub does not provide shell access.
```

git cloneを実行
```
$ git clone git@github.com:Hamanuma/LangChainLambda.git
```

下記はやっといた方がよさそう
```
npm install -g c9

```
.NETでPDFのページを削除

PDF文書は、テキスト、画像やその他の要素を提示するためにページを通して、PDF文書は、通常、複数のページを持っています。 特にネットワークから取得したPDF文書には、空白のページや不要なページ、無関係なページが存在することがあります。 この記事では、.NET Frameworkを使用してPDFページを削除する方法をお教えします。

.NET標準ライブラリに加えて、この記事で説明するアプローチでは、無料のAPIを使用する必要があります。このAPIは、[Free Spire.PDF for .NETのウェブサイト](https://jp.e-iceblue.com/introduce/free-spire-pdf-for-net.html)からダウンロードするか、NuGetコマンドを介してインストールすることができます：
```powershell
PM> Install-Package FreeSpire.PDF
```

## PDF文書からページを削除
このAPIの **PdfDocument.Pages.RemoveAt()** メソッドを使用して、指定されたページ内のPDFファイルをページパラメータ(0 から開始)を通して削除できます。サンプルコードと主な手順があります。
1. **PdfDocument** のオブジェクトを作成します。
2. **PdfDocument.LoadFromFile()** メソッドを使用して PDF 文書を読み込みます。
3. **PdfDocument.Pages.RemoveAt()** メソッドで3ページ目と2ページ目を削除します。
4. **PdfDocument.SaveToFile()** メソッドでPDF文書を保存します。

**コード**
**C#**
```c#
using System;
using Spire.Pdf;

namespace RemovePage
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // PdfDocumentのオブジェクトを作成する
            PdfDocument pdf = new PdfDocument();

            // PDF文書を読み込む
            string input = "サンプル.pdf";
            pdf.LoadFromFile(input);

            // 3ページ目と2ページ目を削除する
            pdf.Pages.RemoveAt(1);
            pdf.Pages.RemoveAt(2);

            // ファイルを保存する
            string output = "output/ページ削除.pdf";
            pdf.SaveToFile(output);
        }
    }
}
```

![PDF文書からページを削除](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/28d41cd1-3a00-1672-21d7-49b581c59412.png)

> この記事では、.NET Frameworkを使用してPDF文書からページを削除する方法について説明します。 この記事では、API Free Spire.PDF for .NETを使用しています。他にも多くのPDF操作機能がありますので、[Spire.PDF for .NETチュートリアル](https://jp.e-iceblue.com/tutorials/java/spire-pdf-java/pdf-java-program-guide-content.html)で紹介されている操作を見てください。
[Flutter] Flutterエンジニアが勉強になったUdemy教材を紹介します

![スクリーンショット 2023-11-03 12.30.00（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/75c842c9-b6de-8c12-4814-08f3285dd7f4.png)



この記事は、「Udemyおすすめ講座をシェアしよう！ by Udemy Advent Calendar 2023」のアドベントカレンダーの投稿となっております。

https://qiita.com/advent-calendar/2023/udemy

# はじめに

世の中にはさまざまな学習教材があると思います。初学者にとっては、たくさんあるからこそ、迷ってしまう場合があります。そんな方にとっておすすめしたいものは「Udemy」の教材だと思っています。
その理由をこの後に説明していこうと思います。



# Udemyがおすすめな理由

- <b>コードを書きながら学習できる</b>
  - インプットとアウトプットが同時でできるのはとても効率的だと思っています。 
  - とても大変な作業かもしれませんが、再生停止して学び直すこともできます。
- <b>一つの講座が割と安い</b>
  - Udemyのサイトを開くと、値段が高すぎないかと不安になる方もいると思います。そんな方に朗報がありまして、たまにセールがあったり、初回登録をすると2000円いないで講座を購入することができます。
  - また、自分に合わないと感じたら、３０日間の間であれば返金も可能です。
- <b>質問ができる</b>
  - 進めていくとどうしても不具合や気になるところが出てくるかもしれません。そんなときは質問をすることができます。全部の講座が返事をくれるかどうかは分かりませんが、僕の経験上だと大体の講座は質問に的確に答えてくれました。
  - もしダメだと思ったら、気軽に返金しましょう。そのクレジットを別の講座で使えばいいと思います。


# Udemyのおすすめ講座

:::note info
一つの意見だと思っていただけると幸いです🙇
僕が学習中のものもあるので、選ぶときは慎重に判断いただけると幸いです
:::

### 基礎から学んでみたい（日本語）

基礎を学んでみたい場合は、一通り網羅しているものがよさそうですね。個人的には、環境構築付きの動画教材があった方が挫折せずに進められるかなと思います。

https://www.udemy.com/course/flutter_starter/

### 基礎から学んでみたい（英語あり）

どうやらとても人気らしいですね。英語で説明していますが、英語を全部聞こうとすると、辛いと思うのでコードを書くことに集中したりしてもいいかもしれません。

https://www.udemy.com/course/flutter-bootcamp-with-dart/


### Firebase関連について学習したい

個人的には、Firebase関連については少し理解が難しかったので日本語の教材を選んでいます。日本語の教材がたくさんあるのでありがたいですね。

https://www.udemy.com/course/flutter-firebase-chat/

https://www.udemy.com/course/flutter-firebase-sns/

### Supabaseについて学習したい

Supabaseについても学習したいと思った時に探してみた時に、日本語の教材は見つかりませんでした。（Youtubeなどでもサンプルコードはありましたので、そちらもおすすめです。）

https://www.udemy.com/course/supabase-for-flutter-developers/


### 簡単なゲームを作ってみたい

簡単なゲームを作ってみたりすることもとてもいいと思いました。簡単に実装ができると達成感も得られますし、間改造も簡単にできると思います。

https://www.udemy.com/course/flutter-firebase-sns/



### 広告の実装をしてみたい

広告を実装してみたい場合は、公式を見ながらやってもいいと思いますが、動画通りに進めた方が楽でした。

https://www.udemy.com/course/flutter-firebase-admob/


# テストについて学習してみたい

テストコードは理解するのが難しかったので、手を動かしながら学習できるのはいいですね。

https://www.udemy.com/course/flutter-tdd/



# 最後に

僕は、最初の学習のステップの中で動画教材を使用して学習することはとても効率的だと思いました。その理由としては、インプットとアウトプットを同時にできる点や、質問をできるところだと考えています。
どうしても文字だけだとわからない場合もあるので、一つの勉強方法と思っていただけると幸いです🙇


# ちょっとした宣伝

株式会社ゆめみの23卒のメンバーでアドベントカレンダーを作成しています。
新卒のフレッシュな記事がたくさん投稿予定なので、少しでも興味があれば購読いただけると幸いです！！

https://qiita.com/advent-calendar/2023/yumemi-23-graduation
SelenideでInvalidSelectorException: invalid selectorエラーが出る

# はじめに

Selenideのエラーの切り分けに時間がかかり解決が大変だったので簡単にまとめます

# 問題
以下のようなコードを書いたところ

```kt
    private fun SelenideElement.coffeeCard(indexPlus1: Int): SelenideElement = this.`$`("div[data-test-id='card'])", indexPlus1 - 1)
```

以下のエラーが発生しました

```
Message: org.openqa.selenium.InvalidSelectorException: invalid selector: An invalid or illegal selector was specified
  (Session info: chrome=114.0.5735.90)
  ```

  # 解決方法

  以下のコードでうまく行きました

```kt
    private fun SelenideElement.coffeeCard(indexPlus1: Int): SelenideElement = this.`$`("div[data-test-id='card']", indexPlus1 - 1)
```

```
"div[data-test-id='card'])"　☓
"div[data-test-id='card']" ○
```

とういような違いがあり、ケアレスミスがあったことがわかりました

# おわりに

Selenide自体の使い方が問題あるのかと思っていたのですが、簡単なミスでした
SECCON online 2015 「Unzip the file」解説

# はじめに
本記事ではSECCONオンライン2015の「Unzip the file」を解説します。

# 問題
https://github.com/SECCON/SECCON2015_online_CTF/tree/master/Crypto/100_Unzip%20the%20file

# 解き方
## 問題の把握
question.txtには以下のように書かれています。
```
Unzip the file
unzip
```
つまり、「unzipファイルを解凍せよ」とのことです。

## 問題ファイルの調査
fileコマンドを使ってunzipファイルの種別を確認します。
```
$ file unzip
unzip: Zip archive data, at least v2.0 to extract, compression method=deflate
```
問題文からも容易に推測はできますが、案の定zipファイルでした。

## unzipフォルダの解凍
unzipコマンドでunzipフォルダの解凍を試みます。
```
$ unzip unzip.zip
Archive:  unzip.zip
[unzip.zip] backnumber08.txt password:（↵Enter）
   skipping: backnumber08.txt        incorrect password
   skipping: backnumber09.txt        incorrect password
   skipping: flag                    incorrect password
```
どうやらunzipフォルダは何かしらの方法で暗号化されているみたいです。
中にflagといういかにもな名前のファイル/フォルダが含まれており、unzipフォルダを復号することでflagファイルを確認できそうです。

## unzipフォルダの復号
同じくunzipファルダに含まれているbacknumber08/09.txtがヒントになりそうです。そこで、この名前を検索エンジンにかけてみると同名のファイルが平文で見つかりました。このことから、既知平文攻撃による解読が有効だとわかります。

## 既知平文攻撃
既知平文攻撃はpkcrackというツールにより実現可能です。

https://github.com/keyunluo/pkcrack

まず、backnumber08.txtをzip化します。
```
$ zip backnumber08.txt
```
同一フォルダ内に、backnumber08.txt、backnumber08.zip、unzip.zipが入っている状態で次のコマンドを実行します。
```
$ pkcrack -C unzip.zip -c backnumber08.txt -P backnumber08.zip -p backnumber.txt -d output.zip -a
```
実行後、flagファイルが平文で生成されます。
fileコマンドを実行するとflagがwordファイルであることがわかるため、ファイル名をflag.docxに変えて開くと、flagを入手できます。

# まとめ
本問はzipの暗号化方式の脆弱性を警鐘している。

# 参考

・入門セキュリティコンテスト

https://gihyo.jp/book/2022/978-4-297-13180-7
redirectとrenderの違い

# はじめに
何番煎じか分かりませんが、業務の中で気になって色々調べて整理することができたので記事にまとめます。

共通点としては、どちらも特定のコントローラーのアクションから、別のアクション（画面）をひっぱりだしたいときに使用します。

# redirect_to
処理が**成功**したあと、画面遷移を行いたい場合に使用します。
GETのHTTPリクエストを送ります。
コントローラーを経由します。

```test_controller.rb
def test
 redirect_to tests_url
end
```

# render
処理が**失敗**したあと、エラーメッセージなどを表示する場合に使用します。
コントローラーを経由しません。

```test_controller.rb
def test
 render :new
end
```

# 役立つかもしれない豆知識

### renderする際は、インスタンス変数を再宣言しないといけない。
コントローラーを経由しないためです。
render先で値を表示するには、render前に値を取得しておく必要があります。

```test_controller.rb
def new
 @test = Modeldata.find(1)
 render :new
end

def create
 # ここで@testを取得しないと、render時に@testを表示できない
 @test = Modeldata.find(1)
 render :new
end
```

### redirect_to後の画面にフラッシュメッセージを表示したい。
少し工夫が必要。
下記のやり方ではフラッシュメッセージが表示できない。

```test_controller.rb
def create
 flash.now[:notice] = "投稿に失敗しました"
 redirect_to action: :new
end
```

`flash.keep`を使えば可能。

```test_controller.rb
def create
 flash[:notice] = "投稿に失敗しました"
 flash.keep(:notice)
 redirect_to action: :new
end
```
# 参考
https://qiita.com/morikuma709/items/e9146465df2d8a094d78
https://zenn.dev/yukihaga/articles/fda5528484865c
擬似言語プログラム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/a63ccc8e-30c3-2982-7a60-dd246fac1ae2.png)
　基本情報技術者試験では、主に科目B試験で、擬似言語を利用したプログラム問題が出題されます。擬似言語では、if,while,forといった、プログラミング言語を問わず一般的に備わっている基本命令を利用します。C、Java、Python、VBA(Microsoft Excelなどで、マクロプログラムを作成するときに利用する言語)などの実際のプログラミング言語を知っている人には、馴染みがあるはずです。
 
 　プログラムは、コンピュータ（機械）が実行するものですから、機械的な動き、つまり、規則的な動作しかしません、規則的な動作は、繰り返し処理で実現します。プログラムを読解するコツは、繰り返し処理の部部分を正確に読み解くことです。擬似言語プログラムでは、繰り返し処理をwhile,forを使って書きます。この部分の動きを正確に読み解くことが重要であると覚えておく必要があります。
homebrewでopenssl関連の警告文 Warningが表示された


# 1.背景
homebrewで``brew upgrade``を定期的に実行して``brew doctor``を実行したら、openssl@1.1のサポートが切れたか何かで警告文が表示されていたので、openssl@1.1をアンインストールしてopenssl@3.0をインストールしました。その後、``brew doctor``を実行したら以下の警告文が表示されました。

````
~ $ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: Some installed formulae are missing dependencies.
You should `brew install` the missing dependencies:
  brew install openssl@1.1

Run `brew missing` for more details.
````
上記の警告文から解読すると、以前のopenssl@1.1に依存している何かが、openssl@3.0と連携できてないみたいですね。
エラーじゃないのですぐに解決すべき事項ではなさそうですが、今後の開発等で影響が出そうなので対策することにしました。個人的にもhomebrewはキレイにしておきたいというこだわりもありますしねｗｗ

# 2.対策
まずは警告文に表示されているコマンド``brew missing``を実行します。

````
~ $ brew missing
liblqr: openssl@1.1
````
すると何やら**liblqr**にopenssl@1.1が依存しているようなので、こいつをアンインストールします。

::::note alert
**※これは、あくまで私の個人的な環境で実施しています。重要な依存関係などあるかもしれないので、十分注意してください。
なにかあっても責任は負えません・・・**
::::

````
~ $ brew uninstall liblqr
Error: Refusing to uninstall /usr/local/Cellar/liblqr/0.4.2_1
because it is required by imagemagick, which is currently installed.
You can override this and force removal with:
  brew uninstall --ignore-dependencies liblqr
````
アンインストールしようとしたら、liblqrと依存しているものがあるので、本当に削除していいか聞かれていますね・・・
あとでliblqrインストールするので強制的にアンインストールを実行しました。

````
~ $ brew uninstall --ignore-dependencies liblqr
Uninstalling /usr/local/Cellar/liblqr/0.4.2_1... (24 files, 133.5KB)
````
これでliblqrをアンインストールできました。
再度、liblqrをインストールします。

````
~ $ brew install liblqr
==> Downloading https://ghcr.io/v2/homebrew/core/liblqr/manifests/0.4.2_1-2
############################################################################################################################################### 100.0%
==> Fetching liblqr
==> Downloading https://ghcr.io/v2/homebrew/core/liblqr/blobs/sha256:03a0e5288bac04044c068ebc27e26cc834f1f2ae483aa7e23663c53a0774495f
############################################################################################################################################### 100.0%
==> Pouring liblqr--0.4.2_1.sonoma.bottle.2.tar.gz
🍺  /usr/local/Cellar/liblqr/0.4.2_1: 113 files, 300.1KB
==> Running `brew cleanup liblqr`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
~ $ 

````

liblrqのインストールができたので、最後に``brew doctor``を実行したいと思います。

````
~ $ brew doctor
Your system is ready to brew.

````
警告文も表示されなくなり、正常に戻りました。

# 参考にした記事
https://qiita.com/y-vectorfield/items/730254270d6d333c5d0d
【ChatGPT無】専門家召喚PromptをCustom instructionsに移植。


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

　今回は、先週アップした専門家召喚PromptをCustom instructionsに移植します。

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　専門家召喚Promptは、
　　ChatGPT初心者向けの
　　　ものでした。　
[【ChatGPT無】簡単な質問に対し、必要な専門家を呼び出すPrompt](https://qiita.com/kabumira/items/284db780a4d32492713a)

　しかし、
　　セッション開始時に
　　　必ずPromptを
　　　　入れなければ使えない、
　　　　　という不具合？があり、
　　　　　　使うのが大変でした。

　そこで、
　　Custom instructionsに
　　　入れることで、
　　　　NewChatするたびに
　　　　　このPromptが
　　　　　　効くように
　　　　　　　なります。

　なので、
　　初心者相手をして
　　　初心者勧誘している人には
　　　　いいのではないでしょうか？

　ということで、
　　Custom instructions用
　　　Promptをどうぞ。
```Text:専門家召喚カスタム指示用Prompt
# 目的
入力されるプロンプトから、求められている回答を得るために、回答するChatGPTのロール（肩書き）を選択してもらい、それを決めてから、ユーザーとのセッションを行なう。

# 注意点
・入力されたプロンプトが、どんなに簡単なものでも、ロール（肩書き）は必須。
・勝手にロール（役割り）を決めない。
・知らなければ、知らないと答えてください。

# 前提条件
入力された問いが、あなたの知識の中に単語として存在していない場合は、「わかりません」と答えてください。これは絶対確実に守ってください。重要です。

# 処理手順
0.入力されたプロンプトに、前提条件に抵触していないかをチェックする。単語を知らない場合は、ロールを「一般人」として5にジャンプする。
1.入力されたプロンプトの方向性を見極める。→Ａ
2.Ａからユーザーに必要な専門家（肩書き）の選択肢（ひとつでも）を用意して、ユーザーに選択してもらう。→Ｂ
3.Ｂをあなた（ChatGPT）のロール（肩書き）として組み込む。
4.そのロールを表示する。
5.その専門家になって、セッションを継続してください。その過程で、知識にない言葉を知らなければ、知らないと答えてください。
```

　この中に、
　　前提条件が
　　　ありますが、
　　　　あまり機能していません。
　　　　　すみません。

　ですから、
　　ハルシネーションは
　　　回避できていません。
　　　　推測も回避できません。

　そこだけは、
　　ご注意を。

　今回は、ここまで。
Virtualbox ubuntuでLVMを拡張する方法

この間、K8Sの環境を作るため、VirtualboxでデフォルトのHDD容量(25GB)を使った
PODの数が増えてるにつれて、容量が足りなくなりました
(mysql, phpmyadmin , test用のphpプログラムのみ...)

この状況になるのも仕方ないですが、再インストールも嫌だし、今回、LVMの拡張をやってみようと思います
まずは、設定でHDDを新規追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/a7d47108-670b-4785-8668-421836fbc7e2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/232e21cf-c004-f8f7-bc38-00fcd8a92030.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/87760ea1-3770-065f-df15-960e8f203f4e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/59751ff5-051a-5798-9fce-2dd0063dc490.png)

設定が無事に終われば、下記のように新しいHDDが見えます、ここで、chooseを押してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/c902d435-9dbf-594e-42b0-890d06c61ec9.png)

この画面で、HARD　DISKがSATA Port1かどうかを確認してください、
SATA Port1なら、ubuntuでこのHDDは/dev/sdbになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/59cd48c9-8ca5-0bf1-157c-9f066df271d3.png)

そのあと、ubuntuを実行して、rootの権限でlvmを拡張します

---
一応簡単でLVMの構成を説明します、LVMの構成はPV,PE,VG、LVがあります
#### **PV**:　
  実在のHDDやパーティションと意味する
#### **PE**: 
  Filesystemのblockに等しいものですが、需要がないなら分からなくても大丈夫だと思います。
#### **VG**:
   実在のHDD(PV)をグループ化する。
   
   ちょっとわかりにくいと思いますが、例えば、HDDが十個ある場合、中の３つを/homeにする、他の７つは/databaseにする場合、VGでグループを作らないと設定は進めないです。
   
   なぜかというと、パソコンにとってHddは一つ一つ独立している存在の訳です。VGでグループを作れば、その３つを一つにすることができます。
    
#### **LV**：
VGの設定が終われば、LVはHDDのパーティション分割と同じです。(ubuntuインストールするときの分割と同じ)

では、設定を行います

fdisk /dev/sdb　▶　p 　で、追加したHDDが見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/93b4bb44-78e1-a8bc-09d6-8a83f4990e32.png)

n ▶ p　　で、新しいパーティションを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/35a66315-d53d-78b7-bb96-6b7a4e8d5bf1.png)

t ▶ 1 ▶8e　(このパーティションのfilesystemをLVMに設定する)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/f1e022ee-5b88-28e1-e876-e2ad46c59592.png)

最後、w　で書き込みます。

---

lvdisplayで、現在のLVMを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/819cde31-8323-f9ea-9cb4-9be0255b1c47.png)

今回、拡張のため、vgextend を使います
> vgextend ubuntu-vg /dev/sdb1  
(/dev/sdb1をubuntu-vgにつけます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/acb5ebe0-cd72-b00a-89ed-b742ff4054a7.png)

>lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
(古いubuntu-lvを拡張します)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/60a78119-8992-0919-d538-dc64155ed7f5.png)

最後，filesystem を　resizeする

> sudo resize2fs /dev/ubuntu-vg/ubuntu-lv

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/f699b4a6-0392-0441-8211-e719de4cb466.png)


こうすると、拡張した容量が見えるようになりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3585442/08aac523-f85b-e9ca-bc7b-2cf432a3e8d9.png)
jsの主要ライブラリ7選を徹底解説

# jsの主要ライブラリ・フレームワーク7選徹底解説

ウェブ開発の世界では、さまざまなライブラリやフレームワークが存在し、それぞれが特定のニーズに対応しています。JavaScriptはウェブ開発において中心的な役割を果たしており、Angular、Vue、Nuxt、React、Next.js、Node、Socket.ioはその代表的な例です。これらのツールはウェブアプリケーションの開発を容易にし、異なるアプローチで開発者をサポートします。

## Angular

### 大規模アプリケーションの強力なフレームワーク

**Angular**は、Googleによって開発された強力なフレームワークで、主にシングルページアプリケーション（SPA）の開発に用いられます。TypeScriptをベースにしており、データバインディング、依存性注入、ルーティングなどの機能を提供します。

#### ビジネスアプリケーションに最適

- **モジュラー構造**：再利用可能なコンポーネントとサービスにより、大規模なアプリケーションの開発を効率化。
- **強力なコミュニティ**：Googleのサポートに加え、大規模な開発コミュニティが存在します。

## Vue

### 軽量かつ柔軟なフレームワーク

**Vue**は、そのシンプルさと柔軟性で人気のあるフレームワークです。初心者にも扱いやすく、リアクティブなデータバインディングとコンポーネントシステムを特徴とします。

#### 小規模から大規模プロジェクトまで

- **簡潔で明瞭な構文**：初心者にも学びやすく、開発の敷居が低い。
- **拡張性**：小規模なプロジェクトから始めて、必要に応じて拡張することが可能。

## Nuxt

### Vueのためのサーバーサイドレンダリング

**Nuxt**はVue.jsベースのフレームワークで、特にサーバーサイドレンダリング（SSR）に焦点を当てています。これにより、ウェブアプリケーションの初回読み込み速度が向上し、SEOパフォーマンスも改善します。

#### ユーザーエクスペリエンスの向上

- **SSRの利点**：サーバーでページがレンダリングされるため、クライアント側のレンダリング時間が短縮され、ユーザーエクスペリエンスが向上します。
- **Vue.jsのシンプルさを維持**：Vue.jsの直感的な構文と組み合わせ、開発者にとって扱いやすい環境を提供します。

## React

### コンポーネントベースのUI開発

**React**は、Facebookによって開発されたJavaScriptライブラリで、コンポーネントベースのアーキテクチャによってUIの構築を行います。データ駆動型のアプローチと仮想DOMにより、効率的なUI更新が可能です。

#### 大規模アプリケーションに適した選択

- **再利用可能なコンポーネント**：コンポーネントを再利用することで、開発速度とコードの品質を向上させます。
- **広範なエコシステム**：多くの追加ライブラリやツールが提供され、様々なニーズに対応できます。

## Next.js

### ReactアプリケーションのためのSSRフレームワーク

**Next.js**はReactに基づくフレームワークで、サーバーサイドレンダリングを容易に実装できます。これにより、ウェブアプリケーションのパフォーマンスが向上し、SEOにも有利です。

#### 効率的なページ読み込みとSEO

- **高速なページ読み込み**：SSRによりクライアント側のJavaScriptの実行時間を削減。
- **SEO最適化**：サーバー側でレンダリングされたページは検索エンジンにより効果的にインデックスされます。

## Node

### JavaScriptのサーバーサイド実行環境

**Node**はJavaScriptをサーバーサイドで実行するためのランタイム環境です。従来のJavaScriptがクライアントサイドに限定されていたのに対し、Node.jsによってウェブサーバーなどのバックエンドアプリケーションの開発が可能になりました。

#### 非同期I/Oと高速なパフォーマンス

- **非同期I/O**：イベント駆動型の非同期I/Oモデルを採用しており、多くのリクエストを効率的に処理できます。
- **npmエコシステム**：Node Package Manager（npm）を通じて、数多くのライブラリやツールを利用できます。

## Socket.io

### リアルタイム通信の実現

**Socket.io**は、ウェブアプリケーション間でリアルタイム通信を実現するJavaScriptライブラリです。これにより、チャットアプリケーションやリアルタイムデータ更新などの機能を簡単に実装できます。

#### 幅広いプラットフォームサポート

- **クロスプラットフォーム対応**：ウェブブラウザだけでなく、Node.js環境でも動作するため、幅広いアプリケーションで利用できます。
- **簡単な実装**：Socket.ioのAPIは直感的で使いやすく、リアルタイム機能の追加を容易にします。

## まとめ

JavaScriptのエコシステムは多様で、Angular、Vue、Nuxt、React、Next.js、Node、Socket.ioなどのツールやフレームワークによってさまざまな開発ニーズに対応しています。Angularは大規模なSPAの開発に、VueとNuxtは使いやすさとSSRのメリットを提供し、ReactとNext.jsは効率的なUI構築とSSRを実現します。NodeはJavaScriptをサーバーサイドで利用するための基盤を提供し、Socket.ioはリアルタイム通信の実装を容易にします。これらのツールを適切に選択し組み合わせることで、効率的で強力なウェブアプリケーションを構築することができます。