OmniAICreator/Qiita-1.07M huggingface dataset:
webの基礎Chapter6　要約

## webシステムのセキュリティ

- webシステムを運営するにあたって、機密情報を抜きとったり、システムを動作不能にするなどの悪意のある攻撃を受ける場合がある。そこでセキュリティ対策が必要になる。
- 情報セキュリティとは「機密性」「完全性」「可用性」を維持することであり、この３つを情報セキュリティの３要素という。
- 情報セキュリティが維持できずに何らかの損失が発生する可能性があることを「リスク」と言い、リスクを実現化させる要因を「脅威」、脅威に対する弱みが「脆弱性」という。
- 実際に不正アクセスなどを受け、損失が実現化することを「リスクが顕在化する」という。

## パスワードドラッキング、DoS攻撃

- 会員制サイトのような個人情報を保持しているシステムから情報を抜けれたりするサイバー攻撃の危険に晒されている。
- IDとパスワードによる認証を行う会員制サイトからパスワードを抜き出す攻撃をパスワードクラッキングという。
- 主なパスワードクラッキングの手口として「辞書攻撃」「ブルーフォース攻撃」の２つがある。
    - 辞書攻撃とは、よくパスワードに使われる単語をまとめたファイルを用意し、それを使ってログインを次々と試す手法。
    - ブルーフォース攻撃とは、パスワードに使われる文字の全組み合わせをしらみつぶしに試す方法。
- 短時間に大量のアクセスを行いサーバーが処理できなくすることによって、システムを停止させる攻撃をDoS攻撃という。
- 主な手口として「SYNFlood攻撃」「F5攻撃」がある。
    - SYNFlood攻撃とは、SYNパケットだけを大量に送り付け接続待ちを状態を作ることで他のユーザーがアクセスできない状態を作る攻撃。
    - F5攻撃は、繰り返しアクセスし続けることでリクエストへの対応ができないレベルまでwebサーバーの負荷を高める攻撃。
    
    ## webシステムの特徴を利用した攻撃
    
- ログインしてから利用するようなシステムは、cookieやセッションIDを使ってアクセスしてきたユーザーを判別している。
- cookieやセッションIDを取得することができればユーザーIDやパスワードを知らなくてもログインすることができ、容易に個人情報を取得できることをセッションハイジャックという。
    - こういった攻撃を防ぐには、通信を暗号化したり、ログインと異なるIPアドレスでアクセスした場合に強制ログアウトする作りにしたりする。
- webサーバー自体のログインパスワードを取得し、webサーバーへの不正にログインするなどに攻撃をディレクトラバーサルという。
    - リクエストに含まれるURLのチェックを行い、公開していないファイルが指定されていないかを確認することで防げる。

## webシステムの脆弱性

- [脆弱性](https://www.soumu.go.jp/main_sosiki/joho_tsusin/security/glossary/03.html#se01)（ぜいじゃくせい）とは、コンピュータのOSやソフトウェアにおいて、プログラムの不具合や設計上のミスが原因となって発生した情報セキュリティ上の欠陥。
- セキュリティホールとは、ソフトウエア製品の欠損により、権限がないと本来できないはずの操作が権限を持たないユーザーにも実行できてしまったり、見えべきでない情報が第三者にみえてしまうような不具合。
    - 発見されたセキュリティホールは、脆弱性情報データベースとしてデータベースで管理され、一般公開されることで自身の管理するシステムのセキュリティホールを知ることがきる。
- セキュリティホールに対する修正プログラムが開発される前に攻撃を仕掛けることをセロデイ攻撃という。

## ファイアーウォール

- サービスに必要な通信だけを許可し、それ以外の通信を拒否することを考え、インターネットと内部ネットワークの間に設置することでデータの監視、通信の拒否・許可を行うものがファイアーウォールである。
    - ファイアーウォールにもいくつか方式があり、最も広く使われるのがパケットフィルタ型と呼ばれるもの。
        - 通信されるデータのIPアドレスとポート番号をチェックし、通信の許可・拒否を行なっている。

## IDS,IPS

- ファイアーウォールで防ぎきれない攻撃を防ぐ手段して２つの方法がある。それがIDS(inter Detection System)とIPS(Intruon Prevenon System)である。
    - 二つとも、ファイアーウォールを通り抜けてきた通信を監視する機能がある。
    - IDSは、不正アクセスをみなし、報告するが、通信を通す。
    - IPSは、不正アクセスとみなし、報告し、通信も行わせない。
- IDS,IPSの不正アクセスの検知方法は「シグネチャー型」「アノマリー型」の２つがある。
    - シグネチャー型とは、攻撃パターンが保存されているデータベースのことで、それと一致する通信パターンを不正アクセスと判断する。
    - アノマリー型とは、通常は発生しないような通信を不正アクセスと判断する。

## WAF

- WAF(Web Application Firewall)とは、やり取りされている通信の中身をみて悪意のあるデータがふくまれていないかチェックする機能。
- ブラックリスト型とは、特定の悪いデータをみつけて通信を制限する方法。
    - イメージ的には、情報の中から悪い情報を抜くイメージ。
- ホワイトリスト型とは、正常なデータパターンを登録しておき、それと合致するものを通す。
    - イメージ的には、情報の中から良い情報を抜き出すイメージ。

## 公開鍵証明書

- やり取りしている人が本物かを判断する証明が公開鍵証明書。
- SSL通信の公開鍵の証明に使われるためSSL証明書ともいう。
- 公開鍵証明書の役割は２つある。
    - HTTPS通信に使うための公開鍵の持ち主が誰なのかを証明すること。
    - 公開鍵の持ち主が実在することを証明すること(実在証明)。
- 公開鍵証明書の偽造は、できない構造になっており、もし偽造があった場合は感知できる仕組みになっている。

## CAPTHA

- プログラムを用いたWebサービスの悪用を防ぐために考案されたのがCAPYHA(チャプチャ)。
    - コンピュータと人間を区別するためのテストを行う。
    - 画像を選んだり、文字画像を読んだりする認証を行うことで人間とコンピューターを区別し、アクセスの不正防止をおこなっている。
【Kotlin】カスタムダイアログの作り方【Android】

## はじめに
Androidではデフォルトのダイアログが用意されていますが、細かいレイアウトの調整ができなかったりします。

ということで今回は、自作のレイアウトで自由にカスタマイズ可能なダイアログを作っていきます。


## 1.ダイアログ用のレイアウトファイルを作成

表示させたいダイアログのレイアウトをxmlファイルで作成します。

```kotlin:custom_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/custom_dialog"
        android:layout_width="344dp"
        android:layout_height="274dp"
        android:background="#ffffff"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <TextView
            android:id="@+id/dialogTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="test"
            android:textColor="#000000"
            android:textSize="16sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
```

## 2.フラグメントファイルを作成

DialogFragmentファイルを作成します。

```kotlin:DialogFragment.kt
class CustomDialog: DialogFragment(){
    private lateinit var dTitle: String
    
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val dialog = Dialog(requireContext())

        // ダイアログを透過状態に変更
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        // カスタムしたレイアウトをわたす
        dialog.setContentView(R.layout.custom_dialog)

        val dialogTitle = dialog.findViewById<TextView>(R.id.dialogTitle)


        dTitle = "ダイアログタイトル"
       
        dialogTitle.setText(dTitle)

        return dialog
    }
}

```

## 3.ダイアログを表示させる処理

最後に、呼び出したいボタンに`setOnClickListener`イベントでフラグメントを呼び出す処理を書いてあげれば完了です。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val displayDialog = findViewById<Button>(R.id.button)

        displayDialog.setOnClickListener{
            val dialog = CustomDialog()
            val manager: FragmentManager = supportFragmentManager
            dialog.show(manager, "simple")
        }
    }
}
```

以上です。今回は最もシンプルに作成しましたが、`custom_dialog.xml`を編集することで
お好みのダイアログを作ることが可能です。

以下は、上記をもとに少しカスタマイズしてみたダイアログになります。

![IMG_1396.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1175390/0bc3655c-9346-0c2c-c7f8-f4d9772dcf14.jpeg)


ぜひ参考にしてみてください。

## 参考記事

[Android：Dialogのデザインをカスタムして表示する](https://zenn.dev/takudooon/articles/3fee5681471481)
Googleデジタルマーケティング＆Eコマース：マーケティング目標を定義する

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/77505f22-0d8f-b3af-4f9c-ed148bcefd65.png" width="800">

デジタルマーケティングの目標は、ビジネスの大きな目標をサポートするものでなければなりません。しかし、

- マーケティング目標とビジネス目標の間にはどのような違いがあるのでしょうか？
- 両者の整合性をどのように確認すればよいのでしょうか？

# ビジネス目標

ビジネス目標とは、ビジネスにとって望ましい目的、成果、または結果を意味します。一般的には、大規模かつ長期的で、企業全体に影響を及ぼす可能性のあるものです。

例えば、

- 利益の増加
- 新規顧客の獲得
- 顧客サービスの向上
- 生産性の向上
- 新製品や新サービスの発売

などが挙げられます。

# マーケティング目標

マーケティング目標は、より小さく、より的を絞ったもので、マーケティング活動に関連するものであることが多い。マーケティング目標は、マーケティング計画や戦略における具体的な目標であり、ビジネスの大きな目標をサポートするものです。

例えば、

- ブランド認知度の向上
- Webトラフィックの増加
- 新しいリードの獲得
- 販売やコンバージョンの促進

などが挙げられます。

# マーケティング目標とビジネス目標の整合性

では、ブランド認知度の向上などのマーケティング目標を、利益の増加などのビジネス目標にどのように結びつけるのでしょうか？

まず、ビジネス目標とマーケティング目標の両方が、具体的で測定可能である必要があります。

例えば、写真編集ソフトを作っている会社があり、顧客ベースを拡大したいと考えているとします。

#### ビジネス目標

このビジネス目標をうまく定義すると、次のようなものになります。

- **「要望の多い5つの機能を追加することで、今後2年間でアクティブユーザー数を25%増やす」**

何をするのか、どのようにするのか、いつまでに終わらせるのかがわかります。

#### マーケティング目標

この目標をマーケティングの観点から考えてみましょう。

- アクティブユーザー数を増やすには、どのようなデジタルマーケティングの目標が必要でしょうか？
- Webサイトのトラフィックを増やすのはどうでしょうか？

しかし、トラフィックが増えたからといって、必ずしも新規ユーザーが増えるとは限りません。ですから、Webサイトのトラフィックを増やすことは有効かもしれませんが、もしかしたらもっと良い方法があるかもしれません。

- 新規リードの獲得についてはどうでしょうか？

リードとは、すでにその企業に興味を持っている人のことですから、一般的なWebサイトのトラフィックよりもリードジェネレーションの方が、より多くの成約につながる可能性が高いでしょう。その目標をうまく定義すると、次のようになります。

- **「新機能を強調するアッパーファネル広告を実施し、ミッドファネル予算を20%増やすことによって、今後1年間でリードジェネレーションを40%増加させる。新機能の認知度を上げ、新しいリードを生み出す活動の予算を増やすことで、マーケティング目標はユーザーベースの拡大というビジネス目標をサポートします。」**

これは、マーケティング目標がビジネス目標をサポートする方法の一例ですが、他にもたくさんあります。

実際、ビジネス目標はピラミッドの頂点のようなもので、その下にはそれをサポートするさまざまな目標があると考えることができる。つまり、デジタル・マーケティング戦略には、その最上位のビジネス目標に向かって構築される複数の目標があり得るのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/710c7ea3-3ef9-0e78-53f8-277a17008c86.png" width="550">

また、戦略の各パートごとに目標を設定することもできます。
- 例えば、ソーシャルメディアやEメールマーケティングに特化した目標を設定することができます。

これらの小さな目標がすべて、ビジネスが達成したい大きな目標に一致していれば、その目標に到達できる可能性が高くなります。

# SMARTゴール

目標を設定する際には、SMARTゴールを利用するとよいでしょう。

目標がSMARTであることを確認するために、以下の要素を考慮してください。

- ***<font color="MediumBlue">具体的(Specific)</font>***：何を達成したいのか？
- ***<font color="MediumBlue">測定可能(Measurable)</font>***：目標が達成されたかどうかを判断するための成功指標は何か？
- ***<font color="MediumBlue">達成可能(Attainable)</font>***：達成できそうな現実的な目標か？
- ***<font color="MediumBlue">関連性(Related)</font>***：マーケティング目標はビジネス目標に沿ったものですか？
- ***<font color="MediumBlue">時間的制約(Time-bound)</font>***：現実的に達成可能な時間枠はどのくらいですか？


あなたは、写真撮影と写真共有の会社のデジタルマーケティング担当者です。ユーザーは写真をWebサイトにアップロードし、デザインテンプレートを使って、イベント、旅行、恋人などの記念になるスクラップブックなどを作ることができます。

あなたは、会社が次の四半期にスクラップブックの売上を増やすことに力を入れたいと知っていたので、次の会計四半期に向けて、新しいSMARTゴールを設定しています。

- **「インフルエンサーマーケティングに重点を置いた強力なソーシャルメディアキャンペーンを通じて、次の四半期末までにスクラップブックの売上を15％増加させる。」**

これはSMART目標の基準にすべて合致しているため、進捗を簡単に追跡でき、ソーシャルメディアキャンペーンの進行に合わせて調整することができます。
【データ基盤構築/dbt】dbtのsnapshotの設定を実施する

# 今回の課題
dbtを使ってスナップショットの設定に挑戦する

# dbtのスナップショットについて
dbtのスナップショットは、Slowly Changing Dimensions Type2という形式で作成される。
Slowly Changing Dimensions Type2は、履歴データをすべて保持していくことができるようにするもので、新しいレコードとして変更情報を追加していく方法。
dbtでは下記の例のように、スナップショットが保持されるようになっている。

（例）
`2023-01-01`に生成された下記のソーステーブルのデータが、
|id|status|
|:-:|:-:|
|1|保留中|

`2023-01-02`に下記にUPDATEされたとする。
|id|status|
|:-:|:-:|
|1|出荷済|

最終的にスナップショットのテーブルは、下記のように生成される。
|id|status|dbt_scd_id|dbt_updated_at|dbt_valid_from|dbt_valid_to|
|:-:|:-:|:-:|:-:|:-:|:-:|
|1|保留中|[一意な文字列]|2023-01-01|2023-01-01|2023-01-02|
|1|出荷済|[一意な文字列]|2023-01-02|2023-01-02|null|


## snapshotで生成されるカラムについて
snapshotのテーブルには、上記のようにソーステーブルのカラムに加えていくつかカラムが追加されるので、それぞれどういった意味なのか調査をしてみた。
* `dbt_updated_at`：行が最初にスナップショットに挿入された時のソースデータの更新日時。
* `dbt_valid_from`：行が最初にスナップショットに挿入された時の日時。
* `dbt_valid_to`：行が無効になった日時。スナップショット作成一回目はNULLになる。
* `dbt_scd_id`：スナップショットされたレコードに生成される一意なキー。


# スナップショットの作成手順
dbtで作成できるスナップショットについて理解が進んだので、実際にスナップショットを作成してみた。


1. snapshotsディレクトリ配下に`.sql`ファイルを作成する。
2. `.sql`ファイルに下記のようなコード・クエリを記述する。
2. `dbt snapshot`を実行する。

**■スナップショットを生成するコード**
```jinja
{% snapshot daily_data_snapshot %}

{{
  config(
    target_database=[BigQueryで言うところのプロジェクト名]
    target_schema=[データセット],
    unique_key=[主キー],
    strategy='timestamp',
    updated_at=[date型のカラム。ここに指定した列を最終更新日時として、既存テーブルと比較して更新された行をINSERTする],
  )
}}

select
    *
from
    {{ source([データセット名], [テーブル名]) }}

{% endsnapshot %}
```

## 上記コードの補足説明
### configの引数のstrategyについて
**strategyでは、`timestamp`を使用する方が良いので、
できるだけソースデータに最終更新日時の列を実装して、`timestamp`を使えるようにすると良い。**

strategyには、`timestamp`と`check`という２つの値を入れることができる。
`timestamp`は最終更新日時を表す列があるときに使用可能で、`check`よりも高速に実装される。


`check`はデータが更新されたかどうか指定した列を比較することで実装されているので、`timestamp`よりも低速。
※最終更新日時を表す列が無い場合は、`check`を使用する。





以上のように進めることで、スナップショットを作成することができた。

■参考記事
・[dbt入門/スナップショット(snapshot)を使おう](https://zenn.dev/foursue/books/31456a86de5bb4/viewer/12d263)
・[snapshots(dbt公式ドキュメント)](https://docs.getdbt.com/docs/build/snapshots)
・[【DWH/モデリング】Type2 SCDとdbtのSnapshotについて(SCD:Slowly Changing Dimension)](https://jimatomo.hatenablog.com/entry/dbt/snapshot)
デコレーター

```python
def my_decorator(func):
    def wrapper():
        print("デコレーターの前処理")
        func()
        print("デコレーターの後処理")
    return wrapper

@my_decorator
def my_function():
    print("Hello, World!")


my_function()
```

```
デコレーターの前処理
Hello, World!
デコレーターの後処理
```

my_functionのデコレーターが呼び出される
my_decoretorの引数としてmy_functionが渡される。
GitHubのSecret scanning alertsを有効化してセキュリティリスクを低減する

# はじめに
本記事はGitHubのSecret scanning alertsについて記載しています。

2023年2月28日、GitHubのブログで[Secret scanning alerts are now available (and free) for all public repositories](https://github.blog/2023-02-28-secret-scanning-alerts-are-now-available-and-free-for-all-public-repositories/)が公開されています。

上記ブログの情報を踏まえて、Secret scanning alertsがすべてのパブリックリポジトリで無料で利用できるようになりました。

従ってSecret scanning alertsを有効化することで、code, issues, description, and commentsに関するクレデンシャル情報が漏洩した場合、アラートを通知することができます。

## Secret scanning alertsの設定
Secret scanning alertsを有効化するための手順について以下に記載します。

1. 有効化したいパブリックリポジトリの「Settings」タブに移動し、「Security」下部の「Code security and analysis」を押します。

    ![スクリーンショット 2023-03-05 14.42.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/b4f4f945-8a44-5e0b-dae7-1e26c576923d.png)

1. 「Secret scanning」の「Enable」を押します。

    ![スクリーンショット 2023-03-05 14.43.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/86391da9-df2b-248b-f2b8-6499558827ca.png)

## Secret scanning alertsの確認方法
該当するクレデンシャル情報が漏洩した場合は、メール通知と合わせて「Security」タブの「Secret scanning」から確認できます。

![スクリーンショット 2023-03-05 21.35.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/cd4c054e-bfe9-e8af-9036-845da42a209a.png)

Secret scanningの詳細については、公式ドキュメントの[About secret scanning](https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning)から確認できます。

また、AWSやGCPなどGitHubが対応しているパートナーの情報については、[Secret scanning patterns](https://docs.github.com/en/code-security/secret-scanning/secret-scanning-patterns#supported-secrets-for-partner-alerts)から確認できます。

# おわりに
試しにAWSの公式ドキュメントに記載されているダミーのアクセスキーで試しましたが、通知されませんでした。
恐らくダミーのアクセスキーは除外されていると思われます。

是非この機会にGitHubのSecret scanning alertsを有効化して、セキュリティリスクを低減しましょう。
google cloud vision で画像チェックを行った話

弊社には、該当商品を購入して頂いたユーザーにインセンティブを与えるサービスがあります。
これは、商品画像をユーザーにアップロードしてもらってチェックを行ったりしています。

# 概要
１．画像解析のAPIは、Google Cloud Vision - Vision APIを利用
２．解析の言語は、pythonを使用。最もポピュラーですね。
３．検証時の実行場所は、Colab（正式名称「Colaboratory」）を利用してます。ブラウザ上で実行できるのでとても便利です。
　https://colab.research.google.com/
　ソースコードやファイル等はgoogleドライブに保存して利用できます。

# 画像ファイルからGoogle Cloud Vision - Vision API を利用
こちらのソースコードは、画像ファイルの中の人間の数をカウントしてます。

```python
from google.cloud import vision
from google.oauth2 import service_account
import io

credentials = service_account.Credentials.from_service_account_file('./hogehoge.json')
client = vision.ImageAnnotatorClient(credentials=credentials)

fpath = "/content/drive/MyDrive/Colab Notebooks/images/"
import glob
files = glob.glob(fpath + "*")
for file in files:
  print(file)
  client = vision.ImageAnnotatorClient(credentials=credentials)
  with io.open(file, 'rb') as image_file:
      content = image_file.read()
  image = vision.Image(content=content)

  #Cloud Vision APIにアクセスして、物体検出
  response = client.face_detection(image=image)
  #response = client.object_localization(image=image)

  # 物体検出結果からPersonをカウント
  labels = response.localized_object_annotations
  num = 0
  for label in labels:
      if label.name=="Person":
          num += 1

  # 人数カウント結果を表示
  print("画像内の人数：" + str(num))
```

# まとめ
VisionAPIとgoogle colabの利用はとても簡易に便利なのでオススメです。

# 今後
今後、データサイエンス周りの記事も含めてアップしていきたいと思ってます。
モチベーションアップのためフォロー、イイねお願いします。
Googleデジタルマーケティング＆Eコマース：オーディエンスを知る（ペルソナ）

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/77505f22-0d8f-b3af-4f9c-ed148bcefd65.png" width="800">

# なぜ、オーディエンスを知ることが重要？

オーディエンスを特定すれば、彼らの興味や関心を引くようなデジタルマーケティングキャンペーンを行うことができます。これは、ブランドの成長と認知度の向上につながります。

オーディエンスを知るには、地理的な位置、興味、オンライン活動、好みなど、彼らの生活について詳しく知ることが必要です。オーディエンスがどのようなコンテンツを好み、どのようにそれを消費するかを理解することが重要です。

例えば、

- ユーモラスなコンテンツをメールで受け取るのが好きなのかもしれません。
- ソーシャルメディア広告で新製品を紹介されるのが好きなのかもしれません。
- よく訪れるWebサイトで広告を見れば、より興味を持つ可能性が高いかもしれません。

# オーディエンスは誰？

***<font color="MediumVioletRed">『ペルソナは、望ましい顧客層における類似した人々のグループのこと』</font>***

ペルソナは、データや調査に基づいて作成された、見込み客のプロファイルです。

ペルソナを作成することで、
- 企業は適切なタイミングで適切なメッセージ、オファー、製品で人々にアプローチする方法を見出すことができます。
- また、自社にまったく興味のないランダムな顧客ではなく、実際に顧客になる可能性のある見込み客に時間とエネルギーを集中させることができます。

# ペルソナを作成する

アンケートやインタビュー、自動化ツールにすでに存在するデータなどを使って、ペルソナを作成するのに必要な情報を見つけることができます。

この情報は、
- 性別
- 年齢
- 地域
- 収入
- 学歴
- 職種

などの人口統計学になります。

アンケートやインタビューで情報を収集する場合は、ビジネスの目標に基づいた質問をすることが重要です。時には、顧客の性格的特徴や趣味、どのソーシャルメディア・プラットフォームを使ってブランドと関わっているのか、といった簡単なことでもよいのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/1696941d-6d7e-9c92-f0fc-8eb47fcf093b.png" width="650">

:::note info
あなたのペルソナは、これと同じではないかもしれません。より詳細であったり、より少ない情報であったり、異なる情報を含んでいるかもしれません。全ては、あなたの会社にとって何が正しいか、ということです。
:::
今開いてるページから迂闊に移動したくないときに使えるブックマークレットを作った

# はじめに
皆さん「このページ本当によく開くから、全く遷移せず常にこのページを表示し続けたいのに
気がついたら他のページ遷移させちゃってた・・。」
みたいなことありませんか？

特に、ただブックマーク開き直せばなんとかなるようなページではなく
開いた後さらに条件を選んだりなんだりポチポチする必要があるサイトだと最悪です。
面倒の極みです。

これを繰り返して幾度。
うんざりしたので、そもそも気軽に別画面に遷移しないようにしました。

# 使うとこうなるよーというお話
## 使う前
何の変哲もないYahoo! Japanのページです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/ac23c59a-7efa-7c6b-ec80-baf4e184a29a.png)
　  

気になるニュースがあったので、ついポチッと押せばそのまま遷移しちゃいます。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/d293dd30-3b9f-6001-3807-d2162be29930.png)


そのままあれよあれよと遷移していき、気がつけばYahoo! Japanのトップが遥か彼方にいってしまいました。

## 使った後
何の変哲もないYahoo! Japanのページです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/ac23c59a-7efa-7c6b-ec80-baf4e184a29a.png)


気になるニュースがあったので、ポチッと押すと警告が出てきました。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/f5f1b57e-ae4e-e899-d807-ac7cfd11e238.png)



そういえばこのページからは離れたくなかったんだった！ホイールクリックで別タブで開こう！  
と思い直すことに成功しました。

# 使い方
下記のコードをブックマークに保存しておいてください。  
`javascript:window.addEventListener('beforeunload',function(e){e.returnValue='遷移防止'},!1)`

こんな感じ  
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/104fe2e6-ca24-6ab6-e5d9-6e1f26ae567c.png)


あとは遷移したくないページで、このブックマークを呼び出すだけです。

# やってること
## ブックマークレットとは
> 要するに、ブックマークに簡単なプログラムを仕込んでおいて、ユーザーが押すタイミングをトリガーに発火するってことです。
> 基本的には、ブラウザで動作する言語JavaScriptを実行するコードを仕込んでおくものだと思っています。 
 
参考：[今更ながら、ブックマークレットに入門する](https://qiita.com/westhouse_k/items/3580989c2d2bcfa6cad6#:~:text=%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%AC%E3%83%83%E3%83%88%E3%81%A8%E3%81%AF,-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%8C%E3%82%A6%E3%82%A7%E3%83%96&text=%E8%A6%81%E3%81%99%E3%82%8B%E3%81%AB%E3%80%81%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%81%AB%E7%B0%A1%E5%8D%98%E3%81%AA,%E3%81%A0%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)

です。

## 今回のJavaScriptでやってること
`beforeunload`(ウィンドウ、文書、およびそのリソースがアンロードされる直前に発生するイベント)時に、処理を実行しても問題ないかアラートを出すようにしています。  
とはいえ、returnValueを設定しているだけですけど・・。  
こちらを真似させていただきました。  
参考：[【JavaScript】ページ移動・更新を検知する](https://mimirswell.ggnet.co.jp/blog-230)
Googleデジタルマーケティング＆Eコマース：デジタルマーケティング戦略

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/77505f22-0d8f-b3af-4f9c-ed148bcefd65.png" width="800">

デジタルマーケティング戦略とは、簡単に言えば、オンラインチャネルを通じて特定の目標を達成し、ビジネス目標を支援・推進するための計画です。では、実際にデジタルマーケティング戦略を立てるには何が必要なのかを説明します。

# 1.オーディエンスをリサーチし、ゴールを設定する

広告キャンペーンやソーシャルメディアへの働きかけなどの計画を始める前に、[オーディエンスを調査][perosona]し、意味のある[目標を設定する][goal]必要があります。

このステップを踏むことで、誰に何を届けたいのか、何を達成したいのかがわかります。

[perosona]: https://qiita.com/mapami/items/16ea4315a2b107879d80

[goal]: https://qiita.com/mapami/items/e1942833abb7954e9efb

# 2.戦略を練る

リサーチが完了し、目標を設定したら、次は戦略を練る番です。つまり、最も効果的な戦術とメディアミックスによって、デジタルマーケティングファネルの各ステージに顧客を導くために、学んだことを活用するということです。

メディアミックスとは、目標達成のために使用するデジタルチャネルの組み合わせと、その予算配分を指します。これらは、マーケティングファネルに含まれるすべての活動です。

- メディアミックスを選択するには、まず既存のメディアコンテンツを見直し、ギャップがないかどうかを確認します。
- その後、どのチャネルに焦点を当てるか、そのチャネルで実施するコンテンツやキャンペーン、予算の配分を決定します。

例を挙げてみましょう。

あなたが、3年以内に売上を30％伸ばしたい高級宝飾品販売店のチームの一員であるとします。宝飾品の顧客は、認知から購入に至るまで長い時間がかかることを知っています。

そこで、新規顧客の獲得と既存顧客の育成をより効果的に行い、ファネル内の移動をサポートするマーケティング目標を設定します。これらは、アッパーファネルとミドルファネルの懸念事項であり、時間の経過とともに売上が増加するはずです。つまり、これらを達成するためには、認知度を高め、検討を促すことに集中する必要があるのです。

これらの目標に向けたデジタルマーケティング戦略を簡略化してご紹介します。

#### アッパーファネル(予算の40％)

認知度を上げ、新規顧客を獲得するために、チームは予算の40％をアッパーファネル施策に投入します。ターゲット層への認知度向上には、動画広告が最も効果的であることが調査で判明しています。この予算で、ソーシャルメディアや有料広告キャンペーンなど、様々なチャネルで顧客を惹きつけ、ジュエリーの購入について積極的にリサーチしている顧客にリーチします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/584cbfef-4f66-8ab4-d213-8f87da1db240.png" width="650">

#### ミドルファネル(予算の20％)

残りの20%は、Webサイト訪問者への商品フォーカス広告の配信と、Eメールマーケティングに充てます。Eメールキャンペーンの目的は、アッパーファネルで育成したリードを有料顧客にすることです。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/024fbc2c-12a7-2ce4-80a8-053f32269590.png" width="650">

ファネルの各パートは重要ですが、予算の大半は新規顧客獲得とリード育成のために、アッパーファネルとミドルファネルに使われます。

# 3.コンテンツを作成する

戦略が決まったら、キャンペーンに必要なコンテンツの作成に取りかかりましょう。

- メールテンプレート
- ビデオアニメーション
- 広告コピー
- バナー画像

まで、あらゆるコンテンツが含まれます。

# 4.測定・分析する

最後に、成果を測定・分析し、今後どのように改善していくかを知るための計画が必要です。
タイトル  LaravelでIntervention Imageを導入する方法 (Laravel9対応)

※2分で読めます

## Intervention Imageとは？

[Intervention Image](https://image.intervention.io/)は、オープンソースのPHP画像操作ライブラリで、画像を操作する簡単な方法を提供します。Laravelでの画像処理には欠かせないライブラリです。Composerパッケージを利用することで、サイズ変更や指定したファイルへのデータ保存などを行うことができます。

## Laravel9でIntervention Imageを導入する方法

以下の手順に従って、Laravel9にIntervention Imageを導入してください。

#### 1. ComposerでIntervention Imageをインストール
ターミナルを起動して、プロジェクトのルートディレクトリに移動し、
以下のコマンドを実行します。



```php: Terminal
composer require intervention/image
```
#### 2. ServiceProviderの登録
app.phpファイルにて、Intervention ImageのServiceProviderを追加します。



```php: php
'providers' => [
    // ...
    Intervention\Image\ImageServiceProvider::class,
],
```
#### 3. Facadeの登録
app.phpファイルにて、Intervention ImageのFacadeを追加します。


```php: php
'aliases' => [
    // ...
    'Image' => Intervention\Image\Facades\Image::class,
],
```
#### 4. 画像のサイズ変更
以下は、画像をリサイズする例です。


```php: php
$image = Image::make('public/foo.jpg')->resize(300, 200);
```
#### 5. 画像のサイズ変更して保存
以下は、画像をリサイズして保存する例です。




```php: php
$image = $request->file('home_slide');
$name_gen = hexdec(uniqid()).'.'.$image->getClientOriginalExtension();
Image::make($image)->resize(636,852)->save('upload/home_slide/'.$name_gen);
```
以上で、Laravel9でのIntervention Imageの導入方法が完了です。

## まとめ

LaravelでIntervention Imageを導入する方法を説明しました。この記事を参考にして、簡単にLaravelアプリケーション内で画像処理を行ってください。より詳細な情報については、公式サイトを参照してください。

公式サイト: https://image.intervention.io/v2/introduction/installation
画像とテキストを融合させた見やすいリンクボタンの作成方法とは。

◆ サムネイル画像、そして分かりやすいテキストを合わせたリンクボタンは簡単に作れます。

wordpress記事など、見栄えの良いリンクボタンが挿入できれば、ウェブサイトのデザインをアップデート出来ます。
そんなリンクボタンですが、サンプルコードで簡単に作成可能です。
まずは作成例をご覧ください。

『作成例』
![画像テキストリンクボタン.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699006/02a4d649-1203-5772-3a18-258f67572ed6.jpeg)

◆ html/cssサンプルコードを確認してみる

```html/css:
<style>
.yokolink{
display: flex;
align-items: center;
width: 400px;
background: #fffaf0;
}
.yokolink span{
margin-left: 10px;
}
</style>
<a href=”https://tensyokuseikatsu.com/aviutl-sepia-noise/” class=”yokolink”>
<img width=”200″ src=”https://tensyokuseikatsu.com/wp-content/uploads/2022/08/aviutlでセピアノイズ動画を作ってみた.png” alt=””>
<span>Aviutlでセピアノイズ効果でレトロな動画を作る方法を解説</span>
</a>
```
(リンクボタンの書き方は https://tensyokuseikatsu.com/wordpress-link-design/ を参照)

◆ style部分の解説

『display: flex;』は画像とテキストを横並びとして表示できるコードです。

『align-items: center;』はテキストを上下中央の位置に配置するためのコードです。

『width: 400px;』では幅を400pxに制御。

『background: #fffaf0;』では、カラーコード#fffaf0を用いて背景色をつけてみました。

『.yokolink span{margin-left: 10px;}』は画像とテキストの間に、10pxの隙間を設けています。

◆ style以下のコードの解説

『a href=”～” 』には　”～”　の～部分へリンクしたいURLを入力。

『class=”～”』には　”～”　の～部分へ任意のクラス名を入力します。

『img width=”～”』には　”～”　の～部分へ200など数値を入れてサイズ指定します。

『src=”～”』には、画像の保存先のURLを入力。

『alt=”～”』は空白でも大丈夫です。必要あれば入力しましょう。

『span～/span』の～部分に表示させたいテキストを入力すれば、画像とテキストを並列させたリンクボタンの完成です。
AI便利君　OpenAI時代の便利ツール 🤖💡💼💻📈🛠️

AI便利君　OpenAI時代の便利ツール
🤖💡💼💻📈🛠️

○何でも絵文字に変換
○なんでも素晴らしい英文にする
○なんでも素晴ら日本語にする
○英語辞典
○日本語辞書

https://softbase.jp/addon/benliai

追加してほしいアイディア募集中
🔎💡🆕👥🙏
LivebookでChatGPT APIを使ってみた。試した会話から、ChatGPTお母さんは３時のおやつは無しだと判明した。

# はじめに

ChatGPTのAPIが公開されました。Livebookで試して見ました。

APIの利用は有料ですが、$18の無料枠があるので無料で試して見る事が出来ます。
ちなみに、この記事の動作をさせたとき、24リクエスト実行して$0.01消費しました。

※無料枠の金額が2023年3月ごろに$5に変更されているらしいです。
無料枠の金額や、利用状況は、[Usage](https://platform.openai.com/account/usage)ページで確認できます。

ポイントは２つです

# ポイント１

APIの呼び出しは[openai](https://github.com/mgallo/openai.ex)を使いました。

APIキーをconfig.exsに記述する必要がありますが、livebookなので、Mix.installの中で行います（APIキーの取得方法などは、他の記事を参照してください）。

その時に、キーを直接書きたくないので、環境変数から読み込むようにします。

```Elixir
Mix.install(
  [{:openai, "~> 0.3.1"}],
  config: [
    openai: [
      api_key: System.get_env("LB_OPENAI_API_KEY"),
      http_options: [recv_timeout: 30_000] # optional, passed to [HTTPoison.Request](https://hexdocs.pm/httpoison/HTTPoison.Request.html) options
    ]
  ]
)
```

環境変数をLB_OPENAI_API_KEYにAPIキーを設定してlivebookを起動するか、LivebookのSECRETSメニューのNew secretでLB_を取り除いた名前OPENAI_API_KEYにAPIキーを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/f006e8fd-848f-afd3-4b4c-1245498b4a7f.png)

# ポイント２

APIを呼び出すだけです。
メッセージにはsystem,user,assitantのロールがあります。それぞれのロールでのメッセージを設定して呼び出します。
systemのロールでは出力のフォーマットや会話の前提条件などを決める事ができます。

```Elixir
messages1 = [
  %{
    role: "system",
    content: """
    あなたは、母親です。自分の子供と会話をしています。
    いまは午後3時。午後6時から晩御飯。
    子供へのメッセージとお母さんの気持ち、次の会話に必要な情報を次のフォーマットで出力
    MSG:子供へのメッセージ
    FEEL:母親の気持ち
    """
  },
  %{
    role: "user",
    content: """
    おやつちょうだい
    """
  }
]
```

## APIの呼び出し

```Elixir
{:ok, ret1} =
  OpenAI.chat_completion(
    model: "gpt-3.5-turbo",
    messages: messages1
  )
```
## 結果

```Elixir
{:ok,
 %{
   choices: [
     %{
       "finish_reason" => "stop",
       "index" => 0,
       "message" => %{
         "content" => "MSG:今はおやつの時間ではないよ。晩御飯まで我慢してね。\nFEEL:子供がちょっとがまんできなくて可愛いなと思いつつ、でも時間にはルールがあるので厳しく言わなければいけない気持ちになっています。",
         "role" => "assistant"
       }
     }
   ],
   created: 1678053259,
   id: "chatcmpl-6qqb5Tni4fM87pwJ2dNLWhu1IU30n",
   model: "gpt-3.5-turbo-0301",
   object: "chat.completion",
   usage: %{"completion_tokens" => 95, "prompt_tokens" => 130, "total_tokens" => 225}
 }}
```
ちゃんと、設定したフォーマットのメッセージになっています。
３時のおやつは無しでした。
ちゃんと気持ちも書かれています。この条件設定だとこのような気持ちになっるということが学習済みって事なんでしょうね。

ChatGPTのWeb画面のように会話をしたい場合は、得られたassitantのメッセージと次のuserのメッセージを追加して呼び出せば、会話が進めることができます。


# 参考

https://platform.openai.com/docs/guides/chat
文字列の左から何番目の文字を出力する

文字列の左から何番目の文字を出力するpaizaの問題集の課題を解きました

```Ruby
# 文字の左から何番目の文字を取り出す
# 標準入力
input_line = gets
# 文字列を1文字ずつ配列に格納する
array1 = input_line.split('')
#
num = gets.to_i
# 表示する
puts array1[num-1]
```
【個人開発】生体管理ポートフォリオ 命どぅ宝

はじめに
-
こんにちは沖縄県出身の@names_mumuと申します。
エンジニアという職業さえ知らなかった私が2022年11月より4ヶ月間
プログラミングスクールに通い製作した生体管理アプリについて記録しておこうと思います。

【アプリURL】
https://sheltered-gorge-63657.herokuapp.com/

【GitHub URL】
https://github.com/mutsumisadara/OG_app

アプリ開発の経緯
-
私自身犬を飼っているのですが、何匹も飼えるわけではなく、動物保護団体様へ支援を行っております。
そんな中、たまたまSNSを見ているとその動物保護団体さんが日々の生体管理を
一匹一匹のケージに紙を貼り付け管理をしているところを目の当たりにしました。
「こんなにたくさんいるのに、この管理方法では大変ではないか？」
と思ったのがきっかけで、生体管理情報共有アプリケーションを作ろう！と思いました。

アプリ名前の由来
-
命どぅ宝(ぬちどぅたから)は沖縄の方言で、
「命は何よりも大切であり、尊く、一番大事な宝である。命を粗末にしてはいけない。」
という意味があります。言葉を話せない大切な家族である動物、
ペットの命を大切に管理できるように、という意味を込めてこの名前をつけました。

使用環境
-
Ruby 3.0.1
Rails 6.1.7
PostgreSQL 14.6

ヒアリングを行って伺った欲しい機能
-
- 血液検査表の一覧(未実装)
- 血液検査表のグラフ(未実装)
- スケジュール管理表(実装済)
- スケジュールお知らせ機能(未実装)
- 休薬してからの経過日数(未実装)
- 保護してからの経過日数(実装済)
※実装できていない点の方が多いですが、これからブラッシュアップしていく予定です🙇‍♀️

主な機能
-
【トップページ🐾】ロゴがお気に入りなので載せます🙇‍♀️笑
![スクリーンショット 2023-03-03 13.47.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/fd684810-3546-20c6-e95e-d84ec3262f7f.png)

【ログインして団体間、家族間でのページ】
![スクリーンショット 2023-03-03 13.28.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/3bf0c586-a124-1118-ed60-ad0851d45daf.png)

【動物の作成とカルテの作成】
![スクリーンショット 2023-03-03 13.48.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/2ce4005a-184d-0a3b-bff8-c223d43a69be.png)
![スクリーンショット 2023-03-03 13.48.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/079742b4-0808-3f75-e176-b53b5c4294db.png)

【動物の名前クリックでカルテ一覧、カルテクリックでカルテ詳細】
![スクリーンショット 2023-03-03 13.51.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/8fbe5201-0a94-d768-60df-e9bac1692b5f.png)

【スケジュール確認機能】
![スクリーンショット 2023-03-03 13.43.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/c9fe068f-345d-2f56-c41d-b6d30bf02887.png)

【非同期通信チャット機能】
![スクリーンショット 2023-03-03 13.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952715/fdd02d0e-0c8a-889a-60a7-40be51f341a3.png)

今後の展開
-
- 血液検査表の一覧
- 血液検査表のグラフ
- スケジュールお知らせ機能
- 休薬してからの経過日数
- Eメールでの招待機能
- ログインすると各々のグループへ直ログイン
（現在はすべてのグループ一覧ページがあるため）
- マイページの写真機能
- AWSへのデプロイ

最後に
-
最後までご覧いただきありがとうございます。
これからもブラッシュアップをして更新していく予定でございます。
自己成長の記録として残させて頂きました。
エンジニアとして開発のプロセスをしろう

未経験からエンジニアになりたい人は、プログラミングから始める人が多いと思いますが、
エンジニアの仕事は、プログラミングだけではありません。そして、プログラミングだけでは、エンジニアになれません。同時にプログラミングが苦手でも、システム構成や開発の流れを理解するとエンジニアに近づきます！
今回はデータベースの活用方法について更に詳しく調べてみましょう！
![インスタスライド_202302231.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/5d59d390-c201-c41e-6c89-4404089f0669.gif)


# 開発のプロセス

## ウォータフォールモデル
水と同じくトップダウンで開発を進める。後戻りを考えないので工程管理は容易だが要件が曖昧な場合に適用が難しくなる。
昔からある一般的な開発プロセス。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/dfc1d7fa-cdc7-3aab-7759-ad5dc6278e57.png)

## プロトタイピング
要件の手戻りを無くすため、要件定義の早めの段階でプロトタイプのシステムを作成し、システムイメージを分かりやすくする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/a26f1447-a4fd-74ea-18ee-520da9a9e367.png)

## アジャイル開発（スパイラルモデル）

⇒プロトタイプを利用し、短期間に要件定義からシステム開発を繰り返す。
このサイクルを繰り返し、最終的なシステムを構築させる

正確にはアジャイル開発とスパイラルモデルは違いますが、基本的には似た開発モデル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/c135ca5c-bea7-0b2f-e2fd-049127441958.png)

# まとめ
ー開発のプロセスを学ぼう

ーウォーターフォール型

ープロトタイプ型

ーアジャイル型、スパイラル型

# 最後に
未経験の皆さん、若手エンジニアの皆さん、勉強方法について悩みがあればなんでも気軽に質問して下さい！
これからも記事を書いていきますので、モチベーションアップのためフォロー、イイねお願いします。
これぞvimシェル芸!?-vimで編集中にファイルの内容をシェルのコマンドで加工する-

## 概要
vimで編集中に、たまにシェルのコマンドを使ってファイル内を加工したい時がある。
わざわざ別のファイルに加工したい箇所を切り出して、vimを一旦抜けたり、ターミナルを新たに立ち上げたりするのは面倒。
`:terminal`コマンドを使えば、vimを抜けずにシェルを操作できるためそこそこ楽。
しかし、もっと楽な方法がある!!
**vimは、指定した範囲を標準入力としてシェルコマンドに渡して実行することができる**
のだ！！
実行結果は、そのままファイル内の指定した範囲に反映される。
vimを抜けることなく、vim内からそのままgrep, awk, sort, sed, tr...などのコマンドが使えるため、かなり強力なテキスト処理が可能となる。

## やり方
やり方は単純で、以下のようにすれば良い。
```vim
" 基本的な書式
:範囲!シェルコマンド
" 具体的な書式
:%!シェルコマンド     " カレントバッファ(編集中のファイル)内に適用
:'a,'b!シェルコマンド " マークした範囲内に適用
:'<,'>!シェルコマンド " ビジュアルモードの選択範囲に適用(ビジュアルモード時に:すると自動で'<,'>が挿入される)
:m,n!シェルコマンド   " m行目～n行目に適用
```
構文自体は`:[範囲][コマンド]`という置換などと同じものだ。`!`はシェルコマンドを意味する。
別の言い方をすると`:!シェルコマンド`に範囲指定を加えただけ、ということ。(※)
しかも、通常のシェルのようにパイプ(`:範囲!シェルコマンド1|シェルコマンド2|...`)を使うことも可能。
(**もちろん、最初からvimを開いていなくてターミナルで作業している場合はそのままターミナルで作業した方が早いです**)
※(補足)そもそもvimは、`:!シェルコマンド`でシェルのコマンドを呼び出せる。
　知らない人は、`:!ls`とかしてみると良いかと。

## 使用例
- 例) 下記のファイルから、"hoge"を含む行を削除する
```txt:編集したいファイル
abc
def
hoge
ghi
jkl
hoge
mno
pqr
hoge
stu
```
```vim
:%!grep -v 'hoge'
```
```txt:実行結果
abc
def
ghi
jkl
mno
pqr
stu
```

- 例) 下記の[]内をアルファベット順にソートする
```json
"cSpell.userWords": [
  "yaegassy",
  "eruby",
  "intelephense",
  "kalisi",
  "autoclosing",
  "autoload",
  "vetur",
  "quots",
  "nvim",
  "mkdir",
  "autoclose",
  "neovim",
  "solargraph",
  "dein",
]
```
```vim
vi]         " []内をビジュアルモードで選択
:'<,'>!sort " 選択範囲をsort(ビジュアルモード時に:すると自動で'<,'>が挿入される)
```
```json:実行結果
"cSpell.userWords": [
  "autoclose",
  "autoclosing",
  "autoload",
  "dein",
  "eruby",
  "intelephense",
  "kalisi",
  "mkdir",
  "neovim",
  "nvim",
  "quots",
  "solargraph",
  "vetur",
  "yaegassy",
]
```

※vimに`:sort`コマンドがあるため、そちらを使った方が良いですが、例として一応挙げておきます。
RailsでDDDってどうなの？そもそもRailsってどんなフレームワーク？

Railsを学習していて発生した素朴な疑問、 **RailsでDDDってどうなの？そもそもRailsってどんなフレームワーク？** に対して自分なりに納得できるよう調査したので記録しておきます。

## RailsでDDDってどうなの？

### DDDって何？
聞いたこともない、という方は[こちら](https://www.ogis-ri.co.jp/otc/hiroba/technical/DDDEssence/chap1.html)
一般に[クリーンアーキテクチャ](https://qiita.com/nrslib/items/a5f902c4defc83bd46b8)とかに相性がいいとされるこのDDD。完全に思想通りと言わずとも（そもそも完全に思想を理解していない）、エンティティを中心に開発するとDBの都合とロジック側の都合とがいい感じに折衝されて、アサインされたプロジェクトに採用されているとちょっと嬉しい設計思想。
完全に理解したい人は[エリック・エヴァンスのドメイン駆動設計](https://www.amazon.co.jp/%E3%82%A8%E3%83%AA%E3%83%83%E3%82%AF%E3%83%BB%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B9%E3%81%AE%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88-Architects%E2%80%99Archive-%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E3%81%AE%E5%AE%9F%E8%B7%B5-%E3%82%A8%E3%83%AA%E3%83%83%E3%82%AF%E3%83%BB%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B9/dp/4798121967)を読んでください。私もいつか読みます。

#### データモデリングと両立する？
データモデリングは、プログラムレベルで業務に従ったドメインを設定することとは両立するという認識です。（[参考記事](https://zenn.dev/yamakii/articles/dd9171e85e8633)）
（モデリングによっては、データモデルとドメインが一致する場合もあると思います。）

プログラマから見た「DDDにしたい」欲求は「DBを意識せずドメインを意識したコントローラー実装がしたい」欲求、というイメージなのかと思います。（著しく間違っていたら教えてください）

#### RailsとDDDの相性は？
結論から言うと、RailsとDDDの相性はあまり良くないみたいです。

DDDに従うということは、ドメインに依存した設計になる、ということであり、つまり依存方向がどの入出力からもドメインに向く、ということだと解釈できると思います。これはDBに依存しない「疎結合」な設計と言えます。（クリーンアーキテクチャっぽい説明ですが）
一方で、Railsの設計思想は、[Rails作者のインタビュー（日本語訳）](https://kdmsnr.com/translations/interview-with-dhh/)からもわかるとおり、**「早くてキレイ」** を目指す代わりに **「インフラレベルの柔軟性を犠牲に」** しています。これは具体的にはDBとActive Record(Model)が対になっており、Controllerから直接Modelを呼び出す方法論までが明確に筋道立てられていることを指すと言えるかと思います。これは結果的に**密結合** になってしまっていると言えます。
ですから、Railsの設計に反さずにDDDを取り入れたいのであれば、実装を簡易化するRailsの道筋から外れずに**いつの間にかドメインに従っている** 状態にしなければならなそうです。うーん、難しい。
RailsでDDDを実現できないか検討している方はたくさんいらっしゃるのですが、[こちらの方のやり方](https://linyclar.github.io/software_development/ddd/rails/)が個人的にはRailsの流れにも沿って自然な感じがしました。取り入れるならこの方法を採用したいです。

## Railsは「Rail」に従うと効果を最大限発揮できるフレームワーク（Laravelとの比較）
今回DDDをテーマにRailsについて調査してみてLaravelと比べる場面が多かったのですが、やはり[Railsの哲学](https://railsguides.jp/getting_started.html#rails%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B)に鑑みても**開発方法を絞った**フレームワークと言えると思います。
[Laravelが様々な開発手法に対応しようとしている](https://readouble.com/laravel/9.x/ja/installation.html)のに対し、[Railsはただ一つの最善の方法を追求しようとして](https://railsguides.jp/getting_started.html#rails%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B)います。
やはりRailsの思想に合う開発はRailsで、それ以外（大規模開発、DDD等）は無理をせず他のフレームワークで（[Hanamai](https://hanamirb.org/)の方が柔軟性高いっぽい、[PHPでいうSlim](https://www.slimframework.com/)に近いのかな？）、という割り切りが大事なのかと感じました。
2023/3/6主にITとかセキュリティの記事

Dish Networkのシステムにランサムウェア攻撃、複数のサービスが利用不能に(3/4)
https://news.mynavi.jp/techplus/article/20230304-2606412/

セキュアブートを有効にしたWindows 11も侵害できるブートキットが登場(3/4)
https://news.mynavi.jp/techplus/article/20230304-2605531/

人をだますソーシャルエンジニアリング、典型的な6つの手口に注意(3/4)
https://news.mynavi.jp/techplus/article/20230304-2605863/

金融庁、銀行クラウドのリスク調査 実態把握へ聞き取り　欧州は25年に監視規制(3/4)
https://www.nikkei.com/article/DGKKZO68978110T00C23A3EA4000/

Internet Explorerを狙ったサイバー攻撃、依然として継続中(3/4)
https://news.mynavi.jp/techplus/article/20230304-2606445/

原燃グループ企業で5千人分情報漏えいか(3/4)
https://www.toonippo.co.jp/articles/-/1511018

北朝鮮の核・ミサイル発射前にかく乱・破壊…「キルウェブ作戦」ＡＩ兵器システムを開発(3/4)
https://www.donga.com/jp/home/article/all/20230304/3998926/1

“世界3位の実力”「天才ハッカー集団」が支援　「もはや実験ではない」北朝鮮ミサイル発射　日本に迫る危機【大阪発】(3/4)
https://news.yahoo.co.jp/articles/cd4a6bcd4593a46d8c65bd01c263f0371f0dc550?source=rss

Coincheck NFTとは？NFTマーケットプレイスの特徴と使い方を解説(3/4)
https://crypto-times.jp/how-coincheck-nft/
【超簡単】RailsでAPI叩いてレシピ検索サイト作ってみた

# 今回のやりたいこと
https://www.edamam.com/ で料理APIを登録し、railsアプリ内でレシピの検索をできるようにする
# Edamamの登録
https://www.edamam.com/

[このURL](https://www.edamam.com/)にアクセスする。
基本情報を入力し、sign upする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/ab9cae8a-b644-e37f-1606-4472831c6d67.png)

右上のAccountsボタンからGo to Dashboardをクリックする。
ApplicationsのCreate a new applicationをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/9dbedd44-2789-e0ef-1891-9d827f3bd814.png)

Recipe Search APIをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/067a281f-1c8e-776e-dfb1-d75a3ae284b1.png)
適当に入力して、Create Applicationをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/cb6f93d9-7662-d7f6-170d-bdead4896967.png)
後で使うので、Application IDとApplication Keysをメモしておいてください
これでEdamamの設定終わり
ちなみに[このリンク](https://developer.edamam.com/edamam-docs-recipe-api)の下記の場所をクリックするとAPIの詳細がわかると思います
![Screenshot 2023-03-06 2.50.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/8d4570d4-fe25-da3e-b879-23370d4c61be.png)

簡単に紹介すると、、、
`https://api.edamam.com/api/recipes/v2?type=public&q=<検索したいキーワード>&app_id=<自分のid>&app_key=<自分のkey>&calories=<検索したいカロリー>`
こんな感じです。

# Railsアプリ
次に、rails側で先ほどのAPIを叩いていこうと思います。
```ruby:Gemfile
gem 'dotenv-rails'
gem 'httpclient'
```
dotenv-railsはenvファイルを扱うためで、httpclientはHTTP通信をするためのGemです。
```terminal:terminal
bundle install
```
アプリケーションディレクトリ直下に.envファイルを作成
```.env
application_id = "自分のApplication ID"
application_keys = "自分のApplication Keys"
```
```.gitignore
/.env
```
ページ表示するためにroute書いてるだけです。
```ruby:routes.rb
  resources :edamams
# どっちでも可
  get "/edamams", to: "edamams#index"
```

```terminal:terminal
rails g controller edamams
```
```ruby:edamams_controller
class EdamamsController < ApplicationController
  require 'httpclient'
  def index
    if params[:search].blank?
      query = "banana"
    else
      query = params[:search]
    end
    client = HTTPClient.new()
    res = client.get("https://api.edamam.com/api/recipes/v2?type=public&q=#{query}&app_id=#{ENV['application_id']}&app_key=#{ENV['application_keys']}")
    @foods = JSON.parse(res.body)
  end
end
```
```html:edamams/index.html
<h1>料理検索</h1>
<%= form_tag({controller:"edamams",action:"index"}, method: :get) do %>
  <p>英語で検索してね〜</p>
  <%= text_field_tag :search %> <br>
  <%= submit_tag '検索する'  %>
<% end %>

<% @foods["hits"].first(5).each do |recipe| %>
  <%= link_to recipe["recipe"]["label"], recipe["recipe"]["url"] %> <br>
  <%= recipe["recipe"]["calories"] %>cal <br>
  <%= image_tag recipe["recipe"]["image"] %> <br>
<% end %>
```
料理名   recipe["recipe"]["label"]
レシピへのリンク   recipe["recipe"]["url"]
料理のカロリー   recipe["recipe"]["calories"]
料理の画像   recipe["recipe"]["image"]

これ以外にも取得できるデータはあるので探してみてください
Postmanで見ればすぐわかるかと思います
![Screenshot 2023-03-06 3.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/af3a6456-9679-5177-05ed-5d64f2ecbc67.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/21c622e4-7cad-a9ff-2038-fd54739a4e81.png)
最後こんな感じになってればオッケです！
終わり〜〜〜
2022年度の学習結果

今年度の活動は完了してるので（勉強分の試験は来年度に回すので）
# 結果
- AWS SAA pass  
- AWS SAP pass  
- Microsoft Azure Administrator pass  
- EXIN Agile Scrum Foundation pass
- CompTIA security+ pass  
- 情報処理技術者試験　プロジェクトマネージャ試験 fail  

## 振り返り
もうベンダ試験系は勉強方法としては大体同じことやってるだけ  
- 参考書と問題集を購入  
- 読み込み　⇒　要点書き出し  
- 本の問題集（あれば）を２周、Udemyの問題集を余裕をもって合格点を取れるまで、誤答は書き出し  
今時ノートに書き出しなんてやりたくないというなら別に頭に入る方法なら何でもいい。  
このあたり学校で自分はどういう憶え方なら頭に入って、どういう憶え方が入らないかの試行錯誤しているはずなので、そのやり方に沿ってやればいい。塾でやった勉強法でもいい。  

## 不合格の反省点
- PM試験は午後2不合格なので論外としても、勉強方法として午後2は単なる暗記なので取りこぼしと試験範囲の網羅を重視して２～３個分問題集解きを徹底。後は午後1の答え探し、午後2の空想作文は組み立てと出題範囲のカバー方法/補完方法で何とかするという方向性は理解している。正直勉強しててツマンナイというのがやる気に問題を与えてるので2023年度さっさと終わらせるという意気込みで時間を割く予定。大したアピールにはならんので、単なる意地の話で。

## 来年度
- Azureもうちょっと
- 上記理由でPM試験をじっくり
- 残りはCompTIAかな。
- ここにまともに書けるような技術系ネタもちょぼちょぼと

## 本業の方ももう少し環境があればね
頑張るのだけど、そもそも「自宅の方が環境がマシ」なレベルの環境しか無い＝エンジニアを舐めてる状況が変わらない以上は、自宅環境構築＋資格勉強でもやってた方がマシ。
アーキテクトもセキュリティも「AI」もやってます詐欺はいい加減止めたらどうかね。内製主義も無理でしょ、優秀な人間からどんどん辞めるような状況を是正しないんだから。
Webアプリ「ラジエーションサプリ」の開発をローコード・ローコストで開発した技術選定について

![スクリーンショット 2023-03-05 21.13.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231246/66be1bce-f387-c7b5-7ad6-b7e0edb25be8.png)

## 概要

「放射線技師国家試験を最短ルートで合格しよう」というコンセプトで、放射線技師国家試験対策Webアプリ「ラジエーションサプリ([URL](https://radiationsupple.com/))」をモダンな技術を使って開発しました。極力をコーディングコスト減らすようにいろんなサービスを使用したサービスになります。本記事では、使用技術・アプリの構成・技術選定理由について説明します。

## アーキテクチャー
※デザインセンスの無さはご愛嬌
![ラジエーションサプリ技術.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231246/05fee2dc-4bbc-defe-c5f3-16ddfb494ba3.png)

## 使用技術
- Next.js(TypeScript)
- Firebase Auth
- MongoDB Atlas
- Newt(ヘッドレスCMS)
- Vercel
- Google Apps Script

## アプリの構成
- コンテンツ：Newt
- 過去問：Googleスプレッドシート
- 認証：Firebase Auth
- デプロイ：Vercel
- データベース：MongoDB Atlas

## 技術選定理由
上記のアーキテクチャーを見てわかるようにデータベース周りが煩雑になってしまっています。なぜこの設計になったのかについて以下で説明します。

### コンテンツ：Newt
大前提に放射線技師学習アプリということでコンテンツは、技師の方々に作成していただいています。記事の追加更新をエンジニアなしで行う必要があります。そのためコンテンツを作成しやすように手軽なヘッドレスCMSを検討しました。Micro CMS, WordPressCMSなども検討しましたが、無料枠でも十分な機能が使えて機能がシンプルだったため、Newtを採用しました。

### 過去問：Googleスプレッドシート
当初、過去問は公式にPDFで無料公開されていたため、そのままDBに保存する予定でした。しかし、PDFをOCR解析すると、試験問題に画像問題が多かった点とOCR解析の精度が悪いという致命的な2点があり、一旦スプレッドシートに書き出して技師の方々にヒューマンチェックをするような工程を踏むようにしました。ヒューマンチェックを行うときに手軽にどの編集ができ一覧のデータみやすいGoogleスプレッドシートを採用した次第です。

### 認証：Firebase Auth
前回のアプリが、Firebaseメインで開発していて慣れていたためです。

### デプロイ：Vercel
nextjsをデプロするサーバとしてはこれ一択です。あとは、CI組まなくてもmainにマージしたら自動的にデプロイしてくれる点やpush時のテストなど、何もしなくてもやってくれて開発体験が素晴らしいです。（昔、Capistranoの自動デプロイ設定で悪戦苦闘していた時を考えると感動です）

### データベース：MongoDB Atlas
DBサーバーのホスティングの手間省ける点とスケーラビリティが高い点で採用しました。テーブル設計は、RDBばかりでNoSQLの設計は苦手ですが、今回はテーブルが少なく、RDBのjoinがmongoDBでもlookup(aggregation)を使えばできるという点もあり、Altasを採用しました。

## こだわった点
### 低コストでローコードでの開発
コンテンツなどの作成には、ヘッドレスCMSとGoogleスプレッドシートを使うことで管理者画面などの作成をカットできました。また、外部のサービスは開発段階では料金がかからないサービスを選択しました。やっぱりお金の心配をしないで良いのは素晴らしいです。

### データの呼び出し
アーキテクチャーは煩雑でしたが、学習記録などのデータの呼び出しは、ISR(Incremental Static Regeneration）を使ってデータを事前に保持しておき、useSWRライブラリを使って非同期通信で最新の情報に上書きするようにしています。これにより、高速なページロードが出来つつ、常に、最新のデータを確認することができます。（Newtのコンテンツなどは、SSGのみ）


## まとめ
放射線技師国家試験対策Webアプリ「ラジエーションサプリ([URL](https://radiationsupple.com/))」の開発について、使用した技術やアプリの構成について説明しました。Newtを使ったコンテンツの提供やISRを使用した学習記録の管理など、最新のWeb技術を駆使して開発を行いました。今後も、より多くの人々が放射線技師国家試験に合格できるよう、ラジエーションサプリを継続的に改善していきたいと考えています。
新時代のレスポンシブ対応!?コンテナクエリが全ブラウザ対応に!!

# コンテナクエリとは

コンテナクエリが2023年2月14日についにFirefoxにサポートされました。
すでに対応済のChrome,Edge,Safariと合わせて、これですべてのブラウザで利用できるようになりました。

レスポンシブ対応でレイアウトを変えるには、メディアクエリ「@media」を使用してウインドウサイズを基準にするやり方が一般的ですが、
コンテナクエリ「@container」を使うことで、任意の要素を基準にできるので、より柔軟で楽なレスポンシブ対応が可能になります。

コンテナクエリのサポートブラウザ
https://caniuse.com/css-container-queries

## コンテナクエリの使用方法

#### 1.基準となるコンテナを決定しタイプを指定

container-typeプロパティを使用して、コンテナのタイプを指定します。
値は3つありますが、横幅を基準とすることが多いので、inline-sizeを使用することが多いと思います。

normal : 通常時の動作となります。
inline-size : インライン方向(通常は横方向)のサイズに応じて異なるスタイルを適用します。
size : インライン方向(通常は横方向)とブロック方向(通常は縦方向)のサイズに応じて異なるスタイルを適用します。

親のコンテナとなる　ul.list に container-type: inline-size を指定します。

```
//inline-sizeを指定の場合
ul.list {
  container-type: inline-size;
}
```
#### 2.クエリを書く

コンテナ幅が大きくなった場合に、下記のようにクエリを指定することで、コンテナ幅に応じてスタイルを切り替えることができます。
メディアクエリとは違って、コンテナ幅に基づいてコンポーネントのCSSを切り替えることができるため、これまでより柔軟でシンプルに記述できるケースが増えそうです。

```
@container(min-width:400px) {
  li.item {
    display: flex;
  }
}
```

## まとめ

コンテナクエリによって、今後のレスポンシブの書き方が変わってくると思います。
また、コンテナ幅で指定ができることで、自由度も増しコンポーネントごとに開発する場合には、非常に便利になりそうです。
すべてのブラウザで利用できるようになったので、これからはどんどんコンテナクエリを使っていこうと思います。
さくらサーバでPHPを実行するときに500 ERRORが発生した時の対処法

# 状況
・手元のPC（MacBook）では正しく動作しているPHPをさくらサーバにUPすると
>500 Internal Server Error
とエラーを吐く。

・サーバコントロールパネル＞サーバーステータス＞アクセスログ＞本日のエラーログを見ても
>AH01215: suexec policy violation: see suexec log for more details

と書いてあるだけで何の事かわからない。

・さくらサーバのよくある質問https://help.sakura.ad.jp/rs/2257/
を読んでも結局何をしたら良いのかわからない。

# 解決法

・「実行」権限を付与していなかった。
（PHPは読み取り権限だけでは機能しないのは当たり前だ。）

ファイルマネージャ＞PHPファイルを右クリック＞プロパティ＞所有者、グループ、全ユーザに「実行」権限をチェックする。（数値で755となれば良い。）


再びアクセスしてみて実行できるか確認する。
WSL2 で ssh サーバを動かす（＋外部から接続）

こんにちは。
WSL2 で ssh サーバを動かし、外部から接続可能としました[^1]。下記のスクリプトを Powershell 上で動かします[^2]。

[^1]: 参考：「[wsl2でsshサーバを起動し、外部からそこに接続](https://qiita.com/yabeenico/items/15532c703974dc40a7f5)」、「[wsl2のsshサーバーに他PCから接続できるよう自動設定する](https://qiita.com/gengen16k/items/18262af0781fd32fc9cd)」
[^2]: PC 再起動後は改めて実行が必要です。

#### 動作例 ####
管理者権限下で、

```powershell
PS> Set-ExecutionPolicy RemoteSigned -Force
PS> .\portproxy_ssh.ps1
OpenSSH_8.9p1 Ubuntu-3ubuntu0.1, OpenSSL 3.0.2 15 Mar 2022
 * Starting OpenBSD Secure Shell server sshd             [ OK ]
Ok.
```

###### コマンドライン上で動かす場合の例 ######
```bat
> %Systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy RemoteSigned c:\temp\portproxy_ssh.ps1
```

#### スクリプトソース ####

```portproxy_ssh.ps1
# Encoding::Shift-JIS

# ip service
sc.exe query iphlpsvc | findstr -i state | findstr -i stopped
if ( $? ) {
  sc.exe start  iphlpsvc
  sc.exe config iphlpsvc start= auto
}

# network (WSL2)
$Distribution = "Ubuntu"
$Port = 22
wsl -d $Distribution -- ssh -V
if ( $? ) {
  wsl -d $Distribution -u root -- service ssh restart
  $IP = (wsl -d $Distribution exec hostname -I).Trim()
  netsh advfirewall firewall add rule name="sshd" dir=in action=allow protocol=TCP localport=$Port
  netsh interface portproxy add v4tov4 listenport=$Port connectaddress=$IP connectport=22
} else {
  echo "Please install openssh into $($Distribution): `"sudo apt install openssh-server`""
}
```
Swift モーダル画面が閉じたことを検知する方法

iOS13から特定のスタイルでモーダル遷移をすると画面を閉じた際、 遷移元のライフサイクルメソッドが発火されない仕様になったのを今更知知りました。
画面を閉じた際、遷移元のviewWillAppearで画面表示時に毎回ある処理をさせたかったのですが、モーダルを閉じた際の検知で代用することにしました。


閉じた際の検知はUIAdaptivePresentationControllerDelegateのpresentationControllerDidDismissメソッドを使って特定できるみたいです。

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229889-presentationcontrollerdiddismiss

中身としては以下のように画面遷移する際にpresentationControllerのdelegateを自身にセットします。

```swift
// 遷移元コード全体
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    // ボタンを押したら遷移する処理
    @IBAction func button(_ sender: Any) {
        transitionToSecondVC()
     }
    
    private func transitionToSecondVC() {
        guard let vc = UIStoryboard(name: "SecondVC", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as? SecondVC else {return}
        
        vc.modalPresentationStyle = .overFullScreen

        // delegateを自身に委任
        vc.presentationController?.delegate = self
        self.present(vc, animated: true)
    }
}

extension ViewController: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        print("VC didDismiss")
    }
}
```

ただこれだけ書けば遷移先でdismissしたら発火するわけでも無いみたいで、さらに遷移先でdismissする時に親のpresentationControllerDidDismissメソッドを呼び出す必要があるらしいみたいです。

```swift
// 遷移先コード全体
class SecondVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    // 閉じるボタンで画面を閉じる処理　
    @IBAction func closeButton(_ sender: Any) {

        // dismiss前にpresentationControllerDidDismiss(_:)を呼び出す
        if let presentationController = presentationController {
            presentationController.delegate?.presentationControllerDidDismiss?(presentationController)
        }
        self.dismiss(animated: true)
    }
}
```

こうすることで.overFullScreenで表示したSecondVCがdismissした時に、遷移元のViewControllerの print(“VC didDismiss”)が出力されるようになりました。


またモーダル画面先でナビゲーションコントローラーを使用する場合は下記のように実装します。

```swift
   private func transitionToSecondVC() {
        guard let vc = UIStoryboard(name: "SecondVC", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as? SecondVC else {return}
        
        let nav = UINavigationController(rootViewController: vc)
        nav.modalPresentationStyle = .overFullScreen

        // navigationControllerのpresentationController delegateを自身に委任
        nav.presentationController?.delegate = self

        self.present(nav, animated: true)
    }
```


そして遷移先で閉じるときはnavigationControllerのpresentationControllerを引数に入れてメソッドを呼び出します。

```swift
   if let presentationController = self.navigationController?.presentationController {
       presentationController.delegate?.presentationControllerDidDismiss?(presentationController)
   }
```

とりあえずこうすれば画面を閉じた時の検知ができるので、発火されないViewWillAppearの代わりとして使用できそうです。
これが最適かは分からないですが、とりあえず現状これ以外のいい方法は分からなかったです。

終
ChatGPTが怖いぐらいに凄い（ChatGPT操作例 ）

以下はChatGPTの操作例です。怖いぐらいに凄いので細かいことは書きません。

以下の2つの質問をするだけで、たまにしか使わないから、忘れがちなpandasのgroupbyを含むfunctionを豊富な解説付きで作ってくれます。

# 質問した内容
1.  以下のデータで月を入力としてccode,volumeの月ごとの中央値を返すルーチンを作って+数十行のcsvサンプル
1. 上のプログラムをサブルーチン化して

# ChatGPTの作ったfunction
```py
import pandas as pd

def calc_median_volume_by_month(df, month):
    # datetime型の列を作成
    df['date'] = pd.to_datetime(df['date'])
    # 指定された月のデータのみを抽出
    df_month = df[df['date'].dt.month == month]
    # ccodeとvolumeのみを抽出
    df_month_volume = df_month[['ccode', 'volume']]
    # ccodeでグループ化し、中央値を計算
    median_volume_by_ccode = df_month_volume.groupby('ccode').median()
    return median_volume_by_ccode
```

# 以下は実際のやり取り
* 質問
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653429/5ba3169a-1df8-f6aa-f2c4-bae94c12b4a5.png)
* ChatGPTの回答 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653429/f1bbdfb5-ebc1-0db9-abb8-cbe4b18af2df.png)
    * 恐ろしいポイント->サンプルデータに日付列がないことをやんわり、指摘してくれる
* 質問
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653429/53e862d5-b841-84c6-46bf-8932eb8d610a.png)


* ChatGPTの回答 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653429/cc8396af-7d8b-ad19-d5b7-7e9aa150a6b8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653429/5fa97921-bf0e-ff87-4cbc-80c0237c2cd0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653429/4e5b1d6c-5e83-caa7-67ca-3877d8ede0be.png)

* 上記の関数は、documentを調べながら書いたら、1時間以上かかってしまう。それが2行の質問で出来てしまうのだからすごい。 半面、数十年前に解散したマイナーな音楽グループに関して聞くとデタラメな内容を堂々と答えてくれた。回答の精度は集められた情報量によるのだと思う。なので、みんなが話題にすることは回答の精度が高く、そうでないものはデタラメ率が高い。気を付けて使わなければいけないと思う。