OmniAICreator/Qiita-1.07M huggingface dataset:
Flutter で Firebase のセットアップをコマンドひとつでできる FlutterFireCLI がすごすぎて感動した

Flutter v2.8.0で発表された`FlutterFireCLI`を使ってみた感想と簡単な使い方についての記事になります。

今まで Firebase の導入はかなり重い腰を上げていたのですが、コマンドひとつで Firebase のセットアップができるというのは、またひとつ Flutter でのアプリ開発のハードルを大きく下げる要因につながると思いました。

独学で開発を始めた頃は、Firebase を入れただけで訳のわからないエラーが出てアプリの起動すらできなくなって...
そんなことに悩まなくなるのは、特に初心者にとってもいいことですね！(今も全然あるなんて言えない...)

やはり、Firebase があるのとないのでは作れるアプリの幅もかなり変わってきますからね。

## 実際に使ってみる

公式のドキュメントに詳しく全てが載っています。

https://firebase.flutter.dev/docs/cli

が、それだと記事にならないのでやっていきます。

### firebase tools のインストール

自分の firebase プロジェクトなどにターミナルから login したりするのに使います

```
$ npm install -g firebase-tools
```

### firebase　アカウントにログイン

Chromeなどからログインするように求められるのでログインします。

```
$ firebase login
```

もし既に他のアカウントに入っていて、違うアカウントに入り直したい時は logout しましょう。

```
$ firebase logout
```

### FlutterFireCLI をインストール

今回の主役をインストールします
しかも主役も一行だけです

```
$ dart pub global activate flutterfire_cli
```

### プロジェクトとの紐付け

紐付けは以下のコマンドを叩くだけです

```
$ flutterfire configure
```

既存のプロジェクトか新規作成かを選べるので、今回は新規作成を選択しましょう

![スクリーンショット 2022-02-20 午後5.40.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901218/6970f96a-8a7b-82bc-98d2-d76390056eb8.png)

プロジェクトの id を入力します

![スクリーンショット 2022-02-20 午後5.45.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901218/14d3b0cd-cd9b-57d2-756a-67d377ec39dc.png)

次に、対応するプラットフォームを選択します
スペースで選択・解除ができます
今回はAndroidとiOSのみにします

![スクリーンショット 2022-02-20 午後5.46.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901218/0cebc9b7-7aea-6916-a194-cca82d0629c6.png)

最後に bundle id を入力します

![スクリーンショット 2022-02-20 午後6.05.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901218/4d5255aa-13a2-cf40-e742-40e3bfd4f7c5.png)

紐付け完了です！！！

![スクリーンショット 2022-02-20 午後6.06.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901218/4c2ea2f4-f70e-bebc-ac8e-01f51f0db223.png)

## 最後に

なんということでしょう！
あまりにも早すぎて記事がこんなにも短くなってしまいました。
開発者にも記事を書く人にも優しい Flutter。
時代がきてますね。皆さんも是非使ってみてください。
C言語のether_header


構造体の要素がどんなだったかよく忘れるからメモ代わりに

```net/ethernet.h
struct ether_header
{
  uint8_t  ether_dhost[ETH_ALEN];	/* destination eth addr	*/
  uint8_t  ether_shost[ETH_ALEN];	/* source ether addr	*/
  uint16_t ether_type;		        /* packet type ID field	*/
} __attribute__ ((__packed__));
```
↑net/ethernet.hに書いてあるether_headerの構造体
```__attribute__ ((__packed__));```は構造体を詰めるためにあるやつだから無視で

### ether_dhost
宛先のMACアドレスが書いてあるやつ
基本的に6byteで、ブロードキャストとかだとff:ff:ff:ff:ff:ffって書いてあったりする

### ether_shost 
送信元のMACアドレスが書いてあるやつ
送信元の事以外が書かれてることはあんまりない

### ether_type
第三層がどのプロトコルかを書いてあるやつ
同じファイルに　#define ETHERTYPE_〇〇 みたいに書かれてるのでそれで見分けてあげればいい



おしまい
You must `await server.start()` before calling `server.applyMiddleware()`の解決方法

## 概要

- Apollo serverのチュートリアルでつまづいたので共有
- 結論、バグっぽいのでダウングレードする or コードを書き直す<br>
  - 公式のissue(https://github.com/nestjs/graphql/issues/1621#issuecomment-878474079) で報告されている

### 環境
- macOS Monterey: 12.2.1
- "apollo-server-express": "^3.6.3",
- "express": "^4.17.3",
- "graphql": "^16.3.0",


##　試したコード
````javascript:index.js
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');

// Construct a schema, using GraphQL schema language
const typeDefs = gql`
  type Query {
    hello: String
  }
`;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
};

const server = new ApolloServer({ typeDefs, resolvers });

const app = express();
server.applyMiddleware({ app });

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
````
- `node index.js`を実行すると以下のエラーが出る

````
You must `await server.start()` before calling `server.applyMiddleware()`
````

## 解決方法
### ダウングレード
- バージョンを2.xにすると大丈夫っぽい

### コードの変更
以下のように変更

````javascript:index.js
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');

// Construct a schema, using GraphQL schema language
const typeDefs = gql`
  type Query {
    hello: String
  }
`;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
};


async function startServer() {
  apolloServer = new ApolloServer({
    typeDefs,
    resolvers,
  });
  await apolloServer.start();
  apolloServer.applyMiddleware({ app });
}
startServer();

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000`)
);
````
【SCSS】自分のコードをリファクタリングしてみた

# はじめに
こんにちは、まさやんです。

■運営サービス一部
https://smart-wordpress.com
業界特化、スマートなWordPressテーマ販売サイト『SMART WP』

以前開発をしていて、SCSSの書き方が間違えていたことに気づいたので、今回は、自分で自分のコードをリファクタリングしてみたいと思います。

# リファクタリングしてみた
## 1.ネストが上手く利用できていない
### ❌ NG
ネストが利用できておらず、省略して書けるというSCSSのメリットを活かしきれていませんでした。

```scss:badge.scss
.c-badge--sm {
  padding: 5px 15px;
  background: #66a3c2;
  color: #fff;
  font-size: 12px;
  border-radius: 2px;
}
.c-badge--lg {
  padding: 8px 20px;
  background: #66a3c2;
  color: #fff;
  font-size: 16px;
  border-radius: 2px;
}
```

### ⭕️ OK
こちらのコードは、ネストが効いています。

```scss:badge.scss
.c-badge {
  &--sm {
  padding: 5px 15px;
  background: #66a3c2;
  color: #fff;
  font-size: 12px;
  border-radius: 2px;
  }
 &--lg {
  padding: 8px 20px;
  background: #66a3c2;
  color: #fff;
  font-size: 16px;
  border-radius: 2px;
  }
}
```
こういったコードを書くことで、c-badgeを何回も書く必要がなく、**開発効率**が上がります。
さらに、例えば、c-badgeの部分をc-labelに変えたいとなった場合に、1箇所だけ変更すればよいので、**保守性が高い**コードになります。

## 2.擬似要素もネストを効かせる
### ❌ NG
擬似要素についてもネストの効いた書き方ができていませんでした。

```scss:btn.scss
.c-btn {
  display: block;
  // ~~~~~~~
}
.c-btn:hover {
  background: #80ddd5;
  cursor: pointer;
}
```

### ⭕️ OK

```scss:btn.scss
// ネストが効いている
.c-btn {
  //~~~~~~
  &:hover {
    // ~~~~
  }
}
```

## 3.Modifierの命名
### ❌ NG
これはSCSSの書き方という訳ではないですが、過去に間違えていたことがあったのでまとめておきます。
下記のようにModifierとすべき部分がハイフン１つ繋ぎになっていました。

```scss:btn.scss
.c-btn {
  &-sm { // ハイフン１つになっている
  //~~~~~~
  }
  &-lg {
  // ~~~~
  }
}
```
### ⭕️ OK
Modifier部分はハイフン２つで繋いであげましょう。
過去にCSS設計について[まとめた記事](https://qiita.com/msya0411/items/36fbb6ebc800bbb74390)もありますので、是非そちらもお読みいただければと思います。

```scss:btn.scss
.c-btn {
  &--sm { // ハイフン２つで繋いであげる
  //~~~~~~
  }
  &--lg {
  // ~~~~
  }
}
```

# おわりに
最後までお読みいただきありがとうございます！
コードを書くだけじゃなくて、いいコードを読むことも大事だと実感しました。
今後も学んだことを発信していきたいと思います。
それでは！
GCP Container-Optimized OS で docker-compose を使う方法 | 5分で Airflow をデプロイしましょう

Google Cloud の [Container-Optimized OS](https://cloud.google.com/container-optimized-os/docs/concepts/features-and-benefits) は、コンテナに最適化された Compute Engine VM 用のオペレーティングシステムイメージです。Docker ランタイムが既に入っているので、プロビジョニングも基本的に不要です。OSの自動更新や、ファイアウォールの遮断など、セキュリティ上の利点もいくつかあります。

多くの場合は、一つのコンテナではなく、複数のコンテナを同時に動かしたいので、docker-compose のようなツールを使います。しかし、Container-Optimized OS には docker-compose がインストールされておらず、VM インスタンスにソフトウェアパッケージを直接インストールすることもできないという制限がかかっています。

## docker-compose を実行する方法

docker-compose を動かしたいなら、Docker が提供する [docker/compose](https://hub.docker.com/r/docker/compose "Define and run multi-container applications with Docker https://docs.docker.com/compose") イメージを利用できます。

```shell
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$(pwd):$(pwd)" \
  -w "$(pwd)" \
  docker/compose:1.29.2 up
```

docker-compose コンテナが Docker デーモンにアクセスできるように、上記コードブロックの2行目で `docker.sock` を Volume としてマウントしています。そして、手元の docker-compose.yaml ファイルを参照できるように、カレントディレクトリも Volume としてマウントし、`-w` で移動します。

上記コマンドの書き方は、以下の記事で紹介されています。

https://cloud.google.com/community/tutorials/docker-compose-on-container-optimized-os

毎回書くのが面倒な方は、`alias` として登録するといいでしょう。

```shell
# ~/.bashrc
alias docker-compose='docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$(pwd):$(pwd)" \
  -w "$(pwd)" \
  docker/compose:1.29.2'
```

## Airflow 環境を立ち上げる

さて、実際にコンテナ化した [docker-compose](https://hub.docker.com/r/docker/compose "Define and run multi-container applications with Docker https://docs.docker.com/compose") コマンドを使ってアプリケーションを立ち上げましょう。私は Airflow をよく利用しているので、事例を挙げたいと思います。

まず、Compute Engine VM を作成します。

- マシンタイプ `e2-standard-4` を選択
- ブートディスクの OS を「Container Optimized OS」に、バージョンを最新 LTS に設定する（当時 `93-16623.102.12 LTS` を使いました）
- ファイアウォール設定で「HTTP トラフィックを許可する」にチェックを入れる

インスタンスを立ち上げたら、SSHでログインします。Airflow UI をブラウザーで開きたいので `8080` 番ポートをフォーワーディングします。

```shell
gcloud --project *** compute ssh instance-1 --zone=asia-northeast1-a -- -L 8080:localhost:8080
```

次に [Airflow のドキュメント](https://airflow.apache.org/docs/apache-airflow/stable/start/docker.html#setting-the-right-airflow-user)の通り、フォルダーの作成と環境変数の設定を行います。

```shell
mkdir -p ./dags ./logs ./plugins
echo -e "AIRFLOW_UID=$(id -u)" > .env
```

そして Airflow の公式 [docker-compose.yaml](https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml) をダウンロードします。

```shell
wget https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml
```

最後に、docker-compose コマンドで環境を立ち上げます。

```shell
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$(pwd):$(pwd)" \
  -w "$(pwd)" \
  docker/compose:1.29.2 up -d
```

1分ほど待ってから `http://localhost:8080` をブラウザーでを開くと、ログイン画面が表示されます。ユーザー名とパスワードをどちらも `airflow` と入力してログインすると、Airflow の管理画面が表示されます。

![Container-Optimized-OS-Airflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525579/f542cc1b-972f-2ab4-620f-ec302a6dce07.png)

## 終わりに

以上、Google Cloud の Container-Optimized OS で docker-compose を使う方法について紹介しました。少しでもお役に立てられたらと思います。コンテナ化したアプリケーションのコンピュート環境として、Compute Engine VM + Container-Optimized OS の組み合わせがとても便利です。この記事で紹介したように、複数のコンテナ実行にも対応できるので、ぜひご検討ください。
【備忘録】window7とMACをローカルネットワークで繋いでみた

#背景
昔使っていた、Windows7にExcelなどのアプリが入っており、作業をインターネットを介さずに行いたかった。
Windows７のデータをMacで触りたいだけのため、Windows７からMacへの操作を許可しないようにしたい。


##環境
・ネットワーク
　　マンションWIFI
　　ルーター（バッファロー）
　　※マンションWI-FIだけでは賄えなかったため購入、
　　　　説明は割愛するが、ローカルネット内の接続ができない設定になっていた

・PC
　　MAC BOOK PRO
 Windows7

##目的
２台のPCをWi-Fiで接続し、ローカルネットワークを構築する
ただし、Windows7はインターネットに接続をしないがMACはインターネットに接続する。

###繋ぎ方
①２台のPCルーターを介しインターネットに接続しIPアドレスを設定する。
この時点で、pingを飛ばし相互に接続ができているかを確認しておくこと。
Windowsはcmdで「ipconfig」
macは設定画面のネットワークから確認

②Windows設定
「Windows 7で共有フォルダを設定する方法」を参考に設定、いつも先達様ありがとうございます。
http://lan-pc.pc-beginner.net/windows_7/7_shared_folder.html

③Mac設定
Finderを開き、上にあるタブから「移動」を選択し、「ネットワーク」を開く。
ネットワークからアクセスしたい端末を選択し、アクセスしたいユーザー名でパスワードを入力する。
※著者はWindows7側で作成済みのユーザーで入る認識です
Windows7内の共有フォルダが、見れる。

④ルーター設定
Windows７のIPアドレスを外部接続する際、ルーターで設定を弾いておく、
ルーター周りが時間かかりました・・・
DHCP機能を使えばいけますね、AWSとか一瞬でやってるけど、
手動でも一瞬でした。。。理解することが大事ですね。
特定の端末のみインターネット接続させない方法
https://www.buffalo.jp/support/faq/detail/15915.html


####余談
上記設定を理解しているとリモートデスクトップもあっさりできました。
Mac から Windows へリモートデスクトップ接続 – アプリ「Microsoft Remote Desktop」
https://pc-karuma.net/mac-app-microsoft-remote-desktop-10/
babelの構成ファイル

# 構成ファイルの種類
- プロジェクト全体の構成 : babel.config.json
- ファイル相対構成 : .babelrc.json, babelキーを持つpackage.json

# babel.config.json
プロジェクト全体の構成を定義する。
この構成の主な欠点は、作業ディレクトリに依存しているため、作業ディレクトリがmonorepoルートでない場合、monoreposで使用するのがより困難になる可能性があることです。


# .babelrc.json
個別のモジュールに対して設定を定義できる。
- package.jsonを含むディレクトリが見つかると検索が停止するため、相対構成は単一のパッケージ内にのみ適用されます。
- コンパイルされる「ファイル名」は「babelrcRoots」パッケージ内にある必要があります。そうでない場合、検索は完全にスキップされます。


# サポートされている拡張子
- .json
- .js
- .cjs 
- .mjs

が babel.config.XXX .babelrc.XXX のどちらに対してもサポートされています。
もしビルド時に計算が必要となる複雑な構成があるときはjsを、そうでないときはjsonを使う。
jsonを使うことによってキャッシュなどができるようになりビルド時間の短縮に繋がります。

# １つのレポジトリで複数のモジュールを開発しているケース
まず開発レポジトリ全体の基本となる設計(babel.config.json)をルートディレクトリに作成します。
次に各モジュールで.babelrc.jsonを用いて上書きしていくのが基本となります。

よくある問題の１つとして基本的にはbabel.config.jsonを使って一部のモジュールで.babelrc.jsonを使うときに、あるモジュールディレクトリでbabelを使用したときにbabelは実行ディレクトリをルートとして動作するので設定ファイルが読み込めないという問題が生じてしまう。

これを解決するためにはrootModeをupwardに設定する。
設定方法はcli、設定ファイル、webpackを使うかによっても変わるので調べる必要がある。



#　補足1 モノレポ

モノレポスタイル開発は次のようなソフトウェア開発手法です。:

- 複数のプロジェクトが、同一リポジトリ内にある
- プロジェクトは相互依存可能で、コードも共有できる
- 変更を行う場合、モノレポでは全てのプロジェクトで再ビルドや再テストをしない。その代わり、変更の影響を受ける可能性のあるプロジェクトだけを再ビルドと再テストする

最後の点は、次の2つの理由で重要です：

- CIが高速になる。大規模な場合は1000倍早くなる
- チームがモノレポ内でも独立して活動できる。もし2つのプロジェクトAとBが相互依存でない場合、どんなときも相互に影響を及ぼすことはありません。チームAが彼ら自身のプロジェクトを開発し、テストし、ビルドし、プルリクをmasterにマージする際、チームBによって書かれたコードが動くことはないです。チームBにイマイチなテスト、ダサいコード、壊れたコード、壊れたテストがあったとしても、チームAは、まったく気にしなくていいです。

[参考文献](https://www.graat.co.jp/blogs/ck1099bcoeud60830rf0ej0ix)
【Serverless Framework】Lambda爆速開発

# なぜServerless Frameworkなのか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/e1e20adb-66e4-a4ec-e1c5-62f4bb7ecd18.png)

私自身、LambdaのコードをGitで管理するためにTerraform + GitHub ActionsでCI/CD構築していましたがデプロイに時間がかかり開発効率が非常に悪いことやTerraformの記述量が多くなってシンプルに管理できないことがデメリットに感じていました。しかし、今回のServerless Frameworkを使うことで爆速かつシンプルに開発することができます。

# 開発手順

## AWS CLIのセットアップ

この記事では深く解説しないのでこちらの記事を参考に設定してください。

https://qiita.com/n0bisuke/items/1ea245318283fa118f4a

## Serverless Frameworkをインストール

```
brew install serverless
```

## Goのテンプレートを使ってプロジェクトを作成

以下のコマンドを実行することでgoファイルなどを自動で生成してくれます。

```
sls create -t aws-go -p project-name
```

＊ ちなみにPythonだと以下のようにする。
```
sls create -t aws-python3 -p project-name
```

## serverless.ymlを編集

デフォルトだとus-east-1に作成されてしまうのでap-northeast-1とする。

```yml:serverless.yml
service: project-name

frameworkVersion: '3'

provider:
  name: aws
  runtime: go1.x
  stage: dev
  region: ap-northeast-1
  # CloudWatchにログが書き込まれる
  iamRoleStatements:
      - Effect: Allow
        Action:
          - logs:CreateLogGroup
          - logs:CreateLogStream
          - logs:PutLogEvents
        Resource:
          - "*"
```

## Goのモジュール管理

```
go mod init serverless
```

```
go get github.com/aws/aws-lambda-go/lambda
```

## シェルスクリプトを作成して実行

goファイルをビルドしてデプロイするまでのコマンドを記述しました。
デプロイが終わったらデプロイ、ダン!!!と喋ってくれます。可愛いですね。

```shell:cd.sh
#!/bin/sh

GOOS=linux go build -o bin/main

echo "build done !!!"

sls deploy

say "deploy done !!!"
```

以下のコマンドで実行します。

```
sh cd.sh
```

## Lambda関数呼び出し
以下のコマンドでLambda関数を実行することができます。きちんとレスポンスが返ってくればデプロイ成功になります。

```
sls invoke -f <function_name>
```

## 環境を削除

```
sls remove
```


# 番外編

## API Gateway ・ EventBridgeなどのAWSサービスとの連携

以下のように記述することで容易にLambdaと連携しREST APIを作成することができます。
デプロイ後にエンドポイントURLがターミナルに表示されます。

```yml:serverless.yml
functions:
  # 関数名
  sample:
    handler: bin/main
    events:
      # API Gatewayとの連携
      - http:
          path: /message
          method: get
          integration: lambda
      # EventBridgeとの連携　（毎朝１０時に実行する）
      - schedule: cron(0 1 * * ? *)
```

## 環境変数を扱う

環境変数を扱うときはserverless.ymlにuseDotenv: trueを記述し.envファイルを作成してキーとバリューをセットします。
＊ .gitignoreに.envと記述し、GitHubにはキーを公開しないようにしましょう。

```yml:serverless.yml
frameworkVersion: '3'

# 追加する
useDotenv: true
・
・
functions:
  sample:
    handler: bin/main
    environment:
      ACCESS_TOKEN: ${env:ACCESS_TOKEN}
```

## 外部ライブラリを使いたい時

標準のものではなく外部のrequestsなどが使いたい時ってありますよね。以下のことを実行するだけで簡単に実装できます。

```
npm install --save serverless-python-requirements
```

```yml:serverless.yml
provider:
  name: aws
  runtime: python3.8

  stage: dev
  region: ap-northeast-1

## 追加する
plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true
```

```requirements.txt
requests
```
セキュリティ学習　〜ブラウザの偽警告編〜

# はじめに
社会人として働くようになり、今までの自分のセキュリティ意識の低さや知識不足を痛感しています。
自分の身を守るため、所属組織や取引先へ迷惑をかけないためにもセキュリティに関して学ぶべきと感じました。

その手口について知らないと、気づかないうちに取ってはいけない行動をとってしまう可能性があるため、IPAの動画などを参考に学んでいきます。


# ブラウザの偽警告について
ネット閲覧中に、「ウイルスに感染しました」等の不安を煽る警告メッセージが表示される「偽警告」というものがあります。

> 表示される具体的な警告のメッセージには以下のようなものがあります。
>
 - Windowsのセキュリティシステムが破損しています
 - パソコンの性能が低下しています
 - マルウェアが検出されました
 - ディスクの空き容量がありません

>また偽警告の中には表示されると同時に「ピー」のような大きな警告音を鳴らすものもあります。突然パソコンから音が鳴るため、偽警告のメッセージに加えて、さらにユーザーを動揺させる要因となっています。
引用元：[偽警告とは？仕組みや種類、セキュリティ対策について徹底解説](https://cybersecurity-jp.com/column/35533)

このようにユーザーの不安を煽り、悪意のあるサイトに誘導したり、ソフトのダウンロードやサポート契約させてきます。

# 偽警告が表示された際にとるべき行動
## 落ち着く
まずは、一呼吸して落ち着くことが重要だと思います。
いきなり警告音とともに、アラートが表示されたら普通はびっくりします。

警告音は、PCのボリュー部分を調整することで対応できます。音がなくなるだけでもかなり落ち着いて対応できると思います。

## 偽警告を閉じる
表示されている偽警告を閉じる。
ただし、表示されている偽警告の閉じるボタン等はクリックせず、ブラウザの閉じるボタン等から閉じる。

偽警告のボタンをクリックしてしまうと、悪意のあるサイトへの移動や、不正ソフトのダウンロードが始まってしまう可能性があるとのこと。

もし、ブラウザがフリーズしてしまい操作ができなくなってしまった場合は以下の方法で強制終了する。

 - タスクマネージャーで強制終了（Windowsの場合 Ctrl + Alt + Delete）
 - 作業中のウィンドウを閉じる（Alt + F4）
 - PCを再起動

## もし偽警告記載の番号に電話し、遠隔操作でサポートしてもらってしまった場合
以下のことに取り組む。

 - 遠隔操作アプリのアンインストール
 - 消費生活センターに相談しサポート契約の解除について相談
 - クレジットカード会社に相談


# まとめ
今回はブラウザの偽警告について簡単ではあるがまとめました。
いざ実際に遭遇した場合、知らないととってはいけない行動をとってしまう可能性があります。
自分の身を守るためにもセキュリティ知識は身に付けておくと良いと思います。

IPAでは情報セキュリティに関して、色々まとめてくださっているのでぜひ見てみましょう。
以下のサイトでは、小学生~一般、指導者向けにわかりやすい動画でセキュリティについて学べます。

https://www.ipa.go.jp/security/keihatsu/imakoso/


# 参考
### IPA その警告メッセージ、信じて大丈夫？ブラウザの"偽警告"にご用心！
https://www.youtube.com/watch?v=sm1UMc97zRc

### 偽警告とは？仕組みや種類、セキュリティ対策について徹底解説
https://cybersecurity-jp.com/column/35533
python ルーティング　まとめ

<h1>環境</h1>
・windows10
・python3.8.2
・docker version 20.10.12
・linux(debian11)
・flaskフレームワーク

<h1>ルーティングについて</h1>
ユーザーからのリクエストに対して、webサーバーがどんな動きをするのかというのをルーティングと言います。

<h1>事前準備</h1>
作業を始める前に、python仮想環境を実行して、開発サーバーをデバックモードで起動しておく必要があります。

まずはpythonプロジェクトを作成したディレクトリまで移動して、そこで```source .venv/bin/activate```で仮想環境を実行します。（私の場合はroot/Flask-Project内の階層に作成しましたので、ここに移動します。）

```terminal
$ cd root/python-project
$ source .venv/bin/activate
```

仮想環境が立ち上がったら、開発用サーバーをデバックモードで起動します。

```terminal
$ export FLASK_APP=test1.py
$ export FLASK_ENV=development
$ flask run
```

<h1>ルーティングプログラミング</h1>
以下の記述でurlの内容によって動作を分けることができます。

```test1.py
@app.route('/')
    def index():
        return 'Index Page'

    @app.route('/hello')
    def hello():
        return 'Hello, World!'
```
「@app.route(‘/hello’)」から始まるブロックを増やしました。
これは、URLに「/hello」が付いていた場合、def hello_world():を実行するとルーティングを行いました。
ルート階層では、「’Index Page’」と表示するように変化しています。

このように、ユーザーがアクセスするURLによって行う処理を記述することができます。

ブラウザから、

「localhost:5000/」

「localhost:5000/hello」

の２つのURLにアクセスをしてみると、それぞれ、プログラミングした文字が表示されるはずです。

もしもpythonプロジェクト内のroot以外のフォルダに入っている場合は、```cd```コマンドで該当のディレクトリまで移動して、実行してみてください。

<h1>変数</h1>
URLの部分に、```<>```で囲む変数を表記することで、ユーザーから引数をもらうことができます。
この引数には、型も指定することもでき、ユーザー名別などでurlの表記を変えたいときなどに使用します。

「test1.py」のプログラムに、次のプログラムを追記してみます。

```test1.py
from markupsafe import escape

    @app.route('/user/<username>')
    def show_user_profile(username):
        return 'User %s' % escape(username)

    @app.route('/post/<int:post_id>')
    def show_post(post_id):
        return 'Post %d' % post_id

    @app.route('/path/<path:subpath>')
    def show_subpath(subpath):
        return 'Subpath %s' % escape(subpath)
```

URLで受け取った値を定義した関数の引数として利用することで、ユーザーからもらった値を処理に使うことができます。

「user/<username>」の部分では、ULRが「/user/」のあとの文字をshow_user_profile関数の引数として受け取り、ページに表示する処理を行なっています。

escapeは入力された文字列のエスケープ処理を行い、入力された文字がクロスサイトスクリプティングなどの攻撃に結びつかないように処理をしておきます。

３つの処理を追加しましたので、それぞれ次のように入力して表示を試してみます。

<h1> localhost:5000/user/yourname </h1>

User namae

と表示されます。

<h1> localhost:5000/post/1234 </h1>
Post 1234

と表示されます。

<h1>localhost:5000/post/-1 </h1>
Not Found

と、404ページが表示されます。負はダメです。

<h1> localhost:5000/path/test/test1 </h1>
Subpath /test/test1

と表示されます。

<h1>型の種類</h1>

``` string ```:デフォルト、スラッシュ以外の文字

``` int ```:正のint（整数）

``` float ```:正のfloat型（小数）

``` path ```:スラッシュも使える文字

``` uuid ```:uuidの文字列
Rails 環境構築

## Homebrewをインストールする

https://brew.sh/index_ja.html

からコピペで実行

## rbenvをインストールする

``` 
brew install rbenv
```

## rbenvにPATHを通す

```
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile

echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile

source ~/.bash_profile
```

1行ずつ実行

## Rubyをインストールする

```
rbenv install -l
```

### すきなバージョンをインストール

```
rbenv install 2.7.1
```

## ローカルで使うRubyのバージョンを指定する

```
rbenv local 2.7.1
```

## Bundlerをインストールする

```
gem install bundler
```
## yarnをインストール

```
brew install yarn
```

## Rails install

```
gem install rails -v 6.0.3.2
```

## MySQLインストール

```
brew install mysql
```

参考
https://qiita.com/fuku_tech/items/a380ebb1fd156c14c25b

## 新規Railsアプリケーションを作成する

作りたいディレクトリに移動して

```
rails _6.0.3.2_ new アプリケーション名 --database=mysql
```

## DB作る

```
rails db:create
```

## DB 起動と止める

```
 mysql.server start
```

```
 mysql.server stop
```

## サーバー立ち上げる

```
rails s
```
DevToysのコードを見てみる① (デバッグ実行編)

# はじめに
DevToysは開発に役立つ色々な機能(JSONフォーマッター,Markdownプレビュー,etc...)をまとめたツールです。
開発者は、なんとMicrosoftで「Visual Studio」の開発に関わっている方のようです。
そんな一流エンジニアのコードを理解できれば、色々と得るものがあるのではないかと思い、コードリーディングをしてみようと思いました。
本稿では、コードリーディングの前準備として、githubからDevToysのソースコードを取得しデバッグ実行するところまでやってみます。

# 前提
- OS:
  - エディション: Windows 10 Home
  - バージョン: 20H2
  - OS ビルド: 19042.1466
- Visual Studio 2022 Community

# デバッグ実行までの手順
githubからDevToysのソースコードを取得します。
```
$ git clone https://github.com/veler/DevToys.git
```
`<cloneを実行したフォルダ>/DevToys/` を開きます。

`init.cmd`を実行します。

`<cloneを実行したフォルダ>/DevToys/src/DevToys.sln`を**visual studio 2022**で開きます。

Debug, x64, DevToys.Startupを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2087075/c105b7e0-3c96-ddb4-33ff-e38293dff83a.png)

**F5**を押下します。

**DevToys**がデバッグ実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2087075/7acde78c-33f0-ca85-d830-6b1a1515bdb9.png)

# おわりに
DevToysは完成度の高いアプリなので、中身を理解することができれば、かなり勉強になるのではと期待しています。
100%理解するのは難しいので、わかる範囲で解析していきたいです。

# 参考
DevToysは以下からダウンロードできます。githubへのリンクもあります。

https://devtoys.app/

DevToysの紹介記事

https://forest.watch.impress.co.jp/docs/news/1382919.html
[Vue3 + Vite + ElementPlus]質問に答えるだけでマークダウン形式に変換してくれるアプリ

# 目的
質問に答えていくだけで、質問項目と入力値をマークダウン形式で出力してくれるアプリを作りたい
質問内容は自分でテンプレートとして作れるようにする


# 技術スタック
### アプリケーション
- Vue 3.0
- Vuex 4
- Vue-router 4
- Vite
- Scss
- Element Plus

### ホスティング
- Amazon S3
- Amazon CloudFront

# 作った物
![全体像.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360809/05e68555-e048-6a17-52a1-f6c3798df557.gif)



↓こちらから利用できます。
https://d2yiqmlxenm8oa.cloudfront.net

Githubはこちらで公開しています。
https://github.com/yuya8696/templator

### 使い方
1. 「新規テンプレート」ボタンをクリックしてテンプレート作成画面を開きます。
1. 任意の質問と入力形式（テキスト形式、テキストエリア形式、日付形式、etc）を選び、テンプレート作成します。
1. 作成したテンプレートの質問項目に回答を入力し、「作成」ボタンをクリックします。
1. 質問と入力内容がマークダウン形式で表示されるので、コピーして使います。


# 大変だったこと
### ViteとElementPlusの組み合わせにハマった
単純にVite環境でElementPlusをインストールしてもエラーで動かなかった

→→追加のプラグインをインストールして、公式ドキュメントの「On-demand Import」に記載の設定をvite.config.jsに書いたら動いた

```bash
yarn add -D unplugin-vue-components unplugin-auto-import
```

https://element-plus.org/en-US/guide/quickstart.html#vite

### Vuexに保存した情報がブラウザ更新で消えちゃう
せっかくテンプレートを作ってもVuexの使用上リロードすると消えてしまう。このためにわざわざDB用意するのも骨が折れるな、、

→→Vuexの情報をローカルステイトに保存する！便利なプラグイン「vuex-persistedstate」を利用
こんな感じで作ったstoreにimport, exportするだけでstoreの値をローカルステイトに保存してくれる

```js:store/index.js
import { createStore } from "vuex";

// ローカルストレージへの保存
import createPersistedState from "vuex-persistedstate";

import { reactive } from "vue";

const state = reactive({
// 省略
});

const mutations = {
// 省略
};

const actions = {
// 省略
};

export default createStore({
  state,
  actions,
  mutations,
  // ローカルストレージへの保存
  plugins: [ 
    createPersistedState({
      key: "template",
    }),
  ],
});
```

### マークダウンの改行を再現する
Vueの変数に格納したテキストエリアの内容をそのままマークダウン形式で出力しても、改行コードが反映されなかった。

→→マークダウン形式でも改行されるように、「改行コード」を「改行コード + スペース2つ」にゴリ押し変換した

```js:src/pages/top.vue
const onClickCreate = (template) => {
  dialogTextarea.value = "";
  dialogContents.title = template.name.templateName;
  for (let item of template.contents) {
    if (item.type === "heading") {
      dialogTextarea.value += `# ${item.label} \n`;
    } else if (item.type === "textarea") {
      // テキスト内で改行がある場合は、スペース2つと改行コードに変換
      dialogTextarea.value += `- ${item.label}：  \n${item.value.replace(
        /\n/g,
        "  \n"
      )} \n`;
    } else {
      dialogTextarea.value += `- ${item.label}：${item.value} \n`;
    }
  }
  dialogVisible.value = true;
};
```

### `<input type="text">`に入力してEnterを押すと画面がリロードされる。（リロードされるんでその他の入力値が消える）
質問項目をFormで作っている場合、Formの中に`<input type="text">`が１つだけあると、input要素に入力した後Enterをクリックすると勝手にSubmitされてしまうらしい。
今回Formの中でSubmitに相当するボタンは書いてないので、Submitされると勝手にブラウザリロードされ、入力項目が全部消えちゃうという罠にはまった。

→→Element PlusのForm要素`<el-form>`にSubmitしないよう`@submit.prevent`を加える

```vue
-        <el-form label-position="top" class="create__card__header">
+        <el-form
+          @submit.prevent
+          label-position="top"
+          class="create__card__header"
+        >
```
pythonのdebパッケージを作る

覚書です


# 手順
1. requirements.txtを作る
1. requirementsで依存関係のwhlファイルを取得する
1. setup.pyを作る
1. whlを作成する
1. debを作るためのファイルを用意する
1. debパッケージを作る

## 1.requirements.txtを作る
- 依存関係にあるpipパッケージを記載する
- 要求するバージョンも記載する

```text:requirements.txt
coloredlogs>=9.0
websocket-client==1.1.0
```

## 2.requirementsで依存関係のwhlファイルを取得する
- 以下のコマンドで依存関係のwhlファイルを取得する
- `wheelhose/`配下にダウンロードされる

```bash
python3 -m pip wheel -r requirements.txt -w wheelhouse --no-build-isolation
```

## 3.setup.pyを作る
- whlを作るための`setup.py`を作る
- `package_dir`配下の`py_modules`のファイルをパッケージに含める
    - この場合`/src/test.py`がパッケージに含まれる
  

```python:setup.py
pkg_name = 'test-tools'
version = '0.0.1'
install_requires = [
    'coloredlogs>=9.0',
    'websocket-client',
]

setup(
    name=pkg_name,
    version=version,
    author="user",
    author_email="user@test.com",
    description="test tools package",
    url='https://github.com/hogehoge/test-tools',
    py_modules=["test"],
    package_dir={'': 'src'},
    install_requires=install_requires,
)

```

## 4.whlを作成する
- 以下のコマンドでwhlを作る
    - `/dist/test-tools-0.0.1-py3-none-any.whl`な感じにできる

```bash
python3 setup.py bdist_wheel
```


## 5.debを作るためのファイルを用意する
必要なのは3つ
- dev.json
- debian/postinst
- debian/prerm

```json:dev.json
{
  "name": "test-tools",
  "maintainer": "user <user@test.com>",
  "description": "test-tools",
  "changelog-cmd": "git log --pretty='format:%cd %h %s %d [%an]' --date=iso --merges",
  "homepage": "https://github.com/hogehoge/test-tools",
  "files": [
    {
      "from": "dist/test_tools-*.whl",
      "to": "/tmp",
      "base": "build/",
      "fperm": "0644"
    }
  ],
  "postinst-file": "debian/postinst",
  "prerm-file": "debian/prerm",
  "copyrights": [
    {
      "files": "*",
      "copyright": "Copyright (c) 2022, hogehoge, Inc. All rights reserved.",
      "license": "",
      "file": ""
    }
  ]
}
```

```bash:debian/postinst
#!/bin/bash -e

pip3 install /tmp/test_tools-*.whl
```

```bash:debian/prerm
#!/bin/bash -e

pip3 uninstall -y test_tools
```

## 6.debパッケージを作る
- 以下のコマンドでdebパッケージが作られる

```bash
go-bin-deb generate --arch amd64 --version 0.0.1 --file ./deb.json --wd pkg-build
```


中間ファイルが大量に発生するので、makefileで一気に処理して、debができたら綺麗にするのが良いと思うけど、とりあえず覚書
STM32L010と液晶、ACM1602K-NLW-BBWで表示 (Keil)


x 原因は、わからないが液晶がちらつく場合は、ウェートを調整してね!!


x Mbed2

x まだ試していない 確認済2022/2/20_18:10
x 74hc164を使用
x Mbed2

目的
液晶のテスト


![o_con88.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/11ac302a-1daf-1b15-f6ce-5e8ed869b0ae.jpeg)

-248

![o_con248.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5aee7408-fe0b-fff3-b632-b91e76512400.jpeg)



SC1602と74HC595バージョン　ソフトは、違う(確定)


-275-


![o_con275.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f352cb98-62cd-5194-3873-6cb0bb8e708a.jpeg)


-277- その1 ソフトウェアの互換　あり


![o_con277.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/149c37c6-5a7d-a9ee-276e-2ac6178eddde.jpeg)

-287-  その2


![o_con287.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/23cbd3a7-555a-36dd-b58d-751e3623eaca.jpeg)


-291-


![o_con291.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8df6ec9b-03b5-9e6c-3da3-80bdf51f7a29.jpeg)




```c++


//ON_LCD_010_1

#include "mbed.h"

//*          *****  *****       ***  * *
//*         *       *    *     *   * * *
//*         *       *    *     *   * * *
//*         *       *    *     *   * * *
//*         *       *    *     *   * * *
//********   *****  *****       ***  * *

#define swclk1  PA_5    //A4
#define swdio1  PA_7    //A6
#define en1     PA_4    //A3

DigitalOut swdclk(swclk1);
DigitalOut swdio(swdio1);
DigitalOut en(en1);

//シフトパターン
//              12345678   12345678   12345678   12345678
char b8[8] = {0b10000000,0b01000000,0b00100000,0b00010000,
              0b00001000,0b00000100,0b00000010,0b00000001 };

//1文字の出力
void seg1(int v,int rs)
{
    for(int jj=0;jj<8;jj++){
        if( (v & b8[jj]) == 0 ){
                swdio=0; //ビットが0
        } else {
                swdio=1; //ビットが1 
        }//endif
        swdclk=1;
        swdclk=0; //clk
    }//for

    swdio=rs;
    en=1;     wait_ms(1);
    en=0;
}//seg1

//文字列の表示 nana_seg
int ns_printf(char *str1) {

    //文字の中身がゼロか
    while(*str1){

        //一文字出力
        seg1( *str1 ++ , 1  );

    } //while

    //戻り値
    return(0);

}//ns_printf

//液晶の初期化コード
int lcd_int[]={
  0x30,0x30,0x30,0x38,0x08,0x01,0x06,0x08+0x04
};//lcd_init


//メイン関数
int main() {

    char buf[16]; //バッファー

    //GPIOの初期化
    en=0;

    //液晶の初期化
    for(int ii=0;ii<8;ii++){ 
        seg1( lcd_int[ii] , 0);wait_ms(2);
    }//for

    seg1( 0x80+0x00 , 0  ); //1ライン目にカーソルを移動

    ns_printf("ON LCD ");//wait_ms(500); //debug

    //画面クリア
    //seg1(   0x01  , 0  ); 
    //wait_ms(5);


    //無限ループ
    while(1){

    }//while

}//main




```
JavaScript83_基本データ型の変換

ここで基本データ型を参照データ型Objectに変換するための方法を紹介する。

基本データ型は下記の５種類があります：
String Number Boolean Null Undefined
参照データ型
Object

JSは３つの構造関数を用意してくれた。それらを使うことで、基本データ型をObjectに変換することができる。
1 String()
  String型データをString型のObjectに変換することができる
2 Number()
　Number型データをNumber型のObjectに変換することができる
3 Boolean()
　Boolean型データをBoolean型のObjectに変換することができる

例：Number型の対象を作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/18a950d4-8dd1-9ea2-88e8-1eeddd291365.png)

Objectデータ型の機能は基本データ型より多く、使いやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/0cc3cc3e-f484-ca48-f48a-8371c2f464e3.png)
注意：開発時にこのように基本データ型をObjectに変換することはあまりしません。
先の例の通りに、たくさんの問題を起こすことがあるためです。
この変換方法を使っているのがほとんどはPC自身です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/055571e5-efe4-83c0-5d51-34541e31d2c5.png)
40 代おっさん GASのMathオブジェクトについて学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## Mathオブジェクトとは

多様な数学演算を提供するオブジェクト

|分類|メンバー|戻り値|説明|
|----|--------|------|----|
|静的プロパティ|Math.E||ネイピア数（オイラー数）|
|静的プロパティ|Math.LN2||2の自然対数|
|静的プロパティ|Math.LN10||10の自然対数|
|静的プロパティ|Math.LOG2E||2を底としたEの対数|
|静的プロパティ|Math.LOG10E||10を底としたEの対数|
|静的プロパティ|Math.PI||円周率|
|静的プロパティ|Math.SQRT1_2||1/2の平方根|
|静的プロパティ|Math.SQRT2||2の平方根|
|静的メソッド|Math.ads(x)|Number|xの絶対値を返す|
|静的メソッド|Math.sign(x)|Integer|xが正の数ならば1、負の数なら‐1、0ならば0を返す|
|静的メソッド|Math.ceil(x)|Integer|xの小数点以下を切り上げた整数を返す|
|静的メソッド|Math.floor(x)|Integer|xの小数点以下を切り下げた整数を返す|
|静的メソッド|Math.round(x)|Integer|xを四捨五入した整数を返す|
|静的メソッド|Math.trunc(x)|Integer|xの整数部を返す|
|静的メソッド|Math.esp(x)|Number|ネイピア数（オイラー数）のx乗を返す|
|静的メソッド|Math.log(x)|Number|xの自然対数を返す|
|静的メソッド|Math.log10(x)|Number|底を10とするxの対数を返す|
|静的メソッド|Math.log2(x)|Number|底を2とするxの対数を返す|
|静的メソッド|Math.max(x, y, ...)|Number|x, y, ...の値で最大の値を返す|
|静的メソッド|Math.min(x, y, ...)|Number|x, y, ...の値の中で最小の値を返す|
|静的メソッド|Math.pow(x, y)|Number|xの y乗を返す|
|静的メソッド|Math.random()|Number|0以上1未満の乱数を返す|
|静的メソッド|Math.sqrt(x)|Number|xの平方根を返す|
|静的メソッド|Math.cbrt(x)|Number|xの立方根を返す|
|静的メソッド|Math.hypot(x, y, ...)|Number|x, y, ...の二乗和の平方根を返す|
|静的メソッド|Math.sin(x)|Number|xのサインを返す|
|静的メソッド|Math.con(x)|Number|xのコサインを返す|
|静的メソッド|Math.tan(x)|Number|xのタンジェントを返す|
|静的メソッド|Math.acos(x)|Number|xのアークコサインを返す|
|静的メソッド|Math.asin(x)|Number|xのアークサインを返す|
|静的メソッド|Math.atan(x)|Number|xのアークタンジェントを返す|
|静的メソッド|Math.atan2(y, x)|Number|y/xのアークタンジェントを返す|

お試し

```javascript
function toshiki4() {
  console.log(Math.PI);
  console.log(Math.SQRT2);
  console.log(Math.sqrt(3));
  console.log(Math.cbrt(27));
  console.log(Math.hypot(3, 4));

  console.log(Math.abs(-3));
  console.log(Math.sign(-3));
  
  console.log(Math.ceil(10.5));
  console.log(Math.floor(10.5));
  console.log(Math.round(10.5));
  console.log(Math.trunc(10.5));

  console.log(Math.max(3, 9, 1, 7, 5));
  console.log(Math.min(3, 9, 1, 7, 5));

  console.log(Math.random());
}
```

## 参考資料

<https://www.amazon.co.jp/s?k=google+apps+script+%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80&adgrpid=110264232688&gclid=CjwKCAiA9aKQBhBREiwAyGP5lSl7AJJLCvOEHb4wQgMlyqW1fll5X8GDTT_Rkd1_soUAyIPMXQr26hoClHEQAvD_BwE&hvadid=553833563682&hvdev=c&hvlocphy=1009076&hvnetw=g&hvqmt=b&hvrand=4378489642044417389&hvtargid=kwd-594191211348&hydadcr=4106_13159878&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_2x1owglv0s_b_p52>
Spring MVCのsuspendなControllerを実行するとInterceptorやContollerAdviceが複数回実行されてしまう

バージョン情報

* Spring Boot: 2.6.3

Spring MVCではKotlinのコルーチンがサポートされています。

Controllerのhandler関数にsuspendをつけると、Springがコルーチンを起動してhandler関数を実行してくれます。

```kotlin
@RestController
class DemoController {
    @GetMapping("suspend")
    suspend fun indexSuspend(): String {
        return "suspend handler is executed."
    }
}
```

このようにhandler関数にsuspendをつけると、Controllerの前段にあるInterceptorやControllerAdviceが複数回呼び出されてしまいます。

シーケンスは以下のような感じです。

![](https://raw.githubusercontent.com/nyandora/universal-static-resources/main/seq.svg)

現時点では、複数回呼び出されてしまうこと自体は避けられないようですので、複数回呼び出されても問題ないようにInterceptorやControllerAdviceを作り込んでおくしかなさそうです。

Interceptorの実装例です。

```kotlin
@Component
class DemoHandlerInterceptor(
        private val asyncHandlerUtil: AsyncHandlerUtil
) : HandlerInterceptor {
    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
        // 非同期処理（Controllerのsuspend fun）の完了後、
        // 後続処理を再開するためにDispatcherServletに再度ディスパッチされる。
        // その時にInterceptorが呼ばれた場合（つまり２回目に呼ばれた場合）は何もしない。
        if (asyncHandlerUtil.isDispatchedToResume(request)) {
            // falseを返してしまうと後続処理の再開も止まってしまうので、trueを返す必要あり。
            return true
        }

        // 非同期処理（Controllerのsuspend fun）を起動するために
        // DispatcherServletにディスパッチされた時のみ（つまり１回目に呼ばれた場合のみ）、
        // 本来の処理を行う。
        println("Interceptorが本来やるべき処理")

        return true
    }
}

@Component
class AsyncHandlerUtil {
    fun isDispatchedToResume(request: HttpServletRequest): Boolean {
        val manager = WebAsyncUtils.getAsyncManager(request)

        // WebAsyncManager.hasConcurrentResult()を利用すれば、
        // 非同期処理（Controllerのsuspend fun）の完了後に再度ディスパッチされたのかどうかを判定できる。
        // see: https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/web/context/request/async/WebAsyncManager.html
        return manager.hasConcurrentResult()
   }
}
```

ControllerAdviceの実装例です。

```kotlin
@RestControllerAdvice
class DemoControllerAdvice() {
    @ModelAttribute("myModel")
    fun addSomeAttributeToModel(request: HttpServletRequest): String? {

        // ２回目にディスパッチされた場合は前回の結果を使う。
        // ２回目にnullを設定するなどもアリかもしれないが、
        // 前回の結果を使う方式の方が堅牢（何回呼ばれても問題は起こり得ない）。
        val cached = request.getAttribute("myModelAttr") as String?
        if (cached != null) {
            return cached
        }

        // 属性値の生成
        val attributeValue = "model!!"

        // ２回目にディスパッチされた時のために、結果をrequestに保存する。
        request.setAttribute("myModelAttr", attributeValue)

        return attributeValue
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    fun handleException(e: Throwable): String {
        // ハンドラ（Controllerのsupend fun）で例外がスローされた場合、
        // ２回目のディスパッチでここにくる。
        return "error occurred."
    }
}
```

コードは以下に置いてあります。

https://github.com/nyandora/spring-handler-executed-multiple-times-demo
S3でアクセス不可になった時の解消方法

S3 でダッシュボードで ACL が見れなくなったり、そのオブジェクトがアクセス不能になったことがあり、その解消方法を記録しておく。

## 原因

どうやら
別アカウントのIDプールでS3バケットにアップロードしたファイルの所有者が別アカウントになっておりアクセス不可になっていた。

## 対応概要

別アカウントから `bucket-owner-full-contgorl` の acl を付加してアクセスできるようになったかも...

コピーすると所有者が変わるが、`--metadata` で何か変更しないとコピーできなかった
参考：[Amazon S3 から 403: Access Denied エラーをトラブルシューティングする方法とは?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-troubleshoot-403/)

## 作業概要

具体的な作業履歴。

### 1. 現状確認

```
aws s3api list-objects --bucket {バケット名} --prefix {キー名プリフィックス} --profile {プロファイル名}
```

で所有者を確認してS3を使っているAWSアカウントとは異なるAWSアカウントが所有者であることを確認した。

### 2. アクセス許可付与 

```
aws s3api put-object-acl --bucket {バケット名} --key {オブジェクトキー名} --acl bucket-owner-full-control --profile {プロファイル名}
```

で別アカウントでもアクセス許可を与える。

### 3. コピーして所有者変更

```
aws s3 cp s3://{バケット名}/{キー名} s3://{バケット名}/{キー名} --profile {プロファイル} --cache-control "max-age=30" --metadata "Version=1"
```

同じファイルにコピー。とりあえず `--metadata "Version=1"` で metadata を変更。
分割代入に型アサーションを使うメモ（Typescript）


## 結論
 as でオブジェクト型を定義してダウンキャストすれば良いです。

## 事の経緯

きっかけは Next.js でダイナミックルーティングの際に、`router.query`を使用したのだが、返却型が`string | string[]`となります。

使用するコンポーネントに対して型エラーが起きたのでそれを解決する方法をメモとして残します。

```tsx
import { useRouter } from "next/router";

export const ParentComponent = () => {
  const router = useRouter();

  // as により型をダウンキャストする
  const { hoge, piyo } = router.query as {
    hoge: string;
    piyo: string;
  };

  return <ChildComponent hoge={hoge} piyo={piyo} />;
};
```

```tsx
type ChildComponentProps = {
  hoge: string;
  piyo: string;
};
const ChildComponent: React.VFC<ChildComponentProps> = ({ hoge, piyo }) => {
  return (
    <>
      <div>{hoge}</div>
      <div>{piyo}</div>
    </>
  );
};
```

## だめな例

型キャストがない状態だと以下のエラーが出力されます。

> Type 'string | string[]' is not assignable to type 'string'.
> Type 'string[]' is not assignable to type 'string'.ts(2322)

```tsx
import { useRouter } from "next/router";

export const ParentComponent = () => {
  const router = useRouter();

  // hoge, piyoは 'string | string[]' 型
  const { hoge, piyo } = router.query;
  // ChildComponent の hoge はstring型なので Error
  return <ChildComponent hoge={hoge} piyo={piyo} />;
};
```

## 他の方法

また分割代入したそれぞれの変数に対して、ChildComponent に渡す際にダウンキャストしても良いです。個人的にはなんかイケてない書き方な気もします。

```tsx
import { useRouter } from "next/router";

export const ParentComponent = () => {
  const router = useRouter();

  const { hoge, piyo } = router.query;

  return <ChildComponent hoge={hoge as string} piyo={piyo as string} />;
};
```

## では number 型にキャストする場合はどうなのか？

子コンポーネントのPropsが以下の場合、numberにキャストする必要があります。

```tsx
type ChildComponentProps = {
  hoge: number;
  piyo: number;
};
```
as unknown により型をアップキャストしダウンキャストするとうまく型エラーを回避できます。

```tsx
import { useRouter } from "next/router";

export const ParentComponent = () => {
  const router = useRouter();

  // as unknown により型をアップキャストし、その後ダウンキャストする
  const { hoge, piyo } = router.query as unknown as {
    hoge: number;
    piyo: number;
  };

  return <ChildComponent hoge={hoge} piyo={piyo} />;
};
```

# 参考文献

[TypeScript の型入門](https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a#as%E3%81%AB%E3%82%88%E3%82%8B%E3%83%80%E3%82%A6%E3%83%B3%E3%82%AD%E3%83%A3%E3%82%B9%E3%83%88)
Webの勉強はじめてみた その33 〜データベース編〜

N予備校「プログラミング入門Webアプリ」を受講しています。
今回は第4章11〜15節です。

## PostgreSQL
Dockerコンテナにデータベースだけを作る
日本語化も併せて。

```Dockerfile:Dockerfile
FROM --platform=linux/x86_64 postgres:12

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y less
RUN locale-gen ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP
USER postgres
ENV LANG ja_JP.UTF-8
ENV TZ Asia/Tokyo
```

```yml:docker-compose.yml
version: '3'
services:
  db:
    build: .
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
```

### コマンド
`psql`
- PostgreSQLに接続。後ろにデータベース名をつけると直接接続できる

`CREATE DATABASE` データベース名
- データベース作成

`\c` データベース名
- データベースへ接続

`CREATE TABLE`　テーブル名 (カラム名 データ型)
- データテーブルの作成

`\q`
- PostgreSQLから抜ける

## データモデリング
データベース設計の作業や手法のこと

### エンティティ
:::note
データベースを使って何を管理したいのか
単体で管理する必要があり、それを親として別のデータが付属するようなもの
エンティティのデータをリレーションともいう。
:::

`Visio`で言葉の意味するところがわからずER図書いてた。

## インデックス
RDBのパフォーマンスを上げるために使う。

`EXPLAIN ANALYZE` SQL文
- 実行にかかった時間等がわかる

`CREATE INDEX ON` テーブル名 (カラム名)
- 対象のカラムにインデックスをつける

別のテーブルが作られるイメージ。
PostgreSQLでは`B-Tree`でのインデックススキャンがデフォルト。

:::note warn
テーブルの更新があった場合、インデックスも作り直す必要がある。
:::

データ量が多いとせっかくインデックスを作ってもシーケンシャルスキャンになった。

https://tech-blog.rakus.co.jp/entry/20190703/postgresql/beginner

## 集計
WHERE 句は「行」についての条件を書くための句。
WHERE 句の条件は、`GROUP BY` によってグループを作るよりも前に使われる。
HAVING 句は、グループを作った後の「グループを対象とする」条件文。

## まとめ
データベースは以前、MySQL, SQL Server, Access, DB2と扱ったことがあるので今回はほぼ復習。ただデータモデリングは勉強になった。
データベースの設計をしても、自信が持てないとコードを書いてても不安がつきまとうので精神的にもきつい。

ところでこれまでずっとアーカイブを追う形で進めてましたが、いよいよ追いついてしまった。
docker composeとdocker-compose、ハイフン有無で何が違うのか？

# 概要
個人での開発や、学習のための環境構築には「docker compose」コマンドを使用していましたが、実務でのdocker環境構築手順では「docker-compose」コマンドが使用されていました。
一見同じことができそうですが、正しい意味を知らずになんとなくコマンドを打つのは怖いので調査してみました。

# 結論
まず結論からです。
２つのコマンドには以下のような特徴があります。
また、互換性があり多くの機能がほぼサポートされています。

### docker compose

- docker-composeをGoで実装し直したもの
- docker-composeに置き換わることを目標としている
- 現時点で未実装の機能もある
- 今後実装されない機能（compose ps --filter KEY-VALUE、compose rm --allなどdocker-composeで非推奨なもの）もある
- Docker Engine（Docker CLI）に含まれている


###docker-compose

- pythonで実装されている
- Docker Engineに含まれていない
- 多くの動作はDocker Engineに依存する
- Docker Compose CLIに含まれている


>Docker CLI 内のcomposeコマンドは、docker-composeコマンドとそのフラグをほぼサポートします。 このコマンドはdocker-composeと完全な互換性を持つものとしています。
>Composeの機能の中でcomposeコマンドでは利用できないものを見つけた場合は、GitHub リポジトリ Compose に issue をあげてください。 優先度をあげて対応することができます。
>[compose コマンドの docker-compose との互換性](https://matsuand.github.io/docs.docker.jp.onthefly/compose/cli-command-compatibility/)


前者はdockerのcomposeコマンド,後者はdocker-composeコマンドという、
ほぼ同じことができる別のコマンドのイメージでいいと思います。


# Docker Engineとは

Docker Engineは３つの主なコンポーネント（構成要素）を持ちます。

- dockerデーモン
- REST API
- Docker CLI

先述したcomposeコマンドはDocker Enigneに含まれており、docker-composeコマンドは含まれていないというのはここのことです。
ユーザーがコマンドを入力した際に、DockerクライアントやREST APIを介してdockerデーモンと通信します。

>![スクリーンショット 2022-02-20 16.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/4b7e84e7-6094-8d18-e9b7-108b62f741a8.png)
>[Docker-docs-ja Docker Engine とは何ですか？](http://docs.docker.jp/v1.12/engine/understanding-docker.html)



## 基本的な機能はあるので今後学習する人は「docker compose」で良さそう

個人的には学習や個人利用の範囲では「docker compose」を使用すると良いと思います。
以下のリファレンスに記載の通り、build、up、psなど使用頻度の高い機能は既に実装されており、どちらでも同じようなことができます。
また、将来的に「docker-compose」に置き換わることも理由の一つです。

>[docker compose　コマンドリファレンス](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose/)


# docker-composeを使用する理由を考えた

では、「docker-compose」を使用している現場は、なぜ使用しているのでしょうか。

- 以前から使用しており、引き続き使用している。
- 「docker compose」コマンドに変更することによる想定外の問題を回避している。
- 現状使用できるあらゆる機能が実装済みであり、「docker compose」では未実装の機能が使える。

このような理由が考えられます。
したがって、同じようなことができるからといって自己判断でハイフンを付けたり省略するのはやめましょう。

# まとめ

- 「docker compose」コマンドは「docker-compose」に置き換わることが目標
- 互換性があり、ほとんどの機能が同じように使える


# 参考文献

>[compose コマンドの docker-compose との互換性](https://matsuand.github.io/docs.docker.jp.onthefly/compose/cli-command-compatibility/)
>[Docker-docs-ja Docker Engine とは何ですか？](http://docs.docker.jp/v1.12/engine/understanding-docker.html)
>[docker compose　コマンドリファレンス](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/compose/)
[Flask] ImportError: cannot import name 'soft_unicode' from 'markupsafe' への対処

FlaskをCloud Runにデプロイしたら、「 **ImportError: cannot import name 'soft_unicode' from 'markupsafe'** 」 が発生したときの対処。

原因特定までできていないのですが、
フロントを色々直して、デプロイしたら、発生して、
ブラウザから接続すると、 service unavailable に……


```requirements.txt
-Flask==1.1.4
+Flask==2.0.1
```

Flaskのバージョンを上げたら、解決した。
max(random(), random()) の期待値

`max(random(), random())` の期待値はいくつなのか、そして**どう計算すればいいのか**気になったので、やってみた。

## 実験
Pythonで100万回ほど試行して平均をとってみる。

```python
from random import random

N_TRIAL = 2**20

sum = 0
for k in range(1, N_TRIAL + 1):
    x = max(random(), random())
    sum += x
    if k & (k - 1) == 0:
        print("{:8d} : {:f}".format(k, sum / k))
```

結果は `0.666...` くらいに落ち着いた。期待値が単純な数になるとすれば、 **2/3** が答えと思われる。

---

ついでに、最大値をとる乱数の量を 2 から N に増やして試してみる。

```python
from random import random

N_TRIAL = 2**20
N = 5

sum = 0
for k in range(1, N_TRIAL + 1):
    x = max(random() for i in range(N))
    sum += x
    if k & (k - 1) == 0:
        print("{:8d} : {:f}".format(k, sum / k))
```

N = 5 のとき期待値は `0.833...` ≒ **5/6** となった。

他も試してみると、乱数 N 個の最大値の期待値は **N/(N+1)** のよう。

## 厳密解の計算
確率変数 X が連続値をとる場合、その[期待値](https://ja.wikipedia.org/wiki/期待値) E\[X\] は以下の式で計算するらしい。

```math
E[X] = \int_\Omega X(\omega) \: dP(\omega) = \int_\mathbb{R} x \: f_X(x) \: dx
```

[確率論](https://ja.wikipedia.org/wiki/確率論)や[ルベーグ積分](https://ja.wikipedia.org/wiki/ルベーグ積分)についてはよくわからないので、見よう見まねでやっていく。

### 方法1
今回は `random()` を2回使っているので、[標準一様分布](https://ja.wikipedia.org/wiki/連続一様分布)に従う独立な確率変数 X<sub>1</sub>, X<sub>2</sub> に置き換えることを考える。

同時確率密度関数は f<sub>X<sub>1</sub>,X<sub>2</sub></sub>( x<sub>1</sub>, x<sub>2</sub> ) = 1 。これを用いて書き換えれば、

```math
\begin{align}
E[X]
&= \int_0^1 \!\!\! \int_0^1 x \: f_{X_1, X_2}(x_1, x_2) \: dx_1 dx_2 \\
&= \int_0^1 \!\!\! \int_0^1 \max(x_1, x_2) \: dx_1 dx_2 \\
\end{align}
```

最大値関数が入っているところが面倒で、素直に計算するなら積分範囲を分割しなければいけない。

```math
\begin{align}
E[X]
&= \int_0^1 \!\!\! \int_0^1 \max(x_1, x_2) \: dx_1 dx_2 \\
&= \int_0^1 \left\{ \int_0^{x_2} x_2 \: dx_1 + \int_{x_2}^1 x_1 \: dx_1 \right\} dx_2 \\
&= \int_0^1 \left\{ x_2^2 + \frac{1}{2} \left( 1 - x_2^2 \right) \right\} dx_2 \\
&= \frac{1}{3} + \frac{1}{2} - \frac{1}{6} = \frac{2}{3} \\
\end{align}
```

`max(random(), random())` の期待値は **2/3** と求まった。ただ、最大値関数の引数が3つ以上になったらどう計算すればいいのかパッと思いつかない。

### 方法2
変数変換せず、元の X の確率分布を求めて直接計算する。累積分布関数 F<sub>X</sub>(x) = P(X ≦ x) がわかれば、確率密度関数 f<sub>X</sub>(x) はその微分で求められる。

P(X ≦ x) は「 X がある値 x 以下となる確率」という意味で、今回なら<strong>「最大値関数 max( x<sub>1</sub>, x<sub>2</sub> ) の結果が x 以下となる確率」</strong>を表す。これを「 x<sub>1</sub>, x<sub>2</sub> の両方とも x 以下となる確率」と読み替えれば、独立な標準一様分布であることから F<sub>X</sub>(x) = P(X ≦ x) = x<sup>2</sup> （ 0 ≦ x < 1 ）となる。

あとは普通に X のとる範囲で積分して、

```math
\begin{align}
E[X]
&= \int_0^1 x \: \frac{dF_X}{dx} \: dx \\
&= \int_0^1 x \cdot (x^2)' \: dx \\
&= \frac{2}{3} \\
\end{align}
```

最大値関数の引数が n 個に増えれば、 x<sup>2</sup> のところが x<sup>n</sup> になり、結果は **n/(n+1)** になる。

### 方法3
ルベーグ積分の定義に従って式を書き換えると、以下の形になる。

```math
E[X] = \int_0^\infty f^*(t) \: dt \\
f^*(t) = P( \{ \omega \mid X(\omega) > t \} )
```

今回の場合は f<sup>\*</sup>(t) = P(X > t) と、前節と真逆の確率になったので、 f<sup>\*</sup>(t) = 1 - t<sup>2</sup> （ 0 ≦ t < 1 ）となる。
（※求める期待値が X でなく g(X) だったりすると、前節と真逆にはならない）

あとは普通に積分すればいい。

```math
\begin{align}
E[X]
&= \int_0^1 \left( 1 - t^2 \right) dt \\
&= 1 - \frac{1}{3} = \frac{2}{3} \\
\end{align}
```

最大値関数の引数が n 個に増えれば、 t<sup>2</sup> のところが t<sup>n</sup> になり、結果は n/(n+1) になる。

## 宿題
`min(random(), random())` の期待値はいくつか。
Windows で Charles

Windows で Charles4系 を使う場合に 証明書をインストールできない。しかし Charle3系を使うとエラーが出て使えない。これらの問題を解消してWindowsでCharlesを使う方法をGoogleで探しても事例が見つからないので試行錯誤した結果をメモ。

* Charles を使う場合、3.12.3 だと `http://charlesproxy.com/getssl` で証明書をダウンロードインストールができる
* Windows の Charles は、SSL/TLS の対応プロトコルが古いらしく `Exhausted available SSL/TLS protocols, trying with everything enabled`のエラーが出て接続できない
* Charles4.6.2 は `http://chls.pro/ssl` で証明書をダウンロード
    + Windows で Charles を実行している場合、証明書がダウンロードできない
* Windows Charles3系 でインストールした証明書で、Windows Charles4 を利用できた
    + SSL/TLSプロトコルも最新に対応している

つまり以下の手順でWindowsでCharlesで使うことができている

1. Windows で 一旦 Charles3系 をインストール、して起動
1. Android/iOS端末で `http://charlesproxy.com/getssl` で証明書をインストール
1. Windows で Charles4系 をインストール、して起動
1. Android/iOS端末でいつも通りプロクシ設定して使う
ブラウザーで GraphQL サーバーにアクセスする方法

こちらで作成した Graph QL サーバーにアクセスする方法です。
[Apollo Server の使い方](https://qiita.com/ekzemplaro/items/98aa688d329e526db516)

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<title>GraphQL Client</title>
</head>
<body>
<h2>GraphQL Client</h2>
<hr />
Feb/20/2022<br />
<script src="client.js"></script>
</body>
</html>
```

```js:client.js
const query = `{ books { title author } }`;
const url = "http://localhost:4000/";

const opts = {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({  query })
};

fetch(url, opts)
  .then(res => res.json())
  .then(data => console.log('data returned:', data))
  .catch(console.error);
```

ブラウザーで見た様子
![graphql_feb20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6456ee49-ca8d-7950-aad7-76e69a0264e7.png)
テストコードってなに？

# はじめに
アプリを実装するにあたってテストコードといった方法があると知ったのですが、
今まで試したことがなかったので、具体的に何をしているのか調べてみました。

## テストコードとは
テストコードとは、「自分が描いたコードが想定した通りに動作するか確認するためのもの」です。
テストコードを書き、
のちにテストをすることで動作確認がしやすかったり、他の方が見て仕様書がわりになります！

## テストコードのメリット
メリットとしては、
・テストがやりやすく不具合の確認が容易になる
・仕様書の代わりになる
・テストに割く時間が減る
自分だけでなく他の方の確認にも使えるので、お得ですね！

## テストコードのデメリット
デメリットとしては、
・テストコードを書くこと自体に時間がかかる
・仕様が変更された場合、書き直しになってしまう
やはりテストコードを書く時間が面倒と思ってしまうことが多いそうです。。。

## まとめ
今回テストコードについて調査してみました。
実機を動かしてテストをやることが多かったのですが、
if文等の分岐する箇所についてはテストが面倒だったりするので、
テストコードを書くことができれば簡単になりますね！

## 最後に
アプリを実装していく中でテストコードを試したことがなかったため、
次は実際にAndroid Studioでのテストコードの書き方調査・実践を試してみたいと思います。
HTML フォーマットだけ置いておく

意外とhtmlの形だけ置いているような記事なかったので、置いておきます。
新しく作るときに、割と既にあるhtmlから持ってきたりしていましたが、消すのが面倒な故。
下記はコピー用にどうぞ。

```
<!DOCTYPE HTML>
<html　lang="ja">
 <head>
    <meta charset="UTF-8">
  　<title>サンプル</title>
　　　　　<!--スクリプトやCSSの記述-->
 </head>
 <body>
 <!--htmlの表示-->
 </body>
</html>
```