OmniAICreator/Qiita-1.07M huggingface dataset:
Googleデジタルマーケティング＆Eコマース：SEMの基礎

# はじめに

”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">

# SEM（Search Engine Marketing）

[ペイド・メディア][paid]とは、ブランドがお金を払ってオンラインに掲載するあらゆる形態のデジタルプロモーションのことです。そのプロモーションの大きな部分を占めるのが、SEM（サーチエンジン・マーケティング）である。

[paid]: https://qiita.com/mapami/items/0922198cbec1003b1526

***<font color="MediumVioletRed">『SEMは、検索エンジンの検索結果ページに表示されるペイド・メディアを通じて、ウェブサイトへのトラフィックを生成するプロセスのこと』</font>***


SEM広告（Paid ads）とは、SERP（検索エンジンの検索結果ページ）の通常の検索リストの上（または下）に表示される広告のことです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/5294ecd4-6377-d0ce-0c1a-0231f6d1505f.png" width="650">


- [SEO][seo]は、SERP内の検索リストのランキングに関係する。
- SEMは、有料広告を通じて行われる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/b57a6f8e-6f4e-9b8a-4d39-0f2d1f35a75e.png" width="650">

[seo]: https://qiita.com/mapami/items/10513c1482447cc863a5

# 広告オークション

SEMは、SEOと同じように、キーワードの調査から始まります。キーワードが決まったら、広告オークションに参加して、キーワードに入札します。

***<font color="MediumVioletRed">『広告オークションとは、誰かが検索を行ったときに、検索エンジンが表示する広告とその順番を決定する方法のこと』</font>***

- キーワードに入札すると、誰かがその言葉を検索して広告をクリックしたときにいくら支払うかを決めることができます。誰かがあなたの広告をクリックしたときにのみ支払うので、これは、PPC(ペイ・パー・クリック）として知られています。
- 誰かがPPC広告をクリックしたときにあなたが支払う金額は、***<font color="MediumBlue">CPC（コスト・パー・クリック）</font>*** と呼ばれています。

検索エンジンは、品質や最大入札額などの要因に基づいて、表示する広告を決定します。

# SEMのメリット

- 特定の顧客に素早くアプローチできます。
- 顧客が検索リストでウェブサイトを見つけた場合、通常はそのウェブサイトのホームページにたどり着きます。しかし、ペイド・メディアは、その訪問者がサインアップフォームや特定の製品ページなど、サイト上のどこに到達するかをコントロールすることができます。

# リマーケティング

ペイド・メディアの最大のメリットは、リマーケティングの機会を創出することです。リマーケティングは、以前の顧客やウェブサイトの訪問者を特定し、他のサイトやソーシャルメディアプラットフォームで有料広告を配信することができます。

例えば、ジーンズのウェブサイトを閲覧していたら、同じジーンズが他のサイトに表示されているのに気づいたことはありませんか？それがリマーケティングです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/cca86a96-8294-69b7-e7a9-40354b621fce.png" width="650">

これは、あなたのブランドにすでに興味を持っている人たちの注目を再び集める方法です。なぜなら、ほとんどのウェブサイト訪問者は、購入などのアクションを完了する前に離脱してしまうからです。購入する前に、選択肢を検討したり、もっと調べたりしたいのかもしれません。

リマーケティングは、そのような人々に、なぜ最初に広告をクリックしたのかを思い出させることで、再来訪を促します。ウェブサイトの訪問者や以前の顧客は、コンバージョンする可能性が最も高い顧客層でもあります。そのため、リマインダーの効果は絶大です。
世代間の身長の変遷をnumpyでシミュレーションしてみた

# はじめに
両親の身長が子供の身長に影響を与えることは既知の事実ですが、ではある集団について身長が与えられたとき、次の世代、そのまた次の世代の身長はどう変遷していくかをシミュレートしてみました。

# シミュレーション

## 式
男子＝ （両親の身長の合計＋13）/ 2＋2
女子＝ （両親の身長の合計－13）/ 2＋2
https://keisan.casio.jp/exec/system/1372142265

## 男子・女子の平均身長
26-29歳　男子　平均171.8cm　標準偏差6.7cm
26-29歳　男子　平均157.9cm　標準偏差5.8cm
https://www.e-stat.go.jp/dbview?sid=0003224177

## コード

```python
# male height
def mheight(x,y):
    mu = (x + y + 13) / 2 + 2
    return np.random.normal(mu, 6.7, 1)[0]

# female height
def fheight(x,y):
    mu = (x + y - 13) / 2 + 2
    return np.random.normal(mu, 5.8, 1)[0]

def simulate():
    # number of men of women
    n = 100
    # number of generation
    niter = 100
    # men's height
    m = np.random.normal(171.8, 6.7, n)
    # women's height	
    f = np.random.normal(157.9, 5.8, n)

    mmean = [np.mean(m)]
    mstd = [np.std(m)]
    fmean = [np.mean(f)]
    fstd = [np.std(f)]

    for i in range(niter):
        m = np.random.permutation(m)
        mf = [[mheight(x,y), fheight(x,y)] for x,y in zip(m,f)]
        mf = list(zip(*mf))
        m, f = mf

        mmean.append(np.mean(m))
        mstd.append(np.std(m))
        fmean.append(np.mean(f))
        fstd.append(np.std(f))
    
    return mmean, mstd, fmean, fstd

mmean, mstd, fmean, fstd = simulate()

plt.plot(mmean)
plt.plot(fmean)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89145/8cb1962b-2a61-ea96-cd68-048c399feb95.png)

値が徐々に上がって爆発してしまいました。では、身長の計算式を微調整してもう一度試します。

```python
# male height
def mheight(x,y):
    # mu = (x + y + 13) / 2 + 2
    mu = (x + y + 13) / 2 # <- it's changed here
    return np.random.normal(mu, 6.7, 1)[0]

# female height
def fheight(x,y):
    # mu = (x + y - 13) / 2 + 2
    mu = (x + y - 13) / 2 # <- it's changed here
    return np.random.normal(mu, 5.8, 1)[0]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89145/11cc3af8-12aa-3bc3-878e-f70bb007dfff.png)

値が安定しました。+2の項はもしかしたら、食の欧米化により世代間で平均身長が上がっていることを考慮しているのかもしれません。ですが、その影響はいつかは飽和するため上に上げたような異様な身長の上昇が現れると考えられます。

以上です。
Googleデジタルマーケティング＆Eコマース：SEOの基礎

# はじめに

”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">

# 検索エンジン

検索エンジンが、どの結果をページの一番上に、どの結果を一番下に表示するかを決定する方法を不思議に思ったことはありませんか？

例えば、私がホームオフィス用の観葉植物を買いたいと思っているとします。 "鉢植えのサボテン販売"というフレーズでウェブ検索すると、2,600万件以上の結果が得られます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/ef2ed141-9a16-2935-e918-1ca9af83df13.png" width="650">

検索エンジンは、インターネット上の何十億というWebページの内容を調査し、インデックスを作成することで機能します。ある言葉を検索すると、検索エンジンはアルゴリズムを使って、関連性と品質で結果をランク付けします。

しかし、どうすれば検索エンジンが関連性があり高品質であると認識するコンテンツを作ることができるのでしょうか？

# SEO（Search engine optimization）

その答えは、検索エンジン最適化、または略してSEOと呼ばれるプロセスです。

***<font color="MediumVioletRed">『SEOは、Webサイトへのトラフィックの量と質を向上させるために考案された一連の手法のこと』</font>***

最も基本的なレベルでは、キーワードと呼ばれる ***<font color="MediumBlue">一般的な検索キーワードを中心にコンテンツを最適化</font>*** し、検索エンジンの結果ページでのウェブサイトの位置を向上させることが含まれます。

検索エンジンの検索結果ページ（SERP）は、誰かが検索を行ったときに表示される検索結果のページです。一般的に、この検索結果ページで上位に表示されればされるほど、お客様がそのサイトをクリックする確率が高くなります。また、訪問者が増えれば増えるほど、販売促進、権威の確立、ブランド構築のチャンスも増えます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/fb441e84-e633-aaa7-2a18-17a644b9efaa.png" width="650">

# SEOとペイド・メディア

- [ペイド・メディア][paid]は、すぐに結果が出ますが、お金を払わなくなるとその結果が消えてしまいます。
- SEOは、その逆です。優れたSEO対策によって得られる露出は、ペイド・メディアよりもはるかに長く続く可能性があります。

[paid]: https://qiita.com/mapami/items/0922198cbec1003b1526

# SEOの基本

### キーワード調査

キーワード調査とは、消費者がオンラインで製品やサービスを見つけるためによく使う検索キーワードやフレーズを特定する作業です。SEO対策の一環として、顧客や製品に最も関連性の高いキーワードを見つけ出し、それをコンテンツに盛り込むことが重要です。

### 質の高いコンテンツ

しかし、ただキーワードを詰め込めば良い結果が得られるわけではありません。顧客にとって有益で、使い勝手のよい、質の高いコンテンツが必要です。つまり、優れたコンテンツを作成するでなく、それを常に最新の状態に保つということです。Webサイトのコンテンツは、あなたのビジネスが現在提供しているものと一致し、キーワードのトレンドを反映していることが必要です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/28bc431b-414e-ec54-2419-63eae1fa3e83.png" width="650">

### Webサイトの構造

また、コンテンツは見つけやすくなければならないので、ユーザーフレンドリーな方法でサイトを構成することも重要です。コンテンツが見つけやすいように整理されたWebサイトは、検索エンジンと顧客の両方にとって、コンテンツのナビゲーションを容易にします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/750ce1dd-6b30-d047-4f4c-66e8ea6b9f92.png" width="650">

:::note warn
優れたSEO対策には、ここで紹介した以外にもさまざまなものがあります。
:::
MACにPostgreSQLをインストールしてVSCodeから操作できるようになるまでの流れ

PostgreSQLでSQLを試したかったのでローカルに環境構築しました。

# 1 MACにインストール → データベース作成まで

## 1-1 MACにインストール

```:MACにインストール
brew install postgresql
```

## 1-2 PostgreSQLのバージョンを確認
以下のコマンドでバージョンが表示されれば、適切にインストールされています。
```:PostgreSQLのバージョンを確認
psql --version
```

このように表示されればOK
![スクリーンショット 2023-03-06 6.39.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/e29f911e-c141-2ec4-d46e-d0ebc513726b.png)

## 1-3 PostgreSQLの起動
```:PostgreSQLの起動
brew services start postgresql
```

## 1-4 PostgreSQLの起動状況を確認
```:PostgreSQLの起動状況を確認
brew services list
```

「postgresql@~」が「started」になっていればOK
![Group 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/703498c3-7ad7-5059-78c1-9c00e0e5d5b8.png)


## 1-5 データベースを作成
```:データベースを作成
createdb データベース名
```
データベース名は「mydb」とか「test_db」とかなんでもOK

## 1-6 データベース一覧を確認
```:データベース一覧を確認
psql -l
```
作成したデータベースが表示されていればOK
![Group 7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/f430c6e6-0bbe-68ae-2055-571c5eb094ef.png)


## 1-7 データベースに接続
```:データベースに接続
psql -U ユーザー名 データベース名
```

- ユーザー名は「psql -l」で表示したデータベース一覧の「Owner」欄で確認できる。
- データベース名は作成したデータベース名を入力すればOK。

- 以下のようにインターフェースが切り替わればOK
![Group 8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/d975331b-350c-3ae6-bc64-57a109f630ef.png)


## 1-8 データベースを切断
あとはVSCodeで操作するので、以下のコマンドでデータベースとの接続を切っておく。
```:データベースを切断
\q
```



# 2 VSCodeを拡張 → テーブル操作まで


## 2-1 VSCodeの拡張機能「PostgreSQL」をインストール
画像のとおりインストール
![Group 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/ec2dcb6a-70d9-ab9b-38c1-756406f35d18.png)

## 2-2 作成したデータベースに接続
画像のとおり進んでいく
![Group 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/1919344b-cf3b-0873-8139-4df2ca0265f2.png)

![Group 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/35d7d8da-10e8-264b-5a63-3456cbc4a47e.png)

### (1/7) ホスト名
「localhost」と入力

### (2/7) ユーザー名
ユーザー名を入力
（ユーザー名は「psql -l」で確認できる）
![Group 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/e4e78de2-9b79-0e7a-0422-49dbf39fd3f3.png)

### (3/7) パスワード
空欄でOK

### (4/7) ポート番号
「5432」と入力

### (5/7) 接続方法
Standard Connection でOK

### (6/7) データベース名
作成したデータベース名を選択

![Group 9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/6008055d-6100-fa97-e0e3-73f0faa9c3ef.png)


### (7/7) 表示するデータベース接続の名前
なんでもOK（例：「localhost/データベース名」）


次のように表示されれば完了
![スクリーンショット 2023-03-07 6.53.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/7fd840fe-7513-cbcd-93fe-27df083fd065.png)


## 2-3 SQLの操作

データベースアイコンを右クリックすると「New Query」と出てくるので、クリックして立ち上がったエディタにSQLを書いて「F5」を押せば実行されます。
![Group 10 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092366/73471194-05db-94aa-342c-b3bcec3c66d2.png)


これで素敵なポスグレライフを送れるよ！
paiza.ioでnadesiko その8

# 概要
paiza.ioでnadesikoやってみた。
配列、やってみた。

# サンプルコード

```

文章＝空。
文章1＝「いろはにほへと」
文章2＝「ちりぬるを」
文章に文章1を追加。
それを表示。
それに文章2を追加。
それを表示。
文章を表示。


「こんにちは」と表示。
「文字を」＆「結合する」と表示する。

あは「あああああ
いいいいい
ううううう」
あ[2]を言う。 
# 「ううううう」が表示される
あ＠２を表示

名前は「くじら」
「私は、｛名前｝です。」と言う。
# ↑「私は、くじらです。」という結果を返す

動物=[]
動物＠０＝「カバ」
動物＠１＝「サル」
動物＠２＝「キジ」
動物を反復
　　「【　{対象}　】」を表示。
ここまで。

「かけうどん,600
たぬきうどん,630
ざるそば,800
日替わり定食,850
天ぷらうどん,1200」をCSV取得して値段表に代入。
# 反復
値段表を反復
　　料理は対象＠０
　　値段は対象＠１
　　値段は値段＋１００
　　「{料理}, {値段}」を表示。
ここまで。

得票辞書＝{"わかな":22,"ちはる":5,"まきこ":3}
得票辞書を反復
　　名前は対象キー
　　得票は対象
　　「😃｛名前｝さんは｛得票｝点でした。」と表示。
ここまで。

値段一覧は[600,630,800,850,1200]
値段一覧を反復
　　対象に１００を足して表示。	
ここまで。

「0,1,2,3」を「,」で区切ってAに代入。
A@2を表示。


```

# 実行結果

```
いろはにほへと
いろはにほへとちりぬるを

こんにちは
文字を結合する
あ
あ
私は、くじらです。
【　カバ　】
【　サル　】
【　キジ　】
かけうどん, 700
たぬきうどん, 730
ざるそば, 900
日替わり定食, 950
天ぷらうどん, 1300
😃わかなさんは22点でした。
😃ちはるさんは5点でした。
😃まきこさんは3点でした。
700
730
900
950
1300
2
```

# 成果物

https://paiza.io/projects/5q4zLvhHzFhtF1CqhDl06A

以上。
paiza.ioでnadesiko その7

# 概要
paiza.ioでnadesikoやってみた。
関数、やってみた。

# サンプルコード

```

●挨拶
  「おはよう」と言う
ここまで
挨拶する

●(AとBの)加算処理とは
　　AにBを足すこと
ここまで。
30と20の加算処理。
それを表示。

●(AとBの)加算処理とは
　　A+Bを戻すこと
ここまで。
30と20の加算処理して表示。

●(AとBの)加算処理とは
　　それ＝A＋B
ここまで。
3と7の加算処理して表示。
5と9の加算処理して表示。

//●(AとBの)加算処理とは
//　　A＋B
//ここまで。
30と7の加算処理して表示。

●（｛参照渡し｝Aと｛参照渡し｝Bを）大小比較とは
　　もしA＜Bならば
　　　　値はA
　　　　AはB
　　　　Bは値
    ここまで。
ここまで

●(VをAのBで)階乗計算とは
　　もし、Bが0以下ならば、Vを戻す。
　　(V * A)をAの(B - 1)で階乗計算して戻す。
ここまで。
1を2の3で階乗計算して表示。
1を2の5で階乗計算して表示。

2を3乗する。
それを表示。

●乗（xをn）
　　答=1
　　カウンターで1からnまで繰り返す
　　　　答=答*x
    ここまで
　　答で戻る。
ここまで

　　
```

# 実行結果

```
おはよう
50
50
10
14
37
8
32
8
```

# 成果物

https://paiza.io/projects/KCnbWVEOr046ckR3NeWNCw


以上。
paiza.ioでnadesiko その6

# 概要
paiza.ioでnadesikoやってみた。
反復、やってみた。

# サンプルコード

```
A=「ABCDE」
B=「abcde」
AにBを追加。
それを表示。
Aを表示。　　　
＃ ABCDEabcdeが表示される


Ａは０
（Ａ＜５）の間
　　「Ａ＝｛Ａ｝」と表示。
    Ａ＝Ａ＋１
    もし、Ａ＝３ならば、抜ける。
ここまで
「いか,たこ,さんま」を「,」で区切る
それを反復
　　「●　｛それ｝」を表示
ここまで
「あ
い
う
え
お」を反復
　　「｛それ｝」を表示。
ここまで　　
Ｉで３から１まで繰り返す
　　Ｉを表示。
ここまで
A=「ABCDE」
B=「abcde」
C=「OPQRS」
Aを表示。
Aに「{改行}{B}」を追加。
Aに「{改行}{C}」を追加。
Aを表示。　　
A=「ABCDE」
B=「abcde」
Aを表示。
AにBを追加。
Aを表示。　　　
＃ ABCDEabcdeが表示される
Aは「いろは」
Aを表示。
Aに「に」を追加。
Aを表示。
Aに「ほへと」を追加。
Aを表示。
#結果→いろはにほへと

「ズン,ドコ」を「,」で区切って、ずんどこへ代入
全体は空
番目は、２の乱数
ずんどこ@番目を、表示
全体に、ずんどこ@番目を、追加
「キ・ヨ・シ！」を、表示
全体を表示
//ながれは、空
//ながれで、１０文字右部分。
//それが、「ズンズンズンズンドコ」でない、の間


nは0
wは0
(wは0)の間
　もし、(2の乱数)が0ならば
　　「ズン」と表示
　　nは(n + 1)
　違えば
　　「ドコ」と表示
　　nは0
　ここまで
　もし、nが4ならば
　　「ドコ　キ・ヨ・シ！」と表示
　　wは1
　ここまで
ここまで

//「生」をSJIS_UTF8N変換してそれの1をDWORDでバイナリ取得して生に代入
//「死」をSJIS_UTF8N変換してそれの1をDWORDでバイナリ取得して死に代入
//愛は生＆＆死
//愛を愛の1にDWORDでバイナリ設定して愛をUTF8N_SJIS変換して愛に代入
//愛を表示





頭数は１００。
足数は２７２。
鶴は、頭数に４を掛けて、足数を引いて、２で割る。
亀は、頭数から鶴を引く。
「鶴は{鶴}羽、亀は{亀}匹」と表示。


おみくじ＝（６の乱数）＋１。
おみくじを表示。
もし、おみくじ＝１ならば
　　結果＝「大吉」。
違えばもし、おみくじ＝２ならば
　　結果＝「小吉」。
違えばもし、おみくじ＝３ならば
　　結果＝「中吉」。
違えばもし、おみくじ＝４ならば
　　結果＝「吉」。
違えば
　　結果＝「凶」。
ここまで。
結果を表示。

親ねずみは２
産む数は2
月数は2
月数回、繰り返す。
    番は、親ねずみを２で割る。
    子ねずみは、番に産む数を掛ける。
    親ねずみと子ねずみを足して、親ねずみに代入。
ここまで。

「{月数}ヶ月後のねずみの数は、{親ねずみ} 匹」を表示。


xは1
もし、xが1ならば
    「Yes」と表示
違えば
    「No」と表示
ここまで
iは1
iが5以下の間
　　iを表示
　　i=i+1
ここまで
計算フラグ=yes
(計算フラグ=yes)の間
    「値1は？」と尋ねて、値1に代入
    「演算子(+,-,*,/)は?」と尋ねて、演算子に代入
    「値2は？」と尋ねて、値2に代入
    (値1が数字か判定)を判定結果1に代入
    (値2が数字か判定)を判定結果2に代入
    もし、（判定結果1は数値0か判定）　または　（判定結果2は数値0か判定）　ならば
      「値1および値2には数値を入れてください」と表示
      //5秒待つ
      //おわり
    ここまで
    もし、演算子が「+」ならば
        答えは値1+値2
    違えば、もし、演算子が「-」ならば
        答えは値1-値2
    違えば、もし、演算子が「*」ならば
        答えは値1*値2
    違えば、もし、演算子が「/」ならば
        答えは値1/値2
    違えば、
        「演算子には+,-,*,/のいずれかを入力してください」と表示
         //5秒待つ
         //おわり
    ここまで
    答えを表示
    「続けますか(yes/no)？」と尋ねて、計算フラグに代入
    もし、計算フラグ＝noならば、抜ける。
ここまで

```

# 実行結果

```
ABCDEabcde
ABCDE
Ａ＝0
Ａ＝1
Ａ＝2
●　いか
●　たこ
●　さんま
あ


い


う


え


お
3
2
1
ABCDE
ABCDE
ABCDE
ABCDE
いろは
いろは
いろは
ドコ
キ・ヨ・シ！

ドコ
ズン
ズン
ズン
ドコ
ズン
ズン
ドコ
ズン
ドコ
ドコ
ズン
ドコ
ズン
ドコ
ドコ
ドコ
ドコ
ズン
ズン
ズン
ズン
ドコ　キ・ヨ・シ！
鶴は64羽、亀は36匹
3
中吉
2ヶ月後のねずみの数は、8 匹
Yes
1
2
3
4
5
値1は？演算子(+,-,*,/)は?
```

# 成果物

https://paiza.io/projects/2ff5hoz0lTtvw74gULQRhA

以上。
paiza.ioでnadesiko その5

# 概要
paiza.ioでnadesikoやってみた。
json、やってみた。


# サンプルコード

```
Sは『
{
    "name": "なでしこ",
    "url": "https://nadesi.com"
}
』
SをJSONデコードしてAに代入。
A@「url」を表示。

//情報 = {  "name": "クジラ",  "url": "https://kujirahand.com/"}
//情報をJSONエンコードして表示

A = {}
＃値の代入
A@「イヌ」＝「わんわん」
A＠「ネコ」＝「にゃーにゃー」
＃値の参照
A＠「ネコ」を表示。

A = {
  "イヌ": "わんわん", 
  "ネコ": "にゃーにゃー"
}
＃値の参照
A＠「ネコ」を表示
AをJSONエンコードして表示

//URL＝「http://nadesi.com/」
//ページ＝URLからHTTPデータ取得


```

# 実行結果

```
https://nadesi.com
にゃーにゃー
にゃーにゃー
{"イヌ":"わんわん","ネコ":"にゃーにゃー"}
```

# 成果物

https://paiza.io/projects/kHpL51VC0NTttroLl0xSKA


以上。
レコメンデーションエンジンの未来

レコメンデーションエンジンは、今ではすっかり普及してきてます。
きっと一般の人でもサイトを見て、これは自分の趣味嗜好にそったコンテンツが並んでいるというのが分かってるんでは無いでしょうか？

でもレコメンデーションエンジンが溢れすぎていて、最近、一体、どんなレコメンドが良いのか考えます。

# レコメンドで染まったYoutube
![スクリーンショット 2023-03-06 12.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/edf9cc69-c2c1-bee1-6bdc-fb52bff8db32.png)

Youtubeは画面を開くと、レコメンドのコンテンツばかりです。
私のYoutubeは、GOLFと犬と格闘技と麻雀ばかりが並びます。
最近、この画面に辟易してます。

昔、Youtubeの責任者の人と食事した時に、Youtubeは、何故レコメンドをあまりしないんですか？と聞いた事があります。
当時のYoutubeは、レコメンドが全くなく、誰が見ても同じトップ画面でした。（多分）

そーすると責任者の方は、レコメンドをやると、趣味嗜好が偏って行き過ぎてしまうので、精神的問題になったり過度な影響を与える可能性があるので入れてないと言ってました。

その時は、そんな事あるかなぁと思ってましたが、実際レコメンドが入って、こればかりになると辟易します。
（何故、レコメンドが始まったかは、知りません）

# ランキングやカテゴリも使ってるAmazonPrimeVideo
![スクリーンショット 2023-03-06 12.07.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/34018270-544c-2676-7026-38ba1c6a9168.png)

AmazonPrimeVideoは、ランキングやカテゴリが結構中心になってる気がします。
もちろん、あなたへのオススメ的なのもありますが、一度で、他は、カテゴリやランキングからのコンテンツ提案です。
今となっては、こちらがとても見やすく思います。

# レコメンドの未来
結局、レコメンデーションエンジンは、過去の行動履歴からのコンテンツをオススメする仕組みであり、ドンドン偏って行ってしまう。
人により仕組まれた新しいコンテンツの提案の方がより興味がわくし、未来の自分にとっては適切な場合が多い。
そう考えるとレコメンデーションエンジンって、探し始めた時等の、瞬間的な短いターム（期間）では、有効であるかもしれないが、長く永続的には不要になってくる事が多い。
優秀な営業マンの様にそろそろ飽きていそうだから、別のカテゴリとか、最近、流行ってるのいかがですか？等の人の心のパラメータとして付加したレコメンデーションエンジンが求められる時代に入ってきていると思う。

# 最後に
マイページ画面については、どんな物を表示させるかについては、サービスの活性化に大きく関係します。
個々人に最適化されたマイページに関して、導入したレコメンデーションエンジンがいつの間にか邪魔なコンテンツになってる可能性があります。
新しいコンテンツにエンカウントできる様なレコメンデーションエンジンの導入について検討してみるべきだと思います。

これからも記事を書いていきますので、モチベーションアップのためフォロー、イイねお願いします。
2023/3/7主にITとかセキュリティの記事

日本原燃の複数関連会社でマルウェア感染 - 視察者情報が流出か
https://www.security-next.com/144228

テキストエディタ「GNU Emacs」に複数の脆弱性
https://www.security-next.com/144237

「MongoDB」の一部ドライバにサービス拒否の脆弱性
https://www.security-next.com/144246

神奈川銀行装うフィッシング - マネロン対策口実に偽サイトへ誘導
https://www.security-next.com/144250

海賊版Final Cut Proでマルウェアを発見！ Macに与える最悪の影響とは？(3/4)
https://news.yahoo.co.jp/articles/e97fd2484cd3bdd9191fd721afc83551c9d23eaa?source=rss

ＴｉｋＴｏｋ「危険性周知を」　情報漏えい懸念し甘利氏(3/5)
https://news.yahoo.co.jp/articles/82339064ea958d76f2cdfd00ba542fed01eba3e6?source=rss

身近に忍び寄るSNSアカウントの乗っ取り(3/5)
https://news.mynavi.jp/article/womansns-92/

米政権、ソフトウェアの安全への適切な注意義務を怠った者に責任を負わせる国家サイバーセキュリティ戦略(3/4)
https://security.srad.jp/story/23/03/04/0956226/

国土交通省が管理する簡易型河川監視カメラへの不正アクセスについてまとめてみた(3/5)
https://piyolog.hatenadiary.jp/entry/2023/03/05/011832

産学研究の拠点完成　県立大情報セキュリティセンター　長崎(3/5)
https://news.yahoo.co.jp/articles/6a8ccda834d487d8b238812f5f9e96ab201c365f?source=rss

サイバー犯罪を未然に防止を　男子バスケットボール　レバンガ北海道の選手がクイズ交えて呼びかけ　札幌(3/4)
https://news.yahoo.co.jp/articles/db5aa43053333a4a34435ef107edd040b259630e?source=rss

地球をぐるりの海の通信基盤、経済安全保障を軸に日本が主導(3/7)
https://xtech.nikkei.com/atcl/nxt/column/18/01819/00025/

多様なベンダーが参入する「SASE」市場、どの機能重視でサービスを選ぶべきか(3/7)
https://xtech.nikkei.com/atcl/nxt/column/18/02375/022200004/

ラウンドワンのWebサイトに対する注意喚起が続々、改ざん被害で別サイトに誘導(3/7)
https://xtech.nikkei.com/atcl/nxt/column/18/00598/021000204/

処分前のパソコンデータ、消去ツールでデータ復元を阻止(3/7)
https://xtech.nikkei.com/atcl/nxt/column/18/02356/020800005/

クアルコム、Snapdragon 8 Gen 2に搭載される「iSIM」のGSMA認証完了を発表(3/6)
https://xtech.nikkei.com/atcl/nxt/column/18/02372/030300017/

SASEを構成する「CASB」と「ZTNA」、役割と動作をやさしく解説(3/6)
https://xtech.nikkei.com/atcl/nxt/column/18/02375/022200003/
pythonモジュールの関数をコマンドプロンプトで出力する


# （追記）この記事を読む前に
ありがたいことにコメントで自分で考えていたより良いやり方を教えていただいたので、以下を使ってください。@asobinin_kinsan さん、@shiracamusさんありがとうございました。

``` one_writner.py
python  -c "import os;print('\n'.join([x for x in dir(os) if x.islower() and '_' not in x]))"
```

``` d.py
import sys
import importlib


def main(module_name):
    module = importlib.import_module(module_name)
    for name in dir(module):
        if name[0] != '_':
            print(name, ':', type(getattr(module, name)).__name__)


if __name__ == '__main__':
    if len(sys.argv) == 2:
        main(sys.argv[1])
    else:
        print(f"Usage: {sys.argv[0]} MODULE_NAME")
```



# （備忘のために残しますが、以下非推奨）はじめに
以下のような人にとって便利だと思います（私です）
- 会社のWindows端末の縛りでjupyter notebookなどが使えない。
- 標準モジュールで何ができるかぱっとわかりたい。公式ドキュメントに行くほどのことでもない。
- dir()を叩くためにVScodeで開いているターミナルでpython3とわざわざ打って対話型に入っている。
- VScodeがいい感じの表示をしてくれない。

# コード
``` d.py
import argparse

def main():

    if args.os == True:
        import os
        d = dir(os)

    elif args.pandas == True:
        import pandas
        d = dir(pandas)

    else:
        d = []

    d_fil = [x for x in d if x.islower() and not '__' in x] 
    print(*d_fil, sep='\n')

if __name__ == '__main__':
    psr = argparse.ArgumentParser()
    psr.add_argument('-o', '--os', action='store_true')
    psr.add_argument('-p', '--pandas', action='store_true')
    args = psr.parse_args()

    main()


```


自分が見たかったのは関数だけなので他の内容はフィルターしています。
importの引数に変数は入れられないので、見たいモジュールが増えるたびにオプションとif文を変更する必要があるのは少し手間ですが自分用なのでOKということで。
ChatGPTのAPIをGolangで実装する

```golang:gpt.go
package gpt

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
)

type IGpt interface {
	GenerateText(message []Chat) (string, error)
}

type Gpt struct {
	apiKey string
	model  string
}

func NewGpt(apiKey string, model string) IGpt {
	return &Gpt{
		apiKey: apiKey,
		model:  model,
	}
}

type Chat struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

func (gpt *Gpt) GenerateText(messages []Chat) (string, error) {
	url := "https://api.openai.com/v1/chat/completions"

	// Escape any double quotes in the message
	// escapedMessage := fmt.Sprintf("%q", message)

	jsonData, err := json.Marshal(messages)
	if err != nil {
		fmt.Println("Error marshaling JSON:", err)
		return "", errors.New("error marshaling JSON")
	}

	jsonString := string(jsonData)
	jsonStr := []byte(fmt.Sprintf(`{
		"model": "%s",
		"messages": %s
	}`, gpt.model, jsonString))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	if err != nil {
		return "error before sending a request to api", err
	}
	if gpt.apiKey == "" {
		return "invalid_api_key", err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+gpt.apiKey)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return "error after sending a request to api", err
	}
	defer resp.Body.Close()

	var m map[string]interface{}

	err = json.NewDecoder(resp.Body).Decode(&m)
	if err != nil {

		return "error after sending a request to api", err
	}
	if errVal, ok := m["error"].(map[string]interface{}); ok {

		errorCode := errVal["code"].(string)

		return errorCode, errors.New(errorCode)
	}

	content := m["choices"].([]interface{})[0].(map[string]interface{})["message"].(map[string]interface{})["content"].(string)
	return content, err
}

```


## テストコード

```golang:gpt_test.go

package gpt_test

// test code
import (
	"fmt"
	"os"
	"testing"

	gpt "gowhale/Gpt"

	"github.com/joho/godotenv"
)

func TestSample(t *testing.T) {
	fmt.Println("TestSample")
	// load the env file
	err := godotenv.Load("../.env")
	if err != nil {
		t.Fatalf("Error loading .env file: %v", err)
	}
	// print the env variable of OPENAI_API_KEY
	// gpt-4-0314
	openai := gpt.NewGpt(os.Getenv("OPENAI_API_KEY"), "gpt-4-0314")
	chat := []gpt.Chat{
		{
			Role:    "user",
			Content: "hello",
		},
	}
	fmt.Println(openai.GenerateText(chat))
	// openai2 := gpt.NewGpt(os.Getenv("OPENAI_API_KEY"), "gpt-4")
	// fmt.Println(openai2.GenerateText("Hello!!"))

}


```
【UIKit】コードからAutoLayoutでSafeArea対応させる方法

AutoLayoutで配置したViewが画面上部のStatusBarなどに被らないよう、SafeAreaに対応させる方法を紹介する。
# anchorで設定する方法
```swift
myView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
```
- 対応させたいViewのanchorに`safeAreaLayoutGuide`のanchorを設定する。
- 基本的にはこの方法で良いと思われる。
# 画面の端からSafeAreaの広さ分スペースを空ける方法

```swift
myView.topAnchor.constraint(equalTo: view.topAnchor, constant: view.safeAreaInsets.top).isActive = true
```
- equalToにはviewのanchorを設定しておき、そこからconstantに設定した値の分スペースを空ける。
- `safeAreaInsets`でSafeAreaのサイズが取得できるため、上下左右から対応させたいものを記述する。
- bottomAnchorとrightAnchorの場合はconstantにマイナスの値を設定する必要がある。例: `constant: -view.safeAreaInsets.bottom`
- safeAreaInsetsの値はviewDidLoad()内だと取得できないため、この方法を使う場合はanchorの設定を`viewWillLayoutSubviews()`などに記述する必要があるため注意。
ド・モルガンの法則

# ド・モルガンの法則とは

AND演算子とOR演算子を相互に変換することで、複雑な演算式を単純化できる。

# ド・モルガンの法則の変更手順

①　問題文をそのまま条件式にする。
②　各条件式の関係演算子を否定する。
③　andをorに、orをandにする。
ChatGPT API で文脈を含めたやりとりをサクッと出来るようにする

# やりたいこと
ChatGPT API でウェブ版のように文脈を含めたやりとりをしたい。

# 仕組み
`messages` に今までのやりとりを含めれば OK です。
まず、`2020年のワールドシリーズを制したのは？`という質問を尋ねる場合は以下になります。 
```js
const response = await openaiClient.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages: [
        {"role": "system", "content": "あなたは役にたつアシスタントです"},
        {"role": "user", "content": "2020年のワールドシリーズを制したのは？"},
    ]
});
```
これのレスポンスが、`ロサンゼルス・ドジャースがワールドシリーズを制覇しました。`だとします。
そしてこの回答のあとに`どこでプレイされたでしょうか`という質問をする場合は以下になります。
```js
const response = await openaiClient.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages: [
        {"role": "system", "content": "あなたは役にたつアシスタントです"},
        {"role": "user", "content": "2020年のワールドシリーズを制したのは？"},
        {"role": "assistant", "content": "ロサンゼルス・ドジャースがワールドシリーズを制覇しました。"},
        {"role": "user", "content": "どこでプレイされたでしょうか？"}
    ]
});
```
このように、質問者は`role`を`user`とし、ChatGPT のレスは`role`を`assistant`として`messages`に突っ込んでいくだけです。
簡単ですね。

# 実装

```js
import { createInterface } from "readline";
import { Configuration, OpenAIApi } from "openai";

// ユーザーの入力を受け付ける
async function getUserInput() {
  const rl = createInterface({
    input: process.stdin,
    output: process.stdout
  });

  return new Promise((resolve, reject) => {
    rl.question('you: ', (answer) => {
      resolve(answer);
      rl.close();
    });
  });
}

// openAIクライアントの設定
const openaiConfig = new Configuration({
  apiKey: "API_KEY",
});
const openaiClient = new OpenAIApi(openaiConfig);

// AIのsystem設定
const system = `あなたは役にたつAIアシスタントです。`;
const messages = [
  { role: 'system', content: system },
];

// 入力を受け付けて ChatGPT からのレスポンスを返し会話を続ける
while (true) {
  const text = await getUserInput();
  messages.push({ role: 'user', content: text });

  const response = await openaiClient.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages: messages,
  });
  const message = response.data.choices[0].message?.content;
  console.log('ChatGPT: ' + message);

  messages.push({ role: 'assistant', content: message });
}

```

# 結果
```
you: こんにちは
ChatGPT: こんにちは！どのようにお力添えできますか？
you: りんごの剥き方
ChatGPT: りんごの剥き方ですね。以下の手順で剥くことができます。

1. りんごを水洗いし、十分に水気を取ります。
2. りんごを切る前に、上下を切り落とし、平らな面を作ります。
3. そこから剥き器を使って、表面を剥きます。剥き器を使わずにおろす場合は、例えばピーラーを使って削いでいくのも良いでしょう。
4. うまく剥けない場合は、りんごの部分部分で剥きやすいところを見つけるか、りんごをさらに小さく切り、切り口から剥き取っていきます。

以上のようにすると、簡単にりんごを剥くことができます。
you: さっき私なんの質問したっけ？
ChatGPT: 少し前に「りんごの剥き方」についての質問をされました。
```
private method `hogehoge' called for のエラーで大混乱したお話

# 概要
最近GASとJavaScriptをお勉強中の @Keichan_15 です:v:

Railsの開発を行う際にとあるエラーに遭遇したのですが、参考記事があまり見当たらず解決に時間が掛かったので、備忘録も兼ねてまとめておこうと思います。
意外と解決方法はシンプルでした…:cry:

# 伝えたいこと
- **Classの外** でそのメソッド定義していない？
  - def 式がクラス定義の **外** (トップレベル)にあれば **private**
  - def 式がクラス定義の **内** にあれば **public**

早速見ていきましょう！


# 発生しているエラー
![2023-03-07 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/c9a039e5-e0e7-5623-d1ab-f4a761fbd884.jpeg)

``private method 'hoge' called for ~~`` のエラーが出ています。
特にモデル側(今回であれば ``User`` )にprivate methodを定義した覚えはないんですが…。:frowning2:

# 実際のコード
```ruby:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  validates :name, uniqueness: true, length: {in:2..20}
  validates :introduction, length: {maximum: 50}

  has_many :books, dependent: :destroy
  has_many :book_comments, dependent: :destroy

  ## 以降のコードは割愛　##

end

def following?(user)
  following_user.include?(user)
end
```

UserのClass **外** で ``following?`` を定義している状況です。
つまりここが怪しそう…。

# 解決方法
```ruby:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  validates :name, uniqueness: true, length: {in:2..20}
  validates :introduction, length: {maximum: 50}

  has_many :books, dependent: :destroy
  has_many :book_comments, dependent: :destroy

  ## 以降のコードは割愛　##

  # Class内にメソッドを移行
  def following?(user)
    following_user.include?(user)
  end

end
```

Classの **中** に `following?` メソッドを移行しました。

Rubyの [リファレンスマニュアル](https://docs.ruby-lang.org/ja/3.2/doc/index.html) によると、 def式がClassの **外** に定義 されている場合、デフォルトで **private** に定義されるようです。

> _デフォルトでは def 式がクラス定義の外(トップレベル)にあれば private、クラス定義の中にあれば public に定義します。_

https://docs.ruby-lang.org/ja/latest/doc/spec=2fdef.html#limit

すなわち、Class **内** に定義する場合は **public** 扱いとなるため、メソッドの呼び出しが可能となってエラーが解消できるということですね。

# おわりに
エラー解決って結局のところ、公式ドキュメントを読み込むことで解決することが多い…。
もっと読み込んでいきたいと思った今日この頃でした。
ばいばい。:wave:
[Servicenow] インスタンスの環境を日本語化にしてみよう

はじめに
-
本記事では、作成した個人インスタンスの環境を日本語化にする内容を書きたいと思います。

【前回の記事】


https://qiita.com/masa3150/items/f3a013229ddbef684fda


個人インスタンスを立ち上げよう
-
・まず初めに、自分のServiceNowIDでログインをしましょう。
![スクリーンショット 2023-03-06 23.45.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/b6f93f41-b61d-05ee-e286-17611742f29c.png)

・「Start Building↗︎」をクリックし、インスタンスを立ち上げます。
![スクリーンショット 2023-03-06 23.51.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/ed75b12b-d175-48de-b831-f91ae4193fe7.png)
※前回の記事でもお伝えしましたが、この作業を10日間しなかった場合、個人インスタンスが削除されるので注意してください。

日本語のプラグインをインストールする。
-
・画面左上の「All」(Servicenowのロゴの右)をクリックし、アプリゲーションナビゲータに「System Definition」と入力して、「Plugins」を選択してください。
![スクリーンショット 2023-03-06 23.59.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/81509ead-b374-8fe5-bcb8-9d20bc60b371.png)

・検索フォームに、「*japanese」を入力し、Japanese Translationsのプラグインを
インストールしましょう。
![スクリーンショット 2023-03-07 0.05.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/c4853e62-ffb8-b774-b39a-f903305cccbb.png)

「Activate」をクリックする。（約20~40分インストールに時間が掛かります）
![スクリーンショット 2023-03-07 0.14.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/92e8aa51-0d45-a006-1b71-026957be10fa.png)
![スクリーンショット 2023-03-07 0.16.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/0a4fb3db-f651-7763-3020-c5f990b6029c.png)

インストールが完了した後、「Close & Reload Form」をクリックする。![スクリーンショット 2023-03-07 0.42.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/a97e412e-7184-d9bb-01db-e6b11cf9c5b7.png)

フォームをリロードした後に、右上の人のアイコンを押して、「Preferences」を選択する。
![スクリーンショット 2023-03-07 0.47.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/04e8aab3-ba6f-6313-4acf-38cae68dc245.png)

「Display」を選択する。
![スクリーンショット 2023-03-07 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/50ae661f-1d25-7c9d-d414-d88228955009.png)

「Language」を英語から日本語に変更する。
※「Language」の項目が出ない場合は、インスタンスを立ち上げし直せば出てきます。
![スクリーンショット 2023-03-07 0.56.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/69235962-4769-a281-18e3-22d8c49dfcc4.png)

日本語に変更して、ポップアップを閉じると、環境が日本語に変わっていることが確認できます。
![スクリーンショット 2023-03-07 0.58.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/4aca9ddd-1647-bea3-c8a0-add4449101f5.png)
![スクリーンショット 2023-03-07 1.00.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/bff82126-165f-32a5-90d4-91dcf246b79e.png)

以上で、「個人インスタンスの環境を日本語化にしてみよう」は終了となります。

終わりに
-
日本語のプラグインをインストールしておくと、英語と日本語が選択できるようになり、状況によって使い分けができるので、仕事の作業効率が上がりおすすめです。
技育CAMPアドバンス vol.1で企業賞をいただきました

# 技育CAMPアドバンスとは
技育CAMPアドバンスとは、サポーターズが行なっている技育CAMPというハッカソンの中で、受賞したチームだけが参加することができる、参加ハードルとレベルが高いハッカソンとなっていました。
開催地は東京の渋谷のオフィスの15階で行われました。
技育CAMPを知らない方は、下記のリンクから公式ページに飛べるので飛べるので見てみて下さい。
https://talent.supporterz.jp/geekcamp/

以下は概要を箇条書きでまとめたものです

- 技育CAMPで受賞した人のみ参加可能
- 開催はオフラインで東京の渋谷で開催
- 期間は１日間で、14時スタートの懇親会含めて20時

詳しいハッカソンの雰囲気等は、Twitterの検索欄に　#技育CAMPアドバンス を入力して検索すると参加者がツイートしているものが出てくるので、参考になると思います。

# いただけるもの
何かをもらうためにハッカソンに参加するわけではないですが、やはりもらえるのはモチベにつながると思います。
ですので、このハッカソンに参加することでいただけるものといただける可能性があるものを紹介します。

- 技育CAMPアドバンスのノベルティ
    - ロゴ入りトートバック
    - ロゴ入りTシャツ
- 企業様からのノベルティ
- 賞
    - 大賞 10万
    - 副大賞 3万　　３チーム
    - 企業賞　　１万＋副賞　　７チーム
- 交通費と宿泊費

企業様からいただけるノベルティや企業賞を受賞した際の副賞はそれぞれ違うので割愛させていただきます。

交通費と宿泊費を出してもらった上で、ノベルティや受賞したら賞金をもらえて、さらに会場ではお菓子や飲み物、懇親会ではサンドイッチやお酒まで出てきました笑

あと、なんといってもリアルで実際にあったり、プレゼンしたりしたことによる経験が他には変え難い、いただいたものだと思います。

# 賞を取れたポイント(個人の感想)

まず、このハッカソンは一度受賞したことがある方しかおらず、どの作品もレベルが高くて、全部受賞の可能性を秘めていました。

その中で大切だと思ったことは、以下の三つです。

- 開発した作品が解決してくれる課題を明確にすること
- プレゼンで作品の魅力等を理解してもらう
- 企業様に興味を持ってもらう

１つずつ詳しく説明していきます

### 開発した作品が解決してくれる課題を明確にすること

今回受賞をした作品の共通点が、ある課題を解決するという目的を明確に持っていることです。
私の作品はタバコのさまざまな情報を数値化するアプリだったのですが、目的は禁煙でした。
大賞の作品は予定管理
副大賞は推しのための家計簿、ハッカソンのアイデアをAIが手伝ってくれるシステム、Chromeのお気に入りタブやフォルダをAIが自動で整理してくれるシステム
でした。
このようにどのアプリも一言ではっきりと課題を解決できることがわかる作品でした。これが最低条件のようなもので、そこからのそれぞれの作品の作り込みがすごく、特にユーザーが実際に使用する際のことを考えて作り込んでいる作品は評価を受けている印象でした。

### プレゼンで作品の魅力等を理解してもらう

これをみて「当たり前だろ？」って思う方もいると思いますが、このハッカソンにとってはとても大事なことになります。
プレゼンの時間で作品を評価してもらうことは今までの技育CAMPと同じなのですが、アドバンスではプレゼンの後に7チームほどで別の部屋に移動し、そのチームの中から企業さんが興味を持ったところにより詳しく作品を見にいくという時間があります。
私の作品も、きてくださった企業様とそうでない企業様がいました。
そして、今回のハッカソンは審査員が企業様で、点数も企業様が全部持っています。
ですので、ここで来ていただけなかった企業様から点数をもらえることは０に近いということです。
つまり、賞をいただける可能性が格段に低くなります。
ですので、自分の作品に足を運んでもらうため、プレゼンで興味を持っていただく必要があるわけです。

### 企業様に興味を持ってもらう

上記でほぼ説明しているのですが、賞を決めるポイントと企業賞の権利は全て企業様が持っています。
ですので、企業様に興味を持っていただくことが必須になります。
プレゼンで興味を持っていただいた後は、その後の30分でプレゼンでは説明できなかった魅力を紹介しましょう。

私が感じたポイントはこのような感じです。

# 私たちが開発した作品
今回賞をいただくことができた作品の情報は以下のとおりです。

チーム名：転生したらプログラマだった件
作品名：やにめもりー
作品URL：https://zingy-profiterole-accecf.netlify.app/

# 最後に
初めてのオフラインハッカソンは、発表中にリアクションがもらえたり、交流することができたりとても楽しかったです！
今後も３ヶ月に1回あるようなので、まずは技育CAMPで受賞できるように頑張っていきましょう！
私もまた参加できるよう頑張ります💪
では、この辺りで〜
Power Apps で Fluent UI を使う方法（解せぬ）

こんばんわ。
「今日、某有名ＩＴ企業の社長に合ったんだぜ」と自慢したい男（思考が小学３年生）です。

表記の件、自社内で教わりました。
Qiita の過去記事にも無かったので、「オレの手柄」ということで記事化しておきます。

## Power Apps の UIデザインって、ぶっちゃけどうっすか？
いやね、Power Apps ってすごくステキなツールだと思うんすよ。
すごく簡単にWebアプリが作れるし。ホントに、生産性爆上がりっすよ。
大好きなんですけど。
ですけどね・・・。

大きな声では言えないですが、正直、UIが微妙だなーって。昔から思ってて。
おそらく、ユニバーサルデザインとか、視覚障害のある方への配慮とか、そういったことだとは思うんですよ。
でも、もうちょっとナントカなんねーのかなぁ、と。

## Fluent UI とは
だって、Microsft にも Fluent UI っていう、それっぽいものがあるらしいじゃないっすか。
せっかくなんで、今流行りの Bing チャットに聞いてやりましたよ。

> Fluent UI とは、Microsoft が提唱するデザインシステムのことです。
 Fluent UI は、見た目だけでなく、革新的なUIやユーザー体験を変えることを目指しています。
 Fluent UI は、Microsoft TeamsやWindows 365などの製品にも使われています。

簡単に言うと、良い感じの UI って事だと思うんですが、これを Power Apps で使いたいんですよ。

## Power Apps で Fluent UI を使う方法
そんなわけで、Power Apps で Fluent UI を使う方法です。
なんか、個人的にすごく「解せぬ」って話なので、今後のバージョンアップでこの方法は使えなくなる可能性があると思います。
簡単に言うと、
「Teams版の Power Apps で貼り付けたオブジェクトを、Web版の Power Apps にコピペする」
ってことで出来ます。

#### 手順１）
Teams版 Power Apps にオブジェクトを貼り付ける（この例では「テキストボックス」と「日付の選択」）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955093/5f8c1052-3384-7186-8c49-80ec1dc10736.png" width = 70%>

#### 手順２）
上記で貼り付けたオブジェクトを選択して「Ctrl+C」でコピーして 、Web版の Power Apps にペースト
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955093/3ef72470-d50c-9f59-ecd2-a812c1524544.png" width = 70%>

以上です。

## ほらね、こんなにオシャレに・・・あれ？
良い感じで貼り付けできたので、ドヤって記事を終わろうとしたんだけど、カレンダーコントロールの月選択が微妙にズレている。
これ、４列で表示しようとして、明らかになんかやらかしてるじゃん。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955093/d21b8ad6-27d7-6ee5-368c-9ab291d78d6d.png" width = 70%>
Teams版でも同じだ。ぐぬぬ・・・。そのうち改善されるとは思うんだけどさぁ・・・。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955093/c91cbe3b-1ffb-ebee-785b-38d0c5a7cb7c.png" width = 70%>

## 結論
まぁ、あれだ。
信じて待っていれば、そのうちオシャレになるんじゃないっすか。

## 参考資料
https://developer.microsoft.com/ja-jp/fluentui

https://www.bing.com/videos/search?&q=fluent+ui+power+apps&docid=603483776021103535&mid=00DE8A660135A64D8D7100DE8A660135A64D8D71&view=detail&FORM=VDMCNR&rvsmid=EB6B8C8440C64A50E549EB6B8C8440C64A50E549&ajaxhist=0

## 追記 (2023/03/07)
Creator Kit をインストするとコンポーネントが使えるようになります。
ただ、単体のアプリで使う場合は前述のコピペの方がラクかも。

https://learn.microsoft.com/ja-jp/power-platform/guidance/creator-kit/setup

https://youtu.be/NMKNA1-eYpo
PyhonでChatGPTのLineBotを作る

### TL;DR
流行りに乗ってChatGPT(本当はOPENAIのgpt-3.5-turboエンジン)のWebAPIをたたくLineBotを作る
ほぼ、下記記事の劣化焼き直し
https://zenn.dev/umi_mori/articles/chatgpt-api-python
https://chatgpt-lab.com/n/n55257c082a9d

### OPENAIキーの発行方法
下記の通り。ただし、https://openai.com/api/はproductのページへリダイレクトされてしまう
https://platform.openai.com/account/api-keys などにアクセスする
https://zenn.dev/umi_mori/books/chatbot-chatgpt/viewer/how_to_use_openai_api#api%E3%81%AE%E7%99%BA%E8%A1%8C%E6%96%B9%E6%B3%95

### LineDeveloper登録
下記などを参考にする。
https://chatgpt-lab.com/n/n55257c082a9d#f877eef2-6a5f-4061-8558-d57d2f91e868

- 応答設定からWebhookを有効、応答メッセージは無効にする

### 実装
今回はWebhookのバックエンドをAWS Lambdaとして、関数URL設定にて作成した。
おおむね下記手順
- AWSコンソールから「関数の作成」を押下
- 一から作成を選択し、ランタイムを選択(今回は使用するLayerの関係でPython3.7にしたが、Python3.9がいいと思う)
- 設定タブから「一般設定」を選択し、「変数」を押下、タイムアウト時間を30秒ほどに設定する
- 設定タブから「関数URL」を選択し、「関数URLの作成」を押下、認証は「NONE」を選択してURLを作成する
- 設定タブから「環境変数」を選択し、「LINE_ACCESS_TOKEN」、「OPENAI_KEY」を設定する
- 後述のコードを関数に張り付ける
- 基本的にはPythonのrequestsモジュールと一緒にzip化したものをアップロードする

### コード
大分雑だが、下記でいけた。
``` handler.py
import json
import requests
import os

OPENAI_KEY = os.environ["OPENAI_KEY"]
LINE_ACCESS_TOKEN = os.environ["CH_ACCESS_TOKEN"]

reply_url = 'https://api.line.me/v2/bot/message/reply'
openai_url = 'https://api.openai.com/v1/chat/completions'

def lambda_handler(event, context):
    # requst情報取得
    body_dict = json.loads(event["body"])
    events = body_dict["events"][0]
    reply_token = events["replyToken"]
    text = events["message"]["text"]

    if text == "":
        #メッセージ以外(スタンプや画像など)が送られてきた場合
        text = '？？？'
    # OPENAIのAPI実行
    prompt = text
    headers_openai = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(OPENAI_KEY)}
    payload = {"model": "gpt-3.5-turbo","messages": [{"role": "user", "content": prompt}]}

    resp_openai = requests.post(openai_url, headers=headers_openai, data=json.dumps(payload))
    openai_replytext = json.loads(resp_openai.content)['choices'][0]['message']['content']
    # LINE replyのAPI実行
    headers = {'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer {}'.format(LINE_ACCESS_TOKEN)}
    body = {
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': openai_replytext,
      }]
    }
    resp = requests.post(reply_url, headers=headers, data=json.dumps(body))
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

### 感想
- 思ったより簡単にできた
- 参考記事ではPython/node.jsなのmoduleを利用するものが多かったがrequestsで簡単にできた
- Lambdaだとタイムアウト時間の設定が必須。3秒でレスポンスは返ってこない
- "role": "system"のプロンプト回りはまだトライしてないので、続きでやる
初めてのReact

# はじめに
JavaScriptの基礎がある程度身についたので、念願のReactに簡単なTodoアプリを作ることで触れてみました。
学習教材として、YouTubeで見つけた動画を選び、ハンズオンでアプリを作成しました。
所要時間：３時間弱

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

## スキルの自己評価
まだ駆け出せてもいない、エンジニアでもない人間です。
Udemyで「Web Developer Bootcamp 2021（日本語版）」を学び終え、JavaScriptの基礎の基礎がわかってきたかな、くらいです。
次のステップとしては、Reactの基礎を学んでいく中で自己解決能力（リサーチ力）を上げていきたいと思っています。

https://www.udemy.com/course/the-web-developer-bootcamp-2021-japan/


# この教材を通して、自分がつまずいた部分
### ターミナルからプロジェクトのVScodeを開く
```React:ターミナル
$ code .
```
これで開けない場合

https://qiita.com/naru0504/items/c2ed8869ffbf7682cf5c


### useState
状態の変数を管理・格納する「Hooks」の理解が難しかった。再レンダリングの概念とも絡んで、何回も公式ドキュメントを見直しました。

https://beta.reactjs.org/learn/state-a-components-memory


### props
propsはオブジェクトである、という意味が理解できなかった。

```React:TodoList.js
const  TodoList = ({ todos }) => {
    return <div>{todos}</div>;
};
```
{}はJSX記法を意味する。この中でJavaScriptを記述できる。


# まとめ
今回の学習で活用させていただいたのはYouTubeの教材ですが、無料と思えないほどわかりやすく、ボリュームもいい感じにまとまっていると感じました。
私は休憩を挟みつつ、ハンズオンでアプリを作り終えるまでの時間は３時間弱でした。
３時間でここまで学ぶことができたので、大満足です。

Reactを触ったのはこれが初めてです。
今後はReactの公式チュートリアルや、Udemyの教材を使って、少しでもReactマスターに近づけるよう頑張ります。
会社の業務効率化を図る試作1号機

フルバーニアンではないです。システムです。(溢れ出るガノタ…)

今回の試作1号機は「「「画像をリサイズするシステム」」」です！！！！🎉
色々と商品画像を載せる際にバカでかい画像達を一つ一つリサイズしていく作業をしていた時、
「これまーじでしんどい」
って思ったやつがいました。僕です。
でもこれってPythonでまとめて一括処理できるのでは？と閃いたってわけです。
さっそくググるぜーって調べたらもうね、出てきましたよ。ナイスです👍👍👍

というわけで参考にさせていただいたサイト↓

https://opty-life.com/study/program/python/python-lecture-36/

習うより慣れろ精神で作っていくZE🌟
「Visual Studio Code」を使いました。


import os
from PIL import Image
↑これでPIL(pillow)からImageをインポートする。※pillowはPythonの画像処理ライブラリ


bairitsu = 4
↑画像サイズの縮小倍率の定義。これで1/4サイズに。


folder_a = "C:~/~/image"
↑ここで縮小したい画像フォルダを指定する。


list1 = os.listdir(folder_a)
↑フォルダ内の画像をリスト化


imagefile = os.path.join(folder_a, list1[i])
imagedata = Image.open(imagefile)
↑画像ファイルを開く。そしてパス名を加える、らしい…？


width, height = imagedata.size
↑画像の縦横サイズを知る


width2 = width/bairitsu
height2 = height/bairitsu
imagedata2= imagedata.resize((int(width2),int(height2)))
↑画像サイズの縮小。整数の変換のために「int」をつける。


newimage = folder_a + "new" + list1[i]
imagedata2.save(newimage, quality=85,optimize=True)
↑変換した画像は分かりやすいようにファイルの頭に「new」がつく仕様。ありがてえ🙏
画像の質は85。これ以下にするとめっちゃ粗くなるらしい。
※やってみたらやばかったから85がいいっぽい。
optimizeは最適化するオプション。Trueにする。

------------------------------------------------------

…丸パクリです。はい。
でも実行したらちゃんとリサイズできたから「え、やば〜！！」ってなりました。
流れは掴めた感ある、これ自分でできたらカッコよすぎだろ！！！！！
最初実行の仕方が分からなかったりPathが通らなくてめっちゃエラー出たけど、色々調べているうちに楽しくなってきちゃった。何より達成感が半端じゃないです！！

効率化させたいものがまだまだあるのでどんどん作って経験値貯めて行こうと思います。
6点+ハンドトラッキング+フェイストラッキングでフルトラッキングする方法

YouTube配信等でハンドトラッキング+フェイストラッキングを含むフルトラッキングをしたい場合の方法を紹介します。
※VRChat, Cluster用ではありません

## 必要なもの
- VIVEトラッカー4つ(mocopiの場合は未検証です)
- INDEXコントローラー(ドングルは別のトラッカーのものを使用するなど別途用意してください)
- ベースステーション
- iPhone or iPad
- PC(Windows)

## 手順
### SteamVRのHMD強制使用をOFFにする
C:\Program Files (x86)\Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings
の「requireHmd」を「false」に，「activateMultipleDrivers」を「true」にします

### トラッカーとドングル，INDEXコントローラーとドングルをペアリングする
電源がついたベースステーションとPCを接続し，各公式サイトを参考にトラッカー，INDEXコントローラーとドングルをペアリングします
[VIVE トラッカー (3.0) をペアリングする](https://www.vive.com/jp/support/tracker3/category_howto/pairing-vive-tracker.html)
[セットアップガイド - Akamaihd.net](https://steamcdn-a.akamaihd.net/steam/apps/1059550/manuals/ControllerQSG_JP.pdf)


### バーチャルモーションキャプチャー(VMC)をインストール
https://booth.pm/ja/items/999760

から入手できます

### waidayoをインストール
https://booth.pm/ja/items/1779185

から入手できます
PCとiPhone/iPadにインストールします。

### waidayoのPC-iOS端末間連携
iOS端末のwaidayoのメニューにある「Send Motion IP Address」にPCのIPアドレスを入力します
![20230306_144229206_iOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3182201/b7cb2c32-7fe0-addc-a6bb-521b8690f221.png)
iOS版waidayoのフェイストラッキングがPC版waidayoに反映されていればOKです

### waidayoとVMCの連携
https://qiita.com/take2_mbh/items/6b99fbcfa7e2b987953b

こちらの記事を参考に，VMC側でOSCの受信を許可します。

### VMCの使い方等
こちらの記事が参考になります
https://styly.cc/ja/tips/vtuber-rapturn-vmc/
strcmp関数を使って2つの文字列を辞書順でどちらが早い順番か判定する方法

# 注意
AtCoderの[abc217_A - Lexicographic Order](https://atcoder.jp/contests/abc217/tasks/abc217_a)のネタバレあり。

# ACしたコード 
```C
#include <stdio.h>
#include <string.h>

int main(void)
{
	char s[11];
	char t[11];

	scanf("%s %s", s, t);
	if (strcmp(s, t) < 0){
		printf("Yes\n");
	} else {
    printf("No\n");
	}
	return (0);
}
```
# わからなかったこと
①strcmp関数の引数に文字列を入れて、第一引数が第二引数より辞書順で早いと負の整数を返す。第二引数の方が早い場合は、正の数を返す事。
②以下の条件式は、sがtよりも辞書順で前であるかどうか判定する事、
```C
if(strcmp(s, t) < 0)
```
<b>chatGDP</b>
Q. if (strcmp(S, T) < 0) { この部分が辞書順になる仕組みを教えてください。
A. strcmp関数は、2つの文字列を辞書順で比較し、その大小関係を整数で返します。

辞書順とは、単語の並び順を表す方法の1つで、辞書の単語の並び方に基づいています。2つの文字列を辞書順で比較する場合、まず最初の文字から比較を始め、2つの文字が異なる場合はその大小関係を決定します。もし同じ場合は次の文字を比較します。一方がもう文字がなくなった場合は、残りの文字列がもう片方の文字列よりも小さいと判定されます。たとえば、"abc"と"abde"を辞書順で比較する場合、最初の"a"は同じなので、次の文字"b"を比較します。"abc"の次の文字は"c"ですが、"abde"の次の文字は"d"ですので、"abc"は"abde"よりも小さいと判定されます。

したがって、 strcmp(S, T)はSとTを辞書順で比較し、SがTより小さい場合には負の整数、SがTより大きい場合には正の整数、SとTが同じ場合には0を返します。このため、 strcmp(S, T) < 0 という条件式は、SがTよりも辞書順で前であるかどうかを判定しています。

③[strcmp man](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/strcmp.3.html)の書式の部分がプロトタイプ宣言を書いていることがわかった。
今までは書式の通りに書けばstrcmp関数を使えると思ってたから同じように書いても使えなかったからなんで書いてあるか理解できていなかった。
External Script Editor にVisualStudioが出てこないときの対処法

Unity Hub (Win)で、でVisual Studio がインストールされているにもかかわらず
External Script Editor に出てこないときの対処法です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/7ece908e-3be1-7597-655c-fb25a8701277.png)

タスクバーの検索欄にVisual Studioと入力すると、関連するファイル一覧が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/1356b65e-2b27-fb3d-f9e3-1b830951dbf8.png)

UnityHubで表示されているバージョンのVisualStudioを選択し、右クリックでファイルの場所を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/9e5cbb76-353f-0e09-7e0e-a1f794a0636e.png)

するとショートカットが表示されるので、もう一度右クリックでファイルの場所を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/8c9e0a71-448c-ee01-e7d7-dc4ae17ff12c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/63e95256-3f9b-c92d-b805-93dc1af74816.png)

Unity上部のメニューから、
Edit>Preferences>ExternalTools>ExternalScriptEditor>Brouse...
を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/84134bb0-0014-7ed5-37f3-493d833c8433.png)

先ほど開いたIDE(devenv.exe)のフォルダPathを入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/63e95256-3f9b-c92d-b805-93dc1af74816.png)

Unity Hubで表示されていたVisual Studioが選択できるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/0ee79117-35de-7525-074c-8a740e72fbbb.png)

DebugでUnityにアタッチできない場合は、
Package manager で Visual Studio Editor
がinstallされているか確認してみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/f7016636-5d91-62b4-d306-a58c6e304e14.png)

以上です。
Vue.jsで画像のsrcに変数を使ったら画像が表示されない


# 起きている事象
```img.vue
<template>
    <!-- 変数を展開せずにファイル名を指定すると表示される -->
    <img :src="~/assets/images/img-1.png" />

    <!-- 変数を展開しても画像ファイルが表示されない -->
    <img :src="`~/assets/images/${fileName}.png`" />
</template>

<script setup>
    const fileName = 'img-1';
</script>
```

# 解決方法
### require()を使う！
```img.vue
<template>
    <!-- require()で囲ってあげる -->
    <img :src="require(`~/assets/images/${fileName}.png`)" />
</template>

<script setup>
    const fileName = 'img_1';
</script>
```

# 読み込めない原因は？

Vue.jsはsrcで指定されているパスをそのまま表示しているわけではなく、vue-loaderというライブラリを使ってコンパイルしています。

これを、、、
```
<img src="../image.png">
```

このようにコンパイルしています。
```
createElement('img', { attrs: { src: require('../image.png') }})
```

コンパイルすることで、imagesディレクトリの場所を示すパスが入り、画像が表示されるようになります。

imgタグのsrc属性をv-bindした場合はこのコンパイル処理が走らなくなるため、わざわざ自分で`require（）`を使う必要があるみたいです。

https://vue-loader-v14.vuejs.org/ja/configurations/asset-url.html
【TypeScript】ローカルに保存したパッケージを他のプロジェクトで使う方法

Remixに関連のあるライブラリをフォークして、ローカルにクローンして修正を行っていた時の話。
これをコミットする前に、Remixプロジェクトにインポートしてきちんと動くか確認したかった。

ちなみにそのパッケージとは、これ。

https://github.com/danestves/remix-auth-auth0

そして、これの`package.json`は次のようになっている。

```json
{
  "name": "remix-auth-auth0",
  "version": "1.6.0",
  "main": "./build/index.js",
  "types": "./build/index.d.ts",
  "scripts": {
    "build": "tsc --project tsconfig.json",
    "typecheck": "tsc --project tsconfig.json --noEmit",
    "lint": "eslint --ext .ts,.tsx src/",
    "test": "jest --config=config/jest.config.ts --passWithNoTests",
    "coverage": "npm run test -- --coverage"
  },
  "keywords": [
    "remix",
    "remix-auth",
    "auth",
    "authentication",
    "strategy",
    "auth0"
  ],
  "license": "MIT",
  "files": [
    "build",
    "package.json",
    "README.md"
  ],
  "peerDependencies": {
    "remix-auth": "^3.x"
  },
  "devDependencies": {
    "@babel/core": "7.20.5",
    "@babel/preset-env": "7.20.2",
    "@babel/preset-react": "7.18.6",
    "@babel/preset-typescript": "7.18.6",
    "@remix-run/node": "1.8.2",
    "@remix-run/react": "1.8.2",
    "@remix-run/server-runtime": "1.8.2",
    "@types/jest": "29.2.4",
    "@typescript-eslint/eslint-plugin": "5.46.0",
    "@typescript-eslint/parser": "5.46.0",
    "babel-jest": "29.3.1",
    "eslint": "8.29.0",
    "eslint-config-prettier": "8.5.0",
    "eslint-plugin-jest": "27.1.6",
    "eslint-plugin-jest-dom": "4.0.3",
    "eslint-plugin-prettier": "4.2.1",
    "eslint-plugin-unicorn": "45.0.1",
    "jest": "29.3.1",
    "jest-fetch-mock": "3.0.3",
    "prettier": "2.8.1",
    "react": "18.2.0",
    "ts-node": "10.9.1",
    "typescript": "4.9.4"
  },
  "dependencies": {
    "remix-auth-oauth2": "^1.5.0"
  }
}
```

調べたところによると、`npm link`を使う方法が一番手取り早そうだった。

まず、ローカルにクローンしたパッケージのルートディレクトリ内にて`npm link`を実行する。

```shell
cd ~/remix-auth-auth0
npm install
npm link
```

そして、このパッケージを使用したいプロジェクト内にて`npm link remix-auth-auth0`を実行する。

```shell
cd ~/remix-app
npm link remix-auth-auth0
```

これでリンクが完了したと思ったので、`npm run dev`を実行したところ次のエラーが発生した。

```shell
The path "remix-auth-auth0" is imported in app/auth.server.ts but "remix-auth-auth0" was not found in your node_modules. Did you forget to install it?
```

なぜ、冒頭で`package.json`を見せたかというと、`"main": "./build/index.js"`に注目して欲しかったからだ。

つまり、`npm link`を実行する前に、`npm run build`を実行して`build/index.js`を生成するのを忘れていたため、上記のエラーが発生した。

なので、ビルドを実行してから、再度`npm link`を実行した。

```shell
npm run build
npm run link
```

そして、`remix-auth-auth0`に依存しているプロジェクト内で`npm link remix-auth-auth0`を実行してから`npm run dev`を実行したところ、エラーは解消された。

もし、リンクを解除したい場合は`npm unlink remix-auth-auth0`を依存しているプロジェクト内で実行すると解除することができる。