OmniAICreator/Qiita-1.07M huggingface dataset:
CDKで既存のVPC情報を参照するときメモ

## 既存のVPCを読み込み使用するコードでエラー発生

`vpc.fromVpcLookUp()` で既存のVPCを取得し、更に `vpc.privateSubnets` でプライベートサブネットを取得したかった……。

謎のエラー発生。
```
Invalid vpc config: subnets cannot be empty
```


## ちゃんとドキュメント読もう

そもそも、パブリックサブネットはCDKコード作成前から追加したが、プライベートサブネットはCDKコードを書いている途中でコンソールから追加していた。

怪しいのは上の違いなのでドキュメントを読みに行く。

fromVpcLookUp()のドキュメントによると、メソッドを実行するとcdk.out.jsonにVPC情報がキャッシュされる。

```
The VPC information will be cached in cdk.context.json and the same VPC will be used on future runs. 
To refresh the lookup, you will have to evict the value from the cache using the cdk context command.
```

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html#static-fromwbrlookupscope-id-options

エラーの原因は、最初にプライベートサブネットがない状態でfromVpcLookUp()を使い、cdk.out.jsonにキャッシュされる。
プライベートサブネット追加したがキャッシュが残ったままなのでプライベートサブネットが取得できないというのが原因でした。
WindowsのPHPを8.2にアップデートしたらClass "ZipArchive" not found

### 結論
WindowsでPHPを8.2.0以降にアップデートしたときに、
`PHP Fatal error:  Uncaught Error: Class "ZipArchive" not found in ***`
のエラーが出たら
php.iniに以下の１行を追加
`extension=zip`

### アップデートすることになった理由
WindowsにPHPを入れて色々なツールを動かしているのだけど、PHP7.3.3でSplFileObjectを使ってCSVファイルを読み込むと、データ中に改行があって""で囲まれているCSVファイルがうまく読み込めない。
他のマシンで試すと同じコードで正しく読み込めた。他のマシンのPHPのバージョンを調べると8.2.2だったので、PHP7.3.3のマシンも8.2.2にアップデートすることにした。

### 結論に達するまで
PHPのコード中でZipArchiveを使っていると
`PHP Fatal error:  Uncaught Error: Class "ZipArchive" not found in ***`
というエラーが出るので、PHPのドキュメントを調べてみると、
https://www.php.net/manual/ja/zip.installation.php
こちらのページに
`PHP 8.2.0 以降では、 php_zip.dll を php.ini で有効にする必要があります。`
と書いてある。「php_zip.dll を php.ini で有効にする」って何だ？？と思って、PHP8.2.2をインストールしたときにできたphp.iniのサンプルphp.ini-productionを開いてキーワード「zip」で検索してみると、
`;extension=zip`
という行があったので、この行のコメントアウトを外して、php.ini に追記したらZipArchiveが使えるようになった。
パワポ用に，LaTex書体の数式を作成できるサイト

パワポ用に，Latex書体の数式を作成できるサイトです．

https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftexclip.marutank.net%2F&data=05%7C01%7C%7Cb4f9eaac4088472cfa9308db0e128662%7C20ee4c8087bd422ca5063a2b0aca0615%7C0%7C0%7C638119244951240122%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=hjxd06ILoS4c8cL%2Fs4a1Cm8aZijJrAnkI7WKhygpOeg%3D&reserved=0

Fontは，txfontsがベターです．画像はコピペできます．
JavaScript 独学

# 独学フロントエンド

都内の自社開発企業でインターンをしています。
独学で学習してから入社しました。
今からあまりお金をかけずにどのようにフロントエンドを学習するかを考えてみました
HTMLやCSSは別途学習してください
## 前提
学習を進めていく中で足りないなと思ったことは自分で取捨選択してください
ゴールはReactで開発を行う。その際にJavaScriptの仕組みや、非同期処理を含めた基礎的なことを理解していることです
記事を書いている人は、ESLintやWebPackの学習経験もありますが、今回は省きます。本質的な部分ではないと思います。必要になったら学習しましょう。

## はじめる

まずは環境構築を行う

https://www.youtube.com/watch?v=wtb0V6a4FXQ

JavaScriptを触ったことがない人が最初に見てほしい。　まずはJSの世界へ入門しよう

https://www.youtube.com/watch?v=gs0l4rsQCGM

https://www.youtube.com/watch?v=E08jeQBa1D0

クイズアプリを通してJavaScriptでアプリ作成をする

https://www.youtube.com/watch?v=fAluwAmHrws

ハンバーガーメニューを作ってみる （スマホで開いた時に右上に出てくる３本線のやつ）
下記はもうすこしオシャンな感じだが、基本的な作り方は一緒なので参考になると思われる

https://www.youtube.com/watch?v=XIj0WIfDFs8

JavaScriptの知識を強固なものにする ボリュームも難しさもあるが、頑張ってほしい
JavaScriptの歴史から学ぶことができる ES5とES6の違いも含めて JavaScriptを語れるようになる

https://www.udemy.com/course/javascript-essence/

Reactへ入門する

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

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

TypeScriptを体験しよう

https://www.udemy.com/course/typescript-complete/

りあクト 　全部で3部構成 

https://techbookfest.org/product/7FQY2BzfDGdsLMNdf7h1Mx?productVariantID=wCVwBWsuJa30n2A93X10MZ

https://techbookfest.org/product/fE1XmKQcKrkfZn2LhwWTqm?productVariantID=6VdKuD7aeSMPFTct5vPfW9

https://techbookfest.org/product/g2S8Rep1LDPS11GT3PuHjQ?productVariantID=ukrtY4Xh7CvXHWeXLcG97

ここからは自分のアイデアを形にしてみよう

ようそこモダンJavaScriptの世界へ
iOSアプリの配信先の国を変更/指定する（開発者向け）

「app store connect 配信国 変更」とか「iOSアプリ 配信先 国 変更」とかでググっても全然出てこなかったし、めちゃくちゃ分かりずらかったから備忘録。




1. 「App Store Connect」にアクセス
2. 配信国を変更したいアプリを選択
3. 「価格および配信状況」の「価格表」でプルダウンから価格を選択
　※これやらないと国選択できない
![スクリーンショット 2023-02-14 12.03.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872351/dbcafd12-29f0-a02e-8e24-8ab35fa76a50.png)




4. 「配信可否」のとこにある「編集」
![スクリーンショット 2023-02-14 11.47.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872351/4ca29795-a83b-8f8c-e912-81c641f6234d.png)

これでEUへの配信を止めればGDPR対応もしなくて済みますね。

めでたしめでたし。
try with resource, AutoCloseable

class implements AutoCloseableがtry with resourceできる
BufferedReadearなど。
try blockの最後でclose()が呼ばれる
class implements AutoCloseableがnullの場合はNullpointerは発生しない。closeもしない
記述した順番と逆順でclose
```java
class Sample implements Closeable {
    String msg;
    Sample(String msg) {
        this.msg = msg;
    }
    @Override
    public void close() {
        System.out.println(this.msg + " close");
    }
    void method() {
        System.out.println(this.msg + " method");
    }
}
public class Outer {
    public static void main(String args[]) {
        Sample s = new Sample("s");
        Sample s1 = new Sample("s1");
        Sample s3 = new Sample("s3");
        Sample s2 = null;
        try (s;s1;s2;s3) {
            method(s);
            method(s2);
        }
    }
    static void method(Sample s) {
        if(s!=null)  s.method();
    }
}
```
```
s method
s3 close
s1 close
s close
```
try block, closeでexception occurの場合、
try block sideのexceptionが表面的なexception
close sideのexceptionは getSuppressed()で取得

```java
class Sample implements Closeable {
    String msg;
    Sample(String msg) {
        this.msg = msg;
    }
    @Override
    public void close() {
        System.out.println(this.msg + " close");
        throw new RuntimeException();
    }
    void method() {
        System.out.println(this.msg + " method");
    }
}
public class Outer {
    public static void main(String args[]) {
        try (Sample s = new Sample("s")) {
            System.out.println(" try");
            throw new Exception();
        } catch (Exception ex) {
            System.out.println(ex);
            Throwable[] ts = ex.getSuppressed();
            for(Throwable t:ts) {
                System.out.println(t);
            }
            System.out.println(" catch");
        } finally {
            System.out.println(" finally");
        }
    }
}
```
```
 try
s close
java.lang.Exception
java.lang.RuntimeException
 catch
 finally
```
AutoCompleteの三角マークを完全に消す方法

# 概要
AutoCompleteを使用していて、三角マーク🔻を見た目だけ消しても謎の余白ができ
入力欄を圧迫するということがあったので、解決策をメモ代わりに残しておきます。

# 実装

## コード全容
```jsx:TimeInput.jsx
import styled from 'styled-components'

const TimeInput: React.FC<Props> = ({
  time,
  onChangeTime,
}) => {
  const options = [
    { value: 0, name: '0秒' },
    { value: 1, name: '1秒' },
    { value: 2, name: '2秒' },
    { value: 3, name: '3秒' },
    { value: 4, name: '4秒' },
    { value: 5, name: '5秒' },
    { value: 10, name: '10秒' },
    { value: 20, name: '20秒' },
    { value: 30, name: '30秒' },
    { value: 60, name: '1分' },
    { value: 180, name: '3分' },
    { value: 300, name: '5分' },
    { value: 600, name: '10分' },
  ]

  return (
    <FieldSet>
      <TimeInputForm
        type="number"
        autoComplete="on"
        list="option"
        onChange={(e: any) => onChangeTime(e.target.value)}
        value={time}
      />
      <datalist id="option">
        {options.map((option, i) => {
          return (
            <option key={i} value={option.value}>
              {option.name}
            </option>
          )
        })}
      </datalist>
    </FieldSet>
  )
}

export default TimeInput

const FieldSet = styled.fieldset`
  width: 80px;
  height: 32px;
  margin-left: 8px;
  border: none;
`

const TimeInputForm = styled.input`
  width: 100%;
  height: 100%;
  padding-left: 6.5%;
  padding-right: 0;
  background-color: #f3f5f7;
  // 🔻を見た目＋幅、マージン、パディングも含めて完全に削除
  &::-webkit-calendar-picker-indicator {
    width: 0;
    margin: 0;
    padding: 0;
    opacity: 0;
  }
  // Numberフィールドのトグルを常時表示する
  &::-webkit-inner-spin-button,
  &::-webkit-outer-spin-button {
    opacity: 1;
  }
`
```

## 解説：完全に消す方法
```css
::-webkit-calendar-picker-indicator {
  width: 0;
  margin: 0;
  padding: 0;
  opacity: 0;
}
```
`-webkit-calendar-picker-indicator`を指定し、`opacity`で見えなくして、
幅、マージン、パディングを消しています。
`display: none;`では反応しなかったので、この方法を取りました。

## 補足
### AutoCompleteの実装方法
1. `input`を`fieldset`で囲む
1. `input`タグの`autoComplete`属性を`on`、`list`属性に`"option"`(`datalist`タグの`id`属性)をセット
1. `datalist`タグの中に`option`タグで候補を入れる

### AutoCompleteとInputの幅を合わせる
```jsx
const FieldSet = styled.fieldset`
  width: 80px;
  height: 32px;
  margin-left: 8px;
  border: none;
`
const TimeInputForm = styled.input`
  width: 100%;
  height: 100%;
  padding-left: 6.5%;
  padding-right: 0;
  background-color: #f3f5f7;
  &::-webkit-calendar-picker-indicator {
    width: 0;
    margin: 0;
    padding: 0;
    opacity: 0;
  }
  &::-webkit-inner-spin-button,
  &::-webkit-outer-spin-button {
    opacity: 1;
  }
`
```
`fieldset`のボーダーを消し、`input`のボーダーを採用します。
また、幅・高さは`fieldset`に合うように100%を指定します。

### Input type="number"のスピンボタンが反応しない
AutoCompleteの当たり判定とInputの当たり判定（フォーカス）が被ることで起きるエラーです。
スタッキングコンテキストの上の方に持ってくる`position: absolute;`で
Inputのスピンボタンの優先度を上げます。
```css
  &::-webkit-inner-spin-button,
  &::-webkit-outer-spin-button {
    position: absolute;
    right: 1%;
    height: 20px;
    opacity: 1;
  }
```
EAS Buildでapp.jsonが読み込まれていない場合

# EAS Build で Config 情報を取得できない場合

- [EAS Build で Config 情報を取得できない場合](#eas-build-で-config-情報を取得できない場合)
  - [エラー](#エラー)
  - [はじめに](#はじめに)
    - [開発環境の用意](#開発環境の用意)
    - [開発環境の起動](#開発環境の起動)
    - [今回の現象と解決方法](#今回の現象と解決方法)
      - [【現象】](#現象)
      - [【原因】](#原因)
      - [【解決方法】](#解決方法)
  - [おわり](#おわり)
  - [参考記事](#参考記事)

## エラー

以下のようなエラーが出力された、または [【現象】](#現象)と同じケースで困っている方はぜひ以下をご覧ください

```
[PREBUILD] CommandError: Input is required, but 'npx expo' is in non-interactive mode.
[PREBUILD] Project must have a `ios.bundleIdentifier` set in the Expo config (app.json or app.config.js).
[PREBUILD] error Command failed with exit code 1.
```

## はじめに

僕が個人で開発している[スマホアプリ](https://konoyubitomare.app)では同じスマホに複数環境をインストールできる、かつ他ライブラリの都合上`app.config.ts(js)`で定義する訳にはいかなかったため、以下のように各環境毎に json 形式で定義し、ts-node を用いて app.json を生成するようにしています。

### 開発環境の用意

```ts
// 開発環境
const dev = {
  "slug": "xxx-dev",
  "scheme": "xxx-dev",
  "ios": {
    "bundleIdentifier": "xxx.yyy.zzz.dev"
  },
  "android": {
    "package": "xxx.yyy.zzz.dev"
  },
}
// 検証環境
const stg = {
  "slug": "xxx-stg",
  "scheme": "xxx-stg",
  "ios": {
    "bundleIdentifier": "xxx.yyy.zzz.stg"
  },
  "android": {
    "package": "xxx.yyy.zzz.stg"
  },
}
// 本番環境
const prod = {
  "slug": "xxx-prod",
  "scheme": "xxx-prod",
  "ios": {
    "bundleIdentifier": "xxx.yyy.zzz.prod"
  },
  "android": {
    "package": "xxx.yyy.zzz.prod"
  },
}

```

### 開発環境の起動

`yarn dev`で開発環境を実行できます。
実際のコマンドは以下のようになっています。

```package.json
scripts: {
  "dev": "yarn make:config:dev && APP_ENV=dev expo start --dev-client",
  "make:config:dev": "APP_ENV=dev ./node_modules/.bin/ts-node ./makeAppJson.ts", // 開発環境app.jsonの生成
  "make:config:stg": "APP_ENV=staging ./node_modules/.bin/ts-node ./makeAppJson.ts", // 検証環境app.jsonの生成
  "make:config:prod": "APP_ENV=production ./node_modules/.bin/ts-node ./makeAppJson.ts", // 本番環境app.jsonの生成
}
```

### 今回の現象と解決方法

#### 【現象】

以下のように app.json の内容がビルドサーバーに含まれていないため、
PREBUILD フェーズで読み込みが行えないとエラーが発生していました。

```
[READ_APP_CONFIG] Using app configuration:
[READ_APP_CONFIG] {
  "name": "zzz",
  "slug": "zzz",
  "version": "1.0.0",
  "sdkVersion": "47.0.0",
  "platforms": [
    "ios",
    "android",
    "web"
  ],
  "currentFullName": "@aaa/zzz",
  "originalFullName": "@aaa/zzz"
}

(省略)

[PREBUILD] CommandError: Input is required, but 'npx expo' is in non-interactive mode.
[PREBUILD] Project must have a `ios.bundleIdentifier` set in the Expo config (app.json or app.config.js).
[PREBUILD] error Command failed with exit code 1.

```

#### 【原因】

`eas build は.gitignore を元にビルドサーバーに app.json を送信`しているらしい。
なので.gitignore に app.json を追加しているとビルドサーバーに app.json が送信されていなくなっていた。

#### 【解決方法】

git に app.json をコミットしたくないがビルドの度に.gitignore を編集するのは面倒な方は以下 2 の手順で解決できる

1. .gitignore から app.json を除く
2. .gitignore を.easignore にコピー & .easignore から app.json を除く

## おわり

この指とまれというアプリを開発しています！
グループ管理に便利な様々な機能を開発・追加予定ですのでもしよければインストールしてみてください 🥳
【iOS/Android】https://konoyubitomare.app

## 参考記事

https://forums.expo.dev/t/error-eas-build-failed-in-prebuild-bash-exited-with-non-zero-code-1/62389/3
Laravel で作った API に空文字を渡すと null になる

Laravel で作った API に空文字を渡すと API 側でエラーが発生するという事象にあいました。

調査してみると、どうやら API に渡した空文字が Laravel 側で null に変換され、その後の処理で意図せず null 参照が発生してエラーとなっているようでした。

空文字を null にするというのは Laravel のデフォルトの挙動です。

https://readouble.com/laravel/9.x/ja/requests.html より抜粋
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960076/fadef631-7493-7f8f-47e3-6ef0bb7334e0.png)

> リクエストに応じてすべての受信文字列フィールドを自動的にトリミングし、空の文字列フィールドをnullに変換します。

なるほどです。 Git for Windows の `autocrlf` 級に、余計なお世話感がある仕様です（個人の感想です）。

この機能をOFFにする場合は、 https://readouble.com/laravel/9.x/ja/requests.html に記載してあるように `skipWhen` を使って局所的にOFFにする方法とミドルウェア自体をOFFにする方法があります。

局所的にOFFにする場合（https://readouble.com/laravel/9.x/ja/requests.html より抜粋し一部改変）
```php
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;

/**
 * 全アプリケーションサービスの初期起動処理
 *
 * @return void
 */
public function boot()
{
    ConvertEmptyStringsToNull::skipWhen(function ($request) {
        return $request->is('admin/*');
    });
}
```

ミドルウェアごとOFFにする場合
`app/Http/Kernel.php` の `ConvertEmptyStringsToNull` 部分を削除（or コメントアウト）します。

```php
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Illuminate\Http\Middleware\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        // コメントアウトしてミドルウェアごと OFF にする
        // \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];
```

本件についてググると沢山の記事がヒットします。皆さん困っているようです。
PHP：Docker環境で初めて環境変数を作成し、それを用いたデータベースへ接続するまでの手順

# Dockerにライブラリ、phpdotenvをインストール

## Docker
起動

## iTerm2
docker-composeを開始(up)
ライブラリのphpdotenvをインストール


# 環境変数の設置

## vscode
環境変数を登録するファイルを作成し、保存場所を決めて保存
変数は以下の要領で記述
※グローバル変数の箇所は「$_ENV」でも「$_SERVER」でも良い。
```
DB_HOST="データベースのホスト名"
DB_USERNAME="データベースのユーザー名"
DB_PASSWORD="決められたパスワード"
DB_DATABASE="データベースの名称"
```

# コーディング

## PHPファイル
当然ながら、データベースを接続する前に指示する。

### 冒頭で全てのライブラリを一括読み込み
```
require __DIR__ . '/../vendor/autoload.php';
```

### 環境変数を書いているenvファイルの場所を示す
```
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
```

### 取得した環境変数の値を、それぞれ当てはまる変数を作成して代入

#### 例
※「$_EMV」でも「$_SERVER」でも良いとされていたため、例ではあえて交互に入れている。
```
$dbHost = $_ENV['DB_HOST'];
$dbUsername = $_SERVER['DB_USERNAME'];
$dbPass = $_ENV['DB_PASSWORD'];
$dbDatabase = $_SERVER['DB_DATABASE'];
```

### あとは環境変数を用いてデータベースへ接続

#### 例
```
$dbConnect = mysqli_connect($dbHost, $dbUsername, $dbPass, $dbDatabase);
```
NetworkManagerを使ってRaspberry PiをWi-Fi接続する

[4GPi]:https://mechatrax.com/products/4gpi/
[slee-Pi3]:https://mechatrax.com/products/slee-pi/
[ADPi]:https://mechatrax.com/products/adpi/
[機能拡張モジュール]:https://mechatrax.com/products/
[イプシム]:https://ipsim.net/
[USB-シリアル変換ケーブル]:https://store.mechatrax.com/product.php?id=38
[弊社]:https://mechatrax.com/
[メカトラックス株式会社]:https://mechatrax.com/
[SORACOM]:https://soracom.jp/
[SORACOM Napter]:https://soracom.jp/services/napter/
[Remote.It]:https://ja.remote.it/
[@hayat00]:https://qiita.com/hayat00
[Raspberry Pi Imager]:https://www.raspberrypi.com/software/
[弊社オンラインストア]:https://store.mechatrax.com/
[Tera Term]:https://ja.osdn.net/projects/ttssh2/
[OSイメージ]:https://mechatrax.com/data/4gpi/


# はじめに
　[メカトラックス株式会社]の[@hayat00]です。

　[弊社]では業務用Raspberry Pi周辺機器の開発・製造・販売、および、それら周辺機器を使用したRaspberry Pi組込機器の受託開発・小ロット製造等を行っており、オリジナルのラズパイ向け[機能拡張モジュール]として、[4GPi]、[slee-Pi3]、[ADPi]などを展開しています。

https://mechatrax.com/

　今回は、シリアル通信等でPCからログインしたRaspberry PiをCUI(CLI)から操作し、NetworkManagerを使ってWi-Fi接続する手順をご紹介します。
　最新のRaspberry Pi OSにはデフォルトでネットワークの設定ツールとしてdhcpcdとNetworkManagerがインストールされており、デフォルトでdhcpcdが使われていますが、ここではCUI上でdhcpcdからNetworkManagerに切り替え、Wi-Fiに接続する方法をご紹介します。
　なお、[弊社]製品の[4GPi]の[OSイメージ](4gpi-bullseye-lite-armhf-20220711以降)ではデフォルトでNetworkManagerが有効化されているため、Wi-Fiを使う場合は今回紹介する方法での接続を行ってください。

# 使用したRaspberry Pi OSの情報
Raspberry Pi OS Lite
- Release date: February 21st 2023
- System: 32-bit
- Kernel version: 5.15
- Debian version: 11 (bullseye)

# NetworkManagerのインストールと有効化
※[弊社]で公開している[4GPi]の[OSイメージ]を使用する場合は、デフォルトでNetworkManagerの有効化がされているので、この章の操作は不要です。

## Interactiveモードでの操作
　Raspberry Piにログインし、下記のコマンドを実行します。
```
$ sudo raspi-config
```

ターミナルソフト上に下記のような表示がされます。
「6 Advanced Options」にカーソルを移動させ、エンターキーを押します。
![WS000102.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113974/581fd762-c085-bfc0-6475-05d4ab61acb3.jpeg)

次に「AA Network Config」にカーソルを移動させ、エンターキーを押します。
![WS000103.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113974/f7259ff9-bb80-6d49-f26b-7006d422c3b9.jpeg)

続いて「2 NetworkManager」にカーソルを移動させ、エンターキーを押します。
![WS000104.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113974/1437bbb4-42f3-0d09-01c1-30a1f4fb72ce.jpeg)

<Finish>にカーソルを移動させエンターキーを押し、再起動を尋ねられるので<Yes>にカーソルを移動させエンターキーを押し、再起動します。

これでNetworkManagerの有効化は完了です。

## Non-Interactiveモードでの操作
　上記の操作を下記のコマンドひとつでNon-Interactiveモードで完了することも可能です。
```
$ sudo raspi-config nonint do_netconf 2
```


# Wi-Fiへの接続
　下記のコマンドでRaspberry Piから見えているWi-Fiを確認します。
```
$ nmcli dev wifi
```

接続をしたいSSIDがあることを確認します。
![WS000084.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113974/6ac2a37e-99b6-6cbb-fa40-1a6f83c6b9a1.jpeg)

下記コマンドでWi-Fiに接続します。SSIDとPASSWORDにはそれぞれ、接続するWi-FiのSSIDとパスワードを入れます。
```
$ sudo nmcli dev wifi con SSID password PASSWORD
```

最後に下記コマンドで接続を確認します。
```
$ nmcli con
```

接続が完了するとWi-Fiの項目が追加されます。
![WS000085.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113974/36553911-35ee-8b25-91e3-0d10bf6144e7.jpeg)

# 終わりに
　今回はNetworkManagerを使ってWi-Fiに接続をする手順をご紹介しました。ぜひ参考にしてください。
【限界集落】PeerCastStationがバージョンアップ！Linuxでの利用が便利に【mono不要】



2022年11月にPeerCastStationの安定版がリリースされました。

別に今までの環境でいいやと2.8.1を使用し続けていたのですが、気が向いたのでバージョンアップしてみたら今までより快適。
P2Pのソフトウェアってこういうソフトウェアアップデートが大事になってくると思います。
みんなはこまめにバージョンアップしようね😉

### 使用環境
CentOS Linux release 7.9.2009 (Core)

### ダウンロード
http://www.pecastation.org/download-stable.html

こちらの
Windows以外向けZIP版ダウンロード
をダウンロードします。

```
wget https://www.pecastation.org/files/PeerCastStation-4.1.0-any.zip
unzip ./PeerCastStation-4.1.0-any.zip
```

お好きなディレクトリに置きます。
```
mv /usr/local/PeerCastStation-4.1.0-any
chown -R root:root PeerCastStation-4.1.0-any
chmod 755 PeerCastStation-4.1.0-any
```

いざ、実行。
```
nohup sudo /usr/local/PeerCastStation-4.1.0-any/PeerCastStation &
```

以上

下記メッセージが出た場合

```
Process terminated. Couldn't find a valid ICU package installed on the system. 
Please install libicu using your package manager and try again.
Alternatively you can set the configuration flag System.Globalization.
Invariant to true if you want to run with no globalization support.
Please see https://aka.ms/dotnet-missing-libicu for more information.

```

ICUパッケージをインストールすることで解決します。
```
sudo yum install libicu
```
Twitter から動向を探る

とある機能を局所的にOFFにするか、全体的にOFFにするかを判断する必要がある場面で「ツイッターで検索してみたところ不人気でした。ミドルウェア自体外して良いと思います。」とコメントをもらいました。

ツイッターから動向を探るという手法は、すごくエンジニアしてるなと思いました（語彙力）。
【Rails】Capistranoによる自動デプロイ

Capistranoによる自動デプロイ設定で出た、Gemエラーの解消法を備忘として。



```ruby:コマンド実行
% bundle exec cap production deploy
```

## エラー内容
```ruby:ターミナル実行結果
01:01 deploy:assets:precompile
      01 $HOME/.rbenv/bin/rbenv exec bundle exec rake assets:precompile
      01 bundler: failed to load command: rake (/var/www/************/shared/bundle/ruby/2.6.0/bin/rake)
      01 Bundler::GemNotFound: Could not find date-3.3.3 in any of the sources
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/spec_set.rb:86:in `block in mate…
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/spec_set.rb:80:in `map!'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/spec_set.rb:80:in `materialize'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/definition.rb:170:in `specs'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/definition.rb:237:in `specs_for'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/definition.rb:226:in `requested_…
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/runtime.rb:101:in `block in defi…
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/runtime.rb:20:in `setup'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler.rb:149:in `setup'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/setup.rb:20:in `block in <top (r…
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:136:in `with_level'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:88:in `silence'
      01   /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/setup.rb:20:in `<top (required)>'
#<Thread:0x00007fc265b3beb8@/Users/admin/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/sshkit-1.21.3/lib/sshkit/runners/parallel.rb:10 run> terminated with exception (report_on_exception is true):
Traceback (most recent call last):

```

## エラー原因
３行目のここに注視！

```ruby:
Bundler::GemNotFound: Could not find date-3.3.3 in any of the sources
```
『**date-3.3.3ていうGem探したけどないよーーーー**』　って言われました。
んむ。バージョンか何かの問題だと推測。
date-3.3.3とGemfileに記述してもエラー。

調べたところ、gem mailがにアップデートにされたことが原因のよう。


## 解消法
ちょうど同じエラー内容だったので[こちらの記事と、](https://qiita.com/ksmj/items/776b70654a7deb39a56e)[こちらの記事](https://qiita.com/9999Fringe/items/74313b8d9adf6de91967)
を参考にさせて頂きました！助かりました〜
<details><summary>実行方法以下引用させて頂きました。</summary>

```rb
①Gemfileの末尾に「gem 'mail', '2.7.1'」を追記。（mailのバージョンを下げる指定をすることで、dateのgemを取得しないようにする為。）
 *Gemfileに「gem 'date', '~> 3.3', '>= 3.3.3'」を記述した場合は、gem 'date'の記述を削除。
②Gemfile.lockの削除
③ローカルでbundle install
④コミットプッシュ
⑤EC2内で自動デプロイ実行(% bundle exec cap production deploy)
```
</details>



gem mailなのにgem dateにかかってくるのもまだ理解できていないですが、
取り急ぎこれにて解決できやっとこさ自動デプロイ完結できました！！
【GAS】「TypeError: Assignment to constant variable」と出る

# はじめに
こんにちは、ユーゴです。
今回は、GASを使っていた時に遭遇したエラーについて紹介します。なぜか調べても出てこなかったので、書き記しておきます。
難易度は初級です。

# 問題
「TypeError: Assignment to constant variable」というエラーが出る

# 原因
constの変数を弄ろうとした。
例えば、以下のようなことをやると出る。

```js
function test(){
    const i = 0;
    i++; //TypeError: Assignment to constant variable
}
```

# 解決
constじゃなくてletを使うか、constに値を再代入しない。

```js
function test(){
    let i = 0;
    i++; // OK
}
```

# まとめ
いかがだったでしょうか。今回は、初歩的なミスの紹介でした。
この他にも、APIの使い方などの記事なども書いております。

お役に立てましたら、いいね・LGTM・フォローの方、よろしくお願いいたします！
Windows10で誤ってUSキーボードに切り替わらないように設定

# 現象

急に下記になって日本語入力できなくなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/899d5308-2ad5-8b41-74e2-b41067ed8c64.png)

どうやら間違えて ```Windowsマーク + Space``` を押してしまった模様。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/6aeab107-42e4-f179-e07d-2a2e35feeba0.png)

いっときUSキーボードを使っていた名残で ```Windowsマーク + Space``` で設定が切り替わってしまう。
USキーボードはもう使ってないので、こういった切替が起きないようにしたい。

# やり方

1. 空っぽの状態で英語（米国）インストール。
1. インストールした英語（米国）を削除。

という流れ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/ef4c1fea-f0be-390d-8f12-45c1046c008b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/faff8f46-ffc7-1136-6b3e-2972d3037849.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/25e5d49d-8e03-0d2f-fb92-5abee43fafe9.png)
全てのチェックを外してインストール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/1d220d8c-caf8-71f2-9740-e4c419bed316.png)
インストールした言語を削除。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/f068e998-d38e-b704-690a-baf65f60b21f.png)

# 参考サイトさん

http://onkochisin.kts.jp.net/2019/05/win10%E3%81%8B%E3%82%89%E8%8B%B1%E8%AA%9E%EF%BC%88%E7%B1%B3%E5%9B%BD%EF%BC%89%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B/

# バージョン

Windows 10 Pro 22H2 OSビルド 19045.2546
BigQuery の Scheduled Query で列の説明を出力する方法を ChatGPT に聞いてみた

BigQuery の Scheduled Query で列の説明を出力できないもんかと思って、ChatGPT に聞いてみました。
本当か嘘かはわからないですが、とてもしっかりとした受け答えに感心しました。

僕
```
BigQuery の Scheduled Query で列の説明を出力する方法
```

ChatGPT
```
残念ながら、BigQueryには、スケジュールされたクエリの結果セット内の個々のカラムに説明を追加する機能がありません。しかし、クエリ自体のコメントを使用して、結果セット内のカラムのコンテキストやドキュメントを提供することはできます。

ここでは、クエリにコメントを追加する例を示します。

# My query to retrieve the daily average temperature
SELECT
  DATE(timestamp) AS date,
  AVG(temperature) AS avg_temperature
FROM
  mydataset.mytable
GROUP BY
  date

コメントは、# 記号で追加します。これらはクエリのどこにでも追加することができ、クエリの各部分が何をしているのか、あるいは結果セットのカラムのコンテキストを示す有用な情報を提供することができます。
```
Docker Composeを使ってWordPressのローカル環境構築

WordPressをローカル環境で試してみたかったので、Docker Composeを使って構築してみました。

# 環境
Windows 11
Docker version 20.10.21
Docker Compose version v2.12.2
Docker Desktop version v4.14.1

※ Dockerは既にインストール済みなので手順は省きます。

# 構築手順

まずはコマンドプロンプトを立ち上げます。
```
C:\Users\hoge>
```

フォルダを作成します。
```
C:\Users\hoge>mkdir wp_local
```

フォルダに移動します。
```
C:\Users\hoge>cd wp_local
```

YAMLファイルを作成します。
```
C:\Users\hoge\wp_local>notepad docker-compose.yml
```

下記の内容をYAMLファイルに保存します。
```yml
version: '3'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
```

コンテナを起動します。
```
C:\Users\hoge\wp_local>docker-compose up -d
```

# 起動の確認

localhost:8000にアクセスしてWordPressのインストール画面が表示されればOKです。
![スクリーンショット 2023-02-14 105839.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/344be9bb-db81-8e95-e3f0-c87859025aec.png)

Docker Desktopを起動すると、作成したコンテナが表示されるので、ここからコンテナの起動と停止、SSHのログインなどができます。
![スクリーンショット 2023-02-14 110220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/e927c911-b8f8-c84f-8177-cff69f8aeb01.png)

# 参考
https://docs.docker.jp/compose/wordpress.html
ざっくりGKEにデプロイ方法を書く

## 事前準備
Googleのアカウント
クラスタ作成
kubectlのインストール
gcrに簡単なrailsアプリをpushしておく
作業ディレクトリの作成


## 早速始めよう
### 1.作ったクラスタ(コンテキスト)を指定する
```
gcloud container clusters get-credentials {cluster_name} --region asia-northeast1 --project {project_name}
```

これ結構大事、作業クラスタが間違ってると事案になる可能性があるので気をつけよう。　
`kube-ps1`等のツールを入れておくと現在のコンテキストが一瞬で可視化できるので便利。

### 2.namespaceを作成
```kubectl create ns {namespace_name}```
namespaceは簡単にいうとクラスタの中で独立した領域を作成できる

### 3.マニュフェストファイルの作成
```
kubectl --namespace={namespace_name} create deploy {app_name} -o yaml --dry-run=client --image={gcr_image} > deploy.yaml
```

マニュフェストファイルはpodを管理するファイル。上記のコマンドでdeploy.yamlが生成される



### 4.deploy.yamlの編集
```yaml
    spec:
      containers:
      - image: asia.gcr.io・・・
        name: app_name
        ports:
        - containerPort: 3000
        env:
```
ポートを指定する。今回は3000番ポートを使用。
envは今回はRailsなのでRAILS＿ENVとSECRET_KEY_BASEとDATABASE_NAMEを設定してればいいと思う。

### 5.デプロイ(apply)
先程のdeploy.yamlをデプロイする

```
kubectl -n {namespace_name} apply -f deploy.yaml
```

デプロイ確認

```
kubectl -n {namespace_name} get deploy
kubectl -n {namespace_name} get po
```

podが出来てることを確認する


### 6.アプリを外部公開する
今回はService: LoadBalancerを使う
```
kubectl -n {namespace_name} expose deploy {app_name} --type=LoadBalancer
```

IPアドレスが割り当てられるのを待つ
```
kubectl -n {namespace_name} get svc
```

でEXTERNAL-IP、PORTを確認する。

https://{EXTERNAL-IP}:{PORT}でアクセス。

Railsの初期画面が見える
![スクリーンショット 2023-02-14 10.56.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664764/62ffbdfa-ca54-01a4-6ccb-6eff7ad8f1b6.png)

# END
railsで指定したバージョンがインストールできない場合

# 概要
railsの学び直しをしようと、新しい環境を作った際に、指定したバージョンをインストールしたはずなのにできていなかった時のまとめです。

# 環境
AWS
cloud9
mac
Linux

# 起こっていたこと
```rails:ターミナル
ec2-user:~/environment/アプリ名 (main) $ gem install rails -v 7.0.4
Successfully installed rails-7.0.4
1 gem installed
ec2-user:~/environment/アプリ名 (main) $ rails -v
Rails 6.1.7.2
```
あれ？rails7.0.4を指定したし、installできたってあるのにversionが違う...

# 解決法
Gemfile.lockを見ましょう。

```Gemfile.lock
    rails (6.1.7.2)
      actioncable (= 6.1.7.2)
      actionmailbox (= 6.1.7.2)
      actionmailer (= 6.1.7.2)
      actionpack (= 6.1.7.2)
      actiontext (= 6.1.7.2)
      actionview (= 6.1.7.2)
      activejob (= 6.1.7.2)
      activemodel (= 6.1.7.2)
      activerecord (= 6.1.7.2)
      activestorage (= 6.1.7.2)
      activesupport (= 6.1.7.2)
      bundler (>= 1.15.0)
      railties (= 6.1.7.2)
      sprockets-rails (>= 2.0.0)
    rails-dom-testing (2.0.3)
      activesupport (>= 4.2.0)
      nokogiri (>= 1.6)
    rails-html-sanitizer (1.5.0)
      loofah (~> 2.19, >= 2.19.1)
    railties (6.1.7.2)
      actionpack (= 6.1.7.2)
      activesupport (= 6.1.7.2)
```
よく見れば、rails周りの設定のバージョンが6.1.7.2になっていたので下記のように直しました。

```Gemfile.lock
    rails (7.0.4)
      actioncable (= 7.0.4)
      actionmailbox (= 7.0.4)
      actionmailer (= 7.0.4)
      actionpack (= 7.0.4)
      actiontext (= 7.0.4)
      actionview (= 7.0.4)
      activejob (= 7.0.4)
      activemodel (= 7.0.4)
      activerecord (= 7.0.4)
      activestorage (= 7.0.4)
      activesupport (= 7.0.4)
      bundler (>= 1.15.0)
      railties (= 7.0.4)
      sprockets-rails (>= 2.0.0)
    rails-dom-testing (2.0.3)
      activesupport (>= 4.2.0)
      nokogiri (>= 1.6)
    rails-html-sanitizer (1.5.0)
      loofah (~> 2.19, >= 2.19.1)
    railties (7.0.4)
      actionpack (= 7.0.4)
      activesupport (= 7.0.4)
```

# 結果

```rails:ターミナル
ec2-user:~/environment/アプリ名 (main) $ gem install rails -v 7.0.4
Successfully installed rails-7.0.4
1 gem installed
ec2-user:~/environment/アプリ名 (main) $ rails -v
Rails 7.0.4
```

治りました！

# 思ったこと
今回はどの記事も見ることなく解決ができました。
知識だけではダメですが、プログラミングを上達させる手段は、いっぱいプログラムに触れて、いろいろなことを知ることが一番の近道ではないしょうか。
そんなことを思いました。
私も初心者なので、まだまだいっぱい勉強をしていこうと思います。
Markdownから職務経歴書を作成する方法

## 背景
転職活動を行なっていると、履歴書・職務経歴書の提出が必要な場合がある。
履歴書のPDFはどの企業様でも求められるが、職務経歴書はPDFかgithubのURLのパターンで分かれる。
githubで職務経歴書を更新してる場合、0からPDF用に作成するのは二度手間なのでmarkdownを元に生成できる方法を紹介。

## PDF生成方法

```bash
### github上で作成してる職務経歴書があるRepositoryをclone
git clone https://github.com/hogehoge/hogehoge.git

### npm経由でDL
npm install -g md-to-pdf

### 変換したいmarkdownファイルを指定して実行
npx md-to-pdf 職務経歴書.md
```

### 生成結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264678/989a8874-4447-62d1-78b6-f0703446b89b.png)


### 参考
md-to-pdf
https://github.com/simonhaenisch/md-to-pdf
web技術の基礎　Chapter4　まとめ

# Chapter4

## HTML

- HTMLとは、タグに囲まれた文章をwebページに表示することができる。
- 「開始タグ」と「終了タグ」に囲まれた文章を要素と呼び、その塊が何を示すかを要素名という。
- 要素は、必要に応じてその要素の特性を示す「属性」を追加することができる。

## Webページで使用される画像形式

- webで画像を扱う場合は、ネットワーク転送量を減らすために基本的にデータサイズが小さくなる形式が使われる。
- JPEG(Joint Photographic Experts Group)
    - ファイルの拡張がjpgやjpegの場合は、JPEG形式になっている。
- GIF(Graphixs Interechange Format)
    - ファイルの拡張がgifの場合は、GIF形式になっている。
- PNG(Portable Network Graphics)
    - ファイルの拡張がpngの場合は、PNG形式になっている。

## XML

- XML(Extensible Markup Language)とは、HTMLと同じマークアップ言語ですがweb特化ではなく汎用的に使われる。
- XMLもHTMLも元はSGML(Standard enneralized Markup Language)というマークアップ言語を改良してできたもの。
- webの世界では、サーバーとのやり取りをする際にXMLが使われる。
- XHTML((Extensible Hyper Text Markup Language)はHTMLをXMLの文法で再定義したもの。
    - XHTMLの中にHTMLの要素を入れたり、XMLの要素を入れたりすることができる。
    

## CSS

- CSS(Cascading Style Sheets)はHTMLやXMLの表示方法を表現するもの。
- スタイルシートとも呼ばれる。
- 一つのスタイルシートをさまざまなHTMLファイルで共有することができる。
- 閲覧する環境に応じてCSSを切り替え、最適な体験や表示ができる

## スクリプト言語

- 動的処理にはスクリプト言語が使われる。
- クライアントサイド・スクリプトとは、javaciptのようなHTMLと分割しても良いし、HTML内に直接スクリプトの記述を書き込んで使うことができる。
- サーバーサイド・スクリプトは、HTMLと分離した別のファイルにする。
    - perl,python PHP,Rubyなどが挙げられる。

## DOM

- DOM(Document Object Model)とは、HTMLやXML文章を扱うためのAPI。
- DOMでは、対象となる文章の各要素を抽出し、それらを階層構造として扱う。
- DOM階層構造とは、HTML,XML内の要素の関係をDOMツリーという。

## JSON

- JSON(Javascript Object Notation)とは、構造化したデータを表すための記述言語。
    
    (例){”名前”:”huga”,”age”:17}
    
- フロント開発側がjavascriptを使うた、webサービスではよく使われる。

## フィード

- フィードとは、webサイトなどの更新履歴を配信するためのファイル。
- web上のフィードを取得し、管理するためのソフトウエアをフィードリーダーという。
- 現在では、フィードではなくRSS1.0,RSS2.0,Atomを使用して更新ファイルを作っている。

## マイクロフォーマット

- マイクロフォーマットとは、HTMLやXHTMLで記述されたwebページの中に意味を表現する記述を埋め込めた書式。
    - classの種類としてhAtom や hCalemderなどがある
- マイクロフォーマットを埋め込むことで外部のコンピューターから読み込んでも自立的に情報の意味を理解、処理するセマンティックwebを実現できる。

## 音声・動画配信

- インターネット配信で音声ファイルや動画ファイルを使用する際に、データ圧縮するするにはコーデックと呼ばれるソフトウエアが使われる。
    - 圧縮することをエンコード、再生するために伸張することをデコードという。
- 動画データをダウンロードしながら再生する方法をプログレッシブダウンロード配信という。
- ストリーミング配信とは、細切れにしたデータをユーザーに配信し、再生したデータをその都度消去する方法。

## メディアタイプ

- インターネットの情報をさまざまなタイプの機器から閲覧していますが、それぞれに対してcss、HTMLを「メディアタイプ」として切り替えることができる。
PySimpleGUIの基本構造

# はじめに
最初に基本構造を示した後に、簡単なデモプログラムの紹介を通して、なんとなくの全体像がつかめたってなるのが本記事のゴールとなります。

# 基本構造
PySimpleGUIを使ったプログラムは以下の３つの部分に分けることができます。
・ウィジェット準備部分
・レイアウト部分
・アプリケーション（各イベントに対する動作を定義する）部分

プログラムで表記するとしたの感じです。
```python:structure.py
import PySimpleGUI as sg

#widget準備部分
widgets = widget11
#layout部分
layout = [
          [widgets],
         ]

#GUI画面の準備
window = sg.WINDOW()

#アプリケーション実行部分
while True:
    event, values = window.read()
    # 閉じるボタンが押された→アプリケーションの終了
    if event == sg.WIN_CLOSED:
        break:

```

# 簡単なデモプログラムの紹介
テキストが表示されているだけのシンプルなGUIの紹介。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507532/cf363539-a0ca-e302-1784-698bfa7fd438.png)
＊widgetととして、３つのテキストボックスを宣言
＊layoutは２重配列で表す。下の例のように書くと、widget1の右にwidget2、下にwidget3が配置される
＊if event == sg.WIN_CLOSED: は、×ボタンが押されたときの動作
```python:structure.py
import PySimpleGUI as sg

text_widget1 = sg.Text("Hello World!")
text_widget2 = sg.Text("XXXX")
text_widget3 = sg.Text("YYYY")

layout =[
        [text_widget1,text_widget2],
        [text_widget3],
        ]

window = sg.Window("Demo",layout)

while True:
    event, value = window.read()
    if event == sg.WIN_CLOSED:
        break
        
window.close()

```

# 終わり
できる限り簡潔にまとめたつもりですが、内容薄すぎたかもしれません。
まぁでも全体構造はわりとシンプルなので、tkinterよりかは書きやすいのかな？と思いました。
ボタン毎のイベント設定やフレームやカラムを用いたウィジェットの配置などについては
また別の記事で書きたいと思います。
VsCodeスニペット登録ショートカット

# **はじめに**
VsCodeでのスニペット登録時に、"（ダブルクォーテーション）でコードを囲む作業を自動化。そのメモ。競プロ用。


# **ソースコード（c++)**
```cpp
#include <iostream>
#include <string>
using namespace std;
// pf（テキスト）を入力してスニペット呼び出し
const string key = "hoge", pf = "pf", des = "des";

int main(void) {
    cout << '\"' << key << "\": {\n";
    cout << "\"prefix\" : \"" << pf << "\",\n";
    cout << "\"body\": [\n";
    string s;
    while (getline(cin, s)) {
        cout << '"' << s << "\",\n";
    }
    cout << "],\n";
    cout << "\"description\": \"" << des << "\"\n},\n";
    return 0;
}
```

# **使用例**
ソースコード（変更箇所）
```cpp
const string key = "Eratosthenes", pf = "eratos", des = "Sieve of Eratosthenes";
```

入力
```
void ET(const int n, vector<int>& prime) {

    prime.resize(n + 1, 1);
    prime[0] = prime[1] = 0;

    for (int p = 2; p <= n; ++p) {
        if (!prime[p])
            continue;

        for (int q = p * 2; q <= n; q += p) {
            prime[q] = 0;
        }
    }
}
```

出力
```
"Eratosthenes": {
"prefix" : "eratos",
"body": [
"void ET(const int n, vector<int>& prime) {",
"",
"    prime.resize(n + 1, 1);",
"    prime[0] = prime[1] = 0;",
"",
"    for (int p = 2; p <= n; ++p) {",
"        if (!prime[p])",
"            continue;",
"",
"        for (int q = p * 2; q <= n; q += p) {",
"            prime[q] = 0;",
"        }",
"    }",
"}",
],
"description": "Sieve of Eratosthenes"
},
```

# **注意点**
keyで初期化する文字列は他スニペットとの重複不可（既に登録済みのスニペットに使用している文字列は使えない）

# **おわりに**
もっと楽な方法があれば教えて!
LANケーブルが微妙に断線気味の可能性をチェックしてみる


### irerfをダウンロードする

https://iperf.fr/iperf-download.php

解凍して「iperf」フォルダなどにiperf3.exeを収納する
サーバー役とクライアント役が必要なので２台の端末を用意する

#### サーバー側

`cd C:\iperf`

`C:\iperf>iperf3.exe -s`

#### クライアント側

`C:\iperf>iperf3.exe -c 192.168.xx.xx`

サーバーのIPを入れる
ポートは指定しなければ5201

#### 共通オプション

`-i (–interval) num`

コマンドプロント上に表示される間隔。デフォルトでは『1秒』で表示されるようになっております。

`-B (–bind) address`

使用するIPアドレス（NIC）を指定することが出来ます。クライアントであれば送信用NIC、サーバであれば受信用NICの指定となり、複数のNICを搭載しているパソコンであれば、指定した方が間違いがないでしょう。

#### サーバー側オプション

`-s (–server)`

iperfサーバを起動させます。

`-p (–port) num`

待ち受けるポート番号を指定することが出来ます。

`-D (–daemon)`

デーモンとして起動させて、バックグラウンドで動作させます。

#### クライアント側オプション

`-c (–client)`

iperfクライアントを起動させます。

`-u (–udp)`

TCPではなくUDPを使用します。

`-p (–port) num`

送信するポート番号を指定することが出来ます。

`-t (–time) num`

トラフィックを流し続ける時間を指定します。デフォルトでは10秒となります。

`-b (–bandwidth) num`

トラフィック量を指定します。TCPのデフォルトは無制限で、UDPのデフォルトは1Mbpsとなります。
laravelにてRequestからバリデーションを使用する際、$thisがnullになってしまう際の対策

request の rules()を使用する際、
Validator::validate
を使用すると引数がnullになる事象について

# 結論
->merge($item)を使用する
```PHP:laravel
$Request->merge($item);
$result['validated'][] = Validator::validate($item, $Request->rules());
```
Ruby 計算プログラムの作成

# 計算プログラムの作成

二桁以上の整数を入力すると、十の位と一の位の数字の足し算、十の位と一の位の数字の掛け算をそれぞれ行います。
最後に2つの結果を足し合わせて出力するプログラムを作成します。

```ruby
def addition(a, b)
  a + b
end

def multiplication(a,b)
  a * b
end

def slice_num(num)
  tens_place = (num / 10) % 10
  ones_place = num % 10
  return tens_place, ones_place
end

puts "二桁の整数を入力してください"
input = gets.to_i

X, Y = slice_num(input)
add_result = addition(X, Y)
multiple_result = multiplication(X, Y)

puts "足し算結果と掛け算結果の合計値は#{add_result + multiple_result}です"
```

## 解説
このプログラムをターミナルで実行したときに、2桁の整数の入力を求められます。
それが以下の部分です。
```ruby
puts "二桁の整数を入力してください"
input = gets.to_i
```

additionメソッドで、10の位と1の位を足した計算結果をadd_resultに代入。
multiplicationメソッド内で、X,Yを引数として渡し、計算結果をmultiple_resultに代入。
slice_numメソッドでは、10の位と1の位をそれぞれ取得し、返り値をX, Yに代入しています。
Oracle Analytics Cloud：削除したはずのワークブックがホームページに表示されている

# はじめに
Oracle Analytics Cloud（**OAC**）では、ログイン直後にホームページが表示されます。
ホームページはカスタマイズ可能となっており、最近使用したワークブック等のコンテンツにアクセスしやすいようにショートカットを表示することができます。
ところが、削除したワークブックへのショートカットが表示されたままになるケースがあります。
これらを正しい状態にするための手順を紹介します。

# ホームページ
これがログイン直後のホームページの様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/e6345277-565d-55e2-979e-af799c86487a.png)
カスタマイズの状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8c608dce-0175-336f-e224-89c728ae8bbd.png)
当然ながら、どのオブジェクトをクリックしても、開くことができます。

# スナップショットをリストア
事情があり、過去のスナップショットをこの環境にリストアします。
OACインスタンスを作成直後に作成しておいたスナップショットなので、すべてのコンテンツがクリアされます。

# スナップショットをリストア後のホームページ
OACに再度同じユーザでログインしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/a27842c0-98b2-3a8e-539a-8aff1af803a1.png)
存在しないはずのワークブックへのショートカットが表示されたままです。その他にも様々なコンテンツへのショートカットが表示されています。
ホームページのカスタマイズの状態は、初期状態に戻っています。（これは正しい動作）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/d65fc938-7a32-05ce-3ceb-0313f0cc8def.png)
試しに、ワークブックのショートカットをクリックしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/7769d013-1e4e-54f7-8de7-1b0cdb69b428.png)
存在しないので、当然ながら開けません。
他のコンテンツも同様です。

# 検索索引を作り直す
「コンソール」に移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/e2d2681e-1e47-b99a-aa52-16fd4314732d.png)
「検索索引」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/97743d35-cc6e-f58c-db3d-9584964fa13f.png)
「データ・モデル」タブにいることを確認し、言語として「English」と「日本語」をコントールキーを押しながら選択します（必要に応じて他の言語も選択してください）。
次に保存アイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/b0980bc8-c8a4-1a1f-7f4b-9b4e12837de0.png)
「カタログ」タブに移動して同様の手順を繰り返し、最後に「今すぐ実行」アイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/fb26996b-5664-d9f2-87b1-4c86b12e2013.png)
「クロールのモニター」をクリックして、状態を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/a5acbe77-1de9-01f6-6244-67afb9dc0ad8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/15f1238d-f378-238f-78a2-25e930d6b3ce.png)

# 再度ホームページを表示
しばらく待ってから、ホームページに移動して確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/23a93b89-1319-2bcf-9a8c-e48637a645be.png)
正しい状態になりました。
クラウドのセキュリティ対策について

# はじめに
こんにちは！株式会社80&Companyの技術広報です。
弊社の開発部署では毎週火曜日の朝9:30から社内勉強会を行なっています。

今回の記事はバックエンド開発業務を行なっているエンジニアが社内勉強会でクラウドのセキュリティ対策について発表したものを紹介します。クラウドのセキュリティ対策について、興味のある方は参考にしてみて下さい♪

# 読者の対象
* クラウドのセキュリティ対策に興味がある方

# 責任分界点を確認しよう
国内企業のクラウドサービスの利用割合は、年々増加傾向にあります。
総務省のクラウドサービス提供事業者向けの情報セキュリティガイドラインというものがあり、下記の画像のような責任分界点を定義しています。境界はデータ、アプリ、ミドルウェア、OS、仮想環境、ハードウェア、ネットワーク、施設・電源といったクラウド基盤に分解しています。クラウドサービスを提供している事業者と利用企業の各々が、責任をクラウド基盤のどの範囲担当するか定めた境界を責任分解点といいます。

![スクリーンショット 2023-02-10 11.18.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3059557/aa85a1b8-3f23-5e4e-25b5-b42702c7460e.png)

全体像を見ると**IaaS**,**PaaS**,**SaaS**になるにつれて、ユーザーのクラウド上での責任範囲というものは、少なくなっていきます。

# 各クラウドサービスに応じたセキュリティ対策
クラウドサービスを利用する際にできるセキュリティ対策にはどのようなものがあるのか、各サービスの特徴や代表的なサービス例、サービスに応じたセキュリティ対策について紹介します。

## SaaSの場合
### SaaSの特徴について
* 事業者が提供するソフトウェアをインターネット経由で使う仕組みですが、事業者はOS・アプリの管理までをサービスに含み、利用企業はユーザIDなどソフトウェア上のデータ管理を行う権限・責任があります。
* 事業者はOS・アプリの管理までをサービスに含み、利用企業はユーザIDなどソフトウェア上のデータ管理を行う権限・責任があります。
* セキュリティ対策は主にクラウド事業者が実施します。一部を除いて、クラウド利用者はクラウドの基礎部分や個別のアプリケーションの設定を管理、操作できないです。

### SaaSの例
**Microsoft office 365**,**Gmail**,**Dropbox**,**サイボウズ**など

### セキュリティ対策
* ログインID/パスワードのポリシー設定
* コンテンツやデータに対するアクセス権限設定

## PaaSの場合
### PaaSの特徴について
* **IaaS**と **SaaS**の間であり、APIの提供や実行環境を提供しています。
* アプリケーションや情報システムの開発・実行に必要なOSやミドルウェアなどのプラットフォームを事業者が提供します。
* 事業者はOSやミドルウェアを管理し、データやアプリケーションの管理は利用企業が行います。
* バックアップ、データ暗号化、ファイアウォールなど事業者が提供するセキュリティ機能を理解する必要があります。
* クラウド利用者は、プラットフォーム上のアプリケーション環境を管理・設定できます。セキュリティ対策はクラウド事業者とクラウド利用者で分割されます。

### PaaSの例
**AWS**(**RDS**、**Lambda**など）

### セキュリティ対策
* SQLインジェクション
* XSSなどを考慮したアプリケーションの作成

## laaSの場合
### laaSの特徴について
* CPUやメモリ、ストレージなど開発に必要なインフラを仮想環境で使えます。
* 仮想環境やハードウェアの管理・責任を事業者が担い、OS含めた全てのソフトウェアの管理を利用企業が行います。
* アプリやOSの障害対応、ミドルウェアへのパッチ適用や脆弱性対応などは利用企業の責任になります。
* クラウドの利用者は、一般に搭載するOSや開発環境の選択に関して、高い自由度を持っています。クラウドの基礎部分を超えるセキュリティ対策はクラウド利用者が実施します。

### laaSの例
**AWS**(**EC2**、**ECS**など）

### セキュリティ対策
* ミドルウェアやOSへのパッチ適用

# AWSの責任共有モデル
AWSが提供している責任共有モデルがあります。AWSのクラウドセキュリティ責任とお客様のクラウドセキュリティ責任といった二つの責任に分けて説明しています。

AWSはAWSクラウドで提供されるすべてのサービスを実行するインフラに対して、保護と責任を負います。
利用者は選択したAWSクラウドのサービスに応じて異なりますが、EC2などはすべてのセキュリティ構成や管理のタスクを実行する必要があり、EC2をデプロイした場合のゲストOSやインスタンスにインストールしたアプリケーションソフトウェアの構成に責任を負います。

Amazon RDSなどの**PaaS**の場合は、AWSはインフラやOSのプラットフォームを運用し、利用者がエンドポイントにアクセスしてデータの保存や取得、管理を行います。適切な権限の適用について、責任を負うという位置でAWSと利用者の責任が分解されています。

![スクリーンショット 2023-02-13 15.37.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3059557/485efe07-e645-60fa-d726-db2662f3c440.png)

# クラウド上でのセキュリティ対策まとめ
最後に、クラウド上でセキュリティ対策を行うためにできることを紹介します。
* 多要素認証や二段階認証の有無
    * メールでのパスワード認証の他にメール認証があるかを確認する
    * パスワードポリシーやアカウント管理を適切に行う
* 使用端末のセキュリティ対策の実施
    * ウイルス対策ソフトの導入、VPNの利用、オープンな場所でアクセスしない
* 利用者のリテラシーの向上
    * クラウドのセキュリティ対策を間違った設定にしないため、定期的な講習の実施などを行う
* 他社のサービスを利用する
    * アプリケーションの追加導入、監視、脆弱性試験などを外部に依頼するなど

# 最後に
今回は、弊社社内勉強会で発表されたについて扱いました。
今後も継続的に80&Companyでの社内勉強会の取り組みを発信していきます！
[Qiita Organization](https://qiita.com/organizations/80andco)や[Twitter](https://twitter.com/80andcoDev)公式アカウントのフォローもよろしくお願いいたします！
最後まで読んでいただきありがとうございます！

# 参考文献
https://aws.amazon.com/jp/compliance/shared-responsibility-model/

https://pfs.nifcloud.com/navi/beginner/boundary_of_responsibility.htm
React x LIFF x tRPC ハンズオン

Killercodaを使ってtRPC経由でLINE UserIdを取得できる動きを確認してみましょう。
ハンズオン資料は下記ページです。

https://killercoda.com/gaomar/scenario/react-liff-trpc-handson-playground

ページを開くと自動的にインストールが始まります。画面左側にある手順書通りに進めていってください。

## バックエンドコード補足
tRPCのコード実態は下記にあります。

zodを使ってLIFFからアクセストークンを取得して、tRPC側で受け取ります。
LINEの[getProfile](https://developers.line.biz/ja/reference/line-login/#get-profile-http-request)処理を行って、ユーザー情報を取得しにいきます。

https://github.com/gaomar/react-liff-trpc-sample/blob/7e6a67e3ded319e1a9ea698e8bcf6fc321c8f2ad/backend/src/trpc/router.ts#L1-L27

## フロントエンドコード補足
LIFFの初期化をmain.tsxで行っています。必ずLIFFの初期化を通過するような作りが必要です。

https://github.com/gaomar/react-liff-trpc-sample/blob/7e6a67e3ded319e1a9ea698e8bcf6fc321c8f2ad/frontend/src/main.tsx#L10-L26

### トップページ
useEffectでLIFF経由でユーザー情報を取得しにいきます。同時にアクセストークンも取得します。

https://github.com/gaomar/react-liff-trpc-sample/blob/7e6a67e3ded319e1a9ea698e8bcf6fc321c8f2ad/frontend/src/pages/Top.tsx#L15-L27

ボタンを押下してバックエンドのtRPCに処理を実行してもらいます。結果は75行目で受け取ります。

https://github.com/gaomar/react-liff-trpc-sample/blob/7e6a67e3ded319e1a9ea698e8bcf6fc321c8f2ad/frontend/src/pages/Top.tsx#L53-L75

## tRPCのスゴイところ
型安全なので、バックエンド側のプロパティ名を変更すると、フロントエンド側にも影響します。
例えば、[userId](https://github.com/gaomar/react-liff-trpc-sample/blob/7e6a67e3ded319e1a9ea698e8bcf6fc321c8f2ad/backend/src/trpc/router.ts#L24
)から`userId2`という別のプロパティ名に変更してみます。

```typescript:backend/src/trpc/router.ts
userId2: z.coerce.string().parse(line.userId),
```

すると、このようにVSCode上でエラーが返ってきて、`userId2`ということを教えてくれます。

![](https://storage.googleapis.com/zenn-user-upload/1018a448718a-20230213.png)

## 謝辞
今回サンプルを作るにあたって、下記を参考にいたしました。

https://dev.classmethod.jp/articles/trpc-sample/

## まとめ
tRPCを使えば型安全にバックエンドとフロントエンドが連携できるので、オススメですね。

システム化のご検討やご相談は弊社までお問い合わせください。

https://www.i-enter.co.jp/
javascript学習備忘録　for文

フロントエンドエンジニアになって約半年ほど。。
普段はVue.jsを使って開発しています。
フレームワークを使って開発を行っていく上でどうしてもJavaScriptを書かないといけないことが増えてきました。
その学習したことを備忘録として残していきます。
今回はfor文

## for文
```JavaScript:
for(初期化式;条件処理;増減式++){}
基本的にはこの形で書いていく。
```
例文１
```
for (let i = 0; i <= 10; i++) {
  console.log("hello world");
}
```
出力結果はhello worldが10回繰り返されます。
これは簡単。

例文2
```
for (let i = 0; i < 10; i++) {
  console.log("hello world");
  for (let j = 0; j < 3; j++) {
    console.log("hello earth");
  }
}
```
次の例文ではforの中にforをネストした書き方となる。
出力結果はherro worldと1回表示されその後hello earthが3回表示される。
[メモ]Promise.allの各非同期関数の結果は配列で取得できる

こんにちはみなさん

昨日ちょっと`Promise.all`の挙動で議論があったので、挙動をメモっておこうかなと思いました。まあ、仕様を読み込めばわかるやろ！って話なんだろうけど、手っ取り早くどうなるんだっけ？ってのを思い出すコストがめんどいんです。

# Promise.all
`Promise.all`は、引数に非同期関数(Promise)の配列をとって、それぞれを同時に実行してその結果を返すものです。

```promiseAll.js
const timeout = async (time) => {
    console.log(`${time} start`)
    await new Promise(res => setTimeout(res, time))
    console.log(`${time} end`)
    return time
}

Promise.all([
    timeout(500),
    timeout(300),
    timeout(100)
]).then(res => console.log(res))
```
`timeout`は指定された時間の待機時間を挟んでコンソールログを出力し、入力した時間を返すだけの非同期関数です。
こいつを実行すると、こんなのが返ります

```
# node promiseAll.js 
500 start
300 start
100 start
100 end
300 end
500 end
[ 500, 300, 100 ]
```
`Promise.all`を使うと、登録されたすべての処理が完了してから、それぞれの結果を配列で取得することができます。また、登録された処理がそれぞれ同時に走っています。

# 複数の非同期処理の結果を使いたい場合のPromise.all
複数の非同期処理の結果を使いたい場合、Promise.allがパフォーマンスの向上に役に立ちます。
例えば以下の処理を見てみます。

```async_res.js
const timeout = async (time) => {
    console.log(`${time} start`)
    await new Promise(res => setTimeout(res, time))
    console.log(`${time} end`)
    return time
}

const all = async () => {
    a = await timeout(500)
    b = await timeout(300)
    c = await timeout(100)

    console.log([a, b, c])
}

all()
```
各非同期処理の結果を変数に格納しているわけですが、この結果は以下の通りです。

```
# node async_res.js 
500 start
500 end
300 start
300 end
100 start
100 end
[ 500, 300, 100 ]
```
各非同期処理が終わらないと次の処理に移っていないことがわかります。
せっかくの非同期処理ですが、これでは最終結果が出るまで余計に時間がかかります。

こんな時にPromise.allを使います。

```timeout_all.js
const timeout = async (time) => {
    console.log(`${time} start`)
    await new Promise(res => setTimeout(res, time))
    console.log(`${time} end`)
    return time
}

const all = async () => {
    console.log('all start')
    const [a, b, c] = await Promise.all([
        timeout(500),
        timeout(300),
        timeout(100)
    ])
    console.log([a, b, c])

    console.log('all end')
}

all()
```
こいつを実行すると

```
# node timeout_all.js 
all start
500 start
300 start
100 start
100 end
300 end
500 end
[ 500, 300, 100 ]
all end
```
3つの非同期処理が全部同時に実行され、その結果がa, b, cに分割代入されている感じですね。
通信などの非同期処理が複数ある場合は、Promise.all使っちゃうのが楽ですね。

# まとめ
Promise.allの挙動を復習してみました。
いや、PHPばかり触っていたので、JSの非同期処理の流れとか、忘れちゃうんですよね。
今回は軽めにこんなところです。
パス設定のお祝いが反映されない


+ [パス設定のお祝いが反映されない](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000NG0WKSA1)

OSの問題らしい

可能性の 1 つは、それを妨げている OS 設定があることです。

1. Windows 11 の場合は、[設定] > [アクセシビリティ] > [視覚効果] > [アニメーション効果] を確認してください
2. Windows 10 の場合、[設定] > [簡単操作] > [表示] > [Windows でアニメーションを表示] を確認します。
 macOS の場合は、[システム環境設定] > [アクセシビリティ] > [ディスプレイ] > [モーションを減らす] を確認してください

https://community.atlassian.com/t5/Trello-questions/Why-is-my-confetti-animation-not-working/qaq-p/2053949


Mac設定を共有いたします(お困りの方いるかもしれないので)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/87dbc866-908d-4161-234a-a6247e793d5f.png)