OmniAICreator/Qiita-1.07M huggingface dataset:
DiscordBotに入力中といわせよう！！

<h1>はじめに</h1>
<p>最近DiscordBotを作って遊んだりしているときに、こう思ったことはありませんか？<br>
「Botにも入力中って出させたいなぁ～」と、<br>
きっとこの記事を見ているということはそう思っているに違いない(そんなことない)と思うので、<br>
さっそく作っていきましょう！！

<h1>開発環境</h1>
<p>OS = Windows 10 Pro<br>
Discord.js = 14.7.1</p>

<h1>必要なもの</h1>
<p>・ある程度完成したDiscordBot<br>
・作りきるという気持ち
</p>

<h1>コード</h1>
<p>まずは、特定の言葉に反応するプログラムを書きます。<br>
ここでは、"Tenma"という言葉が文中にあるかに反応して"Tsukasa"とリプライを返すようにします。</p>

```js:index.js
~~~
if(msg.content.match(/Tenma/)) {
    msg.reply('Tsukasa')
}
~~~
```
<p>ここから手を加えていきます。</p>
<p>ifとms.replyの間に<b>msg.channel.sendTyping()</b>を入れます。

```js:index.js
~~~
if(msg.content.match(/Tenma/)) {
    msg.channel.sendTyping()
    msg.reply('Tsukasa')
}
~~~
```

<p>このmsg.channel.sendTypingは入力中を出す命令なので、実際はこれだけでも表示されるのですが、<br>
「一瞬だけ過ぎて見えない！！」<br>
と言う人のためにもう一工夫入れちゃいましょう！！</p>

```js:index.js
~~~
if(msg.content.match(/Tenma/)) {
    msg.channel.sendTyping()
    setTimeout(() => {
        msg.reply('Tsukasa')
    },1500)
}
~~~
```

<p>これで特定のワードが入力されてから、1.5秒の間だけ入力中と表示されるようになりました。<br>
これで、今までDiscordBot作りで困っていた人の悩みも吹っ飛んだはずです。
</p>

![Memo1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3088564/02cbde5b-d7ce-cbc3-94a6-5a4c4cda15d8.png)

![Memo2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3088564/b266af78-c73b-12c4-4ce7-3aae46a3da59.png)

<p>しっかりと動いていますね。</p>

<h1>あとがき</h1>
<p>Qiitaの記事を書くのは初めてで、ところどころ間違えている場所があるかもしれないので、温かい言葉で指摘してくれると幸いです。</p>

<h2>参考ページ</h2>
<a herf="https://scrapbox.io/discordjs-japan/%E3%83%9C%E3%83%83%E3%83%88%E3%81%AB%E3%80%8C%E5%85%A5%E5%8A%9B%E4%B8%AD...%E3%80%8D%E3%81%A8%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84">https://scrapbox.io/discordjs-japan/%E3%83%9C%E3%83%83%E3%83%88%E3%81%AB%E3%80%8C%E5%85%A5%E5%8A%9B%E4%B8%AD...%E3%80%8D%E3%81%A8%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84</a>
<p>実際作るものは簡単だから、ここよりこっち見たほうが速いかもしれない</p>
3時間でAIチャットアプリをリリースした話

# 作ったもの
![Simulator Screen Shot - iPhone SE (3rd generation) - 2022-12-27 at 16.44.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135021/30757d70-134a-cb28-1fdc-008f7129879a.png)

## ちょっと中身の話
アプリはFlutterを使いました。
FlutterのCHatUIコンポーネントを使うと一瞬でチャット画面を構築できます。
マジで一瞬です。

Flutterはマルチプラットフォームに対応しているので、iOSとAndroid両方のアプリが3時間でできました。

フロントの部分はFlutterで一瞬で作り、AIの部分はGPT-3.5のモデルを使っています。
WebAPIで文字列をバックエンドに送り、処理の結果を返してくれるシンプルなものになっています。

ココで重要な点は、世界最高峰のAIモデルであるGPT-3.5を使ったアプリをたった3時間でリリースできてしまうところです。

恐ろしい時代になりました。

# 3時間の内訳
## フィージビリティ調査（30分）
作りたいもの（AIチャットボット）を本当に作れるのかな？
どうやったら作れるのかな？
作れるとしたらどうれくらいかかるかな？

これらをざっと30分くらいでやりました。
基本的にはAIモデルの使い方とFlutterでチャットアプリを作る方法を調べた上で、それをどう実装に落とし込むかを箇条書きでまとめる感じです。


## 実装（1時間）
フィージビリティの段階で頭の中では設計が完了していました。
ですので、単体テストまでは30分ほどで終わり、フロントとバックを繋いだ結合テストで少し時間を取られました。

## リリース手続き・審査（1時間半）
アプリを実装したらリリースの手続きです。
リリースの経験はありましたが、ここ数年はリリースサイトを覗いていなかったので見た目が変わっていて少し戸惑いました。

しかし、基本的な部分は変わっていなかったので、必要な項目を入力してリリースレビューに投げてあとは待つだけ。

レビュー自体はすぐに通りました。時間帯と時期の相性が良かったのでしょうか、もっと時間がかかる印象でした。

# リリースしたアプリ
GhostWhisperというアプリをリリースしました。

https://apps.apple.com/jp/app/ghostwhisper/id1661735774

ゴーストが話し相手・相談相手になってくれるアプリです。
たまに素っ頓狂なことを言います。

アプリ名でわかる方もいるかも知れませんが、元ネタは攻殻機動隊の有名なセリフです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135021/c676a5b3-83c7-e637-4bf0-21532734b13b.png)
React 環境構築 (たまに忘れるので、備忘録)

# 開発環境
・MacBook Air (2022)
・macOS Ventura (13.1) 
・Apple M2

# ターミナルのコマンド履歴

### homebrewインストール
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
nextstepを求められたので、
表示されたままをターミナルでコマンド入力
＊{ユーザー名}の部分は適宜修正するか表示されているコマンドをコピペしてください。

```
echo '# Set PATH, MANPATH, etc., for Homebrew.' >> /Users/{ユーザー名}/.zprofile
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/{ユーザー名}/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
```

インストール確認
```
brew --version
```

### nvm インストール

```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
```

表示されていたコマンドそのままターミナルで入力
```
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
```

なんかやった方が良さそうなコマンド
```
tail -n 3  ~/.zshrc
exec $SHELL -l
```

nvm バージョン確認
```
nvm --version
```

### node のインストール
```
nvm install node
```

nodeのバージョン確認
```
node -v
```

npmも一緒にインストールされているので、確認
```
npm -v
```

### React が使えるかの動作確認

ターミナルでコマンド入力
```
npx create-react-app react-test
```
対象フォルダに移動して
```
cd react-test
```
```
npx start
```
GCPの全体像について軽くまとめてみた

### この記事を書いたきっかけ
GAE(Google Application Engine)を使用する機会があり，GCP(Google Cloud Platform)についての全体像を掴んでおこうと思った. 何が利用でき、各部分がどのように連携して機能するかを知ることで，進め方を決めるのに役立つと思ったから．

## Google Cloud のリソース
Google Cloud = ハードアセット＋仮想マシン(VM)などの仮想アセット．

これらのアセットが，世界中にある Google のデータセンターでガンガン稼働している．
各データセンターはリージョンに位置している．
リージョンはGoogle Cloudアセットロケーションの最小単位であるゾーンの集合．各ゾーンは文字の識別子とリージョン名を組み合わせた名前で識別される．たとえば、東アジアのリージョンのゾーン a は、asia-east1-a という名前．
Google Cloudはデータセンターにあって，データセンターはリージョンにあって，リージョンはゾーンから構成されていて．と言う感じ

#### なぜ細分化する必要があるのか？
> リソースのこの分布には、リソースをクライアントの近くに配置することによる障害時の冗長性やレイテンシの削減など、いくつかの利点があります。この分布により、リソースを一緒に使用する方法についてのいくつかのルールが導入されます。

もしもの時のために，リージョンが近いと対応しやすいらしい．普通に考えて，データセンターも物理的なものなので災害などで故障してしまうと顧客のクラウドアセットも水の泡になってしまう．そうならないために，データセンターを世界各地に分散させるし，レイテンシ解消のために自分のと近いデータセンターを選択することが推奨されている．

しかし，この分布のためにリソースの使用に以下のような制限がかかる．

## グローバル, リージョン, ゾーンリソース
グローバル リソース→ 他のリソース，複数のリージョンやゾーンによってもアクセスできる．事前設定されたディスクイメージ，ディスクのスナップショット，ネットワークを含む．
リージョン リソース→ 同じリージョンに位置するリソースからのみアクセスできます．静的外部 IPアドレスが含まれます。
ゾーンリソース→ 同じゾーンに配置されているリソースからのみアクセスすることができます。VM インスタンス、その種類とディスクが含まれます。

次の図は、グローバル スコープ、リージョン、ゾーン、またそれらのリソースの一部との関係を示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513017/5d109369-99e3-ade5-0ed2-f1c06700ca3a.png)
この図からもわかるよう，ゾーンリソースは同一ゾーンからしかアクセスできない．リージョンリソースはどんなゾーンからでもアクセスできるが，異なるリージョンからのアクセスはできない．グローバルは．．．(略)

## プロジェクト
Google Cloud のリソースはすべて、プロジェクトに属していなければならない．
プロジェクトとは、構築する対象をまとめて管理する1つの単位と考えることができる．プロジェクトは、設定や権限に加え、アプリケーションに関する情報を記述したその他のメタデータで構成される．**同じプロジェクト内のリソースは簡単に連携させることができる。** これは、リージョンとゾーンのルールに沿った内部ネットワーク通信などによって行われる．（共有 VPC または VPC ネットワーク ピアリングを使用しない場合、あるプロジェクトが別のプロジェクトのリソースにアクセスすることはできません。）

各 Google Cloud プロジェクトには次の属性が含まれる．
- ユーザーが提供するプロジェクト名
- プロジェクト ID（ユーザーまたは Google Cloud が指定）
- Google Cloud から提供されるプロジェクト番号
Google Cloud を使った操作では、コマンドや API 呼び出しでこれらの識別子を使用することがある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513017/3c40ec54-93e9-7937-5df0-e59b0d248329.png)


### プロジェクトの機能
プロジェクトは名前空間として機能する．これは、**各プロジェクト内の**どのリソースもユニークな名前を持っていなければならないことを意味するが、**別々のプロジェクトである場合は、通常リソース名を再度使うことができる．**　（一部のリソース名はグローバルに一意である必要がある）

例えば，同一プロジェクト内にApplication EngineとCloud Storageをリソースとして持っておくと，これら二つのリソースは簡単に連携が可能である．
phpをバージョンアップする際の簡易書式チェック

# 概要
phpがサポート期限切れのためにバージョンアップが必要になったため既存コードを簡単にチェックする
（テストがきちんと作ってあればいいんですが今回は構文チェックで…）

# 事前準備
とりあえずどんなエラーも見つけたいのでphp.iniでエラーレポートをすべて行うように変更しておく

```php.ini
error_reporting = E_ALL
```

# コマンド
findで対象ファイルを探して、grepでエラーがないメッセージは表示しないようにする
`find . -name "*.php" -type f -exec php -l {} \; | grep -v 'No syntax errors'`

# 実行例
適当なものがなかったので、昔のphpmyadminでやってみたらいろいろ出てました
自作のプログラムでこういうのが出ていたら修正ですね

```
PHP Fatal error:  Array and string offset access syntax with curly braces is no longer supported in ./phpmyadmin/libraries/server_privileges.lib.php on line 2678
Errors parsing ./phpmyadmin/libraries/server_privileges.lib.php
```
郵便番号情報をダウンロードしてSupabaseに登録する Python（Google Colaboratory）

## 手順

1. supabaseのプロジェクトの作成
	* supabaseの下記のデータベース接続情報をメモする
		* Host
		* Database name
		* Port
		* User
		* Password
2. Pythonプログラム（Google Colaboratory）の作成
	* supabaseの接続情報をconfig.ymlに設定する
    	* 日本郵政の郵便番号データベースのダウンロード先も設定しておく
    * Pythonプログラム作成

```config.yml
SUPABASE:
  SUPABASE_PROJECT_URL: https://xxxxxx.supabase.co/
  Host: db.xxxxxxxx.supabase.co
  Databasename: xxxxx
  Port: xxxx
  User: xxxxx
  Password: xxxxxx
Postcode:
  CSV_URL: https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip
```

## supabaseの管理画面でのテーブルの作成

SQL Editorを使う

```sql
create table postcode (
  id serial  primary key,
  postcode varchar(8),
  ken varchar(6),
  address1 varchar(50),
  address2 varchar(50),
  updated_at timestamp with time zone not null default now()
);

create index on postcode (postcode);
```

## Pythonプログラム

PythonからPostgreSQLに接続する為のライブラリをインストール
```shell
pip install psycopg2
```
Pythonプログラム本体
```python
import yaml
# configはGoogleドライブに保存
CONST_CONFIG_FILENAME = "./drive/MyDrive/colaboratory/postcode_to_supabase/config.yml"

# configの読込
config = None
with open(CONST_CONFIG_FILENAME, 'r') as yml:
	config = yaml.safe_load(yml)
	print(config)

# 郵便番号情報のダウンロード
import os
import requests

url = config['Postcode']['CSV_URL']
r = requests.get(url, allow_redirects=True)
saveZipFileName = "postcode.zip"
if os.path.isfile(saveZipFileName):
	os.remove(saveZipFileName)

open(saveZipFileName, 'wb').write(r.content)

# 解凍
import shutil
out_dir_name = saveZipFileName.split(".")[0]
shutil.unpack_archive(saveZipFileName, out_dir_name)

# データベース接続
import psycopg2
from psycopg2 import extras

connection = psycopg2.connect(host=config['SUPABASE']['Host'],
user=config['SUPABASE']['User'],
password=config['SUPABASE']['Password'],
database=config['SUPABASE']['Databasename'])

# 一括登録する関数を定義
def insertPostcodeDatas(values):
	with connection:
		with connection.cursor() as cursor:
			cursor.execute("truncate table postcode")
			sql = "insert into postcode (postcode , ken , address1, address2) values %s"
			extras.execute_values(cursor, sql, values)
	
			# # コミットしてトランザクション実行
			connection.commit()
			
			# 終了処理
			cursor.close()


# CSVを読込DBにINSERT

CSV_FILE_NAME = "KEN_ALL.CSV"
csv_file_path = os.path.join(out_dir_name,CSV_FILE_NAME)

import csv
datas = []
with open(csv_file_path, "r", encoding="Shift_JIS") as csv_file:
	f = csv.reader(csv_file)
	for row in f:
		postcode = row[2]
		ken = row[6]
		address1 = row[7]
		address2 = row[8]
		datas.append([postcode, ken, address1, address2])

insertPostcodeDatas(datas)

```

データベースへの登録に3分ぐらいかかる

## その他

supabaseでテーブル（postcode）にRLSを設定して、アプリケーションから利用する
【EC-CUBEエラー】An exception has been thrown during the rendering of a template ("Parameter "route" for route must match "(?:[0-9a-zA-Z_\-]+\/?)+(?<!\/)" ("" given) to generate a corresponding URL.").


EC-CUBEはページを追加したらdtb_pageテーブルにデータを追加する必要があります。


```
mysql> select * from dtb_page where id = 1;
+----+----------------+------------------+-------------+--------------------------------------+-----------+--------+-------------+---------+---------------------+---------------------+-------------+-----------+--------------------+
| id | master_page_id | page_name        | url         | file_name                            | edit_type | author | description | keyword | create_date         | update_date         | meta_robots | meta_tags | discriminator_type |
+----+----------------+------------------+-------------+--------------------------------------+-----------+--------+-------------+---------+---------------------+---------------------+-------------+-----------+--------------------+
| 1 |           NULL | custom product | custom_product | Custom/product |         2 | NULL   | NULL        | NULL    | 2022-12-29 14:49:33 | 2022-12-29 14:49:33 | NULL        | NULL      | page               |
+----+----------------+------------------+-------------+--------------------------------------+-----------+--------+-------------+---------+---------------------+---------------------+-------------+-----------+--------------------+
1 row in set (0.01 sec)
```


```php:Customize/ProductController.php


   /**
    * 
    * @Method("GET", "POST")
    * @Route("/custom_product", name="custom_product") #URLを指定
    * @Template("Custom/custom_product.twig") #ページ遷移先を指定
    *
    */
	public function CustomProduct(Request $request) { 
		$product = null;
		
		return [
			'product'=>$product			
		];
	}

```
Go言語の「アプリケーション なになに への接続を許可しますか？ 」が何回も出てくる問題 (mac)

「詳解GO言語WEBアプリケーション」の本(p127 kindole版はp130?)
を読んでいた時に少しハマったのでメモしておきます.
[本: 詳解GO言語WEBアプリケーション](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3Go%E8%A8%80%E8%AA%9EWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E6%B8%85%E6%B0%B4-%E9%99%BD%E4%B8%80%E9%83%8E/dp/4863543727)
# 問題
「詳解GO言語WEBアプリケーション」の本(p127 kindole版はp130?)のコードを実行した際に
**アプリケーション“main”へのネットワーク受信接続を許可しますか?**
と出る.
この 承諾ボタン を押すのが一回きりならいいのですが, ctrl + c でプログラムを終了して,
再度プログラムを走らせる度に出てきます.
![スクリーンショット 2022-12-30 16.37.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670178/8792ad2c-97bf-343a-2bcb-d4e2e7dbc1a4.png)

 

__コード__
```golang
package main

import (
	"fmt"
	"net/http"
	"os"
)

func main() {
	err := http.ListenAndServe(
		":18080",
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "Hello%s!", r.URL.Path[1:])
		}),
	)
	if err != nil {
		fmt.Printf("failed to terminate server: %v", err)
		os.Exit(1)
	}
}
```
# 結論
ポートの指定を ":18080"　から "localhost:18080" に修正する


```golang
package main

import (
	"fmt"
	"net/http"
	"os"
)

func main() {
	err := http.ListenAndServe(
        // ここをlocalhost:18080に変える
		"localhost:18080",
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "Hello%s!", r.URL.Path[1:])
		}),
	)
	if err != nil {
		fmt.Printf("failed to terminate server: %v", err)
		os.Exit(1)
	}
}
```

原因はportの指定を ":18080" のようにしているからです
":18080"は省略している書き方で　内部では "0.0.0.0:18080" としていることになっている
この 0.0.0.0 というのが問題で、これでサーバーを起動すると

このままだとMacの外部にポート開放しようとしてるけど大丈夫？という意味で
「ネットワーク受信接続を許可しますか？」
とMacのファイアウォールが聞いてくることになる

[詳しい0.0.0.0の意味はこちらの記事を参考にすると良いと思います](https://qiita.com/amuyikam/items/0063df223aed40193ba9)


解決方法は簡単で

":18080"　から "localhost:18080" に修正するだけです

"localhost:18080"　は　"127.0.0.1:18080"　を表している
"127.0.0.1" の部分はループバックアドレスと呼ばれていて、localhostでアクセスする時のアレです



# ループバックアドレスとは？

ローカルループバックアドレスとは、自分自身を表す特別なIPアドレスの1つであり、TCP/IPが有効なコンピュータでは常に利用可能なIPアドレスです. 一般的には以下のIPアドレスが利用されます.

IPv4の場合： 127.0.0.1
IPv6の場合： ::1（0000:0000:0000:0000:0000:0000:0000:0001）

IPv4の場合、IPアドレスの最上位のバイト（最上位の8bit）の内容が「127」であればよいので
「127.0.0.1～127.255.255.254」の範囲内ならばどのIPアドレスでも利用できます
（「127.0.0.0」と「127.255.255.255」の2つはブロードキャストアドレスのため除外される）

ex)
127.0.0.2 や 127.1.2.3
Elixirから覚えるJavaScript　〜map関数〜

僕は普段はElixirを使ってます
必要になったのでJavaScriptの勉強をはじめました
題名はElixirから覚えるJavaScriptですが、逆もできるかも？

今日はmapを見てみたいと思います

お題
[1, 2, 3, 4, 5]のリスト又は配列を2倍する

# Elixir

```elixir
x = [1, 2, 3, 4, 5]
y = Enum.map(x, fn x -> x * 2 end)
IO.inspect(x)
IO.inspect(y)

```

```elixir:実行結果
[1, 2, 3, 4, 5]
[2, 4, 6, 8, 10]
```

# JavaScript

```javascript
x = [1, 2, 3, 4, 5]
y = x.map( (x) => x * 2)
console.log(x)
console.log(y)
```

```javascript:実行結果
/usr/local/bin/node ./hoge.js
(5) [1, 2, 3, 4, 5]
(5) [2, 4, 6, 8, 10]
```


無事に同じ結果になりました

https://qiita.com/t-yamanashi/items/263b53d889dc5f7ddf17
sshでログイン（ローカル：windows,リモート：Linux,MacOS）

## sshサービス起動
### Linux
```
sudo yum install openssh-server
```
sshのバージョン：
```
ssh -V
```
ipアドレス調べる：<br>
```
ifconfig
```
inetの後ろの部分は「ipアドレス」<br>

![スクリーンショット 2023-01-03 122408.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941840/89cdf48b-eadc-8aa4-a67c-aaffde269f72.png)

```
ssh ユーザー名@ipアドレス
```
<br>
### MacOS
「システム環境設定」→「共有」→「リモートログイン」をチェックする<br>
「リモートログイン：オン」表示したら、下のコマンドでログインする可能。<br>

参考：https://pc-karuma.net/mac-ssh-login/

## windowsからsshでログイン
以下の三つの方法でログインする可能：<br>
1,cmd
2,Putty
3,Tera Term 
### cmd 
windowsのcmd(コマンド プロンプト)を開く<br>
```
ssh ユーザー名@ipアドレス
```
<br>
公開鍵をリモートに送る(yesを入力)：<br>

![スクリーンショット 2023-01-03 004513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941840/72b5645b-e722-394e-a6d1-d1f172ed5506.png)

### Putty
ダウンロード：https://www.putty.org/
![截屏2023-01-03 12.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941840/2b0b1a01-2a41-d3e2-9999-889be056debe.png)

<br>
Host Nameにipアドレスを入力<br>
Port：22<br>
Connection type：SSH<br>

![スクリーンショット 2023-01-03 123412.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941840/4dc872be-f93a-b564-ffa5-c39c4c5f86e0.png)

ユーザー名とパスワードを入力する<br>
![スクリーンショット 2023-01-03 123931 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941840/c6bf6db6-d391-6d63-c30d-11a7e60e6def.png)

### Tera Term
ホスト：ipアドレス
ポート：22
サービス：SSH<br>
![スクリーンショット 2023-01-03 123449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941840/792e01b8-2a07-bf04-788e-3b05190ec111.png)
ユーザー名とパスワードを入力する<br>


### 公開鍵 
ホームディレクトリーの.ssh/know_hostsの中に、windowsシステムの公開鍵を見える。
Ruby 3.2 で導入された Integer#ceildiv とは

Ruby 3.2 で `Integer#ceildiv` なるメソッドが導入された。これはどういうものか。

# 用途

テニスボールが 15 個ある。これを「4 個入るケース」に詰めて保管しておきたい。ケースはいくつ必要か。

15 を 4 で割ると 3 余り 2。ということは，3 ケースに 4 個ずつ詰めて，半端の 2 個を別の 1 ケースに入れることになるので，ケースは計 4 個必要になる。

この計算は，Ruby でやるなら

```rb
p 15 / 4 # => 3
# あるいは
p 15.div(4) # => 3
```

で，3 に 1 を足せばよいと分かるわけだが，整商（整数の商）にいつも 1 を足せばよいわけではない。

ボールが 12 個なら半端が出ないので，`12 / 4` がそのまま答えになる。

つまり，整商と剰余の両方を `divmod` で求めて

```rb
p 15.divmod(4) # => [3, 3] # この場合，3 に 1 を足す
p 12.divmod(4) # => [3, 0] # この場合，3 がそのまま答え
```

と考えなければならない。

えっ，剰余が `0` かどうかで場合分けするの？　めんどくさ。

いやいや，そんなことをする必要はなくて，単に商（整商ではない普通の商）を `ceil` で切り上げればよいのだ。つまり

```rb
p 15.quo(4).ceil # => 4
p 12.quo(4).ceil # => 3
```

でいいのである。

`Integer#ceildiv` はこれを一発で行うメソッドだ：

```rb
p 15.ceildiv(4) # => 4
p 12.ceildiv(4) # => 3
```

こういう計算はときどき必要になるので，メソッド一つでできるのは確かにありがたい。

# 補足

ここまでの議論について少し補っておきたい。

## quo について

さきほど，商を求めるのに [Numeric#quo](https://docs.ruby-lang.org/ja/3.2/method/Numeric/i/quo.html) を用いた。これは文字通り商（**quo**tient）を得るためのメソッドである。

被除数・除数がともに Integer の場合，`quo` による商は Rational で返る：

```rb
p 6.quo(4) # => (3/2)
p 6.quo(2) # => (3/1)
```

読者の中には「`fdiv` でいいんじゃね？」と思った人もいるだろう。確かに，

```rb
p 15.fdiv(4).ceil # => 4
p 12.fdiv(4).ceil # => 3
```

でテニスボールケースの必要数が分かるので，一見よさそうだが，**一般には**ダメなんである。

Float に落としたところで，丸め誤差が生じうるので，正しい答えが得られないことがある。実際，

```rb
p (10**23).quo(1).ceil
# => 100000000000000000000000 # 正確

p (10**23).fdiv(1).ceil
# => 99999999999999991611392 # 誤差を含んでいる
```

のようなことになる（環境によって結果は違いうる）。

## ceil について

さきほど，

> 商を `ceil` で切り上げればよいのだ

と書いたが，`ceil` の働きを「切り上げ」と表現するのは，一般には妥当でない。

正の数（やゼロ）については「切り上げ」だが，負数の場合，例えば

```rb
p -1.99.ceil # => -1
```

となる。これは「切り上げ」とは呼ばない。

`ceil` は切り上げではなく，「正の無限大への丸め」なのである。

なお，ceil は ceiling（天井）の略で，[siːl] と読む。だからもし `ceildiv` をカタカナ発音で口にする必要が出てきたら「シールディブ」みたいに読むことになるのだろう（知らんけど）。

# なぜ Integer だけに？

`div` や `quo` や `remainder` の類が Float や Rational でも使えるのに対し，`ceildiv` は Ruby 3.2.0 では `Integer` でしか使えない。

除数は Integer でなくてもいい

```rb
p 1.ceildiv(2/3r) # => 2
p 1.ceildiv(0.3)  # => 4
```

のだが，被除数（レシーバー）は Integer でなければならない：

```rb
1.0.ceildiv(1) # => NoMethodError
```

なぜなのだろうか。

`Integer#ceildiv` 導入の [議論](https://bugs.ruby-lang.org/issues/18809#note-6) を見ると，

> We do not introduce `Numeric#ceildiv` until we see the need.

とあるので，Integer 以外での需要を誰も訴えなかったのだろう。

しかし，次に述べる二つの用途を考えれば，`Float#ceildiv` や `Rational#ceildiv` があってもよかったのではと思う。

## 液体の小分け

3.5 L のバーボンを 0.75 L のボトルに入れていくと，ボトルは何本必要になるか？

`Float#ceildiv` があれば

```rb
p 3.5.ceildiv(0.75) # => 5
```

で 5 本と求められたはずだ。

まあ Float では丸め誤差が出る可能性があるので，数学的に厳密な計算をするには

```rb
p 3.5r.ceildiv(0.75r) # => 5
```

のように Rational オブジェクトでやったほうがよいが。

## カレンダーの行数

2023 年 2 月のカレンダーは何行か？　ただし日曜始まりのカレンダーとする。

まず当該月の日数を求め，そいつに，<ruby>1 日<rt>ついたち</ruby>の曜日に応じた数を足してやり，そいつを `ceildiv(7)` してやれば行数が出る。

つまり

```rb
require "date"

d1 = Date.new(2023, 2, 1)  # ついたち
d2 = Date.new(2023, 2, -1) # 末日

p (d2 - d1 + 1 + d1.wday).ceildiv(7)
```

でよさそうなのだが，このコードは NoMethodError を出す。

なぜかというと，Date オブジェクト同士の差が Rational オブジェクトになるからだ。
もちろん整数なので分母が 1 の Rational オブジェクトなのだが。

整数なので `ceildiv` の前に `to_i` をかませば済む話ではある。しかし，上のコードで NoMethodError が出るのは一瞬ギョッとするし，わけが分かっても面倒だなとは思う。
【Rust】xpathでxmlを検索する方法

# Rustでxpathを使ってxml検索

`amxml`というcrateを使って、xmlを検索します。他にも有用なcrateがあるようです。

```console
$ cargo add amxml
```

```rust
use std::{fs::File, io::Read};

fn main() {
    // contents にファイル全体を読み込み
    let file_name: &str = "src/hoge.xml";
    let mut f: File = File::open(file_name).expect("Fail to open file.");
    let mut contents: String = String::new();
    f.read_to_string(&mut contents).expect("Fail to read file.");

    let document = amxml::dom::new_document(contents.as_str()).unwrap();

    let xpath = document
        .eval_xpath("/Package/types/name[text()='ApexClass']/../members")
        .unwrap();

    for i in 0..xpath.len() {
        let element_name = xpath.get_item(i).as_nodeptr().unwrap().inner_xml();
        println!("{}", element_name);
    }
}
```

# 参考文献

- [rust で XPath できる crate たちのメモ; (1) amxml, (2) sxd-xpath](https://usagi.hatenablog.jp/entry/2020/08/04/184343)
condaって何ですか？？？①

昨日に引き続き本日はcondaについてです。
ちなみにAnacondaのざっくり概要は
https://qiita.com/leigadget/items/4e5837f8e078119493b1
から見れますので興味がある方はぜひ。

---
ひとまずgoogleで
conda　何
と調べて一番上に出てきたpython.jp曰く、
「Anaconda には conda コマンドがインストールされており、パッケージのインストールや、実行環境の作成・切り替えなどを行います。Anacondaの実行環境は Anaconda-Navigator でも操作できますが、ここでは conda コマンドの使い方を紹介します。」
と書かれています。

pythonでのパッケージっていうのは簡単な話、pythonのモジュール(.pyファイル)を複数まとめたものになります。もう少し詳しい話はAnacondaの概要の時に書いてますので是非そちらを参照ください。

ここまでまとめますとcondaはパッケージマネージャーの一種であることがわかりますね。
しかし、ここでの浮かぶのがpipの存在です。pythonではpipがデフォルトでついてきますから。わざわざcondaを使う理由があるのでしょうか。

というわけでここからcondaの主な機能、そしてpipとの違いをまとめていきたいと思います。

まずcondaの一番の強みはpython以外のパッケージも管理することができる点です。

自分も最初は勘違いしていましたが、condaはpythonに限らず様々な言語のパッケージ、そしてさらには環境の管理も可能なシステムとなっています。
実際condaのドキュメントには(以下かっこ内は英文直訳となります)
「あらゆる言語のパッケージ、依存関係、環境管理-Python、R、Ruby、Lua、Scala、Java、JavaScript、C/ C++、Fortranなど。
Conda は、Windows、macOS、Linux 上で動作するオープンソースのパッケージ管理システムおよび環境管理システムです。Condaはパッケージとその依存関係を迅速にインストール、実行、更新します。Condaはローカルコンピュータ上で環境の作成、保存、ロード、切り替えを簡単に行うことができます。Pythonプログラムのために作成されましたが、あらゆる言語のソフトウェアをパッケージ化して配布することができます。」
と表記されています

逆にpipはpython専用のパッケージマネージャーとなっており、それ以外の言語のパッケージに関与することはできません。

というわけでとりあえず第一回まとめますと
conda:様々な言語のパッケージなどを管理することができる。
pip:pythonのパッケージを管理することができる。

というのが大きな特徴みたいです。
もともと一回で終わらすつもりでしたが長くなりそうなので一回区切ります。
今後数回かけてこのテーマをまとめていく予定ですのでよろしくお願いします。
p5.js・JavaScript で map・スプレッド構文・reduce を使って要素数の長さの最大値を得る： 配列の配列（2次元配列）とオブジェクトの配列で

表題の通り、以下のような配列の中で、最大の長さ・要素数を持つものの、長さ・要素数の値を求める話です。

```javascript
const testArray = [
  [5, 10, 8, 7, 11],
  [1],
  [3, 6, 2],
  [12, 8, 7, 4, 2, 1, 0, 9],
  [1, 8],
];
```

```javascript
const testArray = [
  { a: 0, b: 3 },
  { a: 7 },
  { a: 8, b: 6, c: 11, d: 3 },
  { a: 9, b: 2, c: 12 },
];
```

## 2次元配列を対象にした処理
まずは、異なる長さの配列を要素にもった配列、その 2次元配列を対象に要素数の最大の長さを求めてみます。
プログラムは以下の通りで、「単純なループ処理」・「reduce を使ったもの」・「map・スプレッド構文を使ったもの」の 3通りをのせています。

```javascript
const testArray = [
  [5, 10, 8, 7, 11],
  [1],
  [3, 6, 2],
  [12, 8, 7, 4, 2, 1, 0, 9],
  [1, 8],
];

function setup() {
  createCanvas(450, 350);

  // 単純なループで処理
  let maxLength = 0;
  for (element of testArray) {
    if (element.length > maxLength) {
      maxLength = element.length;
    }
  }
  console.log(maxLength);

  // reduce を利用
  const maxLength2 = testArray.reduce((previousValue, currentValue) =>
    max(
      Array.isArray(previousValue) ? previousValue.length : previousValue,
      currentValue.length
    )
  );
  console.log(maxLength2);

  // map・スプレッド構文を利用
  const maxLength3 = max(...testArray.map((arr) => arr.length));
  console.log(maxLength3);
}

function draw() {}
```

ここで、p5.js の関数を使っているのは、 [max()](https://p5js.org/reference/#/p5/max) の部分のみです。
これは、もちろん JavaScript のみで書くなら [Math.max()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/max) で置きかえてやれば OK です。

これらの中では、map・スプレッド構文を利用する形がシンプル。

## オブジェクトの配列を対象にした処理
次に、異なる要素数のオブジェクトを要素にもった配列を対象にしてみます。

上記の map・スプレッド構文を利用する形がシンプルだったので、それを用います。

```javascript
const testArray = [
  { a: 0, b: 3 },
  { a: 7 },
  { a: 8, b: 6, c: 11, d: 3 },
  { a: 9, b: 2, c: 12 },
];

function setup() {
  createCanvas(450, 350);

  // 単純なループで処理
  let maxLength = 0;
  for (element of testArray) {
    if (Object.keys(element).length > maxLength) {
      maxLength = Object.keys(element).length;
    }
  }
  console.log(maxLength);

  // map・スプレッド構文を利用
  const maxLength3 = max(
    ...testArray.map((object) => Object.keys(object).length)
  );
  console.log(maxLength3);
}

function draw() {}
```

## 参照した情報
- [●JavaScriptで配列の最大値・最小値求めるならreduceで - Qiita](https://qiita.com/hachisukansw/items/81d739ef39af343df619)
-  [Array.prototype.reduce() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
- [意外と知られていないJavaScriptのreduceの使用方法 | iwb.jp](https://iwb.jp/javascript-reduce-howto-use/)
- [Array.prototype.map() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
- [reduceの使い方メモ（主に集計目的） - Qiita](https://qiita.com/zaburo/items/fc8f74d144d73b7d70b69)
JavaScriptでの配列のソート（まとめ）

配列の要素の並び替えのまとめです

昇順

```JavaScript
const array1 = [200,300,1000,500,100];

array1.sort((a,b) => a > b ? 1:-1);
array1.forEach((data) => {
      document.write(`<p>${data}</p>`);
})
```

降順

```JavaScript
const array1 = [200,300,1000,500,100];
   
array1.sort((a,b) => a < b ? 1:-1);
array1.forEach((data) => {
      document.write(`<p>${data}</p>`);
})
```
DB2 on Docker part2

[DB2 on Docker](https://qiita.com/suzanHud/items/43f8193234070472cf39)でDB2のインストールについて書きました。
最新の11.5.8.0についても動かしたいと思い色々試してみました。
参考サイトは以下です。
1.[【備忘録】Db2 インストール手順まとめ（Linux）](https://qiita.com/Haruka-Ogawa/items/9576399209b32f3016ea)
2.[DockerコンテナのCentOS7で 「Failed to get D-Bus connection: Operation not permitted」と出た時の対処方法](https://www.opensourcetech.tokyo/entry/20190222/1550822082)

# 作成手順
1.参考サイト2にあるようにCentOS7のイメージを作成します。
タグは「kazu_centos:7」としました。

2.IBMのサイトからDB2を入手します。
v11.5.8_linuxx64_server_dec.tar.gzです。

3.応答ファイルを作成します。
ここではdb2server.rspとしました。
```
PROD                      = DB2_SERVER_EDITION
FILE                      = /opt/ibm/db2/V11.5
LIC_AGREEMENT             = ACCEPT
INSTALL_TYPE              = TYPICAL
LANG                      = JP
HOST                      = db2
INSTANCE                  = DB2_INST
DB2_INST.NAME             = db2inst1
DB2_INST.UID              = 501
DB2_INST.GROUP_NAME       = db2grp1
DB2_INST.GID              = 501
DB2_INST.HOME_DIRECTORY   = /home/db2inst1
DB2_INST.PASSWORD         = db2inst1
DB2_INST.AUTOSTART        = NO
DB2_INST.PORT_NUMBER      = 50000
DB2_INST.FCM_PORT_NUMBER  = 60000
DB2_INST.FENCED_USERNAME  = db2sdfe1
DB2_INST.FENCED_GROUP_NAME = db2sdfe1
DB2_INST.FENCED_GID       = 601
DB2_INST.FENCED_HOME_DIRECTORY = /home/db2sdfe1
DB2_INST.FENCED_PASSWORD  = db2sdfe1
DB2_INST.CONFIGURE_TEXT_SEARCH = NO
```

4.Dockerfileを用意します。
```docker:dockerfile
FROM kazu_centos:7

  RUN yum -y update ; yum -y install file libaio numactl libstdc++.so.6 pam-devel ksh pam-devel.i686 'compat-libstdc++-33-3.2.3-72.*'
  RUN rm /etc/localtime; ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
  RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
  ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

  RUN groupadd --gid 501 db2grp1
  RUN useradd --gid db2grp1 --uid 501 --shell /bin/bash -m db2inst1
  RUN groupadd --gid 601 db2sdfe1
  RUN useradd --gid db2sdfe1 --uid 601 --shell /bin/bash -m db2sdfe1
  RUN echo 'export LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:ja LC_ALL=ja_JP.UTF-8' >> /home/db2inst1/.bashrc

  ADD v11.5.8_linuxx64_server_dec.tar.gz /tmp
  COPY db2server.rsp /tmp/server_dec
  ENV LANG=ja_JP.utf8
```

6.Docker buildを行います。
```
docker build --progress=plain --no-cache -t kazu_db2 .
```

7.Docker runで起動します。
```
docker run -it -h db2 --privileged=true --name="db2inst2" -p 50000:50000 kazu_db2
```

8.Docker execでコンテナイメージに入ります。
```
docker exec -it db2inst2 bash
```

9.db2をインストールします。
```
/tmp/server_dec/db2setup -r /tmp/server_dec/db2server.rsp
```

10.db2を起動します。
```
[root@db2 /]# su - db2inst1
Last login: 火  1月  3 11:56:37 JST 2023 on pts/1
[db2inst1@db2 ~]$ db2start
01/03/2023 11:57:04     0   0   SQL1063N  DB2START の処理が正常に終了しました。
SQL1063N  DB2START の処理が正常に終了しました。
[db2inst1@db2 ~]$
```

Dockerfile上でDB2のインストールまで行わない理由は参考サイトにあるとおりsystemctlを一度動くようにしてからDB2のインストールをするためです。このへんができれば一緒にしたいところです。

## 変更履歴
(2023/01/03)docker execコマンドのオプションの誤りを修正。応答ファイルにポート番号を指定するよう修正。
Snowflake 入門コースやってみた

# はじめに
諸事情によりデータウェアハウスを触る必要が出たので，どうやら流行っているらしい「Snowflake」を触ってみました。
Udemyに良さげな無料コースがあったので，こちらを教材にしました。

https://www.udemy.com/course/snowflake-basic/

# 感想
およそ3時間くらいでコースを終え，以下のことを学習できました。
・Snowflakeの特徴，優れている点
・Snowflakeの簡単な使い方（試用アカウント作成～データ準備～データ可視化）

データウェアハウス触ってみたい！Snowflakeって何？っていう人は試す価値ありだと思います。

# 詰まったこと
### WebUIの構成が違う
クラウドサービスだとよくあることですね。
コースのリリース時と現在（2023年1月）では，画面構成が違いました。
画面上部にあるはずのボタンが画面左側に変わっていたり，ロールの切り替えは画面右上ではなく左上からやる必要があったりと，適宜読み替える必要がありました。
無料なのでこれくらいは全然良いかなって思います。

### WebUIからテーブルをロードできなかった
かつてGUIでできた操作が今は手動でしかできないなんてことある？
と思いつつ，テーブルにデータをロードできそうなところは見つからなかったため，SnowSQL（CUI）を使ってやってみました。
WebUIからやる方法を知っている方，いらっしゃいましたらご教授ください。

https://docs.snowflake.com/ja/user-guide/data-load-internal-tutorial.html

https://dk521123.hatenablog.com/entry/2021/11/15/221245

https://blog.serverworks.co.jp/tech/2020/06/29/snowflake-data-load-from-local/

# おわりに
今までデータウェアハウスをちゃんと触ったことがなかったので，入門者にとっては良いコースだったなと思いました。
Snowflakeが他社のDWHサービスと比較して，何が優秀か実証ベースでは確認できなかったので，データ分析の課題があれば検証してみたいですね。
トライアル期間が3週間余っているので，SnowSQLのコマンドをまとめてみましょうかね。
それではありがとうございました。
Macbook 何を購入するか。

現在利用しているMacbookは、２年ほど前に、画面が壊れて、外付けディスプレイで表示している。　

ハードディスクがいっぱいになり、Appleのサービスで契約して保存している。　

先週、ブラウザのキャッシュが飛びました。　

現在、いろいろ不便しています。　

一昨年、一度は　M1 Macbook Airを購入しました。　

家族に貸し出しています。

再度購入しようと思っています。　

# 仕様、目的

仕様、目的を記載します。

## C/C++規格文書類のコンパイル　

## docker等を利用した機械学習・深層学習プログラムの実演 

## Linux/Posix の試験 (Posix Test Suiteを含む)

## ネットワークプロトコルの試験(Mobile IPを含む）

## ５０歳から毎年１言語学習している学習環境　

## AUTOSAR Demonstratorの試験　

## 箱庭プロジェクト　追試


# 仕様 

|仕様|希望|制約|
|:--|:--|:--|
|主記憶|32G|-|
|記録装置|1TB|-
|価格| 20万円以内|-|
|ディスプレイ|13inch-||


# 選択肢 

## M! or M2

よくわからん。　　

## GPU 8 or 10 
機械学習するには10の方がよさそうな気もする。　
主たる目的ではないところが悩み。



##  メモリ16Gb, or 24Gb

現在16Gb使用。dockerでときどきメモリが足りなくなる。　

## 記録装置 
現在、256Gbであふれている。　
以前は512GB使っていた。　

512GBしか選択肢がなさそう。　

現在icloudの一番安い契約している。契約あげるよりは、記録装置を上げたい。


＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞

# 文書履歴(document history)
ver. 0.01 初稿 　 20230103
ver. 0.02 ありがとう追記 　 20230529
### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

####  Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
草莽Erlang ── 04. タプル

口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## タプルとは

タプルはデータを整理する方法の一つです。メモリ上に連続的に格納されます。このため、タプルの長さを得るのは高速ですが、修正を行うのは高コストとなります。新しいタプルは全ての要素がメモリにコピーされるからです。タプルは波括弧（`{}`）を用いて定義されます。

```erlang
> Point = {8, 4}.
{8,4}
```

https://www.erlang.org/doc/reference_manual/data_types.html#tuple

タプルの長さは [tuple_size/1](https://www.erlang.org/doc/man/erlang.html#tuple_size-1) で取得します。

```erlang
> tuple_size(Point).
2
```

タプルの要素は [element/2](https://www.erlang.org/doc/man/erlang.html#element-2) で取得します。要素の数え方は「１、２、３ぁっダー！」です。最初の要素のインデックスは`1`となります。

```erlang
> element(1, Point).
8

> element(2, Point).
4
```

https://youtu.be/AWxwmqzbOaw

https://youtu.be/FSz7N5hCltw

https://note.com/awesomey/n/n4d8c355bc8f7

パターンマッチを扱う時によりタプルの有用性を享受することができます。

```erlang
> Temperature = {celsius, 25.123}.
{celsius,25.123}

> {celsius, Tc} = Temperature.
{celsius,25.123}

> {kelvin, Tk} = Temperature.
** exception error: no match of right hand side value {celsius,23.213}
```

タプルは関数から付加的な情報を返す仕組みとしてよく利用されます。以下は[file:read_file/1](https://www.erlang.org/doc/man/file.html#read_file-1)でファイルを読み込む例です。

```erlang
> file:read_file("path/to/existing/file").
{ok,"content"}

> file:read_file("path/to/unknown/file").
{error,enoent}
```

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
自社開発企業に転職して感じた周りの人との差

# はじめに

私は、2021年の4月に未経験エンジニアとしてSES企業に転職しました。そこから1年半ほど勤務して、2022年の9月に自社開発企業に転職したという経緯です。

記事執筆時点では入社3ヶ月くらいなのですが、自分の足りない部分や改善していきたい部分をまとめて今後に繋げるために、周りの人との差を感じた部分を書いていこうと思います。

### おことわり

あくまで私自身が感じた差なので、**自社開発企業>>SES企業**ということを伝えたいわけではありません。もちろん、全ての人・会社に当てはまる話でもないので、一個人の考えとして見てもらえればと思います。

# 知識量の差

入社してすぐに感じたのは**知識量**の違いです。

入社してから初めてPRを出した際のコードレビューで、今までで経験したことのない数のコメントが返ってきました。仕様に関する指摘もありましたが、**こんなの知らねえよ**という技術的な指摘が大半を占めていました。
知らなかったことはキャッチアップすればいい話なので、そこまで落ち込むことはなかったのですが、最初は知識量に圧倒されたのを覚えています。。

業務委託で参画されているフリーランスの方も、スーパーエンジニアばかりで圧倒されています。。

### アーキテクチャ周りの知識

入社してからアーキテクチャに関する話もよく聞くようになりました。前職のSES時代の時は、アーキテクチャなんて気にして開発していなかった(そもそも気にしている人がいなかった)ので、**DI**や**SOLID原則**などのアーキテクチャに関する単語を実装する中で初めて知りました。

アーキテクチャに関する知識はまだまだ不足しているので、今後キャッチアップしていかないといけないと感じました。。

# 経歴の違い

SESの時は、新卒か未経験転職の中途が大半を占めていて、大学や前職からゴリゴリやってましたという人がほとんどいなかったのですが、今の会社は未経験転職(知っている範囲で1人だけいます)がほとんどいないという逆の現象となっていました。

チームのリーダーに関しては、大学時代からインターンで開発経験をゴリゴリ積んで、大学院にも行った方なので、経験の差を痛感しました。

資格を取ればチヤホヤされたSESの時と違って、資格なんてほとんど評価されないし、いかに実務で結果を出すかが見られる世界だと感じました。

情報系の学部の人だと4年かけて基礎を学ぶところを、自分は文系の学部卒ということもあり、すっ飛ばしてIT業界に来てしまったので、知識の土台の部分が全然違うと感じました。

# 意識の違い

今の会社では、周りの人の意識や熱量が前職と比べ物にならないと感じました。

前職では、業務時間外に勉強している人なんてごくわずかで、やっても資格の勉強をするくらいだったのが、今では勉強会や発表会の時間があって、積極的にインプットやアウトプットする人が多いですし、新しい技術に関してもキャッチアップの速さが桁違いでした。

前述したように、弊社に未経験で入社した(自分の2ヶ月前)先輩がいるのですが、自分とは比べ物にならないくらい知識があるし、入社4ヶ月目くらいで発表会に登壇していたので、インプット・アウトプットの量が凄まじいと感じました。
(逆に自分はこの1年半くらい何やってたんだという気持ちにもなりました…)

# 技術力以外のスキルも高い

技術力が高いのはさることながら、それ以外の人間力やビジネス戦闘力も高いと感じました。

技術力が高い人ってコミュニケーションに問題があるとか、高圧的な態度を取るとか、あまり良いイメージがなかったのですが(偏見すぎる)、今のところ1人もそのような人に出会っていないので、本当に周りの人に恵まれたなと思っています。

また、ミーティングに参加した際に、1つの意見に対しての思考のアプローチが豊富でした。自分が今まで意識したことのなかった観点で話をしていたので、ミーティングに参加する中で1つずつ吸収したいと思いました。

# まとめ

入社して3ヶ月ほどですが、レベルの高い環境に身を置けたことは本当に良かったと感じています。最初はレベルの違いに心が折れそうになりましたが、自分の足りない部分に気づけたのでプラスに捉えられています。

チームのリーダーも**やればできるよ**と言って背中を押してくださったので、これからも行動あるのみだなと思いました。

2023年はぴょんぴょん飛躍の年にできるように頑張ります🐰
yarn build したときのエラー解決方法（Rails7 アプリで esbuild を使用時）

# エラー内容

以下のようなエラーが出たときの解決方法を記録しておきます。

```bash
docker-compose run --rm app yarn build

Creating ＊＊＊_app_run ... done
yarn run v1.22.17
$ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=app/assets/builds
/myapp/node_modules/esbuild/bin/esbuild:159
          throw new Error(`
          ^

Error: 
You installed esbuild for another platform than the one you're currently using.
This won't work because esbuild is written with native code and needs to
install a platform-specific binary executable.

Specifically the "@esbuild/darwin-x64" package is present but this platform
needs the "@esbuild/linux-x64" package instead. People often get into this
situation by installing esbuild on Windows or macOS and copying "node_modules"
into a Docker image that runs Linux, or by copying "node_modules" between
Windows and WSL environments.

If you are installing with npm, you can try not copying the "node_modules"
directory when you copy the files over, and running "npm ci" or "npm install"
on the destination platform after the copy. Or you could consider using yarn
instead of npm which has built-in support for installing a package on multiple
platforms simultaneously.

If you are installing with yarn, you can try listing both this platform and the
other platform in your ".yarnrc.yml" file using the "supportedArchitectures"
feature: https://yarnpkg.com/configuration/yarnrc/#supportedArchitectures
Keep in mind that this means multiple copies of esbuild will be present.

Another alternative is to use the "esbuild-wasm" package instead, which works
the same way on all platforms. But it comes with a heavy performance cost and
can sometimes be 10x slower than the "esbuild" package, so you may also not
want to do that.

    at generateBinPath (/myapp/node_modules/esbuild/bin/esbuild:159:17)
    at Object.<anonymous> (/myapp/node_modules/esbuild/bin/esbuild:207:27)
    at Module._compile (node:internal/modules/cjs/loader:1126:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1180:10)
    at Module.load (node:internal/modules/cjs/loader:1004:32)
    at Function.Module._load (node:internal/modules/cjs/loader:839:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
ERROR: 1
```

上記のエラーは、
ビルドに使用される esbuild パッケージのバイナリが互換性のないプラットフォームでインストールされていることを示しています。

# 解決方法
以下のコマンドを実行して、パッケージを再度インストールします。

以下のコマンドを実行して、実行環境にあるnode_modulesを削除します。
```bash
rm -rf node_modules
```
以下のコマンドを実行して、パッケージを再インストールします。
```bash
npm install
```

yarnを使用している場合は、以下のコマンドを実行します。
```bash
yarn install
```
これで、パッケージが再度インストールされます。

さいごに、以下を再度実行して正常に終了することを確認してください。
```bash
docker-compose run --rm app yarn build
```
CentOS7にnginxをインストールする（Apache共存）

CentOS7にnginx（エンジンエックス）をインストールした時のメモです。
今回は最新バージョンを利用せずに最も簡単な方法で実現します。
また、CentOS7にはすでにApacheがインストールされているのでポートを分けて共存させてみます。
標準の手順では最新のリポジトリを追加しますが、今回はそこをカットして古いバージョンをインストールします。

# ０．参考資料

* [【入門】Nginx（エンジンエックス）の特徴・デメリット、インストールと初期設定も解説](https://www.kagoya.jp/howto/it-glossary/web/nginx/)
* [Nginx を CentOS 7 にインストールする手順](https://weblabo.oscasierra.net/nginx-centos7-install/)

# １．インストール

最初にnginxをインストールします。
```
# yum install nginx
```
2023年1月3日時点では1.23.3が最新ですがインストールされたのは1.20.1です。
```
# nginx -version
nginx version: nginx/1.20.1
```

# ２．設定

次に設定ファイル（/etc/nginx/nginx.conf）の待ち受けポートを80から9999に変更します。
```
# vi /etc/nginx/nginx.conf
```
listen の二か所を80から9999に変更します。
```
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       9999; # <- 80から9999に変更
        listen       [::]:9999; # <- 80から9999に変更
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}
```

# ３．起動
最後にサービスを起動します。
```
# systemctl start nginx
```
Webブラウザから指定したポートにアクセスします。
http://127.0.0.1:9999/
ページがが表示されれば成功です。最後に永続的に起動するようにしておきます。
```
# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
```

以上で終了です。
ユーザー管理機能(Devise)について

# deviseとは
webアプリケーションにおいて認証機能を実装するためのgemです。

# 導入方法
1\. ターミナルにてcdコマンドを使い、作成しているAppのディレクトリ内に移動する

2\. Gemfile内で追記する
``` .Gemfile
gem 'devise'
```

3\.ターミナル内にてGemをインストール
``` .terminal
bundle install
```
:::note info
gemをインストールした後はローカルサーバーを再起動する
:::

4\.deviseの設定ファイルを作成
```.terminal
rails g devise:install
```

# deviseのモデルを作成
1\.モデルの作成
```.terminal
rails g devise [モデル名]
```

2\.テーブルに必要なカラムを追加
モデルを作成するとdb/migrateのディレクト内に先程生成したdeviseのモデルテーブルが生成されている。そのファイル内で追加を行う

:::note info
ex)nicknameを文字列型、空なしにする場合
```.db/migrate/20XXXXXXXXX_devise_create_***.rb
def change
    create_table :[***] do |t|
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
+     t.string :nickname,           null: false
```
:::

3\.データーベース設計したらマイグレーションを実行
```.terminal
rails db:migrate
```

# バリデーションの設定
```.app/models/user.rb
+ validates :password
+ validates :nickname
```

:::note info
バリデーションを設ける事で設定したカラムが空欄の時はデーターベースに保存されず、エラーを返す様に設定します。
:::

# ビューファイルを作成
1\.ビューファイルを生成
```.terminal
rails g devise:views
```
> app/views/deviseのディレクト内に新規登録とログイン画面のviewファイルが自動に生成される

2\.viewファイルを編集
- registrationsは新規登録画面
- sessionsはログイン画面
- form_withプロパティなどを使いフォーム画面を作成します.
2022年お世話になったCSSフレームワークまとめ

# 初めに
私が2022年に1度でも使ったフレームワークをまとめました。
良ければ参考にしてください。
# 1. Bootstrap
米Twitter社によって2011年に開発されたフレームワークです。

ボタンやフォームなどのテンプレートが用意されているため、デザイン知識がない方でも簡単にオシャレなデザインを実現することができます。またグリッドを使うことで簡単にレスポンシブ対応が可能となります。

たくさんのフレームワークがリリースしてる中でも世界中で非常に高いシェアを獲得しており、情報も豊富なため、これからWeb開発に取り組む方にオススメのフレームワークです。

お世話になっているBootstrap CheatSheet
[Bootstrap 5 CheatSheet](https://bootstrap-cheatsheet.themeselection.com/ "Bootstrap 5 CheatSheet")

# 2. Bulma
Jeremy Thomasによって2014年に開発されたフレームワークです。

使い勝手はBootstrapと非常に似ています。

Bootstrapと比較して、デザインのシンプル度が高く、カスタマイズ性が高いのが特徴です。
また、シェア率も高くないため、Bootstrapよりも個性が出しやすいのがグッドポイント。

# 3. Materialize
Materializeによって2014年に開発されたフレームワークです。

Google社が提唱するマテリアルデザインに基づいたCSSフレームワークとなっています。そのため、Googleが提供しているサービスの見た目を再現することが可能です。

使い勝手はBootstrapとほとんど同じで、Bootstrapを使ったことがある方なら簡単に使いこなすことができると思います。

# 4. Tailwind CSS
Adam Wathan氏が開発したフレームワークで、2022年人気が急上昇しました。

Utility First（ユーティリティファースト）をコンセプトに設計されたCSSフレームワークとなっており、前述した3つのフレームワークとは大きく異なっております。

Utility First（ユーティリティファースト）とは、CSSは使わずにTailwind CSSが提供しているクラスのみを使用してスタイリングする考え方のことです。そのため、自分で新たにcssを用意しなくても、サイトのスタイリングができるのが特徴。

一方で、前述した3つと比較してオシャレなデザインが予め用意されている訳ではないので、初心者の方にとっては難易度が高いと思われます。

cssの扱い方に慣れてくると、Tailwindは非常に使いやすくてオススメです。

# 最後に
CSSフレームワークは年々新しいものが登場し、今では20以上もあります。
そこで、何から始めたら良いか迷った方は、Bootstrapから始めるのをオススメします。そして、慣れてきたら、ぜひTailwindを使いこなしてみてください。

2023年はどんなフレームワークが登場するのか楽しみです！！！
X68000用自作横スクロールシューティングゲームのアセンブラソース(データなし)

## 1. はじめに

X68000が現役だった当時、高校生時代にアセンブラで横スクロールシューティングゲームを仲間内で作り、高校の文化祭で展示しました。
ソースの最終更新日時は1990/04/10でしたが、33年経過した今更ながら、ソースをGitHubに登録しました。
ソースは私、キャラクターは友人、音楽とサウンドはなしです。

![202301031046050403.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534247/5245f1aa-5137-53da-2ba9-04c173a21f80.png)
![202301031047390013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534247/0e0dbad2-a770-4516-230c-846a941deec6.png)

## 2. ソース

mayo55/X68000_STS
https://github.com/mayo55/X68000_STS

|ソースファイル|説明|備考|
|---|---|---|
|sts.s|ゲーム本体||
|stsmap.s|敵出現パターン||
|stssd.s|自機パワーアップの弾道||

データは含んでいないため、これだけでは動きません。

## 3. エミュレータ

画面キャプチャには、XM6 TypeG を使用しました。
!valueで意図しないreturn - falsyな値と0

# 関数に入らない
関数に入らずハマった昔話

フォームから入力された値を加工してAPIに渡すための関数を作り、
valueの値がなければ関数から抜けるようにしていました。

```react
const onFinish = (value) => {
if(!value) return
...
```
ところがフォームの値に数字の0が入っていると、意図せず関数から抜けてしまいます。

# 原因
JavaScriptでは`falsyな値`という括りがあるそうです。
0は`falsyな値`とみなされ、`!value`の条件に合致してしまっていました。

公式で`falsyな値`は以下のように定義されています。
* false
* 0
* -0
* 0n
* ""
* null
* undefined
* NaN

参考：
https://developer.mozilla.org/ja/docs/Glossary/Truthy

# 解決
なので、「値がなければ関数を抜ける」コードは、正しくは
```react
const onFinish = (value) => {
if(value === undefined) return
...
```
でした。
Unityで自作classをListにしてInspectorで扱えるようにする

# Unityで自作classをListにしてInspectorで扱えるようにする

## ポイント：
- 自作classには[System.Serializable]を付けてシリアライズする必要があります。

## 解決方法：

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    // 自作classはSerializableする
    [System.Serializable] public class SpawnInfo {
        public GameObject spawner; // EnemyのPrefab
        public Vector2 pos;        // Enemyのspawn座標
    }
    // 通常のListとしてinspectorで扱える
    [SerializeField] List<SpawnInfo> spawnList = new List<SpawnInfo>();
```

## 結果：(UnityのInspector上の表示)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56003/7bf39718-8409-7649-4e41-f19d9c0f76c4.png)


## 編集後記
- 調べまわって時間消費したのに、
- ChatGPTで「Unityで自作classをListにしてInspectorで扱えるようにするには？」でオワリだった、ははは
M2 Mac Anaconda Tensorflow model.fitでエラー発生

` NOT_FOUND: could not find registered platform `
と出てしまい、どうやらGPUがうまく稼働していないように見える。

Apple Developer Forumsに対策を発見https://developer.apple.com/forums/thread/721619

tensorflow-metal 0.7.0 tensorflow-macos 2.11.0を使用していることが原因の様子で、それぞれ、0.5, 2.9にDowngradeすることで無事にTensorflow model.fitがexecuteできた。
下記を(base)ではなく(tensorflow)環境のterminalで実行。

`python -m pip install tensorflow-macos==2.9`
`python -m pip install tensorflow-metal==0.5.0`
Linux学習記録②

# nmcliコマンドについて
nmcli(Network Manager command-line)は、NetworkManagerを介してネットワークの状況を確認、設定を変更するコマンド。netstatとは違い詳細な情報を取得したいときはnmcliコマンドを使用します。

例えばnmcliのオプション、connection showを使用することで
UUIDやTYPE、DEVICEを確認することができる。接続しているデバイスを指定して情報を確認することができる。例えば、、
$ nmcli connection show 〇〇

現場でもし調査するタスクがあればこのコマンドを実行すればOK、調査のタスクは結構ありますよね。

指定したデバイスをアクティブにする。
$ nmcli connection up 〇〇
このコマンドを実行することによって指定したデバイスをアクティブにすることができます。また使わない場合は非アクティブにすることも可能です。
$ nmcli connection down 〇〇

現場でも常に使われそうなコマンドの一部です。


参考リンク

https://kimamani89.com/2020/05/06/【linux】nmcliコマンドの使い方/


# OpenSSHとは
OpenSSHとは主にコンピュータ間の安全な遠隔操作に用いられるSSHのことを指す。遠隔操作をしてその通信を暗号化して安全に操作できるための仕組みの１つ。

sshとOpenSSHとの違いについて
sshはリモートで通信する際のプロトコル（通信をする際のルールみたいなもの）安全に通信することができる。
OpenSSHはsshのプロトコルを実行するためのオープンソースのソフトウェアになる。そのため
UNIX／Linux系OSにデフォルトでインストールされている。

sshはリモートで通信する際のルール。それを実行してリモートで通信するのがOpenSSHと覚えておく。パスワード認証と公開鍵認証を使用する。


参考リンク

https://qiita.com/miyuki_samitani/items/5d3d4b74334e51c19d07

https://qiita.com/angel_p_57/items/19eda15576b3dceb7608


# /etc/profileについて
UNIX系のOSで使われるファイルでログイン時に読み込まれる設定内容が書かれています。sh系のログインシェルでのみ読み込まれます。

ログイン直後に動いているシェルがshシェル専用の設定ファイルというふうに覚えておくと良い。

ちなみにログインシェルとは、ログインして最初に動き出すシェルのことをさします。シェルはユーザーが打ち込んだ入力内容をコンピュータに伝える翻訳してくれる役割を果たしています。

このログインシェルは複数の種類があり切り替え可能です。shやbashやcshなどの種類があります。

そしてこのログインシェルがsh、bash、ksh、zshだった場合に読み込む設定ファイルが/etc/profileとなります。

参考リンク

https://wa3.i-3-i.info/word11795.html

# chronyコマンドについて
時刻同期先(NTPサーバなど)と同期が取れているかを確認できるコマンドです。

chronyはあくまでNTPが提供しているサービスで昔はntpdが使用されていました。

NtpdのバージョンがRFC1305に対してchronyはRFC5905で
同期が不可でしたが新しくchronyになることで同期が可能になりました。

設定ファイルは/etc/chrony.conf

chrony.confは、ntpdの設定ファイル 「ntp.conf」 とほぼ同じです。

サービスさえ起動しておけば時刻同期を勝手にやってくれます。
-vオプションで同期情報の詳細を見ることができます。

Ntpdの現在の使用用途に合わせてバージョンアップしたのがchronyだと覚えておくこと。

-vオプションで同期情報の詳細を見ることができます。

参考リンク

https://rurukblog.com/post/chronycsources/

https://rin-ka.net/about-chrony/
ktorにLocationsをいれようとするとバージョンエラーがでる

# はじめに

以下の書籍をやっていたところエラーに遭遇して解決に時間がかかったのでまとめます

https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%82%8F%E3%81%8B%E3%82%8B-Kotlin-%E5%AF%8C%E7%94%B0-%E5%81%A5%E4%BA%8C/dp/4863542917/ref=sr_1_8?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=27QECTKRDQ45B&keywords=kotlin&qid=1672704815&sprefix=kotlin%2Caps%2C199&sr=8-8

出版が数年前だったためそれが原因でエラーが発生していました

# 問題

Ktorのプラグインに`Locations`を追加しました

しかし以下のエラーが発生しました

```
com.example.thanks-bank-test:test: Could not find io.ktor:ktor-locations:2.2.1.
```

バージョン不一致が起きているようです



# 解決方法

以下のログからアクセスしたところ

```
   > Could not find io.ktor:ktor-locations:2.2.1.
     Searched in the following locations:
       - https://repo.maven.apache.org/maven2/io/ktor/ktor-locations/2.2.1/ktor-locations-2.2.1.pom
     If the artifact you are trying to retrieve can be found in the repository but without metadata in 'Maven POM' format, you need to adjust the 'metadataSources { ... }' of the repository declaration.
     Required by:
         project :
```

https://repo.maven.apache.org/maven2/io/ktor/ktor-locations/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/b60e57d2-896f-443c-05c1-3fbc68a27d83.png)

バージョンが`1.6.6`までしかありません
ktorはバージョン`2.2.1`を利用しているためどうすればよいかわからなくなりました

[公式](https://ktor.io/docs/locations.html)を見たところ以下の記述を発見

>In v2.0.0, the Locations plugin is deprecated. Use the Resources plugin instead.

`2.0.0`からは廃止されて代わりに`resources`を利用するようになったそうです

プロジェクトを作成し直して`locations`のかわりに`resources`を入れました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2f8541b1-705c-555e-b804-5f38868ed3b9.png)

また、デフォルトのRoutesだとインポートが足りておらず`Article`にエラーが表示される
ので以下を追加しました

```
import io.ktor.server.routing.get
```

するとサーバーが立ち上がりました

# おわりに

この書籍はかなり詳しくKotlinならではの機能の説明をしていたり、実践的なアプリを作成したりするのでやりきれたら力になりそうだなと思っています
バージョンが古いので読み替える必要はありそうですが、できる限りがんばりたいです

# 参考

https://engineering.visional.inc/blog/_324/ktor-routing/
https://ktor.io/docs/locations.html
【Go】# command-line-arguments undefined: への対応

### はじめに

簡単な動作確認時にいつも忘れそうになるのでメモ。

### やりたいこと

1. 以下のようにsample-app内にmain.goとanother.goを作る。
2. main関数内でanother関数を呼び出す。
3. `go run main.go` コマンドを実行

```
sample-app
 └ main.go
 └ another.go
 └ go.mod
```

```main.go
package main

import "fmt"

func main() {
	fmt.Println("main関数です。")
	another()
}
```

```another.go
package main

import "fmt"

func another() {
	fmt.Println("another関数です。")
}

```

### 出力されるエラー

```
# command-line-arguments
./main.go:7:2: undefined: another
```

### 解消法

実行時のコマンドライン引数にanother.goも渡す
`go run main.go another.go`

またはカレントディレクトリ配下の全てのファイルを指定して実行する
`go run .`

#### 実行結果

```
main関数です。
another関数です。
```