OmniAICreator/Qiita-1.07M huggingface dataset:
【Node.js】インターネット上にある画像のURLを指定してローカルに画像を保存する

インターネット上にある画像のURLを指定してローカルに画像を保存する方法です。


## 私の環境
- macOS　Ventura
- Node.js: v20.0.0
- 開発環境： VSCode


## 最初に

HTTPリクエストを行うためのライブラリ axios をインストールします。

```
$ npm init
$ npm install axios
```

コード

```index.js
const fs = require('fs');
const axios = require('axios');

async function downloadImage(url, filePath) {
    try {
        const response = await axios({
            url,
            method: 'GET',
            responseType: 'stream'
        });

        const writer = fs.createWriteStream(filePath);

        response.data.pipe(writer);

        return new Promise((resolve, reject) => {
            writer.on('finish', resolve);
            writer.on('error', reject);
        });
    } catch (error) {
        console.error('Error downloading the image:', error);
    }
}

const imageURL = 'ここに画像のURLを入力';
const localPath = '保存したいローカルパス/image.jpg';

downloadImage(imageURL, localPath)
    .then(() => console.log('Download completed'))
    .catch(error => console.error('Error in download:', error));

```


　以上です。
labelとinputタグについて

## labelタグとinputタグは紐付けが必要

### 紐付け方法1: labalのfor属性とinputのid属性を同じにする 
```html
<label for="cheese"> 
    Do you like peas? 
</label> 
<input type="checkbox" name="cheese" id="cheese" /> 
```
メリット: cssで横並びにしやすい
デメリット: labalのfor属性とinputのid属性を指定する必要がある
### 紐付け方法2: labelタグでinputタグを囲む 
```html
<label> 
  Do you like peas? 
  <input type="checkbox" name="peas" /> 
</label> 
```
メリット: labalのfor属性とinputのid属性を指定する必要がない
デメリット: cssの組み方が限られてしまう(flexboxでの横並びができないなど)

参考: https://developer.mozilla.org/ja/docs/Web/HTML/Element/label
Go：map型の変数にキーが存在するかどうかを判定

# はじめに
map型の変数にキーが存在するかどうかを判定するためのコードを作りました。
理解するのに役立つと思うので、「1. 判定処理、2. 実行結果」の部分を見てみてください。
それに続いて、「3. IF文を使った判定処理、4. 実行結果」のセクションでは、少し複雑なコードを紹介しています。

# 1. 判定処理
```go
package main

import (
	"fmt"
)

func main() {
	seen := make(map[int]string)

	// キー1に対して値を設定
	seen[1] = "存在する1"

	// キー2に対して値を設定
	seen[2] = "存在する2"

	// キー3は設定しない

	// キー1の確認
	value, exists := seen[1]
	fmt.Println("Key 1: Value =", value, "/ Exists =", exists)

	// キー2の確認
	value, exists = seen[2]
	fmt.Println("Key 2: Value =", value, "/ Exists =", exists)

	// キー3の確認
	value, exists = seen[3]
	fmt.Println("Key 3: Value =", value, "/ Exists =", exists)
}
```

# 2. 実行結果
Key 3は、存在しないため、Valueは、**string型のデフォルト値:空値**となります。
```go
Key 1: Value = 存在する1 / Exists = true
Key 2: Value = 存在する2 / Exists = true
Key 3: Value =  / Exists = false
```

# 3. IF分を使った判定処理
```go
package main

import (
	"fmt"
)

func main() {
	seen := make(map[int]bool)

	// 事前にいくつかのキーをマップに設定
	seen[1] = true
	seen[3] = true
	seen[5] = true

	// 異なる値を含むスライスを定義
	numbers := []int{1, 2, 3, 4, 5, 6}

	// range: スライスの要素数分ループ
	for _, v := range numbers {
		if _, boolean := seen[v]; boolean { // booleanは、trueかfalseを返す
			fmt.Println("数字", v, "はseenマップに存在します。")
		} else {
			fmt.Println("数字", v, "はseenマップに存在しません。")
		}
	}

}
```

# 4. 実行結果
numbersに存在する数値が、seenに存在するかどうかを判定した処理です。
```go
数字 1 はseenマップに存在します
数字 2 はseenマップに存在しません
数字 3 はseenマップに存在します
数字 4 はseenマップに存在しません
数字 5 はseenマップに存在します
数字 6 はseenマップに存在しません
```
GitHub.com の Markdown でアラート記法が増えた話

<!-- # GitHub.com の Markdown でアラート記法が増えた話 -->

GitHub.com で利用できる Markdown 記法のアラートは、これまで `[!Note]`・`[!Warning]` と [2023 年 7 月 23 日][update-alert] に追加された `[!Important]` がありました。

[update-alert]: https://qiita.com/Yarakashi_Kikohshi/items/cf3b72db6f3594a3cc0f "詳しくはこちら | GitHub.com の Markdown でアラート記法が変更された話 - Qiita"

このアラート記法は断続的に更新されており、2023 年 11 月 14 日にいくつかの重要な変更がなされました。
本記事では、これらの変更を紹介します。

:::note info
アラート記法は 2023 年 12 月 14 日に正式にリリースされました :tada:
:::

https://github.blog/changelog/2023-12-14-new-markdown-extension-alerts-provide-distinctive-styling-for-significant-content/

## 追加されたアラート

2023 年 11 月 14 日に、これまでのアラートに `[!Tip]` と `[!Caution]` が追加されました :tada:

```markdown
> [!NOTE]
> Highlights information that users should take into account, even when skimming.

> [!TIP]
> Optional information to help a user be more successful.

> [!IMPORTANT]
> Crucial information necessary for users to succeed.

> [!WARNING]
> Critical content demanding immediate user attention due to potential risks.

> [!CAUTION]
> Negative potential consequences of an action.
```

![Alert sample](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590705/ab6014db-2fad-1af5-fe5f-5570d6971cec.png)

## 他の構文とのネスト

これまでアラート記法内で他の構文を利用すると、一部の構文は利用できないバグが生じていました。
今回の更新では、これらのバグのいくつかが解消され、ブロッククォート等によるネストと同じように動作するようになりました。

ただし、Fenced code block のシンタックスハイライトは機能しない等のバグは残されています。バグが解消されることを期待しましょう。

一方で、アラート記法は他の構文にネストされません。すなわち、以下の構文内でアラート記法を利用することが出来ません。

- ブロッククォート
- リスト（箇条書き、番号付き、タスクリスト）
- 脚注

例えば、次のような書き方が出来ません。

```markdown
> ここはブロッククォートです。
>
> > [!NOTE]
> > ここはブロッククォート内のアラートです。
```

他の構文にネストされない仕様には [反対意見][comment-7574895] がなされており、更新に伴って仕様変更される可能性があります。

[comment-7574895]: https://github.com/orgs/community/discussions/16925#discussioncomment-7574895 "Discussion comment 7574895"

## 廃止された記法

アラート記法は β 版公開当初、アラートタグを `**Note**` のようにしていました。
今回の更新以降、この強い強調 (`**`) によるアラートタグは利用できなくなりました。もしも、この記法を使っている場合は気を付けてください。

この記法は 2023 年 6 月 21 日の更新で、近いうちに使えなくなることが予告されていました。

# 余談

今回の更新で追加されたアラート種 `[!Tip]` と `[!Caution]` によって、アラート記法の表現は Microsoft Learn の [Alerts][mslearn-alerts] と同等になりました。

[mslearn-alerts]: https://learn.microsoft.com/en-us/contribute/markdown-reference#alerts-note-tip-important-caution-warning "Markdown reference for Microsoft Learn - Contributor guide | Microsoft Learn"

アラート記法の更新に関する情報は、以下の Discussion のみで公開されています。

https://github.com/orgs/community/discussions/16925
Java仮想マシンのメモリー

## Runtime
JavaアプリケーションはすべてRuntimeクラスの単一のインスタンスを持ちます。このクラスは、アプリケーションとアプリケーション実行環境とのインタフェースになります。現在のRuntimeオブジェクトは、getRuntimeメソッドにより取得できます。
- public long totalMemory()
Java仮想マシンのメモリーの総容量を返します。ホストの環境によっては、このメソッドによって返される値が時間とともに変化する場合があります。
任意の指定された型のオブジェクトを格納するのに必要なメモリー容量は、実装によって異なります。
戻り値:
現在および将来のオブジェクトに利用可能な現在のメモリーの総容量(バイト単位)。
- public long maxMemory()
Java仮想マシンが使用を試みる最大メモリー容量を返します。固有の制限が存在しない場合、値Long.MAX_VALUEが返されます。
戻り値:
仮想マシンが使用を試みる最大メモリー容量(単位はバイト)
## 実装確認
サンプルコード
```java
public class HeapTest {

  public static void main(String[] args) {

    long initm = Runtime.getRuntime().totalMemory()/1024/1024;
    long maxm = Runtime.getRuntime().maxMemory()/1024/1024;
    
    System.out.println("Runtime start memory:"+initm+"M");
    System.out.println("Runtime max memory:"+maxm+"M");
    
    System.out.println("System memory:"+initm*64/1024+"G");
    System.out.println("System memory:"+maxm*4/1024+"G");
  }
}
```
```console
Runtime start memory:243M
Runtime max memory:3586M
System memory:15G
System memory:14G
```
システム物理メモリー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/0501abc9-ff13-62ca-3a23-ccd746f87fc6.png)
【裏技㊙️テクニック】TOEICの捨て問や裏ワザを網羅〜直前に読むだけでもOK！

以下のやり方で`TOEIC800`行きました。
直前に読むだけでもOK！

勉強方法のコツ
リスニングもスピーカーで聞く

解くスピードを早める方法
迷う回数を減らす
７割以上の確率で正解だと思えたら次
同会場の中で一番に終わらせる気持ちを常に持つ
Part7を終わらせるまで見直ししない
裏ワザ
マーク後、本文・選択肢は再確認しない（迷わず即決定、次に行く）
口パクでブツブツ読む（実際には声に出さないが）
文章を読む時は急がず落ち着く。単語の意味を誤解する可能性があるため
問題用紙を谷折りから山折りにする（１ページのみに集中できる）
マークは、50％程度塗りつぶせばOK
解答に迷ったときには「企業として正しい決断」を選ぶ
捨て問を選ぶなら
時間がなかったり、コスパの悪いなと感じる問題は、スキップしても良い。以下が例。

文選択の問題
not問題
imply（ほのめかす）/ infer（推察する）の入っている問題
article(記事)問題
ちなみに、

難しすぎる問題は採点対象外になる

中級者であれば20問から25問、上級者でも5問から10問は捨てても大丈夫。

熟読すべき問題と、適当に読むべき問題
全文を読まずに解ける問題（適当に読むべき問題）

品詞：ある単語の異なる品詞が並ぶ問題
前置詞：ある単語の異なる品詞が並ぶ問題
機能語：each, every, allなどが並ぶ問題
接続詞：both A and B, not only A but also Bなどの一部が並ぶ問題
全文を読まなければならない問題

語彙：同じ品詞が並ぶ問題
大きな接続詞：since, because, ifなど
代名詞：its, himselfやwhich, whoなどの関係代名詞
判断が必要な問題

動詞の形：動詞の活用形が並ぶ
比較：比較級や最上級が並ぶ
バリデーションチェックがなぜ必要か？

## バリデーションとは
日本語で「確認」や「検証」を意味し、データの妥当性を表します。

①入力チェック
必須の入力項目に抜け漏れがないかチェックする。テキスト以外にも、利用規約確認後のチェックボックスの選択漏れも含まれます。

②データの形式チェック
文字の種類・値の範囲・桁数などと幅広く、
・メールアドレスに@(アットマーク)が含まれていない
・パスワードの要件(例：アルファベットや記号など、複数の文字種を入力する)を満たしていない
という様に、不正データを除外する。

③データの妥当性
複数の入力データとの関連チェックを行う。例えば問診票に飲酒の項目があり、「飲む」を選択した場合は頻度と量を入力する様にする

![スクリーンショット 2023-11-16 20.26.41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568357/6c670c60-924b-56d3-c030-6c4eac3c70a8.jpeg)

上の登録フォームではサービスを利用するために、
・どの項目の入力が必要かを米印で表す
・どう設定したら良いかの説明文を載せる
・ユーザーに合ったサービスを提供するため、生年月日や身長も入力して貰う


## バリデーションがなぜ必要か？
**①妥当性のないデータだと、内部処理が正常に動作しない**
「妥当性のない = 確認する必要がない」となると不正データも許容してしまい、内部処理に異常動作が起きやすくなります。「どんなデータで処理するか？」が重要なポイントですね。

**②データ形式の統一が必要である**
例えば電話番号の場合、開始番号に2桁・3桁・4桁があるのはご存知でしたか？

2桁：国内の都道府県などを区別ために使う市外局番
3桁：携帯電話やPHSなどの番号
4桁：フリーダイヤルやナビダイヤルの番号

そして入力する時は、「-(ハイフン)」も入れるのが一般的。それを除外してしまったらどうなるのでしょうか？

例えば「0422559431」の場合、実は複数の開始番号が存在しているんです。

東京都立川市などが指定する「042」→「042-255-9431」
東京都武蔵野市が指定する「0422」→「0422-55-9431」

「-(ハイフン)」なしだと上記のどちらに該当するか分からず、どの地域から発信しているか特定できない。開始番号の桁数から、どの番号なのかを特定するために「-(ハイフン)」も入れるんじゃないかと、私はそう思っています。


## バリデーションが必要な理由をこう勘違いしている方が多い！！

**ユーザーの入力ミスを防ぐため**
入力データの確認より、入力ルールをユーザーに押しつけている様に思えます。必須項目や入力の説明文が多すぎると、ユーザーが登録せずに離脱してしまうので、

「サービスの利用向上としてこのデータが欲しいです」

の気持ちでバリデーションを実装すれば良いかと思います。


## 調べてみて分かったこと
バリデーションは、入力ルールをユーザーに押しつけるのではなく、不正データを入力してシステムの異常動作を防ぐためにあるんですね。小数点や記号などデータの種類が豊富だけど、「サービスを利用するにはどんなデータが必要か？」を意識して、バリデーションを実装しようと思いました。
Power Appsでボタンの動作制限

Power Appsではボタンを多用する。しかし動作してほしくない状況もある。

貸出管理アプリでは、使用できない状況で「借りる」ボタンは押せないのが正解。

この制御はDisplayModeで行う。

If (DataCardValue4.Selected.Value = "使用中", DisplayMode.Disabled, DisplayMode.Edit)

これで使用中はこのボタンが無効になる。この制御はOnSelectに対して行っているので、OnSelectに書かれている動作は無効になった。
Cloudera Data Warehouse (Impala) と Tableau の連携

# この記事について

Tableau から Cloudera Data Warehouse (Public Cloud, Impala) に接続する手順の紹介です。

※一部、Tableau 側のメニュー名などが正確でない部分があるかもしれません。
（英語のUIから日本語を推測して書いているため）
正しいメニュー名をご存知の方は、コメントでお知らせいただけると助かります。

# Cloudera 側の設定

## JDBC のURL取得

該当のDWHの右側の三点マークから、「Copy JDBC URL」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/bde924d8-a428-0dbf-5164-3dae093ec5e1.png)

JDBCのURLがクリップボードにコピーされます。
メモ帳などに貼り付けると、以下のようなURLが表示されるはずです。

`jdbc:impala://coordinator-<データベースカタログ名、環境名などの文字列>:443/default;AuthMech=12;transportMode=http;httpPath=cliservice;ssl=1;auth=browser
`

上記のうちの、`jdbc:impala://` の後から `:443` の手前までの部分を、このあとの設定で使います。

上記の例であれば、使うのは以下の部分です。

`coordinator-<データベースカタログ名、環境名などの文字列>:443`

# Tableau 側の設定

Tableau 側の設定は、バージョンによって手順が異なるようです。

## バージョン2021.2.1 以降の場合

### データソースを開く

データ > 新しいデータソース > To a Server More > Impala

### 接続の設定

以下の箇所を、下表の要領で設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/d7f61914-c487-b830-7fde-f9770163da74.png)

| # |項目|設定内容|
|:-:|:-|:-|
| ① |サーバー|「JDBCのURL取得」の手順で取得した文字列（`coordinator-<データベースカタログ名、環境名などの文字列>:443`）を設定|
| ②|ポート|`443` を設定|
| ③|認証方式|「ユーザー名とパスワード」を選択 |
| ④|ユーザー名|該当のDWHへのアクセス権を持ったCloudera のユーザー名を入力|
| ⑤|パスワード|④に対応するパスワード（Workload Password）を設定|
| ⑥|プロトコル|「HTTP」を選択 |
| ⑦|HTTP Path|`cliservice` を設定 |
| ⑧|SSL|チェックをONにする|


## バージョン2021.2.1 より古いバージョンの場合

### データソースを開く

データ > 新しいデータソース > To a Server More > Cloudera Hadoop

### 接続の設定

| # |項目|設定内容|
|:-:|:-|:-|
| ① |サーバー|「JDBCのURL取得」の手順で取得した文字列（`coordinator-<データベースカタログ名、環境名などの文字列>:443`）を設定|
| ②|ポート|`443` を設定|
| ③|タイプ|「HiveServer2」を選択|
| ④|認証方式|「ユーザー名とパスワード」を選択 |
| ⑤|プロトコル|「HTTP」を選択 |
| ⑥|ユーザー名|該当のDWHへのアクセス権を持ったCloudera のユーザー名を入力|
| ⑦|パスワード|⑥に対応するパスワード（Workload Password）を設定|
| ⑧|HTTP Path|`cliservice` を設定 |
| ⑨|SSL|チェックをONにする|


# 最後に

この記事の内容は以上です。

お役に立った場合は、「いいね」やストックをしていただけると励みになります。
誤りを見つけた場合は、コメントでお知らせください。
nvidia-smiでFailed to initialize NVML: Driver/library version mismatchエラーの解決ログ

## はじめに
`nvidia-smi`コマンドで、
```terminal
$ nvidia-smi
Failed to initialize NVML: Driver/library version mismatch
NVML library version: XXX
```
というエラーが出たときの解決ログです。

まず、再起動などの一般的な対処法を試してみてください。参考記事として、

https://qiita.com/ell/items/be3d3527b723f70f888d

が挙げられます。もし再起動だけでは解決しない場合、以下に筆者が遭遇し解決した具体的な状況と対処法を紹介します。

なお、筆者の環境は`Ubuntu 22.04`です。

## 考えられる原因
この`nvidia-smi`のエラーの原因の一つとして、NVML（NVIDIA Management Library）と NVRM（NVIDIA Resource Manager）のバージョンの不一致が挙げられます。これらのバージョンは、それぞれ以下のコマンドで確認できます。

```bash:NVMLのバージョンの確認コマンド
$ cat /sys/module/nvidia/version
```

```bash:NVRMのバージョンの確認コマンド
$ cat /proc/driver/nvidia/version
```
これらのバージョンが異なる場合に、mismatchエラーが発生する可能性があります。

ここで、NVMLとNVRMのそれぞれの役割について簡単に説明します。

- NVML（NVIDIA Management Library）:
NVIDIA GPUの管理に使用されるライブラリで、GPUの情報の取得や操作を行います。`/sys/module/nvidia/version`で確認できます。

- NVRM（NVIDIA Resource Manager）:
NVIDIA GPUのリソースを管理するカーネルモジュールで、GPUのドライバーとして機能します。`/proc/driver/nvidia/version`で確認できます。

## バージョンが異なる場合に解決方法

以下は、NVML と NVRM のバージョンが異なる場合の解決手順です。筆者の環境での実際のログを交えて説明します。

まず、NVMLとNVRMのバージョンの確認をします。

```bash:エラー時のNVMLとNVRMのバージョンログ
$ nvidia-smi
Failed to initialize NVML: Driver/library version mismatch
NVML library version: 535.129
$ cat /sys/module/nvidia/version
535.129.03
$ cat /proc/driver/nvidia/version
NVRM version: NVIDIA UNIX x86_64 Kernel Module  520.61.05  Thu Sep 29 05:30:25 UTC 2022
GCC version:  gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
```

上記の結果から、NVMLのバージョンが535.129.03で、NVRMのバージョンが520.61.05と異なっていることが分かります。

次に、以下のコマンドでnvidiaとcudaをアンインストールし、再びインストールします。

```bash:エラー解決に使ったコマンド
$ sudo apt purge nvidia-* 
$ sudo apt purge cuda-*
$ sudo apt install nvidia-driver-535 nvidia-dkms-535
$ sudo sh cuda_11.8.0_520.61.05_linux.run
```

そして、これらのコマンドを実行後に再起動すると、NVRMとNVMLのバージョンが一致し、`nvidia-smi`が正常に動作するようになりました。
（※上記は参考までに、nvidia driverやcudaは環境に合わせたものに適宜書き換えてください。[Ubuntu: NVIDIAのドライバはどれをインスールすればよいのだ？](https://qiita.com/abetomo/items/a114a3c423f110460549)によると、`ubuntu-drivers`を実行し、`recommended`が付いたものが良いとされています。）

```bash:エラー解決後のNVMLとNVRMのバージョンログ
$ cat /sys/module/nvidia/version
535.129.03
$ cat /proc/driver/nvidia/version
NVRM version: NVIDIA UNIX x86_64 Kernel Module  535.129.03  Thu Oct 19 18:56:32 UTC 2023
GCC version:  gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
```

## まとめ
この記事では、`nvidia-smi`で発生するエラーの解決として、NVMLとNVRMのバージョンが異なる場合の解決法について紹介しました。あくまで筆者の環境での話ですが、対処法としてアンインストールと再インストールを行うことで直ることを確認しました。

## 参考資料
- [Stack OVerflow: Nvidia NVML Driver/library version mismatch: dkms, modules, drivers and modinfo versions](https://stackoverflow.com/questions/74151409/nvidia-nvml-driver-library-version-mismatch-dkms-modules-drivers-and-modinfo)
- [Stack OVerflow: Nvidia NVML Driver/library version mismatch [closed]](https://stackoverflow.com/questions/43022843/nvidia-nvml-driver-library-version-mismatch/67105064#67105064)
- [Stack OVerflow: How to fix "NVRM: API mismatch" between client version and kernel module version when installing Nvidia drivers for a GTX 560 Ti in Ubuntu 20.04?](https://stackoverflow.com/questions/70276412/how-to-fix-nvrm-api-mismatch-between-client-version-and-kernel-module-version/71672261#71672261)
【Rails】 SassC::SyntaxError について

# 概要
この記事では、**EC2**に**Railsアプリケーション**をデプロイするときに直面した **CSS** 関連のエラーについて追及しています。

# 環境
- Ruby: **3.1.2**
- Rails: **6.1.4**
- CSSFW: **TailwindCSS**

# エラー文
下記がデプロイ時に起きたエラーです。
```sh:Terminal
SassC::SyntaxError: Error: Function rgb is missing argument $green.
        on line 607 of stdin
>>   color: rgb(239 68 68 / var(--tw-text-opacity));
```

# 解決方法
production.rbのファイルの末尾に下記の記述を追加します。

```diff_ruby:config/environments/production.rb
+ config.assets.css_compressor = nil
```

# 原因
**SassC::SyntaxError** が起きてしまう原因としては、TailwindCSSが使用するCSS構文と、Rails6においてデフォルトで含まれる **sassc-rails** 拡張の間の非互換性に起因しているようです。この問題は、sassc-railsがTailwindCSSによって使用されるような現代的なCSS機能を認識しないために発生しているので、scssを使っていない場合は`config.assets.css_compressor = nil`をconfigに記述して解決するのが一番スタンダードみたいです。

:::note info
**Point**
**scss**と**Sass**の関連について記述しておきます。
scssファイルはSassプリプロセッサによって通常のCSSファイルに変換されます。このプロセスでは、scssファイル内のSass特有の構文や機能（変数、ネスト、ミックスインなど）が標準のCSSコードに変換されます。
:::

# さいごに
この問題は、Herokuを含む他のプラットフォームでRailsアプリケーションをデプロイする際にも遭遇する可能性があります。そのため、Railsで、TailwindCSSを使用する場合は、このような問題に遭遇する可能性があることを念頭に置くことが重要だと思っています。さらに、TailwindCSSのバージョンやRailsのアセットパイプラインの設定によってもエラーの原因や対処法が異なる可能性があるため、状況に応じた対応が必要になります。個人的にはissueを見るのが一番良いと思っています。


# 参考文献

https://github.com/tailwindlabs/tailwindcss/discussions/6738
(レジ直)ソフトウェアSPIで遊ぶ(STM32G031)



![o_cop793.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/c0afc192-e26a-2634-1767-c59ff6244350.jpeg)



```c++


//Soft_SPI_test1_031

#define DW    digitalWrite

#define TFT_MOSI PA12
#define TFT_SCK  PA1
#define SPI_MOSI_HIGH() DW(PA12,HIGH)
#define SPI_MOSI_LOW()  DW(PA12,LOW)
#define SPI_SCK_HIGH()  DW(PA1,HIGH)
#define SPI_SCK_LOW()   DW(PA1,LOW)

                        //      5432109876543210
int clk0_on1  = (GPIOA->ODR | 0b0001000000000000)
                            & 0b1111111111111101;
                        //      5432109876543210
int clk1_on1  =  GPIOA->ODR | 0b0001000000000010;

                        //      5432109876543210
int clk0_off1 =  GPIOA->ODR & 0b1110111111111101;

                        //      5432109876543210
int clk1_off1 = (GPIOA->ODR | 0b0000000000000010)
                            & 0b1110111111111111;


void SPI_WRITE8(int s)
{
  for (int bit = 0, x = s; bit < 8; bit++) {
    if (x & 0x80) {
      //SPI_MOSI_HIGH();delay(1);/*|*/SPI_SCK_LOW();delay(1000);
      GPIOA->ODR = clk0_on1;//delay(1000);
      //SPI_MOSI_HIGH();delay(1);/*|*/SPI_SCK_HIGH();delay(1000);
      GPIOA->ODR = clk1_on1;//delay(1000);
    } else {
      //SPI_MOSI_LOW();delay(1);/*|*/SPI_SCK_LOW();delay(1000);
      GPIOA->ODR = clk0_off1;//delay(1000);
      //SPI_MOSI_LOW();delay(1);/*|*/SPI_SCK_HIGH();delay(1000);
      GPIOA->ODR = clk1_off1;//delay(1000);
    }//end if
    x <<= 1;
  }//for
  //SPI_SCK_LOW();delay(1000);
  GPIOA->ODR = clk0_off1;//delay(1000);
}//SPI_WRITE8

void SPI_WRITE16(int s)
{
  for (int bit = 0, x = s; bit < 16; bit++) {
    if (x & 0x8000) {
      //SPI_MOSI_HIGH();delay(1);/*|*/SPI_SCK_LOW();delay(1000);
      GPIOA->ODR = clk0_on1;//delay(1000);
      //SPI_MOSI_HIGH();delay(1);/*|*/SPI_SCK_HIGH();delay(1000);
      GPIOA->ODR = clk1_on1;//delay(1000);
    } else {
      //SPI_MOSI_LOW();delay(1);/*|*/SPI_SCK_LOW();delay(1000);
      GPIOA->ODR = clk0_off1;//delay(1000);
      //SPI_MOSI_LOW();delay(1);/*|*/SPI_SCK_HIGH();delay(1000);
      GPIOA->ODR = clk1_off1;//delay(1000);
    }//end if
    x <<= 1;
  }//for
  //SPI_SCK_LOW();delay(1000);
  GPIOA->ODR = clk0_off1;//delay(1000);
}//SPI_WRITE16

void setup() {

  pinMode(TFT_MOSI, OUTPUT);
  pinMode(TFT_SCK , OUTPUT);

  //DW(PA12, HIGH); // B7
  //DW(PA1, HIGH); // B7




  //SPI_WRITE16(0x5555);
  //SPI_WRITE16(0xffff);
}

void loop() {

/*
  SPI_WRITE8(0x00);
  SPI_WRITE8(0x00);
  delay(2000);
  SPI_WRITE8(0x00);
  SPI_WRITE8(0x55);
  delay(2000);
  SPI_WRITE8(0x00);
  SPI_WRITE8(0xaa);
  delay(2000);
  SPI_WRITE8(0x00);
  SPI_WRITE8(0xff);
  delay(2000);
*/

  SPI_WRITE16(0x00);
  delay(2000);
  SPI_WRITE16(0x55);
  delay(2000);
  SPI_WRITE16(0xaa);
  delay(2000);
  SPI_WRITE16(0xff);
  delay(2000);


}



```
【Laravel】クエリビルダがJOIN済か確認する方法

Laravel=5.6

#### 概要
クエリビルダが、特定のテーブルとのJOINを含んでいるかを確認する方法。getQueryメソッドでクエリビルダについての情報を取得し、その中のjoinsプロパティを参照する。
#### コード例
```XXX.php
private function isJoin (
    Builder $query,
    string $tableName
): bool {
    return count(array_filter($query->getQuery()->joins, function ($join) use ($tableName) {
        // $join->tableの値は"テーブル名 as エイリアス"となっているため、explodeでテーブル名だけを抜き出す
        return explode(' ', $join->table)[0] === $tableName;
    }));
}
```
若手エンジニア奮闘記⑥【情シスって何するの？】社会人２年目社員が紹介する情シスのあれこれ


みなさん、こんにちは。

社会人2年目デザイン学部出身の川村です。
約1ヵ月間の研修を経て、製薬会社の情報システム部門に配属されました。
現在は、社員さんが業務で使うIT機器の運用サポートをメインに行っています。

今回は、IT未経験からIT業界へと入社した社会人２年目の私が、自身の業務内容・経験と絡めて情シス(情報システム部門)についてざっくり紹介していきます！
それでは最後までご一読ください^^

# 目次

[はじめに-情シス(情報システム部門)って何する人達？-](#はじめに-情シス情報システム部門って何する人達-)
[情シスは便利屋さん？-私の業務内容-](#情シスは便利屋さん-私の業務内容-)
[やりがい・大変なこと](#やりがい大変なこと)
[まとめ-情シスはかっこいい-](#まとめ-情シスはかっこいい-)

# はじめに-情シス(情報システム部門)って何する人達？-

簡単に表しますと、「社内のIT機器、ITシステムを整えて社員さんの業務を支える人達」です！
IT機器とはパソコン、スマートフォン、ルーター、複合機、モニター など、業務を行う上で欠かせない機器のことです。
ITシステムとは、業務を行う上で基盤となるネットワークやインフラ、メールシステム。業務の効率化を目的とした、ワークフロー、RPAなどの自動化ツールなどを指します。
情シスは上記の機器やシステムの構築から運用・保守までを幅広く担当し、社内のIT環境を支えております。

# 情シスは便利屋さん？-私の業務内容-

冒頭にも記載しておりますが、私は社員さん達が使うIT機器(社用携帯やパソコン、モバイルWi-Fiルーター、複合機)に関する管理や問い合わせ対応等の運用サポートを行っています。
具体的には以下のような作業をしています。
　・IT機器に関する使い方、トラブルに関する問い合わせ対応
　・社用携帯やモバイルWi-Fiルーターのキッティング作業
　・社用携帯のMDM管理(パスコード解除や紛失時のリモートロック)
　・社内アドレス帳の一括管理・自動配信設定
　・故障機の修理窓口対応
　・Zoomのアカウント/ライセンス管理
　・利用者向けIT機器関連の手順書作成/修正

このように、IT機器関連の「困ったこと」に対してお手伝いをする、言わば”便利屋さん”のようなことをしています。

# やりがい・大変なこと

1番のやりがいは、やはり感謝の言葉をダイレクトにいただくことでしょうか。社会人１年目の頃、拙い問い合わせ対応だったにも関わらず、フィードバックアンケートで「丁寧で熱心に対応いただけて大変満足でした」という言葉が添えられていたことを知った時はジーンとしました。

一方で大変なことといえば、トラブルが発生し緊急で対応しなければならない時に、上手くサポートできなかったと時は胃がきゅーっと痛くなることですかね(^^;
急いでいるときは物言いが強くなることはしょうがないことなので、そのような場合もスムーズはご案内ができるように、自身のレベルアップを日々心掛けております。
理不尽なことを言われる度に落ち込むことはもちろんあるのですが、以前上長から「理不尽なことを言ってくる人は絶対に気にする必要ない、むしろ困っているから助けてあげよう、って上から構える姿勢で対応すれば大丈夫」というお言葉をいただき、気持ちが楽になったことを覚えています…。

# まとめ-情シスはかっこいい-

今回は、「情シスって何するの？」という題材で、簡単ではありますが業務内容や体験をお話しさせていただきました。もちろん大変なこともありますが、「ITで困ったら情シスに頼ろう！」と沢山の人から頼られて、悩みや課題を解決する情シスってすごくかっこよくて魅力的ではありませんか？この記事を読んだ学生の皆さんや就活中の皆さんのキャリアプランに少しでも参考になれば幸いです。

では、次回のブログでまたお会いしましょう！
javaのstackoverflowerrorとスタックサイズ

## javaのstackoverflowerror
アプリケーションでの再帰の回数が多すぎてスタックオーバーフローが起こる場合に、StackOverflowErrorがスローされます。
サンプルコード
```java
public class StackOverFlowTest {
  private static int count = 1;
  public static void main(String[] args) {

    System.out.println(count);
    count++;
    main(args);

  }
}
```
スタック・サイズを200kに指定して実施します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/4aeb26e7-a673-99a4-de53-3f6d72e50b60.png)

```console
2452
2453
2454
2455
Exception in thread "main" java.lang.StackOverflowError
	at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
	at sun.nio.cs.UTF_8.access$200(UTF_8.java:57)
	at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:636)
	at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
	at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
	at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
	at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
	at java.io.PrintStream.write(PrintStream.java:526)
	at java.io.PrintStream.print(PrintStream.java:597)
	at java.io.PrintStream.println(PrintStream.java:736)
```
スタック・サイズを400kに指定して実施します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3184769/45f500e5-36a8-a12a-1cb2-a4819b08dbca.png)
```console
4696
4697
4698
Exception in thread "main" java.lang.StackOverflowError
	at java.io.PrintStream.write(PrintStream.java:480)
	at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
	at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
	at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
	at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
	at java.io.PrintStream.write(PrintStream.java:527)
	at java.io.PrintStream.print(PrintStream.java:597)
	at java.io.PrintStream.println(PrintStream.java:736)
```
スタック・サイズが大きくなると、再帰の回数が多くなります。
【postgre-SQL】〇時間〇〇分と表示させる方法

## 整数から〇時間〇〇分を作り出すQuery
※下記で使用するデータは全てテストデータです。
解答から記載すると下記Queryになります↓
```sql
trunc((数字A/60)) || '時間' || trunc(mod(数字A,60)) || '分'
```
SQLのベテランからしたらイージーな内容かと思いますが、
webで検索しても出てこなかったため初心者の方にはぜひ活用していただきたいと思います。

私が詰まった部分は時間に関するQuery作成時に、分単位までの数字を導けたものの、
そこから何時間何分と表記する方法が思いつかず、web上で検索しまくりました。
しかし解決策は見つからず。。。。
とそんな時思いついたのが上記Queryになります！！

それでは上記Queryについて解説していきたいと思います。
↓↓↓↓↓↓↓↓

#### 解説
(例)"数字A"の部分に138を代入すると
```sql
trunc((138/60)) || '時間' || trunc(mod(138,60)) || '分' 
上記結果は2時間18分と出力されます。
```

分解して説明すると
```sql
trunc((138/60)) || '時間'
138÷60= 2　余り18で、truncにより商の部分の2のみを抽出します。
抽出された2に'時間'をプラスします。
```

```sql
trunc(mod(138,60)) || '分' 
138÷60= 2　余り18で、modにより余りの部分の18のみを抽出します。
抽出された18に'分'をプラスします。
```

上記2つのQueryで作成した文字列を結合して完了となります！
※文字列となるため"数字A"に代入する前に分にして計算を終えておくことを推奨します。


## 最後に
上記を行うことにより分で表された数字を〇時間〇分と表すことができます。
時間の表し方は様々ですが上記の表示の仕方を求めるお客様もおられると思いますので
ぜひご活用ください。



-------------------------------------------------
株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
UTF-16 で絵文字を表す正規表現（Windows の PowerRename で絵文字をファイル名から削除する）

# 絵文字の正規表現

絵文字はおおよそ以下の範囲になるそうです。

```
[\u{2600}-\u{27BF}\u{1F000}-\u{1FFFF}]
```

https://www.mimikaki.net/mi/2018/04/14/q-%E7%B5%B5%E6%96%87%E5%AD%97%E3%82%92%E5%89%8A%E9%99%A4%E3%81%97%E3%81%9F%E3%81%84/


(※あくまでも「おおよそ」なので実際には `☆` が含まれていたり `⏩` が含まれていなかったりしますが、この記事の主題ではないため割愛します。)

これを UTF-16 に変換します。

# UTF-16 の絵文字の正規表現

https://ja.wikipedia.org/wiki/UTF-16

`\u{1F000}-\u{1FFFF}` は下位12ビットが 0 または 1 なので、UTF-16の文字 2文字（サロゲートペアと呼びます）で以下のように表せます。（`?` は 0 または 1 ）

```
1文字目 : 0b_11011000_001111??
2文字目 : 0b_110111??_????????
```

この1文字目と2文字目は独立に（互いに依存しないような形で）正規表現で表せて、それぞれ `[\uD83C-\uD83F]` と `[\uDC00-\uDFFF]` となります。従って、絵文字を表す UTF-16 の正規表現は以下のようになります。

```
([\u2600-\u27BF]|[\uD83C-\uD83F][\uDC00-\uDFFF])
```

# PowerRename で正規表現を使用してファイル名から絵文字を削除する

Dropbox で絵文字を含むファイルが管理できていなかったので、それを削除したいと思います。

https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expression-language-quick-reference

多分 Windows のファイルシステムがそうだからだと思うのですが、PowerRename では UTF-16 での文字コードでファイル名のりネームができるようだったのでやってみます。

PowerRename を使用し、以下の設定で置換を行いました。

置換対象文字列 : `([\u2600-\u27BF]|[\uD83C-\uD83F][\uDC00-\uDFFF])`
正規表現を使用 : ON
すべての出現箇所を一致させる : ON
置換の候補 : `""` (何も入力しない)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78152/b4b2997b-ed99-fe99-019e-b2472d2d26f9.png)

# 参考：合字 と ZWJ (zero width joiner)

ただし、肌の色が指定された絵文字 (ex: `👍🏽`) など、上記の範囲で表せない絵文字もあり、ゴミが残ってしまうこともあります。

https://qiita.com/comware_harase/items/59c60ab1c6e1797f0821

ただ、「絵文字」は削除できたので、一旦目的は達成したことにして、このあたりは気が向いたら調べたいと思います。

# おまけ

Windows10 + Chromium (Twemoji 無し) 環境での絵文字一覧

- 0x2000 - 0x2FFF

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78152/6902b614-7048-f243-7f4f-73fb9a29a8ab.png)

- 0x1F000 - 0x1FFFF

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78152/7c50eb95-1821-6bbc-65e8-fff6cb900c9b.png)

# 余談

ここまで書いて気付いたのですが、今回のように Dropbox を使用したいというケースであれば単に「サロゲートペアで表される文字」を削除すれば良かっただけだったっぽいので、`[\u2600-\u27BF]` を削除する必要性や絵文字の範囲について思いを巡らせる必要性はなかったかもしれません。

その場合、もし、U+10000 から U+10FFFF までを削除したいのであれば、（UTF-16 において）削除対象の文字は以下のようになります。

```
[\uD800-\uDBFF][\uDC00-\uDFFF]
```
【TOEIC 攻略】リスニング問題を時短テクニックで制覇！〜コスパ最強の方法で効率よく解く！

以下のやり方で`TOEIC800`行きました。
直前に読むだけでもOK！

# 問題別テクニック
❌ ... 何も考えずに不正解だと考えて良い（正解の可能性が低い）
👀 ... ここに気をつけて解こう！
🟢 ... 正解の可能性が高い

## Part 1

- ❌　写真にない名詞、動詞はバツ
- ❌　過去形と未来系はバツ
- 👀　進行形は、今やっている行為か？
- 👀　写真に人がいるかどうか
- 👀　現在完了形→現在形

## Part 2

- ❌　設問中に読まれた単語はバツ
- ❌　簡単に類推できる選択肢を疑う
- 🟢　聞き取れない場合、ネガティブな返答
- 🟢　一つ目の選択肢で塗り始めたら答えは１
- 🟢　二つ目の選択肢で塗り始めたら答えは２、３
- 🟢　orが途中で聞こえた設問では、曖昧な表現
- 👀　最初の2~3単語は絶対に聞き取る
- 👀　わからない問題はスキップ
- 👀　否定疑問文→通常の疑問
- 👀　安易にYes/Noに飛びつかない
- 👀　WhyとBecauseはセットじゃない
- 👀　頭の中で問いかけの文を何度も繰り返す

## Part 3
(13問)

- 🟢　聞き取れない場合、本文中に出てきた語彙と同じ解答
- 🟢　正解は言い換えが多い
- 👀　最初の5秒間。どこで、何のための会話なのか
- 👀　先読みで覚えた選択肢を拾い聴き
- 👀　時間短縮のために赤枠の部分だけ読む
![6E9CF3C5-05A4-4DDE-9EB5-5321EC3DB89F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900756/a83944ce-1cda-23ba-d844-b0d729b84e9c.jpeg)

- 👀　時間短縮のために赤線の部分だけ読む
![part4_passage2_ver2.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900756/29a06cdb-c224-1be5-e8eb-2d823a32b0fb.jpeg)

- 👀　設問を大まかに分けて、聴く
![part4_passage_ver2.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900756/b931eea8-7da4-c661-a42e-aa5f186b68ee.jpeg)


## Part 4
(10問)

- 🟢　本文中に登場した単語を含む選択肢
- 👀　テーマは大体こんな感じ
    - advertisement
    - announcement
    - broadcast
    - excerpt from a meeting
    - introduction (セミナー等の導入)
    - news report
    - radio broadcast
    - recorded message
    - talk
    - telephone message
    
## 解く順番について

以下のどちらかで解くと良い

:::note info
解き方1: 2つ目の設問をナレーターが読み終えた時には、次の3問の先読みを始める。
:::

:::note warn
解き方2: 3つ目の設問をナレーターが読み始めた時には、次の3問の先読みを始める。
:::

詳しくは以下...

>【トークが始まる前】
> - 設問3つとその選択肢を先読みします。（時間内に3問分の先読みが難しければ、2問分の先読み）

> 【トークが開始】
> - ナレーターが話していることを聴きながら選択肢を読み、正解を選ぶ。
> - 正解を選べば、ナレーターが話していることを聞きながら、その都度解答用紙にマークする。
> - 設問は3つあるので、3つマークし終われば、次の先読みに進む。

> 【トークが始まる前】
> - 設問3つを何度も読んで、問われるポイントを覚える。
> - 選択肢は余裕があれば最初の2つほど読むと、設問に対する解答がイメージしやすくなる。つまり、AとB。さらに余裕があれば、CとDも。時間は限られるので、問われるポイントをしっかりと覚えることを優先。

> 【トークが開始】
> - ナレーターが話していることを聴きながら、設問に対する答えを記憶。この時、選択肢は読まないで、聴くことに集中する。
> - ナレーターが話し終えたら、選択肢から正解を選び、マークする。
> - 設問は3つあるので、3つマークし終われば、次の先読みに進む。

## `先読み`に使える時間配分

`先読み`に使える時間はナレーターが

- 2つめの設問を読み終えた時は`約24秒`
- ３つめの設問を読み始めた時は`約16秒`

- 1つめの設問 (3~7秒、`約4秒`の時が多い)
- 無音 (`約8秒`)
- 2つめの設問 (3~7秒、`約4秒`の時が多い)
- 無音 (`約8秒`)
- 3つめの設問 (3~7秒、`約4秒`の時が多い)
- 無音 (`約8秒`)
- [Go on to the next page (`約6秒`)]

:::note warn
例外①: Q41-Q43、Q62-Q64、Q80-Q82、のあとは以下の文が追加される
- Question ○○ through ○○ refer to the following (`約4秒`)
:::

:::note warn
例外②: 図表問題は通常約8秒の無音部分が`約12秒`
:::

:::note warn
例外③: 最初の図表問題は、その前に出題されるのが通常の出題パターンなので、4秒の余裕さえなく先読みの難易度が一層上がる。つまり、図表問題はPart1とPart2のDirectionsが流れている間に目を通しておく
:::
協働ロボット(Universal Robots)の通信仕様について

デンマークの協働ロボットURを導入するときに、周辺のPCやPLCとの外部機器とどういう連携ができるか？ということについて簡単に記事にまとめます。

URが実装している通信仕様は以下の通りです。
（他にもありますが、ここでは主に扱われる部分のみまとめます。）

# 実装されている通信仕様
|通信仕様|Dashboard Server|Primary Interface<br>Secondary Interface<br>Realtime Interface|Real-Time Data Exchange|EtherNet/IP|Modbus TCP|
|:---|:---|:---|:---|:---|:---|
|ポート番号|29999|30001<br>30002<br>30003|30004|44818|502|
|主な用途|動作制御<br>保護停止解除<br>再起動|各種データの取得<br>・位置<br>・ジョイント角度<br>・スクリプトによる外部実行|各種データの取得<br>・位置<br>・ジョイント角度<br><br>パラメータ変更<br>・スピードスライダの値<br>・I/OのOn/Off切り替え|PLC連携|Modbus機器連携|


どの通信仕様を使用するかは、協働ロボットを導入する目的や運用上の仕様によって変わりますが、私自身の所見としては下記のようになるかと思います。

### PLCと連携させたい。

こういうときは迷わず、EtherNet/IP一択でしょう。
しかし、これだけではロボットの動作制御(プログラムのスタート・ストップ、再起動など)は扱えないので、ダッシュボードにソケット通信で接続する必要も出てきます。
PLCメーカー各社もソケット通信の利便性向上に向けたライブラリや実装例を用意しているかもしれないので、問い合わせるものありかと思います。

### パソコンやラズパイなどと連携させたい。

Primary InterfaceやReal-Time Data Exchange(RTDE)でデータ取得可能です。
ただ、位置情報やジョイントの温度、I/Oの状態を確認するだけなら、Primary Interfaceのほうが扱いが簡単なのでおすすめです。
より高度なデータ取得やデータ設定が必要になるときはRTDEですが、これはURCapsでロボット内部のデータを制御するときに使われることが多いようです。
（実際に私も使っております。）
「Hello World」を出力するコードが分からない4年目エンジニア


エンジニア4年目にしてJavaをまともに勉強したことのない筆者です。
自社開発でJavaを使うことになったので勉強していますが、さっそく壁にぶつかったのでまとめてみました！

# 1.「Hello World」出力じゃ！！

PHPでHello World出力しよーっと
うん！見てわかるぞ！以前PHPを使った仕事してたからね！
↓

```php:php
<!DOCTYPE html>
<html>
<body>

<?php
echo "Hello World";
?>

</body>
</html>
```

次はJavaだ！

```java:java
    public class Main {
      public static void main(String[] args) {
        System.out.println("Hello World");
      }
    }
```

いやいやいや長いて。
書いてあることからよくわからんし。
System~~~~の部分で出力するのは分かるけども。

初めてみるJavaのコードは呪文だったのでひとつひとつ解いてみるのが最初の勉強でした。

### 1.1. public class Main

まずこれについて解剖します。

```java:java
    public class Main{}
```

まあ流石に分かります。
Mainクラスを作成していて、アクセス修飾子のpublicを付けています。
publicを付けることですべてのクラスからアクセスできます。

**どっからでもインスタンス化してやるぜ！**

ここはオブジェクト指向の部分なので大丈夫です。
問題は次からですね。

### 1.2. static

static????
なんか見覚えがあります。

勉強してみるとやっぱり見覚えがありま。っていうかPHPにもありました。
（全然使ってないので覚えてなかった。。。）

staticを付けることでクラスをインスタンス化せずに関数、変数などを使用することができます。
↓例
```java:java
public class Main {
  static void myStaticMethod() {
    System.out.println("Staticだよ");
  }

  public static void main(String[] args) {
    myStaticMethod(); // 関数呼び出し
  }
}
```


Mainクラスをインスタンス化する前にmyStaticMethod()を呼び出し実行できます。

ぱっとみ呪文ですが一つ一つに分けてみてみると苦手意識が薄まりますね。


### 1.3. void

これが一番見たことない！
また調べてしてみよう。

返り値が無い関数に付けるらしいぞ。
ほんまかいな。void削除して実行してみよう。

:::note alert
Main.java:2: error: invalid method declaration; return type required
      public static main(String[] args) {
                    ^
1 error
:::

めちゃめちゃ怒られました。

voidなんて使ったことないので新鮮です。しっかり覚えとこ。

### 1.3. String[] args

main関数の引数よな。

```java:java
//文字列の配列
String[]
//引数の名前
args
```

Javaを動かすにあたって最初に実行する関数に引数があるのは何か引っかかります。
ついでに調べてみましょう。

↓の記事を参考にしました。大変勉強になりました。投稿者さんありがとうございます。

https://qiita.com/kahatato/items/1b4921bb58731f0b7fea

>String[] argsは、プログラム起動時に指定する値（コマンドライン引数）です。

なるほど！というか冷静に考えるとそりゃそうかですね。
もし任意の二つの数字を足し算するプログラムがあった場合その数字を受け取るためですね。

```java:java
public class Main {
    public static void main(String[] args) {
        // コマンドライン引数から数字を取得
        // ここで必要！！！！
        double num1 = Double.parseDouble(args[0]);
        double num2 = Double.parseDouble(args[1]);

        // 足し算の結果を計算
        double sum = num1 + num2;

        // 結果を出力
        System.out.println("Sum of " + num1 + " and " + num2 + " is: " + sum);
    }
}
```

# 4. 終わりに

そういえば学生時代このコードを見て嫌になった思い出があります。
当時と違ってほかの言語を身に付けており、耐性があったので理解することができました。

最初から難しそうな雰囲気プンプンですがJavaの勉強に勤しんでいきます！

# 5. 予告
12月1日に投稿予定です！
これからもJavaについてガンガン投稿する予定です！

:::note info
これからは小出しにしていくぞ！
（アンドリュー・ワイルズか！！）
:::
Bashでコマンドの出力をHTMLとしてGoogle Chromeで開くやつ（macOS）

## Data URLを使うパターン

```sh
open -a "Google Chrome" "data:text/html;base64,$(base64 -i <(echo '<h1>OK</h1>'))"
```

例えばphpmd実行結果をブラウザで見たい等の時に`echo '<h1>OK</h1>'`の箇所を`./vendor/bin/phpmd . html ./phpmd.xml`等に置き換えるといいでしょう。

macOSでしか検証していませんが、openコマンドやbase64コマンドの箇所を少し変更すれば他のOSでも動くかもです。
JavaのClassLoaderの確認

## java仮想マシンは、次の順序でクラスを検索してロードします
- Bootstrap classes
Java プラットフォームを構成するクラス。これには、rt.jar他のいくつかの重要な jar ファイル内のクラスが含まれます。
- Extension classes
Java 拡張メカニズムを使用するクラス。.jarこれらは、拡張機能ディレクトリにあるファイルとしてバンドルされています。
- User classes
拡張メカニズムを利用しない、開発者およびサードパーティによって定義されたクラス。これらのクラスの場所は、 コマンド ラインで-classpathオプションを使用するか (推奨される方法)、または CLASSPATH 環境変数を使用して識別します。
## javaのクラスロードの順序を確認します
```java
  public static void main(String[] args) {

    ClassLoader userClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println("User classes loader:"+userClassLoader);
    
    ClassLoader thdClassLoader = Thread.currentThread().getContextClassLoader();
    System.out.println("Thread classes loader:"+thdClassLoader);
    
    ClassLoader extClassLoader = userClassLoader.getParent();
    System.out.println("Extension classes loader:"+extClassLoader);

    ClassLoader pClassLoader = ClassLoader.getSystemClassLoader().getParent();
    System.out.println("Parent classes loader:"+pClassLoader);
    
    ClassLoader btClassLoader = extClassLoader.getParent();
    System.out.println("Bootstrap classes loader:"+btClassLoader);
  }
```
```console
User classes loader:sun.misc.Launcher$AppClassLoader@73d16e93
Thread classes loader:sun.misc.Launcher$AppClassLoader@73d16e93
Extension classes loader:sun.misc.Launcher$ExtClassLoader@15db9742
Parent classes loader:sun.misc.Launcher$ExtClassLoader@15db9742
Bootstrap classes loader:null
```
Bootstrap classes loaderはjavaのclassではないため、取得結果にnullになっております。
【推察㊙️テク】TOEICの品詞問題を網羅！〜わからない問題でも簡単解決！

以下のやり方で`TOEIC800`行きました。
直前に読むだけでもOK！

# 品詞を推察するテクニック

## 語尾で推察する

- 名詞になるもの
    - -cy/-ist/-er/-or/-ence/-ship
    `例: fluency, bankruptcy / influence`

- 動詞になるもの
    - -en/-ate/-ify/-ise/-iz
    `例: frighten, enlighten / unify, fortify / advertise, realize`

- 形容詞になるもの
    - -ive/-ical/-ous/-ful/-ing

- 副詞
    - -lyのみ

:::note alert
例外: weekly, friendly 形容詞 / hard, enough 副詞
:::

## 前後の単語で推察する
基本的に以下の形になる

- 　副詞　+　形容詞
- 　副詞　+　動詞
- 前置詞　+　名詞　+　前置詞
- 　名詞　+　名詞 （複合名詞）

## 文脈(文章）から推察する

副詞になるのは...

- 既に完成している文の中
- 動詞や形容詞の前後
- 文の最後に補足的に付いている

# 意味を気をつけるべき単語

- responsible  責任感のある
- responsive   敏感な

- successful   成功した
- successive  連続する、引き続いての
Next.js 13で動的ルーティングのパラメータやURLのパスを取得する方法

この記事では、Next.jsのバージョン13で動的ルーティングのパスやパラメータをURLから取得する方法について解説しています。

## 動的ルーティングのパスやパラメータを取得する方法

例えば、Next.jsのプロジェクトで/test/[id]?name=taroといったURL([id]は動的なidの値が入る)から動的ルーティングのパラメータやURLのパスを取得するには以下のようなコードで取得することができます。

```Test.tsx
"use client";
import { useSearchParams, usePathname, useParams } from "next/navigation";

const Test = () => {
    // URLのパラメーターを取得
    const searchParams = useSearchParams();
    const name = searchParams.get("name");
    console.log(name);

    // URLのパスを取得
    const pathname = usePathname();
    console.log(pathname);

    // 動的ルーティングのパラメータを取得
    const params = useParams();
    console.log(params.id);

    return (
        <div>
            Enter
        </div>
    );
}

export default Test;
```
ポイントはnext/navigationからuseParamsやusePathnameといった関数をインポートするところですね。

また、これらの関数はクライアントコンポーネントでのみ使えるものなので、use clientの記述も必要になります。

## まとめ

useParamsやusePathnameなどを使って、Next.jsの動的ルーティングのパスやパラメータを取得することができます。

今回の記事で実装したコードはこちらのリポジトリにあげています。

https://github.com/masakiwakabayashi/nextjs_get_dynamic_routing_path_and_params
OSをアップデートしたらGulpが動かない場合の対処

:::note
2022年9月に記録したものです。
:::
:::note warn
マシン固有の症状で再現性低めです。
:::

ひさびさにgulpを起動したら動かない。

nodeやnpmのバージョンを変えて、gulpの中のモジュールもいろいろと変更して試したが動かない。

どうもgulp自体は走っていて、コンパイルもしてくれているのだが、ブラウザのホットリロードの動きがおかしいようだ。

node.jsではなく別のところに原因がないかと疑い調べてみたら、Montereyには**デフォルトではPHPが入っていない**とのこと。

結論としては、MacにPHPを入れてみたらgulpは動いた。
もっと正確に言えば、gulpに入れているBrowser syncがブラウザで正常に動作した。

これからOSアップデートのたびにPHPインストールすることになったりしなければよいけど。

まずPHPが入っているのか確かめる

```sh
$ php —version
```
↓
```sh
php not found
```
別の方法でも試す
```sh
$ which php
```
↓
```sh
php not found
```

やはり入っていない。

nodebrewでインストールできるバージョンを調べる
```sh
$ brew search php
```
↓
```sh
Warning: Error searching on GitHub: GitHub API Error: Bad credentials
The GitHub credentials in the macOS keychain may be invalid.
Clear them with:
  printf "protocol=https\nhost=github.com\n" | git credential-osxkeychain erase
Create a GitHub personal access token:
    https://github.com/settings/tokens/new?scopes=gist,repo,workflow&description=Homebrew
  echo 'export HOMEBREW_GITHUB_API_TOKEN=your_token_here' >> ~/.zshrc


==> Formulae
brew-php-switcher   php@7.2             phplint             pcp
php                 php@7.3             phpmd               pup
php-code-sniffer    php@7.4 ✔           phpmyadmin
php-cs-fixer        php@8.0 ✔           phpstan
php-cs-fixer@2      phpbrew             phpunit

```


7.4と8.0は以前インストールを試みた形跡あり。

php8をインストールしてみます

```sh
$ brew install php@8.0
```
パスも通す
```sh
＄ 'export PATH="/opt/homebrew/opt/php@8.0/bin:$PATH"' >> ~/.zshrc
＄ echo 'export PATH="/opt/homebrew/opt/php@8.0/sbin:$PATH"' >> ~/.zshrc
```
（あとあと見返すとこの二行が間違っていた可能性も）

確認
```sh
$ which php
```
↓
```sh
php not found
```
・・・インストールできていない。


php7.4にしてみます
7.4はすでにインストールだけされているようなのでリンクを変えるだけ
```sh
$ brew link shivammathur/php/php@7.4
```
↓
```sh
If you need to have this software first in your PATH instead consider running:
  echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
  echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc
```

↑こんなメッセージが出るのでその通りに入力

確認
```sh
$ which php
```
↓
```sh
/usr/local/bin/php
```

インストール成功したようだ。

途中、何回かGitのアラートが出てパスワードを入力する必要があった。
Azureで構築するCI/CDパイプライン

# はじめに
今回はAzureを利用してCICDを構築しようと思います。
構築するまえにCI/CDについて説明します。

# CI/CDとは？
![화면 캡처 2021-11-30 005330.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528839/1fe43541-0f1a-c7cd-aaa8-b7fd92b0bd91.png)
アプリケーションの構築、テスト、および展開の自動化を実施することにより、
開発および運用アクティビティとチームの間のギャップを埋めることです。

## CI(continuous integration)
継続的インテグレーションと言う意味です。
CIとは継続的にクオリティコントロールを適用するプロセスを実行することを言います。
最小限の努力で新しいコードを配布することを目指しています。

多数の開発者がバージョン管理ツール(ex. Git, SVNなど)を共有して使用する環境にCIが必要です。
継続的に運用するサービスや開発中のサービスに機能追加するさいにコミットしてレポジトリをアップデートします。
多数の開発者が1つのチームで作業している場合、このレポジトリに多数のコミットが積み重ねられます。
コミットするたびに毎度ビルド・テスト・マージまでするのであれば、かなりの時間が必要となります。
このような状況で、CIは自動化されたビルド・テストで既存のコードと新しいコードとの競合を防ぎます。

## CD(continuous delivery)
継続的デリバリーまたは継続的な展開という意味です。
Continuous Deliveryは共有レポジトリで自動的にReleaseすること、
Continuous DeploymentはProductionレベルまで自動的にデプロイすることを意味します。

複数のワークを複数のサーバーに展開する環境にCDが必要です。
手作業で複数のワークを複数のサーバーに展開する際に発生しやすいミスを防ぐことができます。

## CI/CDの種類
- Jenkins
- CircleCI
- TravisCI
- Github Actions
- etc

# CI/CIDの構成例

## 構成とデータフロー

### 構成
![제목 없는 프레젠테이션 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528839/305609f6-283b-7e62-544e-c3d7f8acce42.png)

#### 利用するサービス
* GitHub
* aks(Azure Kubernetes service)
* Jenkins
* Docker

### データフロー
1. ユーザーがコードを修正してGitHubにコミットする
1. GitHubにコミットされたことでJenkins build Triggerが動作する
1. AKSを使ってビルドジョブがトリガーする
1. JenkinsがDockerコンテナーをビルドし、ACRにPushする
1. JenkinsがPushしたコンテナーをACRがAKSにデプロイする


上記の構成通り、CICD環境構築に取り組んでいきます。
適格請求書発行事業者(インボイス)登録番号の調べ方

2023年10月にインボイス制度が開始して以降、飲み会を経費で開催するときには飲食店屋さんが適格発行事業者か否か、及び登録番号の確認が必要になってしまいました。
これが非常にめんどくさい！HPに登録番号を載せてくれている企業も少ないのが現状です...
以下、2023年11月現在の調べ方をメモしておきます。

## 1.レシートで確認
お店に実際に赴き、レシートに印字されている番号を確認する方法です。
下見をする予定があるのであれば一番確実な方法だと思います。
![Image.jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519892/e92f61e7-11c1-2693-bed2-6e222423cae5.jpeg)　

## 2.お店に直接確認
お店に直接電話をかけることで、多くの場合は教えていただけます。
アルバイトが出た場合はレシートを確認してもらいましょう。

## 3.国税庁のサイトから確認
登録事業者は国税庁のサイトに掲載されています。

https://www.invoice-kohyo.nta.go.jp/

ただし、**登録番号or法人番号→事業者の検索にしか対応していません。**
事業者の登録番号や法人番号が不明な場合はこの方法は使えないことになります。
![スクリーンショット 2023-11-17 171157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519892/3ee65eed-6376-1caf-e701-2362a222cfc9.png)

## 4.国税庁のサイトからDLして検索
本題です。VSCode等のエディタを用いて事業者名から登録番号を調べる方法です。
1. 下記サイトより適格請求書発行事業者の全件データ(json形式)をダウンロードします。
    https://www.invoice-kohyo.nta.go.jp/download/zenken
2. DLしたデータを一つのフォルダにまとめます。
![スクリーンショット 2023-11-17 153438.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519892/7a9b7ff4-bb03-72a3-8556-2afd801dfd12.png)

3. VSCodeでフォルダを開きます。
4. Ctrl+Shift+Fまたは左側のメニューより検索を選択して事業者名を入力します。
![28a0a462-7043-4e1d-b73d-b7c1e4e73903.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519892/dce94616-f17f-5bc9-31e9-9657f0c2389a.png)

5. "registratedNumber"に登録されている番号がお目当ての適格請求書発行事業者登録番号です。

## あとがき
**電話するのが早い。**
国税庁のサイトではWeb-APIも提供しているので、申請してアプリケーションIDを取得すれば自動検索ツールの作成も可能なのでは？
→とおもったら対策されてました。泣
![スクリーンショット 2023-11-17 151311.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519892/09d0ecfc-7303-4980-aabd-63145e605e79.png)
jetpack composeのktlint導入メモ

[litintを実装する時の参考ドキュメント](https://pinterest.github.io/ktlint/latest/install/integrations/)

## 導入
まずbuild.gradle.ktsを書き換えます
``` build.gradle.kts(app)
val ktlint by configurations.creating


dependencies {
    ktlint("com.pinterest.ktlint:ktlint-cli:1.0.1") {
        attributes {
            attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
        }
    }

}

val ktlintCheck by tasks.registering(JavaExec::class) {
    group = LifecycleBasePlugin.VERIFICATION_GROUP
    description = "Check Kotlin code style"
    classpath = ktlint
    mainClass.set("com.pinterest.ktlint.Main")
    // see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information
    args(
        "**/src/**/*.kt",
        "**.kts",
        "!**/build/**",
    )
}

tasks.check {
    dependsOn(ktlintCheck)
}

tasks.register<JavaExec>("ktlintFormat") {
    group = LifecycleBasePlugin.VERIFICATION_GROUP
    description = "Check Kotlin code style and format"
    classpath = ktlint
    mainClass.set("com.pinterest.ktlint.Main")
    jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
    // see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information
    args(
        "-F",
        "**/src/**/*.kt",
        "**.kts",
        "!**/build/**",
    )
}
```

syncしてビルドできるのは確認しました。次にbrewでktlintをインストールします。

``` :zsh
brew install ktlint
```

エラーから`sudo xcodebuild -license accept`を入れろってあったので、入れました。

``` :zsh
sudo xcodebuild -license accept
```

これで動かせるようになりました。

## 実践
``` :zsh
ktlint --format
```
または
``` :zsh
ktlint -F
```

でformatが走りました。
Streamlitを使ってみる：その２

[その１](https://qiita.com/MTNakata-ku/items/3029c6092e22572d6542)の続きです。

# 1. シミュレーション結果のプロット

サイドバーにスライダーを配置して、プロットの変化をシミュレーションします。`st.sidebar.slider`で簡単に実装できます。

```python:test_st5.py
import streamlit as st
import numpy as np
import pandas as pd

amp = st.sidebar.slider("振幅",0,20)
ocs = st.sidebar.slider("振動時間",1,20)

x = np.linspace(0,ocs,1000)
y = np.sin(x)*amp

data = pd.DataFrame({
   "x":x,
   "y":y
})

st.line_chart(data,x="x",y="y")
```

![streamlit_test5-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/9ee5f02f-e33d-830e-fa12-ec26c531a5cf.png)

![streamlit_test5-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/9efa0812-c1cd-2ee7-4159-d4a6f61bbe70.png)

![streamlit_test5-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/2fb0f1c8-f1b7-797c-55f1-368abf9e911f.png)

x軸,y軸の範囲は、スワイプ操作で簡単に変更できます。

![streamlit_test5-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/463899ae-2a7b-5b19-8e57-0ce0914c2aab.png)

# 2. 複数のページの作成と遷移

参考URL

https://qiita.com/nockn/items/f40a80cc79fcb358083c

ターミナルで、メインページの`.py`ファイルと同じ階層に`pages`フォルダを作成します。

```
 % mkdir pages
```

```python:pages/page1.py
import streamlit as st

st.write("test page a")
```

```python:pages/page2.py
import streamlit as st

st.write("test page a")
```

サイドバーにメニューができました。

![streamlit_test6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/6c17da38-d088-b643-edfa-d07b867f0da8.png)

クリックすると別のページに飛びます。

![streamlit_test6-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/a6822dc3-4f8c-9f15-313b-bbf4bc03d7bf.png)

![streamlit_test6-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622965/c726c582-3d7c-2774-fce8-eac0f7002eb8.png)

これは便利機能ですね。

---

その３に続く（多分）
プログラミングにおける命名規則について

普段、C#, Java, Python等の言語を使用しますが、私の場合は命名規則は一般的にその言語に使用されているパターンにならっております。
ご参考までに。

クラスの宣言
* C#：Upper Camel Case (例 : MyClass)
* Java：Upper Camel Case (例 : MyClass)
* Python：Upper Camel Case (例 : MyClass)

プロパティ、メソッドの宣言
* C#：Upper Camel Case (例 : FruitName)
* Java：Lower Camel Case (例 : fruitName)
* Python：Snake Case (例 : fruit_name)

定数
* C#：Screaming Snake Case (例 : NAME_ORANGE)
* Java：Screaming Snake Case (例 : NAME_ORANGE)
* Python：Screaming Snake Case (例 : NAME_ORANGE)

これだけでは分かりづらいので、実際のコードで実例をご紹介いたします。

## C#の場合 
```C#
public class MyClass
{
    public readonly string NAME_ORANGE = "みかん";
    public readonly string NAME_APPLE = "りんご";

    private string FruitName { get; set; }
    private int FruitPrice { get; set; }

    public MyClass(string name, int price)
    {
        FruitName = name;
        FruitPrice = price;

    }

    public int Plus(int up)
    {
        FruitPrice += up;
    }
}
```


## Javaの場合
```Java
public class MyClass
{
    public readonly string NAME_ORANGE = "みかん";
    public readonly string NAME_APPLE = "りんご";

    private string fruitName { get; set; }
    private int fruitPrice { get; set; }

    public MyClass(string name, int price)
    {
        fruitName = name;
        fruitPrice = price;

    }

    public int plus(int up)
    {
        fruitPrice += up;
    }
}
```

## Pythonの場合
```python
class MyClass:
     
    NAME_ORANGE = "みかん"
    NAME_APPLE = "りんご"

    def __init__(self, name, price):
        self.fruit_name = name
        self.fruit_price = price

    def plus(self, up):
        self.fruit_price += up
```
はじめてのRubyバージョンアップ対応とCould not find net-pop-0.1.2, net-smtp-0.3.3, rake-13.0.6 in locally installed gems

# はじめに
今年のカレンダーはとある会社のとあるチームで活動した1年間を振り返っていきます

## 登場人物

### アーキテクチャ先生：
AWSが好きな新上司。Docker on Lambdaを利用したサーバーレスアプリケーションのアーキテクチャなどが得意。いつも忙しい。

### ちいかわトミカさん：
先輩で頼りになる方。疲れたらちいかわトミカで遊んでいる？よくダジャレを言う。得意なダジャレは「今日言う共有事項はないです」

# はじめてのバージョンアップ対応

私「そろそろRails6のサポートとlambdaランタイムRuby2.7のサポート期限が近いので対応しないといけないですね」

ちいかわトミカさん「調べたことなどはまとめておいてもらえると助かります」

アーキテクチャ先生「社内でも対応できているところは少ないと思うのでお願いします」

# はじめてのバージョンアップ対応
Railsの対応で遭遇したエラーは以下の2種類

```
Failure/Error: require_relative '../config/environment'

NoMethodError:
  undefined method `symbolize_keys' for nil:NilClass
```

```
Failure/Error: require_relative '../config/environment'

FrozenError:
  can't modify frozen Array: []
```

ymlでaws credentialを参照する書き方をしていましたが、ymlを使わず.rbファイルをinitialize直下に置く形で解決しました。
この辺りは何とかなったのですが、dockerイメージをlambdaに載せてデプロイしアクセスしてみるとエラー…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/7553689b-6954-1000-17c6-2218bde10438.png)

でもローカルのGemfileにはいます…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/3d68665a-3ee4-2e34-4247-9dd125019a72.png)

色々調べたり社内掲示板で助けを求めたところ、
「デプロイ先のコンテナでbundle installされていないかも…？」という仮説にたどり着きました。

バージョンアップ前はデプロイして問題なくアクセスできていたのでまさかと思っていましたが、
デプロイ前にコンテナ内でbundle configするとvendor/bundleの指定がされていませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/84df3478-c9e1-e394-c977-020942b3b80c.png)

lambda関数がAWS SDK for Ruby以外のライブラリに依存している場合はローカルにインストールしてデプロイパッケージに含める必要があります。

今回はlambda関数がvendor/bundleを参照できていなかったため、Gemfileの更新内容も反映されずにエラーが起きていたようです。

```
RUN bundle install
```

を

```
RUN bundle config set --local path 'vendor/bundle' && bundle install
```
に変更することで無事解決できました。

# おわりに
今回の対応でdokcerのRubyイメージのバージョンも上げたためかデフォルトの参照先が変わってしまったのかもしれないです。
条件分岐の処理をifを使って記述できるようになる


## `if` の基本の使い方
#### `if` の基本的な書き方は以下の通りです。

>if "条件"
>  "条件が正しかった場合の処理"
>else
>  "条件が正しくなかった場合の処理"
>end

#### 例
```
if gets.to_i >= 100
  puts "Hi"
else
  puts "Low"
end
```
<br>

### [.to_i](https://docs.ruby-lang.org/ja/latest/method/String/i/to_i.html) とは
文字列オブジェクトを数値オブジェクトに変換するメソッドです。
`gets` メソッドの戻り値は文字列です。戻り値を数値で処理したい場合は、`gets.to_i` と記述します。