OmniAICreator/Qiita-1.07M huggingface dataset:
Ruby on RailsでURLにスラッグを使用する

# はじめに
学習用のメモとして投稿します。
先日[RealWorld](https://github.com/gothinkster/realworld/tree/main) という OSS のプロジェクトで、APIのエンドポイントを実装する機会がありました。
そのAPIスペックに、スラッグの使用が含まれていたので、どのように実装したかについて書いていきます。

# APIスペック
RealWorldでは、ブログ投稿プラットフォームを作っていきます。
多くのエンドポイントがありますが、今回はスラッグに関する部分のみに絞ります。
### ①記事の作成
- リクエスト
`GET /api/articles/:slug`

- レスポンス
```json
{
  "article": {
    "slug": "how-to-train-your-dragon",
    "title": "How to train your dragon",
    "description": "Ever wonder how?",
    "body": "It takes a Jacobian",
    "tagList": ["dragons", "training"],
    "createdAt": "2016-02-18T03:22:56.637Z",
    "updatedAt": "2016-02-18T03:48:35.824Z",
    "favorited": false,
    "favoritesCount": 0,
    "author": {
      "username": "jake",
      "bio": "I work at statefarm",
      "image": "https://i.stack.imgur.com/xHWG8.jpg",
      "following": false
    }
  }
}
```
### ②記事の投稿
- リクエスト
`POST /api/articles`
```json-doc
// リクエストボディ例
{
  "article": {
    "title": "How to train your dragon",
    "description": "Ever wonder how?",
    "body": "You have to believe",
    "tagList": ["reactjs", "angularjs", "dragons"]
  }
}
```

- レスポンス
```json
{
  "article": {
    "slug": "how-to-train-your-dragon",
    "title": "How to train your dragon",
    "description": "Ever wonder how?",
    "body": "You have to believe",
    "tagList": ["reactjs", "angularjs", "dragons"],
    "createdAt": "2016-02-18T03:22:56.637Z",
    "updatedAt": "2016-02-18T03:48:35.824Z",
    "favorited": false,
    "favoritesCount": 0,
    "author": {
      "username": "jake",
      "bio": "I work at statefarm",
      "image": "https://i.stack.imgur.com/xHWG8.jpg",
      "following": false
    }
  }
}
```


# 実装: マイグレーション
`GET /api/articles/:slug`でスラッグは記事特定に使用されているため、データベースに保存する必要があります。
また、レスポンスの内容を見ると、スラッグはタイトルをベースにした内容になっています。
そうすると、①スラッグはuniqueである必要があり、②スラッグのベースとなるタイトルもuniqueである必要があります。

```ruby
class CreateArticles < ActiveRecord::Migration[7.0]
  def change
    create_table :articles do |t|
      t.string :slug, null: false, unique: true
      t.string :title, null: false, unique: true
# ... 略
```

# 実装: モデル
`POST /api/articles`でリクエストボディにスラッグは含まれないため、こちらで作成する必要があります。そこで、タイトルからスラッグを作成するメソッドを作成し、データベースに保存する前に呼び出すようにします。スラッグの作成には色々な方法が考えられますが、今回のAPIスペックを満たすためには、rails6で追加されたparameterizeメソッドで実装できそうだったので、これを使用しました。

また、URLでidではなく、スラッグを使用するために、to_paramメソッドをオーバーライドします。
```ruby
class Article < ApplicationRecord
  before_save :generate_slug
  validates :title, presence: true, uniqueness: true

  def generate_slug
    self.slug = self.title.parameterize if title.present?
  end

  def to_param
    slug
  end
# ... 略

```

# 実装: コントローラー
記事の作成に成功すれば、データベースには、uniqueなスラッグが書き込まれているはずです。
これでスラッグを条件にしてデータが取得できるようになります。

```ruby
@article = Article.find_by(slug: params[:slug])
```

参考にした記事

https://qiita.com/jkr_2255/items/bf8ad8d8a951b8c7b05e

https://luisreyesbartolome.medium.com/a-practical-example-of-using-url-slugs-for-your-rails-parameters-instead-of-ids-3d6759f30125
LazyListで謎のコンポジションが発生する


## はじめに
原因も解決策もわかってません。
ただそういう事象が発生するという共有です。

## 本題
LazyColumn, LazyRowどちらも、画面内にない要素のコンポジションが発生します。

たとえばこういうシンプルなLazyColumnがあったとして
```kotlin
LazyColumn {
   items(100) { i ->
      Box(
         Modifier
            .fillParentMaxWidth()
            .height(48.dp)
      ) {
         Text("$i")
      }
   }
}
```

画面の一番上に10、一番下に40が表示されていたとします。

こういう状態です。
```
  |-------------|
  | 9           |
  |             |
  |             |
  |-------------|
  | 10          |
+-----------------+
|                 |
|-----------------|
|   11            |
|                 |
|                 |
|-----------------|
|                 |
|        :        |
|        :        |
|                 |
|-----------------|
|   39            |
|                 |
|                 |
|-----------------|
|   40            |
+-----------------+
  |             |
  |-------------|
  | 41          |
  |             |
  |             |
  |-------------|
```

このとき、9と41が高頻度でコンポーズされることがあります。

下(41がある方向)にスクロールするとき41がコンポーズされて上(9がある方向)にスクロールするとき9がコンポーズされます。
つまり発生条件は『上下に細かくスクロールしたとき』なので、最も基本的なスクロールをする使い方だけだと発生しません。
スクロール中に指を止めたときに発生することはあります。人間の指は止めているつもりでも細かく震えていますからね。

ちなみにCompose for Desktopでは発生しません。 ~~Androidだけです。~~ いやiOSとWebは試してないのでもしかしたらAndroidだけではないかもしれないです。とりあえずDesktopでは発生してませんでした。

このコンポジションは *スキップされません。*
たとえ引数に何も受け取らなくても、です。
```kotlin
LazyColumn {
   items(100) {
      Content()
   }
}

@Composable
private fun Content() {
   Box(
      Modifier
         .fillMaxWidth()
         .height(48.dp)
   ) {
      SideEffect {
         Log.i("Composed")
      }

      Text("Text")
   }
}
```
たぶんリコンポジションではないんだろうなと思って先程から「コンポジション」と表記しているわけです。

この例ではLazyColumnを使いましたがLazyRowでも同様の現象が発生します。
内部的にLazyLayoutを利用しているHorizontalPagerとVerticalPagerも同様です。

## 原因
わからん。

ソースコード的には画面内にある要素しかコンポジションしてないしデバッガで止めてみても実際画面内しかコンポジションしてないように見える。
そしてLazyLayoutのコードがデカすぎて追い切れず諦めました。

## 対策
LazyListの要素のコンポジションが重くなること自体があまりないからそこまで気にしなくてもいいのかもしれません。
というか、話題になっていないあたり、実際問題にならないことが多いのでしょう。
ただPager系は重くなる可能性もあるので気にしておいたほうがいいかも？

当たり前ですが `remember` していようが再実行されますので重い処理を `remember` しておく対策はここでは使えません。
やるとしたらLazyList外でrememberすることになります。

危ない書き方
```kotlin
HorizontalPager(
   pageCount = 2
) { page ->
   when (page) {
      0 -> {
         Page0(list)
      }
      1 -> {
         Page1()
      }
   }
}

@Composable
private fun Page0(
   list: ImmutableList<Hoge>
) {
   val sortedList = remember(list) { list.sorted() }
}
```

比較的安全な書き方
```diff_kotlin
+ val sortedList = remember(list) { list.sorted() }

  HorizontalPager(
     pageCount = 2
  ) { page ->
     when (page) {
        0 -> {
-          Page0(list)
+          Page0(sortedList)
        }
        1 -> {
           Page1()
        }
     }
  }

  @Composable
  private fun Page0(
-    list: ImmutableList<Hoge>
+    sortedList: ImmutableList<Hoge>
  ) {
-    val sortedList = remember(list) { list.sorted() }
  }
```

## まとめ
- LazyListはユーザーの操作次第で要素が高頻度でコンポジションされうる
- LazyListを利用しているPager系も同様
- このコンポジションはスキップされない
- 要素内で重い処理をするのはなるべく避けよう。rememberしても無駄なので、重い処理は可能ならLazyList外でやる方がいい
Twitterに不正なアカウント扱いをされたので解除するまでの話

# 「きれいな顔してるだろ、止まってるんだぜ」
いくつか運営しているサイトの一つで、
TwitterAPI経由で新着情報を発信してたところ
荒ぶる小鳥に怒られたのと、
アカウントのロックの解除があっけなく終わったんで、
そのレポートです。

## 結論
Twitterにブラウザからログインして、
クリックひとつでアカウントのロックが解除される。
特別なことはまったく不要。

以下は余談。

# 経緯
今月の頭ぐらいからTwitter API経由でのTweetを開始する。
内容は新着情報の発信のみで、いわゆるBotってやつです。
自分がほしい情報が中心なので、一番のユーザーは自分状態。
それで、朝一番でみてみたら止まってたんで、
調べてみたら小鳥に威嚇されてる状態だった。

## 技術的なメモ
- 元ネタは自動作成させている記事。情報源（情報API有り）のデータを記事化したもの
- そのBlogのFeedを定期的に取得し、tweepyでTweet
- 頻度は30分に一回Tweet
- 内容は、Feedから取得した下記の要素を140文字以内で
    - タイトル
    - 本文
    - タグ（categoryをハッシュタグ化）
    - 記事URL
- 同じ記事が投稿されないように制御
- ネタが尽きたときは投稿しない
    - なので、投稿数は max 48 tweet/day
    - 仕組み上最低でも一日 24 tweetは発生する
        - BlogはChatGPT APIで一時間に一本自動生成させてるので

## 対応したこと
まずは、[Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard)を開いて、
APIが反応しているか確認。
※自分の実装がうまく行ってなかったのかと考えたので
![Twitter Dev Portal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/19808a86-92c6-ed6f-5985-7fb4ede8d2ee.png)


Twitter.comへ行けと書いてあるので、素直に従う。
![Twitter rock.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/1920afc7-d7a6-0328-f12c-61d7b5bc4730.png)
ロックされていると書いてある。

書いてあるとおり、ロックの解除を試みる。

![Twitter unrock.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/9a1db991-e9d9-97d4-5078-2c8fb43374c9.png)

何もしないでロック解除。

なんか、あっけなかったので肩透かしを食らったのだけれども、
せっかくキャプチャーも取ったのだから
（なんか、難しいミッションでも出てくるのかと思ってた）
情報共有かわりに記事にしてみました。
【Mac】プレビュー機能だけでPDFに画像を貼り付ける

JPEGに書き換えたり、ソフトを使ったりとネットには色んな方法が載っていますが、以下のサイトの一番目の方法を発見して感動しました。画像のサイズを後からも自由に調整できるので、めっちゃ便利です！

https://yama-mac.com/pdf_insert_picture/#toc2
kubernetesとはなにか簡単に図解してみた

初心者です。
文は、ムズカシいので、図形だけで説明しました。

```mermaid
flowchart LR
	
    subgraph kubenetes
        subgraph Node
        kubelet
        Docker
        kube-proxy
        end

        subgraph master
        kube-apiserver
        kube-schedule
        kube-controller-manager
        etcd
        end
    end

	subgraph User
    kubectl
    end
	
	kubectl-->kube-apiserver
	kubelet-->Docker
	kubelet-->kube-apiserver
```

まずはこれでいい気がします。
Userはkubectlを使用してkube-apiserverへ指示することができるのがわかると思います。
他の機能も気になりますよね。内緒です。次回をお楽しみに。
信頼区間を用いて株式の平均リターンを見積もる

　本稿ではpythonを使用して信頼区間から株式の平均収益を見積もる。
　前回の記事と同様、今回もトヨタ自動車(7203)を対象に分析を行う。
```python
# 使用するモジュールのインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os
import datetime as dt
import pandas_datareader.data as web
from scipy.stats import norm

# ticker入力 (今回はトヨタ自動車)
ticker_symbol="7203"
ticker_symbol_dr=ticker_symbol + ".JP"
 
# 期間の指定
start='2003-01-01'
end = dt.date.today()
 
# データ取得
toyota = web.DataReader(ticker_symbol_dr, data_source='stooq', start=start,end=end).sort_values("Date")
```

　これでサンプルの用意はできたが、このサンプルが母集団の"良い代表"であれば、母集団の平均は標本平均に近くなる。少なくとも、母集団の平均は標本平均を中心としたある一定の範囲内にあると考えられる。
　そのため、この分析において我々が行うべきことは、母集団の平均が位置する範囲を見積もることである。

　そのためには、異なるサンプルは異なる平均と標準偏差を持つため、標本平均を標準化する必要がある。
　ご案内の通り、標本平均の分布は正規分布である。標本平均を標準化するためには母集団の平均から標本平均分布の平均を引き、母集団の分散を標本サイズnの平方根で割った標本分散で除する必要がある。

```math
\frac{\bar{x}-\mu}{\frac{\sigma}{\sqrt{n}}}
```

　標準化した後は標準正規分布となり、これはZ分布に従うようになる。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3356009/106d8812-1a8d-ff26-3e95-6a4b9c0ad24c.png)

　この分布における$Z_\frac{\alpha}{2}$と$Z_{1-\frac{\alpha}{2}}$の間の確率は$1-\alpha$となる。Z分布は0を中心に左右対称となるので、$-Z_\frac{\alpha}{2} = Z_{1-\frac{\alpha}{2}}$となる。
　標本平均の標準化した形もZ分布であるため、

```math
P(Z_\frac{\alpha}{2} \leq \frac{\bar{x}-\mu}{\frac{\sigma}{\sqrt{n}}} \leq Z_{1-\frac{\alpha}{2}}) = 1 - \alpha
```
　を得られる。これを式変形すると以下のようになる。
```math
P(\bar{X} - \frac{\sigma}{\sqrt{n}}Z_\frac{\alpha}{2} \leq \mu \leq \bar{X} + \frac{\sigma}{\sqrt{n}}Z_\frac{\alpha}{2}) = 1-\alpha
```
　これは、母集団平均、すなわち期待リターンの上限と下限を示してくれるものである。
　この$\sigma$は母集団の標準偏差であり通常はわからない値である。しかし、実務上はサンプル数が十分に大きければ標本標準偏差に置き換えて計算してしまうことができる。
　ここで、$\mu$の範囲は「$1-\alpha$のレベルの信頼区間」を呼ばれる。

　それでは、実際にトヨタの平均リターンを見積もってみる。ここでの$\frac{\alpha}{2}$は0.05とした(すなわち、信頼水準は90%である)。

```python3
# Lets build 90% confidence interval for log return
sample_size = toyota['LogReturn'].shape[0]
sample_mean = toyota['LogReturn'].mean()
sample_std =toyota['LogReturn'].std(ddof=1) / sample_size**0.5

# left and right quantile
z_left = norm.ppf(0.05)
z_right = norm.ppf(0.95)

# upper and lower bound
interval_left = sample_mean + z_left * sample_std
interval_right = sample_mean + z_right * sample_std
```

　結果として、トヨタの平均収益は90%の確率で、
(-0.00013182221183375743, 0.0006855071186437733)
に収まることが分かった。
　ここでもし下限の値がプラスであれば、その銘柄は強い上昇トレンドにあるということが言えるだろう。
PDFをパワーポイントで編集する方法


## 利用シーン

たとえばこういう申込書がPDFで配布されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/ad5ae909-fd63-2468-8e05-b6d6b32c2f81.png)
https://www.pref.saitama.lg.jp/documents/195633/syupinnmousikomisyo.pdf


印刷して書いて出せばいいだけなんだけど、手書きの書き損じがどうしても発生するのがいや。
自分の住所の長さの見積もりと記入欄のバランスでうまくいった試しがない。
そこでPC上でPDFに直接記入する方法を試行錯誤しておすすめできる方法がこれ。

## 概要

1. PDFをSVGに変換する（pdf2svgコマンド）
2. PowerPointをA4縦置きの用紙設定の文書を開く
3. SVGを取込む
4. オートシェイプで編集
5. 印刷機能でPDFにする

## 各操作方法

### PDFをSVGに変換する（pdf2svgコマンド）

pdf2svgコマンドがなければインストールする。poppler-utilsをインストールすると一緒に入る。

こちらでありとあらゆるインストール方法が紹介されている。

- Windowsならバイナリのインストーラーを使うのがいい
- Macならbrewで入る
- Ubuntuならaptで入る

https://texwiki.texjp.org/?Poppler


変換を実行

ブラウザからPDFを手元PCにダウンロードしてpdf2svgコマンドでsvgに変換する

```
pdf2svg pdfファイル名 svgファイル名
```

これでsvgファイルを作成。意外に速い。

### PowerPointをA4縦置きの用紙設定の文書を開く

A4縦置きのPDFがほとんどなので、PowerPointの用紙設定もA4縦置きにする。
A4縦置きは、21cm x 29.7cm なので、その設定をする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/9b7c0004-ed2a-62ae-dd90-32858211810b.png)


### SVGを取込む

PowerPointのページにSVGファイルをドラッグ＆ドロップでOK。
A4のPDFから生成したSVGはA4で作られてるのでA4のPPTにピッタリフィットするはず。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/0313e973-4c75-bcff-e231-0419914d859e.png)

### オートシェイプで編集

ここからはオートシェイプで上から編集をするだけ。
手書きでは難しい小さな領域でもやりなおし可能できれいに記入できる。
自署でかくべきサイン欄や、郵送直前に書き込みたい日付欄だけは残しておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/1a6ba364-01e9-06e5-dd5f-b50b2220caa1.png)


### 印刷機能でPDFにする


あとはリアルな作業のみ

- コンビニプリントで印刷
- レターパックを買って宛名をかく（これは手書きでないとダメ）
- ポストに投函

ローソンなら、[ネットワークプリントサービス](https://networkprint.ne.jp/sharp_netprint/ja/top.aspx)があってポストもあるので一箇所で完結する。

## 代替手段

今回はPowerPointを使ったけど当然他の手段もありえる。
いずれもいまいち。
特に元テキストもいじれる形に変換するのは体裁が崩れる。
元PDFは背景として使いたいだけなのだ。

- PDFを直接開く
    - Wordで開く
        - Word形式に変換するため体裁が崩れる
    - GoogleDocument
        - GoogleDocument形式に変換するため体裁が崩れる
- PDF2PPT
    - フォントが置換される
- Illstrator
    - PDFも編集できる
    - そんなにみんな持ってない（私も持ってない）
- AdobeAcrobat
    - PDF周りではデフォルト
    - 有料版ではないと編集できない
- Inkspace
    - 無料なのでこれがIllstratorの代替として一番近い
    - 滅多に使わないので操作に慣れが必要
- AdobeAcrobat Online
    - https://www.adobe.com/jp/acrobat/online/pdf-to-ppt.html
    - 無料で使える
    - 元テキストも編集可能なpptx形式にしてくれるので本当に再編集できる
    - 元テキストも再編集可能にした途端に体裁がちょっとだけ崩れる（かなりいい線いってるが元PDFをの体裁崩れはゼロにしたい）
- SVGをGoogleSlideで取り込んで同じことをしたい
    - パワポで行けるならGoogleSlideでも同じことできそう
    - だけどGoogleSlideはSVGを取り込めなかったのでボツ
- PowerPoint Onlineでは？
    - 純正PowerPointのライセンスにお金を払いたくない
    - 無料で使えるPowerPoint Onlineではどうだろうか
    - PowerPoint Onlineは用紙設定ができないのでボツ
- 手書きで出す（実はこれが一番の競合手段）
    - 書き損じを想定して複数印刷してから手書きをする
    - 間違ったら二重線＋訂正印という慣習もあるし恥じることではない
    - レターパックで宛名を書いてる時点で手書きで住所を書いてる。お前は手書きで長い文章を狭い記入欄に書けるやつだ。お前はできる！がんばろうニッポン！
【Windows】PgAdmin4を使用してローカル環境で利用する。

## 手順メモ
https://www.pgadmin.org/download/pgadmin-4-windows/
公式サイトから最新版を選択してダウンロードする。
ダウンロード完了後はexeファイルをダブルクリックしてインストールする。

pgAdmin4を起動。
画面左上のServersを右クリックしてRegister→Serverを選択。

Generalタブのnameには任意の名前を入力。

Connectionタブを選択。
ローカル環境に接続したいので、
Hostname/addressに「127.0.0.1」と入力。
usernameとpasswordを入れて、「Save」ボタンを押下する。

>備考：127.0.0.1とは
>「127.0.0.1」＝ループバックアドレス＝「自分」を意味するIPアドレス
> https://wa3.i-3-i.info/word17065.html

>username：
Usernameはpostgresqlでsuperuserに設定したアカウント名を通常は入力してください。
もし、superuserのアカウントがわからない場合はデータベースをpsqlで立ち上げて「\du」コマンドを入力してください。
引用記事：
https://qiita.com/prg_mt/items/c5c8edbf45dfe87b54ef

Saveボタンを押下した際、下記エラーが出たら、パスワードに誤りがある可能性あり。
「サーバに接続できません:connection failed:FATAL:password authentication failed for user "xxxxx"〜」

https://www.postgresql.jp/document/7.4/html/client-authentication-problems.html

http://a23.sblo.jp/article/186677663.html

自分はこのパスワード認証で詰まっていたが、
対象ユーザのパスワードを変更したところ、
正常にサーバに接続ができるようになった。

```
psql

↓

ALTER USER ユーザ名 PASSWORD 'xxxxxxx';

```
.NetFrameworkのクライアントと.NetCoreのサーバでAzureSignalRを介して会話する

# やりたいこと
.NET Frameworkで動作するwindowsアプリと、サーバ(Azure上のWebApp)の間でリアルタイム通信をしたい。通信にはAzure SignalRを使いたい。

## 疑問
* Azure SignalR ServiceはASP.NET Core SignalRをベースとしている。.NET Frameworkで動作するアプリからASP.NET Core SignalRを使用することは可能か？

## 確認結果
* [このページ](https://learn.microsoft.com/en-us/aspnet/core/signalr/version-differences?view=aspnetcore-2.1#how-to-identify-the-signalr-version)に、ASP.NET Core SignalRのクライアントには[Microsoft.AspNetCore.SignalR.Client](https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client/)を使用するという記載がある
* [Microsoft.AspNetCore.SignalR.Client](https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client/)を見ると、.NET Framework4.6.2以上と互換性があると書いてある

## やってみる

### サーバ
* Azure上にSignalR Service/AppServiceをデプロイ
* AppServiceには[このサンプル](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/ChatRoom)をそのままデプロイ(Azure SignalR Serviceの接続文字列はデプロイしたものに合わせて変更する)

### クライアント
* [これ](https://learn.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-2.1&tabs=visual-studio#connect-to-a-hub)を参考に下記のようにコーディング

```C#
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private HubConnection _connection;
        public Form1()
        {
            InitializeComponent();
            _connection = new HubConnectionBuilder().WithUrl("https://webappのドメイン/Hubの名称").WithAutomaticReconnect().Build();
        }


        private async void btnConnect_Click(object sender, EventArgs e)
        {
            _connection.On<string, string>("broadcastMessage", (user, message) => {
                MessageBox.Show(message);
            });

            try
            {
                await _connection.StartAsync();
            }
            catch (Exception ex)
            {
            }
        }

        private async void btnSend_Click(object sender, EventArgs e)
        {
            await _connection.InvokeAsync("broadcastMessage", txtName.Text, txtMessage.Text);
        }
    }
}

```

### 動かしてみる
通信できた！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77403/fb86f415-ba05-f0e0-3264-17b8bd36f954.png)
【ChatGPT無】人物のサンプルデータをいじくる。

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

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

　今回は、
　　人物のサンプルデータを
　　　ChatGPTさんに作成してもらい、
　　　　それをあれこれしました。

>こんにちは。
サンプルリストが10件欲しいです。
姓名、フリガナ、性別、年齢です。
お願いします。

　で、10件分、出してくれます。
　　どの名前も、
　　　どこにいても
　　　　おかしくない名前です。

>ありがとう。
このリストをテーブルで表示して。

　うん、
　　ちゃんとマークダウン記法の
　　　テーブルです。

>フリガナでソートしてもらえますか？

　うん、
　　ちゃんとソートしているわ。

>それから性別は♂♀で、年齢は「歳」を除いて表示してください。

　うん、変わった。

　で、次に、
　　今までの指示を
　　　まとめてもらいました。

>ここまでの指示をまとめてください。

>以下は、指示のまとめです。
>
>1.サンプルリストのテーブル表示
>・カラム: 姓名、フリガナ、性別、年齢
>・10件のデータを表示
>2.ソート
>・フリガナで昇順ソート
>3.表示の修正
>・性別を「♂」と「♀」で表示
>・年齢から単位の「歳」を除いて表示

　そのあと、
　　男女別に分けたり、
　　　フリガナで
　　　　逆順にソートして
　　　　　もらいました。

　この逆順のソートで、
　　問題が発生しました。

　ヤマさんが、
　　一番最初に出るはずが、
　　　タカさんが頭に出てきました。
　　　　ヤマさん、二番目です。

　指摘したら、
　　直りましたけど

　こういうところで、
　　ポカするChatGPTさん、
　　　カワイイ、と許すか。
Django 初期設定

# Django 導入と初期設定

### venvを使った仮想環境の作り方
　　
ターミナルで、仮想環境を作りたいディレクトリに移動
```
$ python3 -m venv <仮想環境名>
```
(仮想環境名は **venv**　や　**myvenv** など任意でよい)
　　
　　
binディレクトリに移動して、「activate」を実行

```bash
$ source myvenv/bin/activate
```
または
```
$ cd my_venv/bin
$ source activate
```
　　
### プロジェクトとアプリケーションの作成
次に仮想環境にdjangoをインストールする
```
$ pip3 install django
```
python3の環境を使う場合はpipではなくpip3と明示することで、Python3環境に紐づけることができる。
　　　　
　　
djangoのプロジェクトを作る
configにしとくと分かりやすい
（プロジェクト名やアプリケーション名にすると同一の名前で重複するので、ディレクトリがごちゃごちゃしてしまう）
```
$ django-admin startproject config .
```
　　
　　
プロジェクトを構成するアプリケーションを作る
仮想環境化のプロジェクトディレクトリで
```
$ python3 manage.py startapp todo
```
todoの部分が任意のアプリケーション名
　　
　　 
configのsetting を編集
【探したり移動するのに便利なvscodeのショートカット　　command + f 】
　　
TEMPLATESのDIRSを編集
```
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
```
manage.pyファイルがある階層にtemplatesフォルダを作成する
　　
  
```
TIME_ZONE ='Asia/Tokyo'
LANGUAGE_CODE='ja'
に設定する
```
  
新しいアプリケーションを作成したら、
setting.pyのINSTALLD_APPSの配列に
アプリケーション名を追加する。
```
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'todo.apps.TodoConfig',
]
```

  
さらに
STATIC_ROOT= os.path.join(BASE_DIR, 'static')
//staticはcssなど静的ファイルの場所でありこれの場所を明示する

ターミナルに戻り
cd  プロジェクト名　mkdir static
//上で記述したstaticフォルダを作る



理由：djangoのテンプレート機能がそのアプリケーション内にあるtemplatesフォルダを検索できるようにするため。
テンプレートはプロジェクトフォルダ内のアプリケーションフォルダの中にtemplatesフォルダを作りその中にアプリケーションと同名のフォルダを作る。
その同名フォルダにhtmファイルを作りhtmlを記述する。
  
  
### URLの繋ぎこみをする
configの中のurls.pyを編集する
```py:urls.py
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('todo.urls')),
]
```
  
アプリディレクトリの中にurls.pyファイルを作り、中身はconfig内のurls.pyをコピペし
adminだけ残す
　　
```py:urls.py
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
]
```
[読書感想] "ネットワークはなぜつながるのか第2版"

# 感想
なんとなくケーブルで繋いでいたルータやモデムの中身について知ることができて嬉しかったです。毎月お金払って回線を契約させてもらってるプロパイダがどんなことをしているのかも知れました。パケットが作られていく過程やそれが読まれていく過程など詳しく説明されていました。

## 内容振り返り
1. webブラウザがプロトコルスタック(OS)に依頼するまでの流れ
    -  httpリクエストを作るためにもすることがたくさんある
    -  URLから欲しいファイルを特定する
    -  それがおかれているサーバーのIPアドレスを特定する(DNS)
    -  ソケットライブラリを呼び出してソケットの作成/接続/送受信/切断する
2. プロトコルスタックがLANアダプタに信号を送るまでの流れ
    -  ウィンドウサイズを守りながら送受信する
    -  データが大きいときは小さく分けて漏れに注意しつつやりとりする
    -  ACK, SYNなどで通信を管理する
3. スイッチとルーターの中身について
     - ケーブルの仕組み(よりで信号の劣化をふせぐ)
     - ルータは経路表で案内する
      - リピータハブは全部に案内する
      - スイッチングハブはアドレステーブルで案内する
  4. プロパイダの中身について
      - 電柱、地下、電話局などを伝ってNOCにたどり着く
      - ADSLについて
      - IXがすごい
  5. サーバーの手前まで
     - ファイアウォールはパケットのあて先とどこから来たかで判断する
     - 中身を見ないから正しいポートを指定したうえで悪いパケットを防げない
     - サーバーは複数あることもある
     - キャッシュサーバーでも負荷を減らせる
 6. サーバーが返答する
     - ソケットの切断処理など
     - クライアントが返答を画面に表示して終了


# 読みやすかった
去年の講義で買わされたまま積みっぱなしだった本を読んでみたらとても面白かったのでまとめてみました。作者さんが本への質問に答えてくれるサイトを用意してくださっており、現在も定期的に質問が投げられているようでした。
久々に本を読みました。皆さんのおすすめの本があれば教えてくれると幸いです！
ありがとうございました。
ネストしたオブジェクトの値を取り出す。

## はじめに
TypeScriptのRecord型に詰めた値をfor文で引っ張り出す方法がすぐ出てこなかったのでメモです。
やることはシンプルで、TypeScriptのRecord型というよりかはネストしたオブジェクトの値を取り出したかっただけです。

## Record型とは　
ReacordとはTypeScriptに用意されたユーティリティ型の一つで、以下のように`Record<Keys,Type>`　の形式で記述できます。プロパティキーがKeysで、プロパティ値がTypeであるオブジェクトタイプを構築します。
このユーティリティを使用すると、ある型のプロパティを別の型にマップできます。

##　解決したいこと
今回取り出したい値は以下の変数smallTownBに格納されている、ageの値だけ取り出したいです。期待値は`25 17 16`です。
```ts
interface MenberInfo {
  age: number;
  job: string;
}
 
type MenberName = "memcho" | "juso" | "ruby";
 
const smallTownB: Record<MenberName, MenberInfo> = {
  memcho: { age: 25, job: "youtuber" },
  juso: { age: 17, job: "actor" },
  ruby: { age: 16, job: "idol" },
};
```
## 解決方法
TypeScriptというよりかは単純にJavaScriptの構文を使用して、ネストしたオブジェクトから値を取り出します。
Object.values()とforEachで値をずつ取り出すことができました！
```ts
Object.values(smallTownB).forEach((item) => {
  console.log(item.age)
})
```
多次元のオブジェクト作るの意外と苦戦した

## 何があった？
普段laravelのeloquentで出来上がったオブジェクトばかり触っているため、オブジェクト作成という初歩的なところでつまづいたので記事にしました。

せっかくなのでクイズ形式にしてみましたので、ぜひ皆さんもエラーシューティングできるか腕試ししてみてください。


## 問題
それでは問題ですが、下記でどこが悪いかわかりますか？

```javascript:失敗した書き方
const questionnaire_contents = [
    {id: 1, question: '質問１', answer_option: '{"1": "回答１", "2": "回答2", "3": "回答3"}', created_at: '2023-06-11T15:00:00.000000Z'},
    {id: 2, question: '質問2', answer_option: '{"1": "回答１", "2": "回答2", "3": "回答3"}', created_at: '2023-06-11T15:00:00.000000Z'}
];

let prepare_answer_option = {};
for (const questionnaire_content of questionnaire_contents) {
  for (const key in JSON.parse(questionnaire_content.answer_option)) {
    prepare_answer_option[questionnaire_content.id][key] = JSON.parse(
      questionnaire_content.answer_option
    )[key];
  }
}

```


エラー文の様子
```
Uncaught (in promise) TypeError: Cannot set properties of undefined (setting '1')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555157/b825c216-7fcf-587b-6a3b-5972a2e5f475.png)



 ＝＝＝＝以下で間違って答えが見えないように空白の改行を入れます＝＝＝＝
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />


## 答え
正解は"それぞれの次元で最初に空のオブジェクトを準備する必要がある"でした。

```javascript:成功した書き方
const questionnaire_contents = [
    {id: 1, question: '質問１', answer_option: '{"1": "回答１", "2": "回答2", "3": "回答3"}', created_at: '2023-06-11T15:00:00.000000Z'},
    {id: 2, question: '質問2', answer_option: '{"1": "回答１", "2": "回答2", "3": "回答3"}', created_at: '2023-06-11T15:00:00.000000Z'}
];

let prepare_answer_option = {};
for (const questionnaire_content of questionnaire_contents) {
  prepare_answer_option[questionnaire_content.id] = {}; // この行を追加で成功
  for (const key in JSON.parse(questionnaire_content.answer_option)) {
    prepare_answer_option[questionnaire_content.id][key] = JSON.parse(
      questionnaire_content.answer_option
    )[key];
  }
}
```

## 考察（ここから先はエラーで困っただけの方は読まなくて大丈夫です）
せっかくつまづいたので、なぜ今回のエラーが起きるのかコンピューターサイエンス的に考察してみました。

まず結論ですが、メモリでは変数で使う領域を２段以上飛ばして紐付けしきれないのが原因(＝メモリ上で変数は一つ上の親要素との関連しか保存できないため）だと考えられます。（ポインタの仕組みより）

例として`$objに格納された{A:{B:C}}という多次元オブジェクト`を作るときに、コンピューターは以下のような処理をしています。

```
$objの保存領域として100バイトくらい確保
↓
Aの保存領域として100バイトくらい追加確保して$objの保存先（ポインタ番号）も記憶
↓
Bの保存領域として100バイトくらい追加確保してAの保存先（ポインタ番号）も記憶しつつ、Bの内容としてCを保存
```

もし事前準備なしで`$obj[A][B]='C'`と指定してしまうと、「objに紐づくAに紐づくBの部分の内容としてCを保存してください」という命令文になりますが、コンピュータとしては「Aの保存先は存在しませんが？せめて$objの保存先くらい準備してくださいよ」となると言えます。

なのでメモリに寄り添うと、２段飛ばしにならないようにしてあげる必要があることがわかります。
具体的には`$obj={};`で$objの保存先を記憶させ、`$obj[A]={}`で$objに紐づくAの保存先を記憶させてから、`$obj[A][B]='C'`で$objに紐づくAに紐づくBの保存先とその内容を記憶させてあげなければならないことがわかります。
（※余談ですが、逆に`$obj={A:{B:C}}`なら、$objに紐づくAに紐づくBの内容がCとなるのに必要なものを**全てこの場で作って保存してください**となるのでエラーにならないといえることもわかります。）

そしてこの考察があっているかの確認ですが、今回のエラーを起こしたときの状況が上記の事前準備ができなかった場合のものと一致し、かつ同じ内容のエラー文を出しています。

このことからコンピューターサイエンス的に分析すると、今回のエラーはメモリでは変数で使う領域を２段以上飛ばして紐付けしきれないのが原因で間違いないと考えられます。（2段飛ばしできない理由をもっと詳しく知りたい方はポインタの原理を学んでみてください）


## 終わりに
ここまでつらつら考察してきて、確かに考察の内容を理解すると記憶の定着は進みそうですが、毎度考えると疲れそうだし作業が進まなそうだと思いました。

なので皆さんは今後多次元オブジェクト作成でエラーが起きた時は、考えすぎずとにかく**初期値の設定**を忘れていないかだけを確認していただくのが良いかなと思います。

## 追記
コメントいただいていた部分を、修正いたしました。

外に出てしまっており回答できずの間に消えてしまっていたのですが、とてもありがたかったです。

引き続き間違いなどありましたら、気兼ねなくご指摘いただけると嬉しいです。
【AtCoder】Jupyter Lab上でexit()が使えないときの対処法

## はじめに

#### 自己紹介
Python勉強中の大学院生です。自分が詰まったところを記録していきます。

#### 今回の内容
atcoderの問題をjupyter lab上で解いていた際に、`exit()`が使えなかったので、その対処法を書きます。
具体的にはflag変数を用います。

## 問題となったコード

ここでは問題の内容は関係ないですが、一応紹介しておきます。
[atcoderの問題](https://atcoder.jp/contests/abc298/tasks/abc298_b)

この問題の`exit()`を用いた解答がこちらです。

```py
import numpy as np

n = int(input())
a_ = [list(map(int, input().split())) for i in range(n)]
b_ = [list(map(int, input().split())) for i in range(n)]

#np.ndarrayに変換
a = np.array(a_)
b = np.array(b_)

for i in range(4):
    if np.min(b - a) >= 0:
        print("Yes")
        exit(0)
    #aを回転する
    a = np.rot90(a)
print("No")
```
ここでは、for文のなかで条件を満たせば`Yes`と出力し、そのままfor文から抜けるだけでなく、プログラム自体を終了するというものです。

atcoder上であれば問題なく実行されます。しかし、jupyter labで実行するとkernelが再起動？するような挙動が見られ、うまく実行できませんでした。

## 解決策
`eixt()`を使わずに、for文を抜けて、かつプログラムを終了するためには、`フラグ変数`を使用します。

### フラグ変数を用いた解答

```py
import numpy as np

n = int(input())
a_ = [list(map(int, input().split())) for i in range(n)]
b_ = [list(map(int, input().split())) for i in range(n)]

a = np.array(a_)
b = np.array(b_)

flag = False
for i in range(4):
    if np.min(b - a) >= 0:
        print('Yes')
        flag = True
        break
    
    else:
        a = np.rot90(a)

if not flag:
    print('No')
```

for文の前に`flag = False`と設定します。そして、if文の条件を満たせば`flag = True`とし、breakでfor文を抜けます。
このままでは、プログラムを終了していないことになりますが、最後の`print('No')`の前に、flagのif文を設けることで、for文のなかのif文の条件を満たしていればここは実行されずに、プログラムは終了します。

## まとめ
今回はatcoderの問題の中で、`exit()`を使わずにflag変数を用いてプログラムを終了する方法を整理しました。flag変数にブール値を代入することで、if文を用いてプログラムを終了させることができました。
【ROS2】YAMLで設定したパラメータが反映されない

# 概要

YAMLで設定したパラメータが反映されないことが多々あったため、症状別に確認事項をまとめてみました

<table>
  <thead>
    <tr>
      <th>症状</th> <th>確認事項</th> <th>該当リンク</th>
    </tr>
  </thead>
  <tr>
    <td rowspan="2">全部のパラメータが反映されない</td>
    <td> YAMLファイルはインストールされている？ </td>
    <td> <a href="#yamlファイルはインストールされている">リンク</a> </td>
  </tr>
  <tr>
    <td> YAMLファイルのノード名は正しい？ </td>
    <td> <a href="#yamlファイル内のノード名は正しい">リンク</a> </td>
  </tr>
  <tr>
    <td rowspan="2"> 一部のパラメータが反映されない </td>
    <td> declare_parameterしている？ </td>
    <td> <a href="#declare_parameterしている">リンク</a> </td>
  </tr>
  <tr>
    <td> YAMLファイルは再インストールした？ </td>
    <td> <a href="#yamlファイルは再インストールした">リンク</a> </td>
  </tr>
</table>

想定される状況とかっこよく書いていますが、自分が遭遇したときの状況となっています(新種に遭遇したら増やすかもしれないです)

# 全部のパラメータが反映されない

## YAMLファイルはインストールされている？

### 想定される状況

以下のいずれかかと思います
- `CMakefile.txt`でYAMLファイルを含むconfigディレクトリをinstallしていなかった
- `setup.py`でYAMLファイルを含むconfigディレクトリを`data_files`に指定していなかった

### 対応策

それぞれ以下のコードを追加すればよいです(configディレクトリをそのままコピーしています : 実装方法によって適宜変更してください)

- C++の場合
    ```cmake:CMakefile.txt
    install(
      DIRECTORY config
      DESTINATION share/${PROJECT_NAME}
    )
    ```
- Pythonの場合    
    ```python:setup.py
    data_files=[
        ...
        # copy config files
        (os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*'))),
    ],
    ```

## YAMLファイル内のノード名は正しい？

### 想定される状況

- launchファイルで実行名(`executable`)とは別のノード名(`name`)を指定した
- YAMLファイルでは、ノード名として実行名を指定している

この状況では、launchファイルは以下のようになっていると思います
```python:example.launch.py
def generate_launch_description():
    # YAMLファイルのパスの指定
    example_info = PathJoinSubstitution(
        [FindPackageShare(example_package), "config", "example.yaml"]
    )

    return LaunchDescription(
        [
            controller_node = Node(
                package="example_package",
                executable="example",
                name="example_node", # executableとは別のノード名を指定
                parameters=[example_info]
            )
        ]
    )
```

### 対応策

YAMLファイルのノード名を修正すれば良いです

```yaml:config.yaml
example_node: # ここをnameに揃える
  ros__parameters:
    hello: HELLO
    world: WORLD
```

ROSではノード名を指定する必要がなかったので、ROS慣れしていると遭遇しやすいかもしれないです

# 一部のパラメータが反映されない

## declare_parameterしている？

### 想定される状況

- YAMLファイルに新しいパラメータを追加したが、ソースでは`declare_parameter`を追加していない

(私はこれで1週間位沼りました)

### 対応策

新規パラメータに対応する`declare_parameter`をソースコードに追加しましょう

## YAMLファイルは再インストールした？

### 想定される状況

- `--symlink-install`フラグを利用せずに、`colcon build`をしている
- YAMLファイルを再編集したが、ソースコードに変更はなかったので、`colcon build`していない

### 対応策

とりあえず何かを編集したら、`colcon build`するようにしましょう
(確認していませんが、`colcon build --symlink-install`したら、毎回`colcon build`しなくて良いかもしれないです)


# 参考

- `colcon build`について : https://qiita.com/seshimaru/items/ed344530ead80ab1733f
- YAMLでのパラメータ設定について : https://qiita.com/NeK/items/15bf1e657d8d694592ed
スクリプト言語のmapの比較

いろんな言語で以下の処理を書いてみた

- 1から5までの配列を作り
- それぞれ2倍にした配列を作る

## Pythonリスト内包表記

```python
[i * 2 for i in range(1,6)]
```

## Python map
```python
list(map(lambda x: x * 2  ,range(1,6)))
```
## Perl 

```perl
map { $_ * 2 } (1 .. 5);
```

## JavaScript

```js
Array.from({length: 5}, (_, i) => i + 1).map(x => x * 2);
```

## PHP

```php
array_map( function($x) { return $x * 2;}, range(1, 5));
```

## Ruby

```ruby
(1..5).map{|i| i * 2}
```

## まとめ

意外と「1から5までの配列を作れ」ができる子とできない子に別れる。Pythonは１から５をrange(1,6）と書かざるをえないのがつらい。Perl、Ruby、PHPが「1から5」で人間から見れば素直。機械側に寄り添うのか人間様に寄り添うのかの思想の違い。

mapは後ろから前に持っていく子たち、関数として第一引数に無名関数を入れる子たちに別れる。Rubyのブロックが異彩を放つ。前から順に読めばいい。Rubyからプログラムを覚えた人は、他の言語でブロックではなく引数にコールバック関数を入れるという発想に慣れずに半日うろたえる。
HTMLとGAS使ってコメントをつくってみた

こんにちはAtsu1209です。♪
今日はHTML使ってコメントを作ってみました。
# いつもの
いつものやつ書きます。
~~~ html:main.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>Comment</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css">
        <meta name="viewport" content="width=device-width,initial-scale=1.0"> 
    </head>
    <body>
        
    </body>
</html>
~~~
いつものようにCSSがめんどくさいのでMaterializeを使います。

# 形作り
形を作っていきます。
~~~ html:main.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>Comment</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css">
        <meta name="viewport" content="width=device-width,initial-scale=1.0"> 
    </head>
<body>    
    <div class="input">
    <form action="#URL" method="post">
      <input type="email" name="email" placeholder="メールアドレス" required>
  <input type="text" name="com" placeholder="コメント" required>
      <input class="btn" type="submit" value="送信">
     <h6 class="flow-text">コメントありがとうございます</h6>
    </form>
</body>
</html>
~~~
フォームの`#URL`の場所に後でURLを貼ります。
# GAS
次にGASでコードを書いていきます
~~~JavaScript:Main.gas
function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var rowData = [];
  rowData.push(new Date());
  rowData.push(e.parameter.com);
  rowData.push(e.parameter.email);
  sheet.appendRow(rowData); 
  return ContentService.createTextOutput("Success");
}

~~~
`rowData...`のところで送られてきた情報の中のクラス(`e.parameter.#クラス名`)で取得してスプレッドシートに書き込みます。今回はコメント`class=com`とメールアドレス`class=email`を取得しています。
そしてGASのコードをウェブアプリとしてデプロイします。
先程のHTMLの`#URL`の場所にデプロイしたURLを貼り付けます。
# 感想
今回のコードを自分のホームページなどのところに貼り付ければ
コメント機能が実装されると思います。是非参考にしていただけると
嬉しいです。では
SnowflakeでPythonワークシート作成

# 概要
SnowflakeのPythonワークシートを試しに使ってみる

# 初期設定
1. メニューで「請求と利用規約」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/a6cb81f6-e062-fad1-4123-2fa1ec6fe08a.png)

2. Anaconda Pythonパッケージで「有効化」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/72dda934-db37-bd40-7362-067498e44ce3.png)

3. 「確認して続行する」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/25d85cd3-1dbb-cefa-4b58-5b586972894e.png)

# 試行

1. メニューで「ワークシート」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/55c783d8-c65c-c60d-a964-55e0e65b1418.png)

2. 右上の「＋」ボタンをクリックし「Pythonワークシート」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/f7c6afc6-398a-fc9c-6495-9bb7589f51a7.png)

3. デフォルトのコードが開かれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/19575074-69d9-2dfa-219c-2aa0367331e2.png)

4. データベース選択欄から使用するデータベースとスキーマを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/7946d021-fbaf-a3ad-a6f7-64f4b2aee831.png)

5. 「実行」を押下 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/50730dc9-07e2-19f0-73e6-2f122c48e1c8.png)

6. 利用できるPackage一覧が取得できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171904/5fe790e0-5d6d-6b9d-ff23-895a96510c7d.png)
Dockerを使ってPHPとMySQLをとりあえず動かしてみる方法

## バージョン情報

- Docker：v20.10.17
- PHP：v8.1
- MySQL：v5.5

## ファイル構成


DockerでPHPとMySQLの実行環境を作成するファイル構成は下記です。

- docker-compose.yml
このファイルでnginx、PHPコンテナをまとめてインストールできます
- html/index.php
表示するないようをhtmlで記述
- php.init
実行環境の設定

```
docker-php-first-step
├ docker-compose.yml
├ html
│　└ index.php
└ php.ini
```

ソースコードはGitHubに公開しています。

https://github.com/mako5656/docker-php-first

## ソースコード

### docker-compose.yml

Docker公式イメージとしてDockerHubに公開されている

- php:8.1-apache
- mysql:5.5
- phpmyadmin/phpmyadmin
を利用します。

composerのパッケージのように記述されているものを引っ張ってくるイメージです。

```yml
version: '3'

services:
  php:
    image: php:8.1-apache
    volumes:
      - ./php.ini:/usr/local/etc/php/php.ini
      - ./html:/var/www/html
    ports:
      - 8080:80
  mysql:
    image: mysql:5.5
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=test
      - MYSQL_USER=test
      - MYSQL_PASSWORD=test
      - TZ=Asia/Tokyo
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      - PMA_USER=test
      - PMA_PASSWORD=test
    ports:
      - 4040:80
    volumes:
      - ./phpmyadmin/sessions:/sessions
```

### index.php

表示したい内容をここに記述

```php
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
Hello World
</body>
</html>
```

### php.ini

必要ないかもしれませんが一応タイムゾーンや言語などを設定しておきます。

```ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
```

## 実行方法

下記の1コマンドでDockerコンテナのビルドが走ります。

```bash
docker-compose up
```

※「docker-compose up -d」で裏で動かしても大丈夫です

いろいろなものがダウンロードされてたあとPHPファイルやphpmyadminの画面が開けるようになります。

■ダウンロード画面

![スクリーンショット-2022-10-07-0.14.22-scaled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552607/b94d3cb7-ea64-ee2d-fa8d-795938e15572.jpeg)

■ビルドされている画面

![スクリーンショット-2022-10-07-0.15.23-scaled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552607/dae633ed-2925-1d8d-5cff-80c55c94c3dd.jpeg)


■記述したPHPファイルを開く(そっけない画面ですが一応載せておきます)

http://localhost:8080/ (PHPファイルに記載した内容)

![スクリーンショット-2022-10-07-0.21.10-scaled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552607/780b4e93-69e5-5fa8-ef58-8898c684a376.jpeg)

■phpmyadminを開く

http://localhost:4040/ (phpmyadmin)

![スクリーンショット-2022-10-07-0.20.53-scaled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552607/10876fef-47c6-a1e9-3c34-6e2523902b41.jpeg)
Object から null 値を全て undefined に置換する | typescript 

本記事では以下を実施します

## 実施事項

* Javascript の Object 内に null が存在した場合 undefined に置換する
* Typescript の型判定も null ではなく undefined に変換する

## 結論

作成したコードを以下に掲載します

```typescript
type Primitive = number | string | boolean | bigint | symbol | undefined | null;
type Builtin = Primitive | Function | Date | Error | RegExp;
type NonNullableValue<T> = T extends null ? undefined : T;
type NoNNullableObject<T> = {
  [Key in keyof T]: T[Key] extends object ? NoNNullableObject<T[Key]> : NonNullableValue<T[Key]>;
};

export function generateNonNullObject<T>(obj: T): T extends Builtin ? T : NoNNullableObject<T> {
  if (typeof obj !== 'object') {
    return obj as T extends Builtin ? T : NoNNullableObject<T>;
  }

  const _obj: any = {};
  for (const o in obj) {
    if (obj[o] === null) {
      _obj[o] = undefined;
      continue;
    }
    if (typeof obj[o] === 'object') {
      _obj[o] = generateNonNullObject(obj[o]);
      continue;
    }
    _obj[o] = obj[o];
  }
  return _obj;
}
```

## 解説

一部パーツを簡単に解説します

```typescript
type NonNullableValue<T> = T extends null ? undefined : T;
type NoNNullableObject<T> = {
  [Key in keyof T]: T[Key] extends object ? NoNNullableObject<T[Key]> : NonNullableValue<T[Key]>;
};
```

Typescript の型定義内では変数を用いたり if 分岐を定義することが可能です。本件の場合は null である場合 undefined に置換をしたいため、 `T extends null ? undefined : T` にて変換を行なっています。 extends の詳細は以下を参照ください。

https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

以下は見たままですが、 object を再起的に走破し、 null の場合は undefined を代入しています。

```typescript
export function generateNonNullObject<T>(obj: T): T extends Builtin ? T : NoNNullableObject<T> {
  if (typeof obj !== 'object') {
    return obj as T extends Builtin ? T : NoNNullableObject<T>;
  }

  const _obj: any = {};
  for (const o in obj) {
    if (obj[o] === null) {
      _obj[o] = undefined;
      continue;
    }
    if (typeof obj[o] === 'object') {
      _obj[o] = generateNonNullObject(obj[o]);
      continue;
    }
    _obj[o] = obj[o];
  }
  return _obj;
}
```

以上、何かのお役に立てれば幸いです。
vscodeでJava Mavenを設定

## はじめに
Java環境を手軽に構築したいと思ったので、vscodeでmavenを設定しました。
Javaを触りたいけど環境構築がわからず、挫折しかけている人の助けになればと思います。

また、pom.xmlにlog4j2ライブラリを設定して、ログを出力する方法も記載しています。
せっかく環境を構築したのに動かさないのはもったいないと思うので、ぜひログ出力して構築した環境を試してみてください。

※ 本記事はmacOSでの手順となります。Windowsの方は若干手順が異なるためご注意ください。

## mavenのインストール手順
- 以下にアクセスをして、ファイルをダウンロードしてください
https://maven.apache.org/

- ~/.zshrcに以下を追記して、PATHを通します
```
% cat << EOF >> ~/.zshrc
heredoc> export PATH=$PATH:~/apache-maven-3.9.2/bin
heredoc> EOF
% . ~/.zshrc
```
-  以下でmavenがインストールされていることを確認してください
```
% mvn -version
Apache Maven 3.9.2 (c9616018c7a021c1c39be70fb2843d6f5f9b8a1c)
Maven home: /Users/***/apache-maven-3.9.2
Java version: 17.0.7, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "13.4", arch: "aarch64", family: "mac"
```

## vscodeの設定手順
vscodeの拡張機能で「Extension Pack for Java」をインストールしてください。
![スクリーンショット 2023-06-12 23.31.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3421620/194b36fc-8b6a-731f-b0fd-850273b3e6b3.png)

## mavenプロジェクトの作成
- 以下を実行してmavenプロジェクトを作成します。
```
mvn archetype:generate
```

- vscodeで作成したプロジェクトを開けば、すでにmavenが設定されています。
![スクリーンショット 2023-06-16 0.04.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3421620/f4c4e177-3119-8c7b-9cb1-81b0083fef5e.png)



## pom.xmlにlog4j2を設定する
- 以下をpom.xmlに追加します。
```
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.20.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.20.0</version>
  </dependency>
```
- 以下のコードでログを出力してみます。
```
package com.example;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class App {    
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger();
        // ログメッセージの出力
        logger.info("info message.");
        logger.trace("trace message.");
        logger.debug("debug message.");
        logger.warn("warning message.");
        logger.error("error message.");

        // 変数をログに埋め込む例
        String greeting = "hello";
        String world = "world";
        logger.info("'{}', '{}'", greeting, world);
    }
}
```
- 実行結果
```
23:58:13.368 [main] INFO  com.example.App - info message.
23:58:13.369 [main] DEBUG com.example.App - debug message.
23:58:13.369 [main] WARN  com.example.App - warning message.
23:58:13.369 [main] ERROR com.example.App - error message.
23:58:13.372 [main] INFO  com.example.App - 'hello', 'world'
```
※ log4j2.xmlを適切に設定して、```src/main/resources```に配置してください
localhostをスマホからアクセスする方法(同じWiFi環境の場合)

ローカルで Web の開発中にスマホで確認したい場合やローカル画面を多数の人に簡単に見てもらいたい場合どうすればいいのって時に便利な方法を紹介します。

同じWiFi環境内であればおそらくこの方法が一番簡単だと思います。

## localhostについて

localhostはPCのIPアドレス「xxx.xxx.x.xx」に対応のホスト名です。

## 接続する手順

1. PCと接続したいスマホを同じWiFi環境に設定する
2. PCのIPアドレスを確認する(Macの場合:システム環境設定=>ネットワーク)
3. localhostを起動
4. スマホ・PCで「 http://xxx.xxx.x.xx:8080/ 」にアクセス(「8080」はポート番号)

これで見ることができます。

### IPアドレスを確認する方法

ターミナル上で「ifconfig」を実行することでネットワーク環境を確認することができ、「inet」もしくは「192.」と文字列を検索してIPアドレスを確認できます。
※Macの場合：システム環境設定=>ネットワーク=>利用しているWi-Fi=>詳細でIPアドレスが確認できます。

![スクリーンショット 2025-01-23 15.35.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552607/e0663e16-0f1f-1751-16d2-10d30d22f292.png)
「プロになるためのweb技術入門」を読んで

[「プロになるためのweb技術入門」（著：小森裕介）](https://www.amazon.co.jp/%E3%80%8C%E3%83%97%E3%83%AD%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AEWeb%E6%8A%80%E8%A1%93%E5%85%A5%E9%96%80%E3%80%8D-%E2%80%95%E2%80%95%E3%81%AA%E3%81%9C%E3%80%81%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AFWeb%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%92%E9%96%8B%E7%99%BA%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B-%E5%B0%8F%E6%A3%AE-%E8%A3%95%E4%BB%8B/dp/4774142352/ref=sr_1_1?adgrpid=75383294303&hvadid=651073465345&hvdev=c&hvlocphy=1009340&hvnetw=g&hvqmt=e&hvrand=11623293411147062570&hvtargid=kwd-366914365829&hydadcr=9522_13659639&jp-ad-ap=0&keywords=%E3%83%97%E3%83%AD+%E3%81%AB+%E3%81%AA%E3%82%8B+%E3%81%9F%E3%82%81+%E3%81%AE+web+%E6%8A%80%E8%A1%93+%E5%85%A5%E9%96%80&qid=1686964292&sr=8-1)を読んでいくつかのwordをまとめてみました。

## 前置き
### ハイパーテキスト
テキストにハイパーリンクやその他のマルチメディア要素を含むことができるテキストの形式のこと。Webページの主要な構成要素であり、Webページ内でリンクをクリックしたり他のページに移動したりするための仕組みを提供する

**特徴**
1. リンク機能:他の文書やWebページ、画像、ビデオなどのリンクが含まれており、ユーザーがリンクをクリックすることで他のコンテンツに直接アクセスできる
1. 非線形的なナビゲーション：ユーザーはリンクを辿ることでWebページ内やWebサイト間を自由に移動できる
1. 相互参照性:複数の文書やリソースが相互に参照し合うことができるこうぞ王であるため、関連する情報を見つけやすくなる
1. 拡張性と柔軟性:拡張性が高く、新しいリンクやリソースを追加しやすい特徴がある

## 1. プロトコルとは
webサーバーとクライアント間でどのように情報をやりとりするのかという取り決めのこと 
以下のものがある
`FTP`: HTMLファイルwpサーバーにアップロードする
`HTTP`, `HTTPS`:アップロードしたwebサイトを公開する
`SMTP`:バックエンドプログラムからメールを送信する
`SSH`:サーバーのセットアップやメンテナンスを行う 


##  2. リクエストとレスポンス
👩‍💻 ⇄　🌐　 webアプリケーションではリクエストとレスポンスを繰り返している

### リクエスト
 クライアントからサーバーに対する要求のこと

###  レスポンス
サーバーからクライアントに対する応答のこと


##  3. ステートフルとステートレス
クライアントとサーバー間のやりとりにはステートフルとステートレスという２つの仕組みがあり、大きな違いは **やりとりを維持するかしないか**のみ

### ステートフル
前回のデータを保存して、データ保存した内容を処理結果に反映させる仕組み

:::note warn
ステートフルなシステムは複数のクライアントに対しサーバーが１つしかないと負荷が高くなる
:::

### ステートレス
ステートフルとは異なり前回のデータを保存せず、処理内容に反映させない仕組み
`HTTP`は ステートレスな通信であるが **セッション**を用いることでステートフルを実現できる



:::note 
通信プロトコルの特性に合わせてステートフルかステートレスを選ぶと良い◎
:::

## 4. Cookie(クッキー)
HTTPを拡張しWebサイトとユーザー間でやり取り・保存されるアクセス情報のこと
これによりステートレスなHTTPでステートフルのような通信が実現できる

:::note
cookieを有効にしていると、ユーザーごとに割り振られた識別IDや氏名、電話番号、サイト訪問日時といった情報がユーザーのPCやスマホに保存される
:::

### Cookie とキャッシュの違い
**キャッシュ**はブラウザで表示したページ自体のデータであるため、保存することで再度ページにアクセスした際の読み込み速度が早まり快適に利用できるもの
**cookie**はユーザーのアクセス情報のみを保存する




## 5. IPアドレスとポート番号
### IPアドレス
IPアドレスはインターネットに接続する全てのコンピュータ（スマートフォンも含む）１つ１つに、割り当てられており、コンピューターを特定することができる

###  ポート番号
TCP/IP通信において、 コンピュータが通信に使用するプログラムを識別するための番号で自動的に割り当てられる

`HTTPS`は443、`HTTPS`:80となっている

:::note
IPアドレスは**住所**、ポート番号は**部屋番号**と考えると分かりやすい！
:::


## 最後に
本投稿は上記の書籍をまとめたものになります。書籍はWebアプリケーションの開発方法をインターネットの仕組みの根本原理から解説しています。webアプリケーションの開発に関して必要な知識の土台となるためしっかり学び今後の学習に繋げていきたいと思います。
composerでメモリ制限のエラーが出た場合の対処法

## エラー内容

```bash
Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar:///usr/local/bin/composer/src/Composer/DependencyResolver/Solver.php on line 223

Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.%
```

メモリーが足りないよというエラー

### メモリの容量を確認してみる

```bash
$ php -i | grep memory_limit
memory_limit => 128M => 128M
```

## 根本的な解決方法

php.iniを変更する方法

```bash
// php.iniのパスを確認
$ php -i | grep php.ini

Configuration File (php.ini) Path => /opt/homebrew/etc/php/8.2
Loaded Configuration File => /opt/homebrew/etc/php/8.2/php.ini
```

memory_limitをVimで書き換えます。
先程の確認したパスをここに記載します。
```bash
$ vim /opt/homebrew/etc/php/8.2/php.ini
```

```diff_ini
- memory_limit = 256M
+ memory_limit = 16G
```
※メモリ使用量を無制限にしたい場合`memory_limit = -1`と設定します。

## 一時的な解決方法(あまりつかわない)

```bash
$ COMPOSER_MEMORY_LIMIT=-1 composer　〇〇〇〇〇〇(実行したいこと)
```

COMPOSER_MEMORY_LIMIT=-1をつけることで一時的に無制限して実行できます。

## 特定の関数を入れて解決する方法(全く使わない)

ini_setを使用することで一時的にメモリ使用量を上げることも出来ます。

```php
<?php
ini_set("memory_limit", "512M");
 
// 処理
```
django-allauthを使用して、ユーザーを新規作成したとき、モデルに値を設定する

# 結論
`DefaultAccountAdapter`を継承したカスタムクラスを作成し、`new_user`関数をオーバーライドすることで新規登録したときに値を設定できます。

# 前提
- django-allauth機能を使用してサインアップ、もしくはソーシャル認証を通してのアカウント作成ができる状態まで実装できていることとします。
- 使用モジュールの各バージョンは以下です
  - Django              3.2.19
  - django-allauth      0.54.0

# 手順
1. 認証ユーザーモデルが存在しているアプリフォルダの中に新規でpyファイルを用意して以下のカスタムAdapterクラスを作成します。認証ユーザーモデルには値を設定できるフィールドをもたせるようにカスタマイズしておきます。

```users/adapters.py
from allauth.account.adapter import DefaultAccountAdapter

class CustomAccountAdapter(DefaultAccountAdapter):
    def new_user(self, request):
        user = super().new_user(request)
        # Userモデルはカスタマイズしてhogeのフィールドを持たせておきます。
        user.hoge = <新規登録するときに設定したい値>
        return user
```

2. settings.pyに以下のコードを加えておきます。

```project/settings.py
…
INSTALLED_APPS = [
    …
    # 追加
    'django.contrib.sites', #for djnago-allauth
    'allauth', #for djnago-allauth
    'allauth.account', #for djnago-allauth
    'allauth.socialaccount',#for djnago-allauth
]
…
# 追加
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
]
…
# 追加
SITE_ID = 1 #django-allauthがsitesフレームワークを使っているため
…
# 追加
ACCOUNT_ADAPTER = 'users.adapters.CustomAccountAdapter'
```

これで新規登録のときにユーザーモデルに値が設定されます。
以上です。

# 参考

https://qiita.com/Kei-Segawa/items/aa38f72fc5409a3517c6

https://qiita.com/hibit/items/6d3e2434f3eec6a93b0c

https://github.com/pennersr/django-allauth/blob/master/allauth/account/adapter.py