OmniAICreator/Qiita-1.07M huggingface dataset:
OpenShiftで作ったサービスを、Routeを使わずにアクセスさせる


# はじめに
OpenShiftのチュートリアルや教育資料を見ると、OpenShift上のアプリケーションへのアクセスにRouteを使う例が多いです（ちなみにRouteがOpenShiftとしての奨励手段のようです）。Routeを使うと、"oc expose"コマンドでServiceを外部からURLでアクセスできるようになります。たとえば、"myservice"というServiceを、"myservice.ocp4.example.local"というホスト名で公開したい場合、以下のようなコマンドでRouteをつくることができます（なお、ホスト名は"<任意の名前>.<OCPのクラスターID>.<OCPのドメイン>"という形になります）。

~~~shell
oc expose service myservice --hostname=myservice.ocp4.example.local
~~~

ただ、Routeを使いたくない！という場合もあり、本記事ではRouteを使わずにServiceを公開する方法を紹介します。なお、単にNodePort + Load Balancerを使う、というだけのお話なので、OCP/k8sに詳しい人は読み飛ばしてください(^^;)

# RouteでServiceを公開するハードル

前述の方法でServiceをRouteを使って公開することができるのですが、実際には少しハードルがあります。それは、このの例の"myservice.ocp4.example.local"という名前を、OpenShiftの前段にあるLoad BalancerのIPアドレスに解決する必要があるということです。OpenShiftを構築するときには、こういった名前解決を行うためのDNSが必要となるため、Helper Node上に独自にDNSを立ることもあるかと思います。このDNSを使えば、上記の名前解決はできます。
ただし、外部からアクセスするクライアントは、Helper Node上のDNSではなく、イントラネット上に存在するDNSを使っているはずです。そのため、名前解決ができず、Routeへアクセスできない、というケースも有るかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143277/5f940637-2f88-7498-c09f-471643d841bf.png)

これを解決するためには、ワイルドカードDNSレコードをイントラネット側のDNSに設定する必要があります。これによって、イントラネット側から"*.ocp4.example.local"という名前をLoad BalancerのIPアドレスに解決できるようになります。ただ、なかなかこれが難しい場合があります。理由としては・・・

1. イントラネット側のDNSが、そもそもワイルドカードDNSレコードをサポートしていない場合がある
1. イントラネットのDNSにワイルドカードDNSレコードを登録してもらうための社内申請やネゴが面倒

というようなことが考えられます。

# Routeをつかわないでサービスを公開する簡単な方法

そこで、Routeではない他の単純な方法でサービスを公開したくなります。一番簡単な方法は、PodへアクセスするためのServiceをNodePortとして作ることです。NodePortを使うと、各Workerノードが持つIPアドレスを使ってアクセス可能になります（なお、どのworkerノードへアクセスしても、Podが存在するノードへ転送されます）。ポート番号はデフォルトの設定では、30000〜32767の間のいずれかが自動割当されます。ポート番号を明示的に指定することも出来ます。
以下のサービス定義例では、myappというdeployのポート8080を、NodePortのポート30030として公開しています。

~~~yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp
  name: myservice
spec:
  type: NodePort
  ports:
  - name: nginx
    port: 8080
    protocol: TCP
    nodePort: 30030
  selector:
    deployment: myapp
~~~

これで、"workeｒノードのIP:30030"でOCPクラスター外からサービスにアクセスできるようになりました。ただ、これだと外部からアクセスするときに特定のworkerノードのIPを指定する必要があります。workerノードの一部がメンテナンス中のときには他のworkerノードにアクセスする、みたいなことをクライアント側にやらせたくありません。
そこで、OpenShiftには必須なLoad Balancerを使って、リクエストを全workerノードの30030ポートへ分散させることにします。これによって、あるworkerノードがメンテナンス中の場合も、他のノードが自動的に使われるようになります。外部からアクセスするときは、"LoadBalancerのホスト名:転送元ポート"のような形でアクセス可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143277/ea816753-914f-2558-fab3-72bf2d370c64.png)


たとえば、Load BalancerとしてHAProxyを利用していて、ポート8000から、各workerノードのポート30030へ転送したいときは、以下のような設定をhaproxy.cfgへ入れることになります。

~~~
frontend nginx-http
    bind *:8000
    default_backend nginx-http
    option tcplog

backend nginx-http
    balance source
    server worker0 10.91.51.118:30030 check
    server worker1 10.91.51.119:30030 check
    server worker2 10.91.51.120:30030 check
~~~

これで、イントラネット側のDNSにワイルドカードDNSレコードを定義せず、お手軽にServiceを外部へ公開できるようになりました！
なお、Load BalancerはPodがどのWorkerノードで動いているか知っているわけではないので、指定したアルゴリズムで機械的に各ノードへ分散させているだけです。そのため、Load Balancerがリクエストを転送したworkerノードから、さらにPodが動いているWorkerノードへリクエストが転送されるオーバーヘッドが生じており、かならずしもパフォーマンス面からは最適なソリューションでは無いかもしれませんので、ご注意ください。
ノイズ除去、圧縮、近似、分解などに関する世間話

# 世間話

世の中色々なデータの変換があるんだけど、彼らは何でこんなことしてんの？ということが書かれていない場合が多い。
意味がわからん。する必要ないでしょ。と考える人のための読み物。  

# 背後にある物語

同じデータを別の表現にすることは、大きな目的がある。
例えば、ある画像の情報量を半分にしたい場合、どうする？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128461/794d7c17-2921-2c39-18ad-0f8fbfcff875.png)　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128461/93564a55-ea00-8409-7a5f-5ea20e89aae6.png)

これは困ります。右半分が見れないから。ところが、 以下のような情報量の削減方法があります。

![名称未設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128461/c723865d-33bb-a109-8b70-380becec9266.jpeg)

こっちの方が良いでしょう。細部は潰れたりしていますが全体はそこそこ同じですから。

# どうやってやったの？

ここからが今日の本題です。
同じデータを別の表現に変換することで、以下のことが可能となります。

- データ圧縮
- 次元削減
- データ分解
- ノイズ除去
- データ解析
- フィルタ
- 近似

より具体的に説明します。上の例では、

$$ (画像データ) = フーリエ変換 => (周波数成分) \cdot (周波数強度）$$

ここで、（周波数強度）は**重要度**としてみなしても良いでしょうから、小さい強度を0にしたら圧縮できるでしょう。
そうやって圧縮したものが上の画像です。
画像データでなくて音声データであればMP3ファイルになります。
低周波数の強度を上げるとローパスフィルターになります。

ここで重要なのが、この考え方自体は、フーリエ変換でなく別の変換であってもよい訳です。
- データを削減していれば、データ圧縮、次元削減と見ることもできる
- データを成分毎に分解しているためデータ分解と見ることもできる
- 削減したデータが細部やノイズであればノイズ除去と見ることもできる
- 求めているデータに対して近づけるようなデータ加工をすると近似と見ることもできる
- データ加工に利用していればフィルタと見ることもできる

すべては以下のような形式であれば可能なので、この3つはほぼ同じで呼び方が変わるのは人間の都合で実体はほぼ同じものでしょう。
以下は、実例ですが、書き方を似せて書いているので完璧に正しくはありません。
雑な理解を目指しているため、このようなファンタジーが混じります。ご了承ください。

- 特異値分解　： $X =U \Sigma V^{*}$
- テンソル分解　： $X =UV^T$
- タッカー分解　： $X =UCV$
- 主成分分析　：$ X=U \Sigma W^T $
- フーリエ変換　：$ X=AW$

かなり似ているのがわかるかと思います。$U$などの記号の意味はそれぞれの方法によって違いますし、データ形式が行列であるとかテンソルであるとかは違いますが、大まかな全体の形式的な部分がかなり似ています。
そのため、これを利用した技術の方向性も似たようなものになるでしょう。
実際、データ圧縮やノイズ除去などは似ていますしね。

# まとめ

今回、かなり雑多な話をまとめましたが、こういう技術の勉強をしていて方向性を見失った時に参考にしていただければと思います。
【備忘録】AWS LightsailでRedmineの初回ユーザとPWの確認

Lightsailで初回ログイン時にユーザとPWがわからず、困る。
そこで、userIDとPWの確認方法を記載する。

①ユーザID：`user`で固定
②PW：パスワードはSSH接続し、ログを確認する。下記コマンドで確認できます。　
```
bitnami@ip-172-26-8-75:~$ cat ~/bitnami_application_password 
Password
```
【FileMaker】gmailをSMTPで送るには？

FileMakerからメールを送信する手段として、「[メールを送信](https://help.claris.com/ja/pro-help/content/send-mail.html)」ステップでメールを送れるのはみなさんご存知だと思います。
その他、「[URL を開く](https://help.claris.com/ja/pro-help/content/open-url.html)」でcurlを使って送信する方もいらっしゃいます。
どちらがどう、というのはまずは脇に置いておき、「メールを送信」ステップを使ってgmailを送る際の実装についてです。
正しくは、「googleのSMTPサーバーを経由してメールを送るやり方」、でしょうか。

ブラウザから検索窓にて
"[filemaker smtp gmail](https://www.google.com/search?q=filemaker+gmail+smtp&rlz=1C5CHFA_enJP912JP912&sxsrf=ALiCzsZUW0ECRj04zOC_K6sUmKh5KmP21g%3A1654825150641&ei=vqCiYsfZJq2x2roPjcOFgAM&ved=0ahUKEwjHsJOK4KH4AhWtmFYBHY1hATAQ4dUDCA4&uact=5&oq=filemaker+gmail+smtp&gs_lcp=Cgdnd3Mtd2l6EAMyBAgjECcyBAgAEBMyCAgAEB4QCBATMggIABAeEAgQEzoHCAAQRxCwA0oECEEYAEoECEYYAFCtEFirJGC1KWgBcAF4AIABgAGIAcMCkgEDMS4ymAEAoAEByAEKwAEB&sclient=gws-wiz)"
とキーワードを入れて検索すると、たくさんのTipsが出てきますので、あえて書く必要は、、、と思いましたが、備忘録観点と、「インプットしたらアウトプットせよ」と、はるかかなた向こうのどこかにいる師匠の教えに則り、ここに記事を残します。（大袈裟）

# 準備
## 必要なもの
まずは、googleアカウントがなければ、アカウントを作成します。

### gmailアドレス
gmailアドレスを準備します
通常は、gmail.comとドメインのあるメールアドレスですね。

### アプリパスワードを発行する
こちらは聞きなれない言葉かもしれません。
gmailアドレスでメールボックスへログインするパスワードではなく、「え、アプリに「Google でログイン」機能がないの！？あ、2段階認証プロセス使える？なら、仕方ないなぁ、これ使ってよ」と勝手に過大解釈しましたが、要は、何かしらアプリケーションからgmailを送信する際のパスワードと思ってください。
ただし、「仕方ないなぁ」なので、可能ならOAuthとかで認証するAPIでの通信が望ましい、という感じだと思ってます。
堅牢なシステムを構築したり、メーリングリストを配信するなど大量のメールをさばきたいなどの場合は、別の方法を検討してください。

https://support.google.com/accounts/answer/185833?hl=ja#zippy=%2C%E3%82%A2%E3%83%97%E3%83%AA-%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A8%E3%81%AA%E3%82%8B%E7%90%86%E7%94%B1

アプリパスワード方式は、メール以外にも、用途としてカレンダーなどもありますので、用途ごとにアプリパスワードを発行します。
やり方についてはFileMakerに限らずいろんな方が解説してくれているので、ここではサクッと解説するのみとします。


こんな感じで発行できます。
![スクリーンショット 2022-06-10 14.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/3e87eb85-b47d-89a4-7be0-6a5f3eb9a7cd.png)

:::note warn
アプリパスワードは2段階認証がオンのアカウントのみ利用できます。
２段階認証がオンになっていない場合は、オンにしてからアプリパスワードを発行してください。
:::

### SMTPサーバー情報
送信SMTPサーバ：smtp.gmail.com
ポート番号：~~465~~ 587
接続の暗号化：~~SSL~~ TLS

:::note info
@Hi_Noguchi さんから、ポート番号と接続の暗号化についてアドバイスをいただきました。ありがとうございます！
SendGridのこちらのサイトに詳しく書いてあるので、合わせて参考にしてください。
https://sendgrid.kke.co.jp/blog/?p=12945
:::

# 実装
では、実際にFileMakerからメールを送りたいと思います。
1行で済みます。
![スクリーンショット 2022-06-11 13.25.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/4f14b423-8c8b-7c74-350a-ec76ada48263.png)

# テスト
この1行を実行してメールが届くか確認します。
![スクリーンショット 2022-06-10 11.01.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/d08c0c42-e9d1-e898-9c9a-bb17779d0b70.png)
はい、届きました。

# アプリパスワード方式を使うことの安全性は？
アプリパスワード方式は、googleに限らず、Microsoft Outlookなどでも使われている方式ですが、いずれも「2段階認証がサポートされていないアプリやデバイスでセキュリティが堅牢ではないけど代用する方法」という位置付けのようです。
運用上管理者しか見えない仕組みにしたり悪用されない仕組みを実装して、可能な限り安全に運用していく形で実装しましょう。
基本的にはGoogleではアプリパスワードによるログインは非推奨で、よく見かける「Googleでログイン」によるログインでログインしてください、となっています。
ただ、システムの自動化という観点からは、実装の方法によっては「Googleでログイン」画面が表示されてもログインできない、ということもあるので、アプリパスワード方式、もしくはより認証のハードルが高いOAuth、APIでの認証を実装した方がよいと思います。
まー、そうは言っても、OAuthとかハードル高いと思っちゃいますよね。
でも、仕組みとしてはどこでも使える仕様なので、一度OAuth認証を実装すると次も同じように実装できますので、アプリパスワード方式でメール送信に自信がついたら是非ともOAuth認証実装にもトライしてみてください！
【備忘録】AWS LightsailのRedmineをhttps通信にする

## はじめに
[前回までの記事](https://qiita.com/kouji0705/items/39e9a18e7ad2ce398986)でRedmineの環境にドメインを紐づける所まで実施しました。では、最後にHTTPS通信化しましょう。

### HTTPS化手順

①bncert-toolを実行する。
Bitnamiが提供するプロダクト(WordPressやRedmine）は簡単にSSL化できるようにツールが提供されています。それが「bncert-tool」なので、これを利用してHTTPSかします。

```shell:
sudo /opt/bitnami/bncert-tool

----------------------------------------------------------------------------
Welcome to the Bitnami HTTPS Configuration tool.

----------------------------------------------------------------------------
Domains

Please provide a valid space-separated list of domains for which you wish to 
configure your web server.

Domain list []: 
```
②登録するDomainを入力する

```
Domain list []:登録するDomainを入力 
```
③以降は記載しますが、各自適当に実施してください。


③ドメイン名にwww含めるか聞かれる。
```shell
The following domains were not included: www.ドメイン名. Do you want to add them? [Y/n]:
```

④HTTPからHTTPSへのリダイレクト実施するか？
```shell
Enable HTTP to HTTPS redirection [Y/n]: Y 
```
⑤色々変更あるけど、了承してくれる？？

```
Changes to perform

The following changes will be performed to your Bitnami installation:

1. Stop web server
2. Configure web server to use a free Let's Encrypt certificate for the domains: 
3. Configure a cron job to automatically renew the certificate each month
4. Configure web server name to: 
5. Enable HTTP to HTTPS redirection (example: redirect XXX)
6. Start web server once all changes have been performed
Do you agree to these changes? [Y/n]: Y
```

⑥Emailアドレス教えて！！
```
E-mail address []:
```

⑦Successの連絡
```
Success

The Bitnami HTTPS Configuration Tool succeeded in modifying your installation.

The configuration report is shown below.
```

はい、これで完成！！！めっちゃ簡単にSSL化できます！！！
試しにDomainを叩き直すと、HTTPS化されています！！！
35世代保持する設定のRDSスナップショットが60個あった件

RDSを設定していて、バックアップとしてスナップショットを35世代保持する設定をしていました。
数ヶ月経ってスナップショットを確認すると、なんと35個ではなく60個以上作成されていました。

この件について、調べてわかったことをまとめます。

# 対象RDSについて

- 1. エンジンはPostgreSQL
- 2. シングルAZ構成(冗長化なし)
- 3. ランニングコスト削減のため夜間帯(21:00-07:00)は停止している

# スナップショットがやたら多い

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435280/b2df5968-577c-667c-5e9f-cf45f9b2f361.png)

35世代分取得するはずなのに、なぜか62個スナップショットがあります。
なぜでしょうか。。。

# 少し調べてみた


> Q: 自動化された DB スナップショットの数が、DB インスタンスに対するリテンション期間の日数よりも多いのはなぜですか?
> 
> リテンション期間の日数よりも 1 日か 2 日自動化 DB のスナップショットの日数が多いのは正常です。自動化スナップショットは 1 日余計にとられていて、リテンション期間中のいつにでも復帰できる時点を設けています。例えば、バックアップウィンドウが 1 日に設定されている場合、自動化スナップショットは 2 つ必要で、これで過去 24 時間中の任意の時点への復帰をサポートしています。また、さらに多くの自動化スナップショットがある場合もありますが、これは新たな自動化スナップショットが、最も古い自動化スナップショットを削除する前に常に生成されるためです。。

https://aws.amazon.com/jp/rds/faqs/


1/2日分のスナップショットが余分に保持されているのは正常な動作と書かれていますが、35世代に対して60個は明らかに多すぎます。なので別の原因があると想定します。

# さらに調べてみた

> DB インスタンスの停止中は、自動バックアップは作成されません。
DB インスタンスが停止している場合、バックアップ保持期間より
長くバックアップを保持できます。RDSには、バックアップ保存期間の
計算時にstopped状態にあった時間は含まれません。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_WorkingWithAutomatedBackups.html#USER_WorkingWithAutomatedBackups.BackupRetention

つまり
`保持日数の設定は日にち単位でのカウントではなく、時間単位の計算となっている`
というわけです。

これがどういうことかというと、例えば
`
10日分保存する設定にしていれば、24 x 10 = 240時間分のバックアップ(スナップショット)を保持する事になる。RDSが停止している時はこの時間にカウントされない。もし夜間停止などを行なっているRDSがあり1日に12時間起動する場合、240 / 12 = 20世代のバックアップが取得される。
`
ということになります。

今回、RDSは21:00-07:00にて夜間停止を行なっています。つまり一日あたりの起動時間は14時間です。
一日あたり14時間起動するRDSのスナップショットを35日分取得するとなると、
```
35 x 14/24 = 60
```

辻褄が合いそうですね。




# まとめ

RDSのスナップショットにおいて、
**保持期間は日にち単位ではなく時間単位の計算となる(保持期間 ≠ 保持世代)**
treeで罫線が文字化けした際の対処方法

## Linuxでtreeコマンドを使用した際に罫線が文字化けした場合の対処方法

## 環境

```shell
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
```
```shell
$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
```
## 事象

Teretermで接続し、引数無しで実行すると以下のようになる
```
$ tree
.
├─ buildscripts
│?? ├─ checkdeps.sh
│?? ├─ cicd-corpus
│?? │?? ├─ disk1
│?? │?? │?? └─ bucket
│?? │?? │??     └─ testobj
│?? │?? │??         └─ 2b4f7e41-df82-4a5e-a3c1-8df87f83332f
│?? │?? │??             └─ part.1
│?? │?? └ disk2
...省略
```

更にwindowsにコピーすると以下のようになる
```
.
tqq buildscripts
x?? tqq checkdeps.sh
x?? tqq cicd-corpus
x?? x?? tqq disk1
x?? x?? x?? mqq bucket
x?? x?? x??     mqq testobj
x?? x?? x??         mqq 2b4f7e41-df82-4a5e-a3c1-8df87f83332f
x?? x?? x??             mqq part.1
x?? x?? tqq disk2
...省略
```

## 対策(Teratermだけで表示する場合)
Teratermで確認するだけなら`tree -A`とする
```
$ tree -A
.
├─ buildscripts
│   ├─ checkdeps.sh
│   ├─ cicd-corpus
│   │   ├─ disk1
│   │   │   └─ bucket
│   │   │       └─ testobj
│   │   │           └─ 2b4f7e41-df82-4a5e-a3c1-8df87f83332f
│   │   │               └─ part.1
│   │   └ disk2
...省略
```

しかしwindowsにコピペすると化ける

```
.
tqq buildscripts
x   tqq checkdeps.sh
x   tqq cicd-corpus
x   x   tqq disk1
x   x   x   mqq bucket
x   x   x       mqq testobj
x   x   x           mqq 2b4f7e41-df82-4a5e-a3c1-8df87f83332f
x   x   x               mqq part.1
x   x   tqq disk2
```

## 対策2(Windowsにコピペしたい場合)
UTF-8だと化けるのでLANG＝Cで実行することでコピペ化けなくなる

```
$ tree --charset=C
.
|-- buildscripts
|   |-- checkdeps.sh
|   |-- cicd-corpus
|   |   |-- disk1
|   |   |   `-- bucket
|   |   |       `-- testobj
|   |   |           `-- 2b4f7e41-df82-4a5e-a3c1-8df87f83332f
|   |   |               `-- part.1
|   |   |-- disk2
```
もしくは`LANG=C tree`でも行けるが、上記までの結果と違いアルファベット順(-v)での表示となるので、オプションを付与してソートが必要
```
$ LANG=C tree
.
|-- CNAME
|-- COMPLIANCE.md
|-- CONTRIBUTING.md
|-- CREDITS
|-- Dockerfile
|-- Dockerfile.cicd
|-- Dockerfile.dev
|-- Dockerfile.hotfix
|-- Dockerfile.release
```

```
  ------- Sorting options -------
  -v            Sort files alphanumerically by version.
  -r            Sort files in reverse alphanumeric order.
  -t            Sort files by last modification time.
  -c            Sort files by last status change time.
  -U            Leave files unsorted.
  --dirsfirst   List directories before files (-U disables).
```
新卒エンジニア1年目を終えて(遅刻)

#### 1年目は社会人エンジニアとして、日々の学習癖と知識の土台作りを目標に生きました。

## 自己紹介
情報学部卒業の21卒エンジニアです。
社内の基幹システムを保守(開発)するのがメイン業務のSEです。

## やったこと
* 資格取得
* 社会人としての報連相
* 読書(IT,哲学,デザイン)
### 資格勉強
エンジニアとして知っておきたい内容を抜粋して勉強しました。

|資格名  |取得年月  |勉強期間(概算)  |
|---|---|---|
|応用情報技術者試験  |2021/04  |6ヵ月  |
|日商簿記 3級  |2021/10  |1ヵ月  |
|Java Silver  |2021/12  |1.5ヵ月  |
|LinuC レベル1  |2022/02  |2ヵ月  |
|CCNA  |2022/06  |4ヵ月  |

です！

### 社会人としての報連相
##### 苦戦しました。
最初の3か月ほどは"報連相すべきこと・報連相しなくてよいこと"の区別が付かなかったです。
(主に報連相が少ない)

自宅のPCを触っているノリで検証用のサーバー及び格納されているアプリケーションを操作していました。
僕「まぁこの操作では壊れないし不都合も起きないだろう」 ﾎﾟﾁｰ!

-説教後-
「今後はデスクトップ画面をクリックしたり、キーボードを1つ押すのにも逐一報連相すれば良いということですね！」
という感じで周囲を困らせました。
~~「linuxで右クリックしたらコピーされるの、行動前に報連相するの無理では..？」~~

## これからやること
小さなアプリを作ったり、それを通してアウトプットをしていきたいです。
自分の頭の中にある「これあったら便利だよなあ」を実現できるのがエンジニアのとても良いところの一つだと思っています。



本記事で書き足りないことを発見したら、時間があるときに加筆更新します。
Reactで画像ファイルを選択したときにプレビュー画像を表示する方法

## 概要
`<input type="file">`で画像ファイルを選択したときに`FileReader`を使用してプレビュー画像を表示する方法

## プログラム
### 画像ファイル選択のJSXのコード

```JSX
// ※MUIのButtonコンポーネントを使用している
<Button variant="contained" component="label" color="success">
   画像ファイルを選択
   <input type="file" accept="image/*" onChange={onChangeFileInput} hidden />
</Button>
```

### input要素が変更された時のイベントハンドラーのコード

```js:app.js
// プレビュー画像のデータURLを格納するstate
const [imagePreview, setImagePreview] = useState<string | ArrayBuffer | null | undefined>(undefined)

/**
 * ファイル入力欄が変更したときのイベントハンドラー
 * @param {React.ChangeEvent<HTMLInputElement>} event ファイルインプットイベントオブジェクト
 * @returns {void}
 */
const onChangeFileInput = (event: React.ChangeEvent<HTMLInputElement>): void => {
  setImagePreview(undefined)

  // 何も選択されなかったら処理中断
  if (event.target.files?.length === 0) {
    return
  }

  // ファイル画像でなかったら処理中断
  if (!event.target.files?.[0].type.match("image.*")) {
    return
  }

  // FileReaderクラスのインスタンスを取得
  const reader = new FileReader()

  // ファイルを読み込み終わったタイミングで実行するイベントハンドラー
  reader.onload = (e) => {
    // imagePreviewに読み込み結果（データURL）を代入する
    // imagePreviewに値を入れると<output>に画像が表示される
    setImagePreview(e.target?.result)
  }

  // ファイルを読み込む
  // 読み込まれたファイルはデータURL形式で受け取れる（上記onload参照）
  reader.readAsDataURL(event.target?.files[0])
}
```

### プレビュー画像表示用のJSXのコード

```JSX
// imagePreviewにプレビュー画像用のデータURLが格納される
{!!imagePreview && (
  <output>
    <img src={imagePreview} alt="画像プレビュー" />
  </output>
)}
```
【備忘録】AWS LightsailでRedmineとDomainを紐づける（Route53)

## Route53でドメインを紐づける
[前回の記事](https://qiita.com/kouji0705/items/195b97ed708382dac3a2)ではLightsailでRedmineの構築方法を紹介いたしました。本記事ではRoute５３を利用し、Domainと紐づける作業を実施します。

## ①Domainの取得
Route53からDomainを購入しましょう！！
1. ドメインの登録画面に遷移する
![スクリーンショット 2022-06-10 14.01.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/cc39e77f-161f-34b8-403d-b04f4d2e82a2.png)

2.　Domain名で検索する
![スクリーンショット 2022-06-10 14.11.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/19ae10a7-53dc-b580-2046-a645dfc4ac20.png)

3. 個人情報を入力する。
![スクリーンショット 2022-06-10 14.03.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/873613b4-eff5-5f2a-0cdc-5ff3d9f6ccc6.png)

これでクレジット決済すれば、見事Domainが購入する事ができました！！

## ②Domainの紐付け
Route53を開き、値の箇所にIPアドレスを設定しましょう。
ちなみに、IPアドレスはLightsailのネットワーキングから確認できます。
![スクリーンショット 2022-06-10 14.30.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/ba6dc938-235b-cf3d-4d51-e6c5c0af8ac1.png)

3分程度でDNSの更新が完了するので、ドメインを叩いてみるとRedmineが立ち上がっています。

![スクリーンショット 2022-06-10 14.32.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/4d3eee67-f362-d509-dcd7-d0694cf570f7.png)
【Android】ボタンの上下左右に画像を動的に配置する

# リソースIDによる配置
不要な箇所は```0```を入れる

```Kotlin
binding.button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.image_left, R.drawable.image_top, R.drawable.image_right, R.drawable.image_bottom)
```

# Drawableによる配置

不要な箇所は```null```を入れる
```Kotlin
val imageLeft:Drawable = //省略
val imageTop:Drawable = //省略
val imageRight:Drawable = //省略
val imageBottom:Drawable = //省略

binding.button.setCompoundDrawablesWithIntrinsicBounds( imageLeft, imageTop, imageRight, imageBottom)
```
Terraform - Route 53 alias のホストゾーンID のお話

# 背景
Terraform で Route 53 で alias を使う際に必ず欲しい情報のはず。

# 課題
「zone_id 何設定するんだっけ？」の答えを知りたい。
そんな時のブックマークです。

# 解決
## Amazon API Gateway
https://docs.aws.amazon.com/ja_jp/general/latest/gr/apigateway.html

## AWS AppSync
https://docs.aws.amazon.com/ja_jp/general/latest/gr/appsync.html
調査中...

## Amazon CloudFront
https://docs.aws.amazon.com/ja_jp/general/latest/gr/cf_region.html

## AWS Elastic Beanstalk
https://docs.aws.amazon.com/ja_jp/general/latest/gr/elasticbeanstalk.html

## Elastic Load Balancing(Application, Classic, Network)
https://docs.aws.amazon.com/ja_jp/general/latest/gr/elb.html

## Global Accelerator
調査中...

## Amazon Simple Storage Service
https://docs.aws.amazon.com/ja_jp/general/latest/gr/s3.html

## Amazon Virtual Private Cloud
https://docs.aws.amazon.com/ja_jp/general/latest/gr/vpc-service.html
調査中...

# 一言
一部調査中ですみません。
何も考えずに当該ドメインのホストゾーンID設定するとコケますよ。
Android で日付の言語および、24時間表示対応

Android で日付や時刻を表示する際の、言語設定や２４時間表示設定への対応方法をまとめます。

対応は簡単で、[DateUtils](https://developer.android.com/reference/android/text/format/DateUtils) を使うだけです。
```kotlin
        val date = DateUtils.formatDateTime(
            this,
            System.currentTimeMillis(),
            FORMAT_SHOW_YEAR or
                    FORMAT_SHOW_DATE or
                    FORMAT_SHOW_WEEKDAY or
                    FORMAT_SHOW_TIME
        )
```

上記の場合は、西暦、日付、曜日、時刻の文字列を生成しています。
こうすることで、下記のように文字列が生成されます。

|  言語設定  |  24時間表示設定  |  文字列  |
| ---- | ---- | ---- |
|  日本語  |  24時間  |  2022年6月10日金曜日 13:00  |
|  日本語  |  12時間  |  2022年6月10日金曜日 午後1:00  |
|  英語  |  24時間  |  Friday, June 10, 2022, 13:00  |
|  英語  |  12時間  |  Friday, June 10, 2022, 1:00 PM  |
CloudCircus社【Fullstar】　×　Chrome拡張機能でDOM取得

# この記事でお話ししたいこと
Chrome拡張は開発ハードルも低く、公開しなければ無料で始められるとても魅力的なサービスです。
CloudCircus社では【Fullstar】という製品の一部としてChrome拡張を利用しています。

　* もっともっとWebエンジニアにとって使いやすい拡張がもっと増えたらいいな
　* 初級編では拡張機能試したけどその後は何もやってないのよねって人への「こんなこともできるよ」入門編

## どうしてDOMを取得したいの？
まずは下記の動画をご覧ください。
　サイト上に吹き出しや画像を表示し、システムを利用するための導線や説明をわかりやすく説明しています。
![FULLSTAR（動画）.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632570/0b0487d0-7bd8-691c-5a0e-daaefaab405c.gif)

このように「どの要素をハイライトして」「要素からどの程度の距離（座標）に吹き出しを表示するか？」という設定を
Chrome拡張から行います。

## Chrome拡張から表示中のサイトのDOMを取得する仕組み
Chrome拡張から、表示中のサイトにアクセスしてDOM情報を取得します。
![要素選択.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632570/53b98937-60f1-f70d-c08e-3efdaf819a71.gif)

マウスで直接選択することでHTMLとか知らないですって人もかんたんに要素を選択できます。

ざっくりですが理屈としては下記のような処理を行います。
①マウスポインタから画面の座標位置を取得
②座標の位置からアクティブタブの要素を取得
③一致した要素からCSSセレクター文字列を生成

![取得方法説明.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632570/7ab1dccb-2f7b-2e8a-17a5-76210a31562d.gif)

:::note info
「CSSセレクター文字列を生成」ですが、独自の優先順位で生成しています。
ID　>　Name属性　> Class（一意なもの） > 疑似クラス※など

※擬似クラス　こちらがとってもわかりやすいです
https://www.asobou.co.jp/blog/web/css2#Anth-childnn
:::

拡張内のJSファイルでの値渡しは
```
chrome.scripting.executeScript
chrome.tabs.sendMessage
```
などを利用します。

:::note warn
Manifestバージョン３前提です！まだ２の人は該当しない可能性があります、ご注意ください
:::


## Chrome拡張で必要な「パーミッション」とは
Chrome拡張で機能を作り込むほど無視できないのがManifestファイルの「Permission」です。
Fullstarの一部を書き出してみました。
```
{
  "manifest_version": 3,
   "permissions": ["activeTab", "cookies", "tabs","scripting"],
  　　"host_permissions": [
    "FullstarのURL"
  　　],
   "background": {“service_worker”: “xxxxxxxx”},
   "web_accessible_resources": [{
        "resources": ["拡張機能のIframe", "拡張機能内の操作.js",...]
   }],
  "action": {
    "default_popup": "popup.html",
   },
  "author": "Cloud CIRCUS inc.",
}
```

今回のように「表示中のタブについて取得したい」ときは`actibeTab`と`tabs`が必須です。

:::note warn
一応注意
あったらいいでしょ！ってPermissionを追加して開発すると利用者に警戒されるだけでなく
審査のときすべて理由を記載する必要がある　＋　審査に時間がかかる（特にhost_permissionsは時間がかかります）ので注意です。
:::

## まとめ
ざっくりな内容でしたが、Chrome拡張で自分用に作ってみたいなとかこれがあればWebエンジニア的に助かるなみたいなものが
今後作られていくといいなと思います。

では最後に個人的にChrome拡張を導入後に感じているメリット・デメリットで締めさせてもらいます。

:::note info
Good
:sunny:Javascriptで開発可能なので特別なツールもいらない、マシンスペックも気にせず開発可能
:sunny:オリジナルの拡張機能を作ると、既存の拡張機能使う時の「この拡張機能、検索すると「危険」とか出てきて怖い…みたいなのがない
:sunny:ManifestファイルのPermissionによるが、審査の時間が早い、公開も安い:moneybag:
:::

:::note warn
Warning
:frowning2:前回のリリース時には引っかからなかった部分で審査に落ちることが稀にある。リリース日程には余裕を
:frowning2:V2⇨V3の情報が混じって情報収集に混乱しがち。書籍も少ないのでWebでの情報収集に難航しがち
:::

注意点としてはオリジナルでの開発としてはデメリットでもないと思いますが、もし製品の一部に考えてますって方の参考になればと思います。
Draw.ioをVSCodeで使用する。

上手く使いこなせてはいませんが、Draw.ioをVSCodeにインストールするだけで、ネットに繋がずに使用できるので入れてみました！
後でどうやって入れたかな？とならないように忘却録を残します。

VSCodeを立ち上げ、拡張機能の検索窓に「Draw.io」と書き込めばいくつか候補が出てきますが多分一番上に出てきている「Draw.io Integration」をインストール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514815/1f3e5925-8fa9-5772-284e-24378e8ceb67.png)
その後VSCodeを再起動させれば終了。

使い方としては新規ファイルを作成し、.drawio、.dio、.drawio.svg、.drawio.png　などの拡張子で保存するだけ。
すると新規作成したファイルがDraw.io用のファイルとして保存され使用できるようになります。
kotlinでdefer的なことをする

kotlinで、他の言語のdeferのようなことを実現するコード。

```kotlin
import java.lang.Exception

class MyDefer {

    val list = ArrayList<() -> Unit>()

    fun defer(fn: () -> Unit) {
        list.add(fn)
    }

    fun doDefer() {
        list.reversed().forEach {
            try {
                it()
            } catch(_: Exception) {
            }
        }

    }
}

fun mydefer(fn: MyDefer.() -> Unit ): MyDefer {
    val mydefer = MyDefer()
    try {
        mydefer.fn()
    } finally {
        mydefer.doDefer()
    }
    return mydefer
}


fun main() {

    mydefer {
        print("1\n")
        defer{ print("defer1\n") }
        defer{ print("defer2\n") }
        print("2\n")
    }
}
```

書いてはみたが、きっと使わない気がする。
【java】javaの連想配列の2次元配列 キーを指定しないデータ構造  こんな感じのデータ [{名前=高橋, 国語=78}, {名前=吉田, 国語=50}]

# コード
```java
import java.util.*;
    public class Main {
    public static void main(String[] args) throws Exception {
        List<Map<String, Object>> nameMap = new ArrayList<>();
        //
        Map<String, Object> scoresMap_suzuki = new LinkedHashMap<String, Object>();
        scoresMap_suzuki.put("name", "高橋");
        scoresMap_suzuki.put("japanese", 78);
        scoresMap_suzuki.put("math", 90);
        //
        Map<String, Object> scoresMap_satoh = new LinkedHashMap<String, Object>();
        scoresMap_satoh.put("name", "吉田");
        scoresMap_satoh.put("japanese", 50);
        scoresMap_satoh.put("math", 40);
        //
        nameMap.add(scoresMap_suzuki);
        nameMap.add(scoresMap_satoh);
        System.out.println(nameMap);
        nameMap.forEach(s -> System.out.println(s.get("name"))); // forEachメソッド
    }
}

```

# 結果
```
[{name=高橋, japanese=78, math=90}, {name=吉田, japanese=50, math=40}]
高橋
吉田
```

もっと短くコードをかける方法を知ってたら、教えてね
【Rails】BootstrapとFontAwesomeの導入

# はじめに
課題で読んだ本の感想を投稿するアプリケーションを作りましたが、色々と苦戦しましたので備忘録として記事を投稿しようと思います。
今回はBootstrapとFontAwesomeの導入について記載します。

# 環境
- 開発 (cloud9)
- 言語 (Ruby 2.6.3)
- フレームワーク(Rails 6.1.6)

# Bootstrapの導入
#### yarnでインストールする
導入方法はいくつかあるらしいのですが、今回はyarnでインストールします。

```:terminal
$ yarn add jquery bootstrap@4.5 popper.js
```
`jquery`…Bootstrapを動かすのに必要なjQueryです
`bootstrap`…Bootstrapの本体です
`popper.js`…機能を利用するのに必要なものらしいです

bootstrap@4.5の`@4.5`はBootstrapのバージョンになります。好みのバージョンを指定してください。ただし、Bootstrapのバージョン5はjQueryが必要ないそうです。今後、jQueryが必要になる機能を実装する予定があるのならバージョン4でいいかもしれません。

#### jQueryとPopper.jsを使えるようにする
environment.jsを編集して、jQueryとPopper.jsを利用できるようにします。

ファイルの場所は以下になります。
`config/webpack/environment.js`
```ruby:config/webpack/environment.js
# 以下を追記する
const webpack = require('webpack')
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: 'popper.js'
  })
)
```

#### Bootstrapを使えるようにする
まず、`app/javascript`に「stylesheets」という名前のフォルダを作成します。次に、作成した「stylesheets」の中に「application.scss」という名前のファイルを作成します。

作成した「application.scss」ファイルに、以下のコードを記述しましょう。
```ruby:app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
```

次は「application.js」にコードを追加します。

ファイルの場所は以下になります。
`app/javascript/packs/application.js`
```ruby:app/javascript/packs/application.js
:
:

import "channels"

# ここから
import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application" 
# ここまで追加

Rails.start()
Turbolinks.start()
ActiveStorage.start()
```

最後に「application.html.erb」を編集します。

ファイルの場所は以下になります。
`app/views/layouts/application.html.erb`
```erb:app/views/layouts/application.html.erb
:
:

  <!-- 変更前 -->
  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

:
:
```

```erb:app/views/layouts/application.html.erb
:
:

  <!-- 変更後 -->
  <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

:
:
```

- stylesheet_link_tag の場合
`app/assets`にあるcssファイルを参照する

- stylesheet_pack_tag の場合
`app/javascript`にあるcssファイルを参照する

という仕組みのようです。例えばcssは`app/assets`、JavaScriptは`app/javascript`というように管理を分けるという場合は、コードの記述を変更が必要になります。

これでBootstrapの導入は完了です。次はFontAwesomeの導入をします。

# FontAwesomeの導入
#### yarnでインストールする
今回もyarnでインストールします。

```:terminal
$ yarn add @fortawesome/fontawesome-free@5.15.4
```
`@5.15.4`の部分はバージョンになりますので、好きなバージョンを指定してください。

#### FontAwesomeを使えるようにする
まず「application.js」にコードを追加します。

ファイルの場所は以下になります。
`app/javascript/packs/application.js`
```ruby:app/javascript/packs/application.js
:
:

import "channels"

import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application" 
# 以下を追加
import '@fortawesome/fontawesome-free/js/all'

Rails.start()
Turbolinks.start()
ActiveStorage.start()
```

次に、先ほど作成した「application.scss」ファイルへコードを追加します。
```ruby:app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
# 以下を追加
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
```
これでFontAwesomeの導入完了です。

# 最後に
記事をご覧いただきありがとうございました。
記事の内容に誤りや理解不足な点がありましたら、ご指摘いただけると幸いです。
Chrome起動の度に同期が一時停止中になってしまう際の対処法

## 環境
macOS Monterey - Version 12.4
Google Chrome - Version 102.0.5005.115（Official Build） （x86_64）

## 状況
Chromeを起動するたびに同期が一時停止中となり再ログイン要求される
→自動入力等が使えない...

## 解決
1. 設定を開く
1. プライバシーとセキュリティー
1. Cookieと他のサイトデータ
1. すべてのウィンドウを閉じるときにCookieとサイトデータを削除するをON
1. Chromeを再起動
1. 右上の一時停止中→もう一度ログインする
1. 設定を開き［4］（Cookieとサイトデータを削除する）をOFFに戻す
<img width="256px" alt="settings-privacy" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880779/33046d07-6ea9-22df-b942-6aeee638ef0d.png">
<img width="256px" alt="settings-privacy" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880779/2ed23a99-5582-3f30-a1e6-5fd5ef3b0e2d.png">

## 参考にしたサイト
[【困ったChrome】ChromeのログインがChromeの起動の度に一時停止中になってしまう時の対処法](https://www.b-space.net/chrome-login-trouble-shooting/)

**ありがとうございました。**
リードの取引開始とは？

# 対象読者
* システム管理者
* 認定アドミニストレーター試験受験者

# リードの取引開始って何ができるの？
リードの取引開始機能を利用すると、リードオブジェクトの項目を「取引先」「取引先責任者」「商談」の項目へマッピングしてレコードを自動で作成することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2642898/cbb1f8cd-67ad-22c3-86f0-3a0948329310.png)

# 必要な権限は？
Salesforceの[ヘルプページ](https://help.salesforce.com/s/articleView?language=en_US&type=5&id=sf.leads_convert.htm)にある通り、「取引先」「取引先責任者」「商談」への作成/編集権限が必要になります。
さらに、プロファイル単位で設定されるリードの取引開始権限も必要となりますのでボタンが表示されない場合はオブジェクト権限以外にプロファイルもチェックしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2642898/7263018c-209b-b84f-3e44-250054d09757.png)

# リードの取引開始項目のマッピング
マッピングできる項目は標準項目だけではなく、リードのカスタム項目も各オブジェクトへマッピングすることができます。
リードの数式項目に関してもマッピング対象とすることができますが、マッピング先項目は数式の型に対応したものとなり、自動採番項目はテキストかテキストエリア型の項目をマッピング先として指定できます。
例）数式（数値）の場合は、数値型項目
ここに関してもアドミニストレータ試験で問われる範囲なので要注意ですね！

マッピングはリードの「リードの項目対応付け」から行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2642898/e5336441-fac9-c71f-3ec5-6312a73adb7c.png)

遷移した先で①マッピング先のオブジェクトを選択し②でリード項目に対応させるマッピング先オブジェクトの項目を選択し設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2642898/2d8f8f5f-c487-9401-951d-b18ff78b818f.png)

# リードの取引開始時に注意事項
## 商談
「商談」レコードの作成は任意とすることができますので不要な場合は下図のチェックをいれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2642898/6c20a4f8-5959-6ad6-afdf-d55e29c7f1ce.png)
また、商談レコードをリード作成プロセスで作成する場合に標準では商談完了日が当会計四半期の最終日となることは留意しておきましょう。
## 取引開始後のリード情報
取引開始後のリード情報はリストビューや検索結果に表示されなくなりますがレポートでは表示が可能です。
また「取引開始済みのリードの表示および編集」権限を付与していない限りリード情報としては表示や編集ができなくなります。
この権限はプロファイル単位に設定されるシステム管理者権限となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2642898/6e2372c6-5ecb-8710-5e47-92078de72b53.png)

# 最後に
今回はリードの取引開始機能について解説しました。
この内容は、実案件でも利用されることが多いと思いますし、アドミニストレータ試験でも問題として出題される内容となりますので、しっかりと内容は押さえておきたいですね！
Apple Developer Programに登録せずmacOS Beta を入手する(MacOS標準機能使用)

# 最初に
WWDC2023、皆さんはもうご覧になったでしょうか(見ずにここへたどり着いた人はいないでしょうが。)
前置き要らんっていう人も#最初には読んでください。諸注意が書いてあるので。
読んだら#実際にBeta入手してみるに飛んでください。

さて、前置きはほどほどに。macOS Sonomaですが、早速ダウンロードしてみました。
最初はAppleから公開されている正規の方法で試してみたのですが、AppleDeveloperProgramに登録できる条件を満たしていないために入手できませんでした。
しかし、実際にはMacOSに入っている標準コマンドのみでダウンロード可能なようです。自分の環境では問題なくダウンロード、インストーラー起動まではたどり着いたのですがAppleから公開されている手法ではないですのでご注意ください。なおこれより下の操作を実際に行う場合はくれぐれも自己責任でお願いします。

# なんで入手できなかったか
前述のとおりです。学生なのでカードはおろか年齢という基本的な条件すら満たしていません。
Sonoma Betaほしいのにっっっっっっ (`；ω；´)

# 簡単な方法があった
そんな中見つけたのが次のサイトです。

https://mrmacintosh.com/how-to-enroll-your-mac-into-beta-with-seedutil-macos-monterey/

このサイトによればHighSierraからseedutilコマンドなるものが導入されたようです。
それによりAppleDeveloperProgram登録なしでBetaを入手する方法ができたようです。

```terminal
sudo {ディレクトリ}seedutil (登録/登録解除) シード
```

といった具合でコマンドにて登録などの手続きをせずDevBetaを入手できるようです。
~~書いてて実はみんな知ってるんじゃないかと怖くなってきた。
自分はこれ見つけるのに相当時間かかったのでよくわからないんだよね~~

# 実際にBeta入手してみる
## 使い方
このコマンドは以下のディレクトリにあり、sudo権限を必要とします。使用方法を見るには次のようになります。

```terminal
sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil 
```

## 入手する
さっそく入手しましょう。
terminalを開いて次のように入力します。
ちと長いのでコピペしやすいように最初の%は外してあります。

```terminal
sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil enroll DeveloperSeed
```
### 結果
![export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222532/929efe1b-c78e-435e-8081-c6131b5f1923.png)

これでDeveloperBetaを受け取れるようになりました。
早速システム環境設定->ソフトウェアアップデートを確認しましょう。何度か読み込んだ後に"macOS 14 beta"と表示されるはずです。出てこない場合は何度か開いて戻ってを繰り返してみましょう。
### システム環境設定
実行前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222532/16b4683b-b6fa-fdb2-fcc7-76671e615ae5.png)
実行後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222532/25de6813-2931-32c4-4887-c9eabe7c3d5f.png)


"今すぐアップグレード"をクリックしダウンロード完了を待ちましょう。完了後自動的にインストーラーの確認画面が開くのですぐにアップグレードしたくない場合はアイコンを右クリックして終了しましょう。
お約束のcreateinstallmediaコマンドもちゃんと入っていました。
とりあえずiso化もできています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222532/b92ba8c2-cb4a-0e5a-f405-216343de576c.png)


なおBetaの為アップグレード前にはデータバックアップを取り、初期化してもいい環境で実行しましょう。間違ってもメインのMacでバックアップせずに、なんて無謀なことしないでください。筆者は責任を取りません。

## 解除
unenrollでDeveloperBetaを受け取る状態を解除できます。

```terminal
sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil unenroll
```

## 状態確認
currentで現在のseedを確認できます。
```terminal
sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil current
```

# 最後に
ダウンロードできましたでしょうか。
もしこのコマンドが動作しない、また新たな問題を吐いた、等ありましたらコメントにお願いします。
何しろ自分も知ったばかりの物なので勝手が理解できているかというとそういうわけでもないんです。
参考サイトを張っておきます。それでは。

## 参考サイト
ありがとうございました。

https://mrmacintosh.com/how-to-enroll-your-mac-into-beta-with-seedutil-macos-monterey/

https://gist.github.com/pookjw/b17da769e9c3b061f9a5bcf3f7990866
IBM Cloud の Secrets Manger に証明書をインポートしてALBで利用する

# はじめに

Certificate Managerはサービス終了することが発表されており、後継としてSecrets Managerの利用が推奨されています。

これまでALB(Application Load Balancer)でHTTPSを終端する場合にはCertificate Managerでインポートした証明書を指定していましたが、今後はSecrets Managerでインポートした証明書へ変更する必要があります。

:::note warn
ALBでHTTPS用のFrontend Listnerを作成しようとすると下記画面が表示されます。
:::
![ALB_HTTPS作成時の警告](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329464/384d5999-c97c-0d82-0e4b-f0e3d765e107.png)

CISで発行した起点証明書(Origin Certificate)をSecrets Managerにインポートし、
ALBのHTTPS用Frontend Listenerに設定してみました。

# Secrets Managerへのインポート

### CISでの起点証明書発行

CISでの起点証明書発行手順は省略します。
cis-origin-cert.pem：　起点証明書
cis-origin-key.pem ：　起点証明書秘密鍵

### シークレット・グループの作成

必要に応じてアクセス権限を設定

### シークレットの作成

Secrets Manager > シークレット > 追加 > TLS証明書 > 証明書のインポート

![Secrets](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329464/647ed173-aec2-f0c0-fb82-712fa6c96b16.png)


# VPC Loadbalancerに対してSecrets Managerへのアクセス権限付与

管理 > アクセス(IAM) > 許可 > 作成
![VPCLoadbalancer](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329464/15bec470-6538-659a-9bfb-817a916cdd69.png)

ソース・サービスで VPC Infrastructure Services
選択された属性に基づくリソースのリソース・タイプで Load Balancer for VPC
を選択すると、ターゲット・サービスに Secrets Manger が選択できる

サービス・アクセスには、リーダーとライターを選択する。
（選択しなければALBでの選択時に権限不足のエラーが表示される）

:::note warn
アクセス権限を付与せずにALBのFrontend ListnerでSecrets Managerの証明書を選択すると、以下のエラーが表示される
:::
![ALB_Error](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329464/9b2bbc8d-dd6b-8929-de09-c6592952cfb7.png)


# ALBのHTTPS用Frontend Listenerにインポートした証明書を設定

フロントエンド・リスナー > リスナーの作成

プロトコル: HTTPS
証明書ソース： Secrets Manger
秘密鍵管理者： Secrets MAanagerのインスタンス名
SSL 証明書：　Secrets managerで作成したシークレット名



# 動作確認

ALBにて適切なSecurity Group(HTTPS用Portの許可)の設定を行うことが前提

直接ALBのIPにHTTPSでアクセスし、利用されているサーバ証明書がCIS(CloudFlare)発行であることを確認した。


# 参考

IBM Cloud：Secrets Managerの概要
https://qiita.com/takason/items/3860854b54e0dd4550d7

IBM Cloud: Secrets ManagerとCertificate Managerの機能比較
https://qiita.com/takason/items/51cb67e46fa24b6ab2c0

クライアントとサイト間の認証のセットアップ
https://cloud.ibm.com/docs/vpc?topic=vpc-client-to-site-authentication#creating-iam-service-to-service

10 February 2022 Deprecation of the Certificate Manager service
https://cloud.ibm.com/docs/certificate-manager?topic=certificate-manager-release-notes#certificate-manager-feb1022
mysql_secure_installationコマンドがこけるようになった話

最近になってmysqlの`mysql_secure_installation`コマンドのrootユーザーパスワード設定項目でエラーが出るようになっていました。
具体的なエラー

```
Please set the password for root here.
New password: （複雑なパスワード）
Re-enter new password: （複雑なパスワード）
Estimated strength of the password: 100 
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
```

```
... Failed! Error: SET PASSWORD has no significance for user 'root'@'localhost' as the authentication method used doesn't store authentication data in the MySQL server. Please consider using ALTER USER instead if you want to change authentication parameters.

```

どんなに複雑にしても怒られます…

## 解決法

あらかじめrootユーザーのパスワードを設定しておくとエラーが出ずに最後まで進めます。
※下の例ではデフォルト認証方式も変えてますが変えなくても良い
```
$ mysql ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<password>';
```
```
$ >mysql exit
```
ufwでip指定条件でファイアウォールを設定する

## やりたかったこと
- ip制限をufwでしたい

```
# ファイヤウォールの有効化
$ sudo ufw enable
```

```
$ sudo ufw allow from xxx.xxx.xxx.xxx/xx to any port 3306 proto tcp
```

```
# 設定内容確認
$ sudo ufw status
```
curl: (59) failed setting cipher list: 出たときの対処法memo

メモ走り書き

そもそもNSSかOpenSSLか (curl -v で見た目判断)

自分の場合、サーバ引越し時に
移転元がNSS
移転先がOpenSSL

と変わっている状態だった。
OpenSSLの場合、Cipherのリストは
```shell
openssl ciphers -v
```
で確認できる

openSSLとNSSでは設定する値の表現が違うので、NSS<->OpenSSLで環境が変わるとエラー。

```shell
curl -v https://apple-pay-gateway.apple.com --cipher ecdhe_rsa_aes_128_gcm_sha_256
```
でエラーが出るのであれば、以下で試す形になる

```shell
curl -v https://apple-pay-gateway.apple.com --cipher ECDHE-RSA-AES128-GCM-SHA256
```

PHPのCURLでも同様。
フロントエンドのテストについて

## ■はじめに
私は現在フロントエンドエンジニアとしてJestを学習しているのですが、そもそもテストについての根本知識が0であり、どのようにテストを進めていけば良いのか分かりませんでした。
そこで今回は「そもそもフロントエンドのテストとは何ぞや」という事について私がサイトを漁って取得した情報をまとめたいと思います。

※テストについてはプロジェクトや個人によって意見が異なる部分があるため、あくまでも参考程度にご覧ください。

## ■テストを何故行うのか？
:::note info
ソフトウェアが正しく動作する事を保証する、信頼を上げる目的で書く
:::

カバレッジ率や品質を上げる事が目的ではない

## ■フロントエンドのテストの種類
### ◎静的テスト(Statictテスト)
typo チェックや型チェック等、コード作成中に行う
ツール：eslint、prettier等

### ◎単体テスト(Unitテスト)
最小単位のメソッド、コンポーネントのテスト
ツール：Jest、Mocha等
対象　：詳細設計

### ◎結合テスト(Integrationテスト)
複数のメソッド、コンポーネントを繋げてテスト
ツール：Jest、AVA、Testing Library、Enzyme
対象　：基本設計

### ◎End to Endテスト(E2E,UIテスト)
・ユーザの動作を想定しながら実際に画面を操作して行う
・シナリオ(動作の流れ)を基にテスト
・動作前後でスナップショットを撮り、保存しておくのがおススメ(後で確認しやすい)

ツール：Cypress等
対象　：要件定義、ユースケース

*****
それぞれの区別は、買い物サイトで例えるなら下記のイメージ…？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365717/d4e5de30-631f-f364-623d-dced79da37e4.png)
*****


### ◎目線での分類
**・ホワイトボックステスト**
　→コードの内容を知った上でテスト＝エンジニア目線
　 　静的テスト~結合テスト

**・ブラックボックステスト**
　→コードの内容が分からない状態でテスト＝ユーザ目線
　  　E2Eテスト

### ◎手法での分類
**・リグレッションテスト**
　→コードになんらかの変更を行った後に動作が担保されているかを確認するために実行

**・スナップショットテスト,ビジュアルリグレッションテスト**
　→動作前後画面を比較、見た目が大きく変わっていないかをテスト

## ■どのタイミングでテストをする？
### 実装の前
◎**TDD(Test Driven Development：テスト駆動開発)**
実装する前にテストコードを書く→それに合わせて実装
テストに通るようなコードを書いていく手法

**◎BDD(Behavior Driven Development：振る舞い駆動開発)**
TDDとほぼ同じだが、具体的やり方テンプレート？があるので少し進めるのが楽

### 実装中
これは後述でのCI/CDでの開発にあたると考えられる。

### 実装の後
設計→実装→設計を基にテスト

## ■テストを行う際に意識すること
**・結合テストを手厚く**
→Kent C. Dodds氏が述べている記事から、結合テストは「工数」「コスト」「保証」のバランスが一番良いため。
 また結合テストを行えば単体テストの部分はある程度網羅出来、逆にE2Eでは範囲が大きすぎてバグに気が付かないため結合テストの立ち位置が丁度良いのではないかと考えられる。

**・なぜそこをテストするのか？を明確に**
→無駄なテストは行わない。

**・単体テスト、結合テストではAPI等外部システムは使わず、モックしてテストする**
→原因がAPIにある可能性もあり、純粋なフロントのテストにならないため

## ■テストの粒度
ではどのレベルでテストを行えば良いのか？

**◎単体テスト**
バグが起こったらまずいところを重点的にテストする
→具体的にはアクセス集中ゾーン、課金ゾーン等

**◎結合テスト**
全体的に網羅することを目指す。
しかしカバレッジ率を上げる事が真の目的ではないので、あくまでも「テストの意味がある範囲で」100％を目指す。
モックはなるべく少なく、早く回せるように意識

## ■おまけ：最近よく聞くCI/CDとは何ぞや
GitHub等にコミットするとその都度自動でテストを回してくれる
→問題なければマージ、デプロイされる

**◎メリット**
・アジャイル開発にとても良い
・環境に左右されないテストが出来る

**◎デメリット**
・コミットとマージの間が少し空く→コミットをこまめにして変更部分を少なくする

**◎主なツール**
オンプレミス型：Jenkins
クラウド型：Travis CI、CircleCI

## ■まとめ
とりあえず下記を意識しておけば問題なさそうです。

:::note info
・テストは結合テストに重きを置く(全体的に網羅する)
・外部のシステムは使わずにモックして行う
・単体テストは重要だと考えられるメソッドのみで行う
・カバレッジ率よりも「そのメソッドに対してテストをする意味」を大事にする
・テストを行うタイミングはプロジェクトによる
:::

テストはかなり奥が深く、正解を突き詰めるときりがなさそうな印象でした。
そもそもフロントのテストは時間や工数的に全て行う事が不可能なため、どこまでやるかの定義が難しくなってしまうのですね。。

ここまでご覧頂きありがとうございました。

## ■参考URL
https://zenn.dev/koki_tech/articles/a96e58695540a7

https://blog.owlcode.net/posts/20211114-front-test

https://zenn.dev/seya/scraps/6f930e359d6a7c

https://testingjavascript.com/

https://qiita.com/noah-dev/items/3fd211deb8711fae8204

https://zenn.dev/mmomm/articles/c5de7cbfef7788a7ccbb

https://liginc.co.jp/397365

https://pfs.nifcloud.com/navi/words/ci_cd.htm
Herokuでpukiwikiを運用するときに困った話


## 困ったこと
初期設定が終わったpukiwikiをHerokuへデプロイ。
その後、公開状態のpukiwikiを編集しても、一定時間後(※)に初期化されてしまう現象に見舞われました。
※FreeのHerokuだったのですが、sleep->再起動のタイミングくらいです。

## 結論
ファイルシステムの特性上、1度のデプロイで永続的に運用できるわけではなさそう。
[Ephemeral filesystem](https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem)
以下Google翻訳
>各dynoは、最後にデプロイされたコードの新しいコピーを使用して、独自のエフェメラルファイルシステムを取得します。dynoの存続期間中、実行中のプロセスはファイルシステムを一時的なスクラッチパッドとして使用できますが、書き込まれたファイルは他のdynoのプロセスに表示されず、書き込まれたファイルはdynoが停止または再起動された瞬間に破棄されます。

要は、停止・再起動の度にファイル構成が最終push時の状態に戻る。
pukiwikiはwikiフォルダ配下に記事情報を格納してるっぽいので、助からない。

## 対処法
ローカルにて記事更新 -> push を繰り返すしか思い浮かばない。

#### つぶやき
WordPressみたいに記事をDBに格納できれば、良い感じにHerokuで運用できるんだろうなあ...:persevere:
pukiwikiに限った話ではないので、賢い回避方法がある気がしています。
yamlファイルを使って一連のROSメッセージをpublishする

ROSノードの自動テストなどで、一連のメッセージを、値を指定してpublishしたいときがあります。
たとえば、`/cmd_vel`トピックに、`Twist`型で、1秒おきに
`linear = {x:1.0, y:0,0, z:0.0}, {x:0.0, y:1.0, z:0.0}, {x:0.0, y:0.0, z:1.0}`
の3つのメッセージをpublishしたいとしましょう。
そんなとき、通常は
- トピックにメッセージをpublishするROSのプログラムをpythonなどで書いてrunする。
- なんとかして一連のメッセージを入れたbagファイルを作ってplayする。

といった方法で実現するかと思います。
今回はこれをコマンドラインツール`rostopic`とyamlファイルを使って行います。
### yamlファイルを作る 
ROSメッセージの値が入ったyamlファイルを作ります。
まず目的のトピックに、目的の型のメッセージをpublishします。
中身の値はなんでもいいです。
今回は`/cmd_vel`トピックに`geometry_msgs/Twist`型のメッセージをpublishします。
ここからはpub側とsub(echo)側で、2つのターミナルを使います。
```bash:term_pub
$ rostopic pub /cmd_vel geometry_msgs/Twist "linear:
  x: 0.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0"
```
途中までタイプすると、自動補完してくれると思います。
メッセージの値はyamlフォーマットになっています。
つぎにこのトピックを`rostopic echo`します。
```bash:term_sub
$ rostopic echo /cmd_vel 
linear: 
  x: 0.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
```
yamlフォーマットで出力してくれます。
これをファイルに保存します
```bash:term_sub
$ rostopic echo -n 1 /cmd_vel > cmd_vel_val.yaml
$ cat cmd_vel_val.yaml 
linear: 
  x: 0.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
```
Twist型のメッセージの値が1個入ったファイルができました。
### yamlに入っているデータをpublishする
このデータをpublishしてみます。
sub側のターミナルで`rostopic echo`しておきます。
```bash:term_sub
$ rostopic echo /cmd_vel
```
もう一方のターミナルで以下のようにします。
```bash:term_pub
$ cat cmd_vel_val.yaml| rostopic pub /cmd_vel geometry_msgs/Twist
```
すると
```bash:term_sub
$ rostopic echo /cmd_vel
linear: 
  x: 0.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
```
と、yamlファイルに入っていたデータが/cmd_velトピックでpub/subされます。
### 複数のメッセージをpublishする
複数のメッセージをpublishします。
cmd_vel_val.yamlを編集して、以下のようにします。
```yaml:cmd_vel_val.yaml
linear: 
  x: 1.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
linear: 
  x: 0.0
  y: 1.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
linear: 
  x: 0.0
  y: 0.0
  z: 1.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
```
3つのTwistの値が入ったファイルになりました。
これをpublishすると
```bash:term_pub
$ cat cmd_vel_val.yaml| rostopic pub /cmd_vel geometry_msgs/Twist
publishing and latching message for 3.0 seconds
publishing and latching message for 3.0 seconds
publishing and latching message for 3.0 seconds
```
```bash:term_sub
$ rostopic echo /cmd_vel
linear: 
  x: 1.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
linear: 
  x: 0.0
  y: 1.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
linear: 
  x: 0.0
  y: 0.0
  z: 1.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---
```
このように3つのメッセージが順にpublishされます。
term_subの`rosotpic echo /cmd_vel`はterm_pubの`rostopic pub`より先に実行しておいてください。
この方法では、rostopic pubすると3つのデータが待ち時間無しでpublishされます。
一定の時間間隔でpublishしたい場合は
```bash:term_a
$ cat cmd_vel_val.yaml| rostopic pub -r 1 /cmd_vel geometry_msgs/Twist
```
のように、`-r`オプションを付けてください。
これで`/cmd_vel`トピックに、1秒おきに
`linear = {x:1.0, y:0,0, z:0.0}, {x:0.0, y:1.0, z:0.0}, {x:0.0, y:0.0, z:1.0}`
の3つのメッセージをpublishすることができました。
### 所感
自動テストで一連のメッセージを、値を指定してpublishしたいときなどに、
テキストエディタで値をいじれて便利なやり方ではないでしょうか。
【備忘録】AWS LightsailにRedmineを構築する。

## はじめに
AWSのLightsailを利用してRedmineを構築する記事です。Lightsailとは月額の固定金額でサーバを簡単に作成できるサービスです。
難しいことは言いません、真似して作ってみてね！！

## 1.LightsailでRedmineを立てる
①AWSの管理コンソールから、Lightsailを起動しましょう
![スクリーンショット 2022-06-10 11.49.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/d7b844ca-89d6-5a4b-76cf-1e1fa2da29e9.png)

②インスタンスイメージを設定
![スクリーンショット 2022-06-10 11.51.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/496c9f35-1040-8fd9-0ab9-7f4fc74604ba.png)

③サーバスペックを決定する。
とりあえず、デフォルトで良いと思います。稼動後にスペックは変更できますので。
![スクリーンショット 2022-06-10 11.51.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/f47d6374-929c-e0f3-f54a-7929431a7fe0.png)

④インスタンスを作成する。
![スクリーンショット 2022-06-10 11.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/789d2ff2-ac7b-5573-cb74-ad9ec5d2d2c7.png)

⑤インスタンス完成
![スクリーンショット 2022-06-10 11.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/a49903ce-a2a1-5072-cfd4-014d8c6af755.png)

⑥ブラウザからIPアドレスにアクセスする！！
はい、出来上がったことが確認できますね！！
（サンプルで表示しているRedmineは既にサーバ落としているので、アクセスできません。ご容赦ください。)
![スクリーンショット 2022-06-10 11.58.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/8c58519e-aa42-34d6-fa00-a5ef9e26de40.png)

はーい、とっても簡単でした！！！！
iexで関数の挙動を調べて遊ぶ

# iexを起動する
`iex` と打ちます
![Screenshot from 2022-06-10 11-34-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/580b7a2a-6ef9-1075-dbfb-f4850ded27b5.png)

# 例えばEnumモジュールで遊ぶとする

まず`Enum.`まで打つ
![Screenshot from 2022-06-10 11-35-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/6e3528f5-935e-a5c4-2a2e-da2149925cac.png)

次に`tab` キーを打つ

![Screenshot from 2022-06-10 11-36-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/c76048c1-7cd1-b74b-088f-9a718e726230.png)

Enumモジュールで使える関数が補完されます
ここから、遊んでみたい関数を決めます


# 例えばmapで遊ぶ
map関数の仕組みを調べる為に`h` を使います
![Screenshot from 2022-06-10 11-41-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/6a6ac5d1-86a9-a36f-3ec4-719132e004aa.png)

# Examplesを打ち込む
![Screenshot from 2022-06-10 11-43-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/0e00aa5c-6d1c-82ae-f71d-e19c3f815d08.png)

期待の結果になります

# ここからがポイント、引数等をいじってみる
「↑カーソルキー」を押して、前回入力した文を呼び出します
![Screenshot from 2022-06-10 11-45-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/23d67092-8765-354b-612e-dd2c31745f20.png)

例えば `x * 2` を　`x * 4` にしてみましょう
その時結果を予想します。
`[2, 4, 6]`が　`[4, 8, 12]`になることが予想できます。
![Screenshot from 2022-06-10 11-49-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/232f4517-f0cf-f9d3-58f3-4399ab450f60.png)

`[4, 8, 12]`になりましたね

例えば`[2, 4, 6]`　を　`[1, 2]`に変更してみます
![Screenshot from 2022-06-10 11-52-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/0c488876-b6e0-feeb-fd0d-89ac15107a01.png)
`[4, 8]` になりました


引数を、変えて変化を予想できるようになれば理解できると思います
コツは、思いつく範囲で引数を変えてみることです