OmniAICreator/Qiita-1.07M huggingface dataset:
JavaのArrayListクラス、ジェネリクス、イテレーター(Iterator)

## ArrayListクラスとは
・java.utilパッケージに含まれている複数のオブジェクトをまとめて管理出来る**コレクションクラス**の一つ
・配列は最初に格納出来る要素数は決まっているがArrayListクラスは要素の数が**動的**に変わる配列で文字列や整数などのいろいろな配列を入れる事が出来る。

・格納する要素のデータ型の指定する際には**ジェネリクス（＜＞）**　内に指定する（ジェネリクスとして<〜>で囲んだ指定部分を「型パラメータ」とも呼び、型パラメータにはクラス名を指定する。）
```
ArrayList<データ型（型パラメータ）> オブジェクト名 = new ArrayList<>();
```
データ型の部分には ArryaListの要素に格納する値のデータ型を指定する。例えば文字列を格納する場合は次のように記述する。
```:例
ArrayList<String> list = new ArrayList<String>();
//クラス名　　オブジェクト名　　＝　　new　　クラス名；
```
右辺のArrayList<String>で一つのクラス名と考える

ArrayListはListインターフェースを実装したクラスなので、次のように Listオブジェクトとして作成することもできる。 
Listオブジェクトとして作成した場合は、ArrayListクラスでのみ定義されているメソッドは利用できなくなりますが、同じListインターフェースを実装したクラスへ変換する場合などに便利。
```
List<String> list = new ArrayList<>();
```
＊主に使用するメソッドは Listインターフェースで定義されているので、通常は List オブジェクトとして作成することが多い

データ型には基本データ型であるintやdoubleなどは指定することが出来ないのでこれらの数値を格納したい場合には、それぞれの基本データ型に対応したラッパークラスを使用する。
```:int 型の値を格納する ArrayList クラスのインスタンスを作成
List<Integer> list = new ArrayList<>();
```

### ArrayListクラスでよく使われるメソッド
・addメソッド：1つの値をリストの要素としてに追加するメソッド
・getメソッド：リストに追加されている要素の中で指定したインデックスの要素に格納されているオブジェクトを取得する
・sizeメソッド：リストに現在追加されている要素の数を取得する

```:サンプルコード
import java.util.ArrayList;

public class ArrayListSample{
  public static void main(String[] args){
    ArrayList<String> list = new ArrayList<String>();
    list.add("Java入門講座");
    list.add("ここまで");
    list.add("よく頑張りましたね！");
    
    for(int i = 0; i < list.size(); i++){
      System.out.println(list.get(i));
    }
  }
}
```
```:出力結果
Java入門講座
ここまで
よく頑張りましたね！
```

## イテレーターとは
・コレクション内の要素を指し示すカーソルの様なモノでコレクションに対してデータを取り出す役割をする。
・使うことで、HashSet クラスやLinkedList クラスなどのさまざまなコレクションの要素に、同じプログラムコードで１つずつ効率的にアクセスでき、**コレクションの中の要素を１つすつ順番に参照する能力を持っている。**
・コレクションクラスの**iteratorメソッド**で取得出来る。
```
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(20);
Iterator<Integer> it = list.iterator();
```
### Iteratorの代表的なメソッド
・hasNextメソッド：配列からデータを繰り返し取り出す処理をする際に、次のデータが存在すればtrueを返す。
・nextメソッド：繰り返し処理の際に、次のデータを取り出す。
・removeメソッド：最後に返した要素を削除する。

```:サンプル
import java.util.ArrayList;
import java.util.Iterator;

public class IteratorSample{
  public static void main(String[] args){
    ArrayList<String> list = new ArrayList<String>();
    list.add("これからも");
    list.add("Javaの勉強を");
    list.add("楽しんでいきましょう！");

    Iterator<String> it = list.iterator();
    while(it.hasNext()){
      System.out.println(it.next());
    }
  }
}
```
```:出力結果
これからも
Javaの勉強を
楽しんでいきましょう！
```
hasNext()で要素が残っているかを調べて残っているなら処理を続ける。
next()で要素を取得し、イテレーターは次の要素に移動する。

## 参考記事
https://www.youtube.com/watch?v=jItwrnszVQc&list=PLru8-xuz0Yvx8uLgIbKh7pI5N5zpsmBek&index=44&t=316s

https://www.youtube.com/watch?v=svO6bcUfmK4&list=PLru8-xuz0Yvx8uLgIbKh7pI5N5zpsmBek&index=45

https://www.javadrive.jp/start/collection/index1.html#section4
React – 定期的にバックエンドAPIにリクエストし続ける  (例 1秒間隔でsleepする) (リアルタイム更新したい)

# バックエンドAPI

JSONで現在時刻を返すAPIを用意しておく

```json
{
  "time": "2023-01-04T12:31:56.487Z"
}
```

# React コード例

```js

import {useState, useEffect} from 'react'

const AxiosGet = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('http://localhost:3000/');
      const data = await response.json();
      setData(data);
    }

    const interval = setInterval(() => {
      fetchData();
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return data ? <div>{data["time"]}</div> : <div>Loading...</div>;
}

export default AxiosGet;

```

# 動作例

1秒ごとに時刻表記が更新されるのが分かる

![image](https://user-images.githubusercontent.com/13635059/210555531-8df03e64-b4df-4e5d-bcd9-bb226f248483.png)
![image](https://user-images.githubusercontent.com/13635059/210555558-afa65dc1-8b8b-4756-a263-c27123baee8d.png)



# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
【Ruby】private、protectedの使い分け

# praivate
class内でprivateメソッドを定義されたメソッドはレシーバを指定して呼び出すことができなくなります。


```ruby
class Fooz
  
  private
  
  def say
    p "Hello"
  end
end

foo = Foo.new
foo.say
```
この場合はエラーが発生します。


次の場合はエラーが発生せずに実行が可能です。
```ruby
class Foo
  
  def greeting
    say
  end
  
  private
  
  def say
    p "Hello"
  end
end

foo = Foo.new
foo.greeting
```
privateメソッド内で定義されたsayメソッドは、クラス内で呼び出すことで、インスタンスで使用することが可能となります。

# protectedメソッド
privateメソッドと同じようにクラスの外から直接メソッドを呼び出すことができなくなります。
同じインスタンス内で呼び出すことができます。
ここまではprivateメソッドと同じですが、この機能に加えて他のインスタンスでも同じクラスやサブクラスのメソッドであれば呼び出すことが可能となります。

同じクラスのオブジェクト同士ではprotectedメソッドで定義されたオブジェクトを共有できることができるので、情報のやり取りが円滑にできることがあります。

ただし、protectedメソッドは特殊なメソッドであることも覚えておきましょう。
VSCodeでコミットメッセージのdescriptionを書く

## descriptionとは

コミットメッセージの下記の位置に表示される文章。コミットログなどには表示されないので、文字数などを気にせずに詳細情報を記載することができる。

![スクリーンショット 2023-01-04 16.49.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402627/42d30467-fabe-5732-b6ba-36d797796f53.png)

## VSCodeのGit連携機能を使用した書き方

入力欄で改行して2行目を空行にするだけ。Enterで改行できる。1行目はtitle、3行目以降は全てdescriptionとして登録される。

![スクリーンショット 2023-01-04 16.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402627/04cbe96f-c3a9-264a-bac6-9bf7ada1f8be.png)

## 表示確認

### `git log`

titleのみ表示される

![スクリーンショット 2023-01-04 16.49.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402627/dd16323d-ae97-0501-0fd7-42e670043ae6.png)


### `git log --all`

descriptionも表示される

![スクリーンショット 2023-01-04 21.02.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402627/e2175339-0fa1-c466-0eb4-6bf5d5e90cc3.png)


### プルリクエストのコミット履歴

titleのみ表示される

![スクリーンショット 2023-01-04 16.58.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402627/b8c753b2-ff4c-f0a8-6c00-5d7716ad6632.png)

### コミット詳細ページ

descriptionも表示される。（「descriptionとは」にも貼ってるけど一応貼っておく）

![スクリーンショット 2023-01-04 16.49.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402627/42d30467-fabe-5732-b6ba-36d797796f53.png)


## ちなみにコマンドでdescriptionを登録するには

下記の書き方でOK

```zsh
git commit -m 'titleだよ' -m 'descriptionだよ'
```

## 参考

https://tyoshikawa1106.hatenablog.com/entry/2016/04/08/015920

https://git-scm.com/docs/git-commit#_discussion
GASでDALL·E 2 APIを組み込んだLINEbotを作成する方法[コード付き]

# 課題
　DALL·E 2 APIを使用したLINEbotを作成しようとしましたが、「DALL·E 2 API line bot」で検索しても良いサイトが見つかりませんでした。
　そのため、DALL·E 2 APIを使ってLINEbotを作成する方法を共有します。

# 準備
　LINEbotの作成においてGASを開くところまで出来てる方は、こちらを飛ばしていただいて結構です。

　準備は主に2つあります。1つ目がOPENAIのAPIキーの取得で、2つ目がLINE Messaging APIをGASで実行するLINEbotの作成です。
　以下に、それぞれを丁寧に説明してくれてるサイトをご紹介します。

①OPENAIのAPIキーの取得方法：
　以下の記事が、わかりやすかったです！

https://laboratory.kazuuu.net/how-to-get-an-openai-api-key/

②LINE Messaging APIをGASで実行するLINEボットの作成
以下の記事が、わかりやすかったです！
ここで、GASにコードを入力するところまでいっていただければ、準備完了です！

https://auto-worker.com/blog/?p=5141#

# 結論
　以下のコードをGASにコピペして、①~③を行って下さい！

①`"OPENAIのAPIキー"`を、自分のOPENAIのAPIキーで置き換えます。
例：`"aaaa-aa-aaa-TW"`

②`"LINE Messaging APIで取得したチャネルアクセストークン"`を、自分のチャネルアクセストークン（長期）で置き換えます。
例：`"aaaaaaaaaaaaaaaaaa-aa-aa-aaa-PU="`

③DALL·E 2 APIを呼び出す際に、言葉でオプションを追加したい場合は、`add_order_message`に追記する。ただし注意点として、意味的な区切りを作る場合はできるだけカンマ(,)か読点（、）をつけるようにして下さい。
例①：`"デジタルアート風、"`←「デジタルアート風」で意味的に区切っているので、読点をつける。
例②：`"朝ごはん、"`←「朝ごはん」で意味的に区切っているので、読点をつける。

```javascript:コード.gs
// LINE Messaging APIを使用するためのライブラリを取り込む
var LINE_API = "https://api.line.me/v2/bot/message/reply";
var LINE_API_KEY = "LINE Messaging APIで取得したチャネルアクセストークン";

// DALL·E 2 APIを使用するためのライブラリを取り込む
var DALLE2_API = "https://api.openai.com/v1/images/generations";
var DALLE2_API_KEY = "OPENAIのAPIキー";

function doPost(e) {
  // 受け取った内容を取得する
  var message = JSON.parse(e.postData.contents).events[0];

  //受け取った内容の文字列を取得
  var str_message = message.message.text;
 
  //DALL·E 2 APIを呼び出す際に、言葉でオプションを追加したい場合は、ここに追記
  var add_order_message="";
  
  //受け取った内容の文字列と追加オプションを結合
  var sending_message = add_order_message + str_message;

  // DALL·E 2 APIを呼び出すためのリクエストを送信する
  var imageUrl = generateImage(message.message.text);

  // リクエストを送信するためのオプションを設定する
  var options = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + LINE_API_KEY
    },
    "payload": JSON.stringify({
      "replyToken": message.replyToken,
      "messages": [
        {
          "type": "image",
          "originalContentUrl": imageUrl,
          "previewImageUrl": imageUrl
        }
      ]
    })
  };

  // リクエストを送信する
  UrlFetchApp.fetch(LINE_API, options);
}

// DALL·E 2 APIを呼び出し、出力結果の画像のURLを取得する関数
function generateImage(text) {
  // リクエストを送信するためのオプションを設定する
  var options = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + DALLE2_API_KEY
    },
    "payload": JSON.stringify({
      "prompt": text,
      "model": "image-alpha-001",
      "num_images": 1,
      "size": "256x256",
      "response_format": "url"
    })
  };
  // リクエストを送信する
  var response = UrlFetchApp.fetch(DALLE2_API, options);
  var data = JSON.parse(response.getContentText());

  // 画像のURLを取得する
  return data.data[0].url;
}

```

# 最後に
　DALL·E 2 APIを使用したLINEbotを作成する方法を紹介しました。今回のプログラムを他のAPIと組み合わせることで、さらに多くの機能を追加することができます。
ご参考になれば幸いです。
最後までお読みいただき、ありがとうございました！



参考になったサイト：
①OPENAIのAPIキーの取得方法：

https://laboratory.kazuuu.net/how-to-get-an-openai-api-key/

②LINE Messaging APIをGASで実行するLINEボットの作成


https://auto-worker.com/blog/?p=5141#
C# ラムダ式でローカル変数を使用するとどうなるのかやってみた

# はじめに

C# ラムダ式で<b>（ラムダ式の外側の）</b>ローカル変数を使用するとどうなるのか気になり、やってみました。

本記事は実験的な内容であり、この実装方法を推奨するものではありません。実用的な内容でもありません。
（どちらかというと、うっかり書かないように気を付けましょうという内容です。）


# 実験１

下記のプログラムを実行し、ボタンをクリックするとコンソールに何が表示されるでしょうか？

```c#
using System;
using System.Drawing;
using System.Windows.Forms;

class LambdaSample : Form
{
    static readonly int N = 3;
    Button[] btn;

    LambdaSample()
    {
        btn = new Button[N];

        for(int i=0;i<N;i++)
        {
            btn[i] = new Button(){
                Location = new Point(0, 30*i),
                Size = new Size(50, 25),
                Text = i.ToString(),
            };
            Controls.Add(btn[i]);
            btn[i].Click += (s,e)=>{Console.WriteLine(i);}; // ...(※)
        }
    }
    
    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new LambdaSample());
    }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/2f576641-cea3-fc00-b51f-66b3c2aa935b.png)

## 結果

いずれのボタンを押しても

```
3
```

が出力されます。
変数`i`が、for文を抜けても生き残っているようです。
（※のラムダ式`(s,e)=>{...};`から`i`が参照されているのでスコープを抜けても生き残っているよう。）

## 逆アセンブル結果

ILDASMで見てみると、`<>c__DisplayClass3` という謎のクラスが生成され、`i`がフィールドとして存在しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/bef826c0-46cd-bbd2-4413-ea25a9f62b02.png)

ちなみに、(※)の部分のコードから`i`を削除すると下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/349250b3-9243-b9d9-4f6e-3151f3bd0f06.png)


# 実験２

```c#
btn[i].Click += (s,e)=>{Console.WriteLine(i);}; // ...(※)
```

の部分を

```c#
btn[i].Click += (s,e)=>{Console.WriteLine(i); i++;}; // ...(※)
```

にしてみると、
いずれかのボタンを押すたびに

```
3
4
5
```

と出力されます。つまり、`i` が生き残っていることが確認できます。
フロント コーディングメモ

# v-onで便利な機能
### v-on:prevent
v-onだけだとページのリロードが発生してしまうが、preventでサブミットだけキャンセルできるあ。
```:vue
<p v-on:click="onPClickEvent('green', $event)" v-bind:style="{backgroundColor: pBgColorEvent}">{{pMsg2}}</p>
```
```:typescript
const msg = ref("未送信")
const onFormSubmit = (): void => {
  msg.value = "送信されました"
}
```


# リンク
[Javascriptで用意されている主なイベント](https://qiita.com/shizen-shin/items/17094a68a0369e126d41)
GitHubレポジトリ学習のすゝめ

プログラミング初心者の方もエンジニアとして数年経つひとも、みなさん勉強してますか？？？

私は実は仕事以外で何を勉強していいのか、何を作ったらいいのか路頭に迷っていました。

前はUdemyやYouTubeといった動画で学習したり、大学の図書館にある技術書を読み漁ったりして勉強していましたが、勉強のモチベーションを無くしていたためしばらくできていませんでした😓

そこで勉強の仕方を変えたり、有益なリソースがないか調べていたところGitHubで**無料**で公開されているコンテンツが非常に完成度が高かったため紹介させていただきます😆

---

# 未経験・初心者向け

## [developer-roadmap](https://github.com/kamranahmedse/developer-roadmap)
　フロントエンドやバックエンド、ブロックチェーンといった各分野のエキスパートになるための道筋が細かくまとめられています。
　闇雲に開発の勉強をしていても永遠に勉強が終わらないので、体系立てて学習するための指標として非常に参考になります。

## [computer-science](https://github.com/ossu/computer-science)
 　コンピュータサイエンスが一通り学べるレポジトリで大学の講義で学ぶ内容を一通り学べます。
　プログラミングだけ書ける人材がもう不必要になると囁かれているのでコンピュータの仕組みを知ってシステムを創れる人になるために必要だと思います。

# 中級以上向け

## [awesome-design-patterns](https://github.com/DovAmir/awesome-design-patterns)
　 各プログラミング言語のデザインパターンが載っているレポジトリです。
　特にオブジェクト指向の概念の理解を深めたい時に参考になりそうです。
　私の場合は、Vueでよく使われるパターンをこのサイトで学んでいます。

## [project-based-learning](https://github.com/practical-tutorials/project-based-learning)
 　何か作って学びたいという人にはこのレポジトリをお勧めします。
　各プログラミング言語ごとに簡単なアプリケーションを一通り開発するチュートリアルが紹介されており、急にその言語を使うことになって習得する必要があるときなどに便利です！


# 学習する時には**Star**しておこう
　学習するときはStarの登録をしておくとGitHubのホーム画面から簡単にレポジトリを探すことできます！
　Starのトグルボタンを押して`Create Lists`で学習用のリストを作成して、そこに登録しておくと便利ですー！

![Screen Shot 2023-01-04 at 20.57.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486680/4bb8cafc-6b3d-42f4-f0b9-919b18d5dc4b.png)


---

実は人生初めてのQiitaの投稿でした😮
これから一人で多くの人の人生が華やかになるように情報を与えていきたいと思うので、ぜひよろしくお願いします。
phpMyAdmin の localhost ログインが 2002 エラーで失敗する状況の対処

# サマリ
/etc/phpmyadmin/config-db.php の $dbserver を 127.0.0.1 に変更する
```diff_ruby
-$dbserver='localhost';
+$dbserver='127.0.0.1';
```

# 環境
- Windows 10 + WSL2 (Ubuntu 20.04.2 LTS)
- mysql-server   8.0.31-0ubuntu0.20.04
- phpmyadmin     4:4.9.5+dfsg1-2

# 参考資料
## インストール手順
https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04-ja

https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-phpmyadmin-on-ubuntu-20-04-ja

## トラブルシュートに役立ったリンク
https://gist.github.com/abobija/228e36441d31ae17ecc36edc9a47ceb5?permalink_comment_id=4246466#gistcomment-4246466
https://support.ntt.com/mw-businessr3/faq/detail/pid2300001k7e/

# 反省
- エラーメッセージで原因を詳細に特定すること大切。勝手に PW の問題と決めつけて進めてしまったが、エラーメッセージは mysql の設定自体の問題を指していた。
- また、リカバリの過程でパッケージのクリーンナップがうまくいかない問題も再起動で直るようなものなのに試せていなかった。
- トラブルシューティングの基本。
【手順書】snortをamazon linuxに速攻入れる

### ポイント
・daqをパッケージでインストールするためにリポジトリepelを利用
・snortがインターネットプロトコルを使用するために必要なライブラリlibdnetを読み込むためにシンボリックを作成する

### 実際のコマンド
```
sudo su
wget https://www.snort.org/downloads/snort/snort-2.9.20-1.centos.x86_64.rpm
amazon-linux-extras install epel -y
yum install -y gcc flex bison zlib libpcap pcre libdnet tcpdump libnghttp2 daq daq-devel
ln -s /usr/lib64/libdnet.so.1.0.1 /usr/lib64/libdnet.1
yum install -y snort-2.9.20-1.centos.x86_64.rpm
systemctl start snortd
```
```txt:サービスの起動を確認
# systemctl status snortd
● snortd.service - SYSV: snort is a lightweight network intrusion detection tool that currently detects more than 1100 host and network vulnerabilities, portscans, backdoors, and more.
   Loaded: loaded (/etc/rc.d/init.d/snortd; bad; vendor preset: disabled)
   Active: active (exited) since Wed 2023-01-04 11:38:52 UTC; 6s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 3590 ExecStart=/etc/rc.d/init.d/snortd start (code=exited, status=0/SUCCESS)
```

### 参考
公式手順書：https://upcloud.com/resources/tutorials/installing-snort-on-centos
ソース：https://www.snort.org/downloads
シンボリックリンク：https://teratail.com/questions/230985
[初心者]React-express APIで躓いたこと


# WEBエンジニア<br>REACTを使ってみて躓いたとこ


## 環境
UI：React
API server : express
DB : mysql

## やりたいこと
expressを使って、mysqlのデータを取得、
取得したデータをReactを使ってWEBに表示

## 躓いたこと
expressからのデータをreact側で受け取るときに、undefinedになる。

express上では、データが取得できていることは確認できている。

以下、React App.jsコード抜粋

``` App.js 抜粋
~~~

  const [message, setMessage] = useState('');
  useEffect(() => {
    // fetchでexpress上に作ったAPIよりデータを取ってくる
    fetch('/getData')
    .then((res) => {
      // 失敗していたらエラーを返す
      if(!res.ok){
        console.log("error");
        throw new Error('error');
      }
      // 成功していたら、取得したデータを次のthenへ
      res.json();
    })
    .then((data) => {
      // コンソールで表示　←　もちろんundefined
      console.log(data);
    })
    .catch((err) => {
      console.log(err);
    });
  }, []);
```

原因
fetchでデータを取得したときに、
thenでreturn を返していなかったから。

thenを｛｝で囲むときには、returnで明示的に値を返す必要があるみたい。


以下、値を取得できるコード

``` App.js 抜粋
~~~

  const [message, setMessage] = useState('');
  useEffect(() => {
    // fetchでexpress上に作ったAPIよりデータを取ってくる
    fetch('/getData')
    .then((res) => {
      // 失敗していたらエラーを返す
      if(!res.ok){
        console.log("error");
        throw new Error('error');
      }
      // 成功していたら、取得したデータを次のthenへ
      return res.json();　// <- ここのreturn がいる
    })
    .then((data) => {
      // コンソールで表示
      console.log(data);
    })
    .catch((err) => {
      console.log(err);
    });
  }, []);
```


# あとがき
WEBエンジニアではあるけど、自社のPHPフレームワークを使ったシステムの開発をしているため、
JSのフレームワークや開発環境に憧れがあり、やってみました。

途中でわからんからAPIはLaravel使ったほうが早くね？
ってなりましたが、まあ遊びだしいいかと思いやってみました。
これで一応ReactでAPIデータを表示できるところまでできたので、
自分の作りたいものの学習にはなったからいいかと思っています。
anonymous class, local class, inner class

Java Gold

```java
interface SampleInterface {
    void method();
}
public class Outer {
    public static class InnerStatic {
        static int i1;
        static void method() {
            System.out.println("i am Inner class method of static");
        }
    }
    public class InnerInstance {
        int i1;
        void method() {
            System.out.println("i am Inner class method of instance");
        }
    }
    public static void main(String[] args) {

        class LocalClass {
            int i2;
            void method() {
            System.out.println("i am local class method");
            }
        }
        
        Outer.InnerStatic.method();

        Outer o = new Outer();
        InnerInstance ii = o.new InnerInstance();
        ii.method();
        
        LocalClass l1 = new LocalClass();
        l1.method();
        
        SampleInterface si = new SampleInterface() {
            @Override
            public void method() {
                System.out.println("i am anonymous class method");
            }
        };
        si.method();
    }
}
```
```
i am Inner class method of static
i am Inner class method of instance
i am local class method
i am anonymous class method
```
MyBatis GeneratorでBLOBをbyte[]ではなくInputStreamとして出力する

# 概要

MyBatis Generatorでデフォルトの設定のままModel/Mapper一式を生成すると、DB上でBLOBで持っているカラムがModel上でbyte[]型になってしまいます。
byte[]型の代わりにInputStream型で出力させる方法を備忘録として書き残しておきます。

GitHubに実際のリポジトリ例も置いてあります。
https://github.com/ishioka0222/spring-boot-file-upload-download

# 手順

MySQLで以下のようなDDLで生成される`FILE`テーブルがあるとします。

```sql:schema.sql
CREATE TABLE DEMODB.FILE (
    TYPE_ID INT NOT NULL PRIMARY KEY,
    NAME VARCHAR(256) NOT NULL,
    CONTENT LONGBLOB NOT NULL
);
```

このとき、MyBatis Generatorの`generatorConfig.xml`の中に設定を追加します。
以下では、`DEMODB.FILE`テーブルの`CONTENT`列を`InputStream`で保持するように設定しています。

```xml:generatorConfig.xml
...
<table schema="DEMODB" tableName="FILE">
    <property name="useActualColumnNames" value="true" />
    <columnOverride column="CONTENT"
        javaType="java.io.InputStream"
        typeHandler="org.apache.ibatis.type.BlobInputStreamTypeHandler" />
</table>
...
```

この状態でMyBatis Generatorを実行すると、生成されたModelが以下のように`CONTENT`列をInputStream型で保持するようになります。

```java
package com.example.demo.model;

import java.io.InputStream;

public class File {

    ...

	/**
	 * This field was generated by MyBatis Generator. This field corresponds to the database column file.CONTENT
	 * @mbg.generated
	 */
	private InputStream CONTENT;

    ...
```
C# でタイムスタンプリクエストを作成する

C#でタイムスタンプリクエストを作成するには、[Rfc3161TimestampRequest クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.pkcs.rfc3161timestamprequest?view=dotnet-plat-ext-7.0)を利用します。

```c#
// See https://aka.ms/new-console-template for more information

using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Text;

// 文字列
string str = "Hello World";
byte[] beforeByteArray = Encoding.UTF8.GetBytes(str);


//タイムスタンプリクエストの作成
Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromData(beforeByteArray, HashAlgorithmName.SHA256, null, null, true);
byte[] reqByteArray = req.Encode();

// バイト配列を16進数文字列に変換、16進文字列で標準出力に出力
StringBuilder sb = new StringBuilder();
foreach (byte b in reqByteArray)
{
    sb.Append(b.ToString("x2"));
}
Console.WriteLine(sb);


// ファイルに出力
string fileName = @"HelloWorld.req";

using (var writer = new BinaryWriter(new FileStream(fileName, FileMode.Create)))
{
    //書き込む処理
    writer.Write(reqByteArray);
}
```


作成したタイムスタンプリクエストを以下のOpenSSLのコマンドで表示してみました。

```
>openssl ts -query -in HelloWorld.req -text
Using configuration from C:\Program Files\Common Files\SSL/openssl.cnf
Version: 1
Hash Algorithm: sha256
Message data:
    0000 - a5 91 a6 d4 0b f4 20 40-4a 01 17 33 cf b7 b1 90   ...... @J..3....
    0010 - d6 2c 65 bf 0b cd a3 2b-57 b2 77 d9 ad 9f 14 6e   .,e....+W.w....n
Policy OID: unspecified
Nonce: unspecified
Certificate required: yes
Extensions:

```
C# でハッシュ値を生成する

C#でSHA1のハッシュ値を作成するには、[SHA1クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.sha1?view=net-7.0)を使用します。SHA256のハッシュ値を作成するには、[SHA256クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.sha256?view=net-7.0)を使用します。



SHA1, SHA256アルゴリズムでハッシュ値を生成し、出力するプログラムです。

```c#
using System.Security.Cryptography;
using System.Text;

// See https://aka.ms/new-console-template for more information

// 文字列
string str = "Hello World";


byte[] beforeByteArray = Encoding.UTF8.GetBytes(str);

// SHA1 ハッシュ値を計算する
SHA1 sha1 = SHA1.Create();
byte[] afterByteArray1 = sha1.ComputeHash(beforeByteArray);
sha1.Clear();

// バイト配列を16進数文字列に変換
StringBuilder sb1 = new StringBuilder();
foreach (byte b in afterByteArray1)
{
    sb1.Append(b.ToString("x2"));
}

// SHA256 ハッシュ値を計算する
SHA256 sha256 = SHA256.Create();

byte[] afterByteArray2 = sha256.ComputeHash(beforeByteArray);
sha256.Clear();

// バイト配列を16進数文字列に変換
StringBuilder sb2 = new StringBuilder();
foreach (byte b in afterByteArray2) {
    sb2.Append(b.ToString("x2"));
}

Console.WriteLine("SHA1");
Console.WriteLine(sb1);

Console.WriteLine("SHA256");
Console.WriteLine(sb2);
```
【連載】Dockerコンテナ内からリモートサーバーにrsyncでデプロイ【その１：sshコマンドでリモートサーバーにログイン】

## 前置き
Dockerコンテナからリモートサーバにrsyncを使ってデプロイできるようにしたので、その方法を3回に分けて投稿していこうと思います。

## 目次
<b>その１：sshコマンドでリモートサーバーにログイン</b>
その２：rsyncコマンドでリモートサーバーにファイル同期
その３：シェルスクリプトにまとめてデプロイ

## 結論
```
ssh -p [ポート番号] -l [リモートサーバのログインユーザ名] \
-i [秘密鍵ファイルパス] \
[リモートサーバのログインユーザ名]@[リモートサーバのホスト名]
```

* [ポート番号]：ssh接続するリモートサーバのポート番号
* [リモートサーバのログインユーザ名]：ログインに必要なユーザ名
* [秘密鍵ファイルパス]：ssh接続に必要な秘密鍵ファイルのパス(拡張子が「pem」のやつとか)
* [リモートサーバのホスト名]：ホスト名のほかIPアドレスでもいいかもしれない。（動作未確認）
※1つのコマンドが1行だと長い場合、「\」を入力することで1つのコマンドを複数行で記載可能になります！

## 環境
### Dockerローカル環境
| 使用イメージ    | サービス名 | 備考                                                        |
| -------------- | --------- | ----------------------------------------------------------- |
| nginx:1.11     | web       | ※docker-compose.ymlの設定で、```depends_on: - app```と記載。 |
| php:7.3.33-fpm | app       | ```docker-compose exec app bash```でコンテナの中に入って```php --version```を実行したところバージョンは7.4.33だった。 |

### リモート環境
お名前.com レンタルサーバー
PHP 7.3.33
SFTPメモ

## why
winscpを使って、ファイルの転送(sftp)を行ってましたので、(あやふやなので)メモとして投稿する。

## what
### sftp
- SSH File Transfer Protocol(SFTP)は、信頼性の高いデータストリーム（英語版）上でのファイル転送やファイル管理を提供する通信プロトコルである。
- Internet Engineering Task Force(IETF)によって、安全なファイル転送機能を提供するためにSecure Shellバージョン2.0(SSH-2)の拡張として設計された。
- IETFのインターネットドラフトでは、このプロトコルはSSH-2に関連付けて説明されているが、TLS(Transport Layer Security)経由の安全なファイル転送や、VPNアプリケーションの管理情報の転送など、さまざまなアプリケーションで使用できると述べられている。
- このプロトコルは、SSHなどのセキュアな通信路で実行されること、サーバが既にクライアントを認証していること、クライアントユーザのIDがプロトコルで利用可能であることを前提としている。（[wikipedia](https://ja.wikipedia.org/wiki/SSH_File_Transfer_Protocol)）
### winscp
- 簡単にsftpを利用したファイル転送を行われるGUI(Client)。（自身の理解）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3019265/3c36d8b7-3e21-d78b-b3bd-eecb67eabbdb.png)
- [ホームページ](https://winscp.net/eng/docs/free_sftp_client_for_windows#:~:text=An%20SFTP%20client%20is%20a,and%20from%20a%20remote%20computer.)

## how

### 条件

1. SSHキーが存在する：転送protocalへloginする際に必要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3019265/32bb7a8e-c9a0-d87f-41e1-decf5f130d45.png)

2. 転送protocalのホスト名、ユーザー名、パスワードが分かる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3019265/701c23ba-8049-bde4-ec27-d02c154d7213.png)

### 使い方
上記条件２の赤い枠に、手元にある全てのアカウント情報を入力すれば、ファイルの転送が可能になる。
Pythonでjson.dumpsのsepatatorsオプションを使ってファイルサイズを軽量化する

# はじめに
Pythonの`json.loads()`で、ある.jsonを読み込み、読み込んだ直後のオブジェクトに対して`json.dumps()`を実行すると、実行後にファイルサイズが増加する現象に直面しました。

調査したところ、原因が`json.dumps()`を実行するときの`sepatators`オプションにあり、デフォルト値だとファイルサイズが増加してしまうケースがあることが分かったため、対応方法を備忘録として残します。

# separatorsオプション
`separators`オプションはJSONのKey-Valueおよび要素間の区切り文字を指定するものですが、**デフォルトだと`(',', ': ')`が指定**され、コロンの後ろに半角スペースが挿入されます。

>separators はもし指定するなら (item_separator, key_separator) というタプルでなければなりません。デフォルトは indent が None のとき (', ', ': ') で、そうでなければ (',', ': ') です。最もコンパクトな JSON の表現を得たければ空白を削った (',', ':') を指定すればいいでしょう。
>
>バージョン 3.4 で変更: indent が None でなければ (',', ': ') がデフォルトで使われます。
>
>https://docs.python.org/ja/3/library/json.html#basic-usage

この仕様より、元々の.jsonで既に半角スペースが除かれているケースにおいては、出力時に`json.dumps()`をデフォルトオプションで実行することでファイルサイズが増加してしまうことになります。

# separatorsオプションから空白を取り除く
上記で解説されているように、**空白を削った`(',', ':')`を明示的に指定**することでファイルサイズを削減できます。

```python
json.dumps(obj, separators=(',', ':'))
```

# 検証結果
条件(要素数など)によって変わりますが、手元のテストファイルで試した時には、separatorsオプションがデフォルト値の時のファイルサイズが71.4KBに対し、separatorsオプションを明示的に指定した時のファイルサイズが69.5KBとなり、1.9KB削減できました。

# まとめ
1ファイルでは大したことありませんが、ETLなどの処理を実行する場合、数十万から数百万というファイル数になると、大きな差となって現れますので、このようなテクニックは頭の片隅に置いておくと良さそうです。

# 関連記事
* [json --- JSON エンコーダおよびデコーダ](https://docs.python.org/ja/3/library/json.html)
Next.js / React + Axios – JSX に変数の中身を表示するには useState が必要のようだ

# 動かない例

axios get の値をそのまま変数として利用しようとした場合

console.log では値が得られるが 
画面には表示されない

```js
import axios from "axios";

const AxiosGet = () => {
  const fetchURL: string = "https://jsonplaceholder.typicode.com/posts/1";

  var post;

    axios.get(fetchURL).then((response) => {
      post = response.data;
      console.log(post)
    });

  if (!post) return null;

  return (
    <div>
      <h1>{post['title']}</h1>
      <p>{post['body']}</p>
    </div>
  );
}

export default AxiosGet;
```

# 動く例

動かすには変数を useState の器に入れてやる必要がある
おそらくaxiosの非同期処理が関係しているのではないだろうか

```js
import axios from "axios";
import React from 'react'

const AxiosGet = () => {
  const baseURL = "https://jsonplaceholder.typicode.com/posts/1";
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    axios.get(baseURL).then((response) => {
      setPost(response.data);
    });
  }, []);

  if (!post) return null;

  return (
    <div>
      <h1>{post['title']}</h1>
      <p>{post['body']}</p>
    </div>
  );
}

export default AxiosGet;

```

# 環境

next@13.1.1

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
Julia MacroTools

## Julia のマクロとパターンマッチ
Julia には強力なマクロ機能があるが、引数のASTを分解するのに便利なパターンマッチ機構が、言語でサポートされていないので、やや使いにくい。
[MLStyle](https://github.com/thautwarm/MLStyle.jl)を入れるとパターンマッチが使えるようになるが、構造体の分解はサポートされていない? ようで、ASTの分解にはあまり役に立たない。

## MacroTools
どうするのが正しいのか調べてみたらMaroToolsというものがあった。

https://docs.juliahub.com/MacroTools/

これは、その名の通りマクロの定義に便利な関数などをまとめたもの。

### capture
`capture` はパターンマッチを行い、パターン中に書いた変数に部分式をマッチしてくれる。

```
e = :( 
    function test(a, b)
        a + b
    end
)
```
このような関数定義式は、次のようにパターンマッチできる。
```
@capture(e, function fname_(args__) body_ end)
```
`fname_` のようにアンダースコアがついた変数がプレースホルダになり、
アンダースコア無しの変数にマッチした部分式を束縛してくれる。
また、`args__` のようにアンダースコアが複数ついた変数は、複数の部分式にマッチし、それらをベクタに入れて、アンダースコアをとった名前の変数に束縛する。

```julia
julia> fname
:test

julia> args
2-element Vector{Any}:
 :a
 :b

julia> body
quote
    a + b
end
```

また、@capture マクロ自体が真偽値を返し、失敗時にはfalseとなるので、複数のパターンのいずれかにマッチさせるような書き方も容易だ。

## 型指定
プレイスホルダにマッチするAST要素の型を指定することができる。アンダースコアの後ろに型を書く。
``` julia
# マッチする
julia> @capture(:(foo("a")), foo(x_String))
true
# マッチしない
julia> @capture(:(foo("a")), foo(x_Symbol))
false
```

複数の型のいずれかにマッチさせることもできる。
``` julia
julia> @capture(:(foo("a")), foo(x_String_Symbol))
true
julia> @capture(:(foo(a)), foo(x_String_Symbol))
true
```

文字列の場合、interpolation がある文字列はASTでの表現が違うので注意が必要。
``` julia
julia> dump(:("aa$(a)bb"))
Expr
  head: Symbol string
  args: Array{Any}((3,))
    1: String "aa"
    2: Symbol a
    3: String "bb"

julia> dump(:("aa1bb"))
String "aa1bb"
```
interpolationのある文字列には全部小文字の`string`でマッチするので、interpolationのあるなしに関わらずマッチさせるには `x_String_string`のように書く必要がある。

## Union マッチ
複数のパターンのいずれかにマッチさせることもできる。`|`でパターンを区切る。
Juliaには関数定義の際に、`function`キーワードを使用する方法としないほうほうがあるが、いずれにもマッチするようにするには以下のように書く。

```julia
@capture(ex, (f_(args__) = body_) | (function f_(args__) body_ end))
```
いずれかのパターンで使用されないプレースホルダに対応する変数には`nothing`が束縛される。

## 関数定義のパースと合成
Juliaの関数定義は大変複雑なので、パース関数`splitdef`が提供されている。

``` julia
e2 = :(
    function add(a::X, b::X) where X <: Real 
        a+b
    end     
)
```
のようにASTを定義しておいて、この関数を適用すると、パース結果の格納されたディクショナリが返される。
``` julia
julia> splitdef(e2)
Dict{Symbol, Any} with 5 entries:
  :name        => :add
  :args        => Any[:(a::X), :(b::X)]
  :kwargs      => Any[]
  :body        => quote…
  :whereparams => (:(X <: Real),)
```

逆に、このディクショナリを用意して与えると、ASTを作ってくれる関数`combinedef`も用意されている。

``` julia
combinedef(splitdef(e))
```
とすると`e`が再現される。


これらを使うと、たとえば関数名を変更する(後ろに`_2`をつける)ような関数を定義するマクロが次のように書ける。
``` julia
macro add_name_2(fdef) 
    d = splitdef(fdef)
    d[:name] = Symbol(string(d[:name]) * "_2")
    combinedef(d)
end
```
これを使って次のように定義すると、`testA` ではなく `testA_2` が定義される。
``` julia
@add_name_2 function testA(x, y)
    x + y
end 
```

splitdef がいろいろな関数定義方法に対応しているので、短い書き方でも動作する。便利。
``` julia
@add_name_2 testB(x, y) = x + y
```

## splitarg, combinearg

`splitarg`は関数定義の引数定義の解析を行い、
`(arg_name, arg_type, is_splat, default)`の形のタプルを返す。

```
julia> e = :( test(x::Integer=0) = x )
julia> splitarg(e.args[1].args[2])
(:x, :Integer, false, 0)
```

これの逆操作を行う`combinearg`も用意されている。


## Expression Walking
式をトラバースして、各ノードに対して指定された関数を適用する、`prewalk`, `postwalk` が用意されている。

## その他
他にもいろいろ用意されているようだ。
行番号情報を削る `rmlines` なども有用そう。
IRリモコン(M5stick-CPlus)で部屋の温度を快適にする（その１）

まず、筆者が現在住んでいる環境の説明をば、

>・よくあるワンルームマンション
・ワンルーム部分は約6畳
・石油ストーブ禁止
・24時間換気義務付け物件

そして

採光面がなんと北！天井高2.3mという環境にもかかわらず
エアコンの暖房システム出力は約2.2kWという貧弱スペック！！！

大体体感で２、３時間は適温に上がってくるまでかかります。
というわけで、下記の理由・目的で着手していきます。

>・会社に出かけている間エアコンつけっぱはもったいない
・効率を考えて段階的に設定温度を上げていきたい。
・M5stick-Cで遊びたかった

ということで下記を用意しておきます。

・M5stick-C(今回の肝、便利すぎる）
>M5StickC - スイッチサイエンス
https://www.switch-science.com/products/6470?_pos=4&_sid=3f94a217e&_ss=r

・IRUnit　（簡単お手軽なキット）
>https://www.switch-science.com/products/5699?_pos=5&_sid=1ef5b8ce8&_ss=r

まずはM5stick-Cの標準IR受信プログラムを動かして「detected！」と表示させます。
これはArduinoIDEのスケッチ例から入手できます。

```
#include <M5StickCPlus.h>
// select the input pin for the potentiometer
int ir_recv_pin     = 33;//受信のIOに合わせて変更
int ir_send_pin     = 32;//送信のIOに合わせて変更
int last_recv_value = 0;
int cur_recv_value  = 0;

void setup() {
    M5.begin();
    M5.Lcd.setRotation(3);
    pinMode(ir_recv_pin, INPUT);
    pinMode(ir_send_pin, OUTPUT);
    // send infrared light
    // now, you can see the infrared light through mobile phone camera
    digitalWrite(ir_send_pin, 1);
    // M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(0, 0);
    M5.Lcd.print("Test for IR receiver: ");
}

void loop() {
    // now, once you press the button on a remote controller to send infrared
    // light the screen will display "detected!"
    cur_recv_value = digitalRead(ir_recv_pin);
    if (last_recv_value != cur_recv_value) {
        M5.Lcd.setCursor(0, 25);
        M5.Lcd.fillRect(0, 25, 150, 25, BLACK);
        if (cur_recv_value == 0) {  // 0: detected 1: not detected
            M5.Lcd.print("detected!");
        }
        delay(100)
        last_recv_value = cur_recv_value;
    }
    Serial.println(cur_recv_value);
    delay(100);
}
```
これをArduinoIDEでコンパイルして流し込みます。

PC接続用のUSB-Cのケーブルは100円均一でそろえて使っています。
＠モバイルバッテリー用に購入したダイソーの60WのPD対応のものを流用しちゃってます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954102/6fe9d511-4bf7-1777-5f51-75e18a63342d.png)

赤外線センサに向かってエアコンのリモコンを押すと無事にdetected！の表示がされました。（ちっちゃいですけどね）
![IMG_2984.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954102/687bf383-0daa-366c-b8c4-027207661b39.png)

受信しているときは表示されています。

今回の記事はここまでにします。
次回はリモコンの送信コードを取得、M5stick-Cから再送信でエアコンが動かせるか確認していきます。

ここまでお読みくださりありがとうございます。
近日中にその２を投稿したいと思います。
（既に実施済みのため）
関数プログラミング

## 変換
```java
public class Main{
	public static void main(String[] args) {
		final List<String> friends = Arrays.asList("Braian", "Mike", "Neal", "Hana");
		// すべてのデータを出力
		friends.forEach((final String name) -> System.out.println(name));
		// 大文字に変換後に出力
		friends.stream().map(name -> name.toUpperCase()).forEach(name -> System.out.print(name + " "));
		System.out.println();
		// 関数を使用した場合
		friends.stream().map(String::toUpperCase).forEach(name -> System.out.print(name + " "));
}
}
```

## 検索
```java
public class Main implements differentName {
	public static void main(String[] args) {
		final List<String> friends = Arrays.asList("Braian", "Mike", "Neal", "Hana");
// 検索
		final long countFriendsStartH = friends.stream().filter(startsWithH).count();
		System.out.println(countFriendsStartH);
		System.out.println();
		final long countFriendsStartM = friends.stream().filter(startsWithLetter.apply("M")).count();
		System.out.println(countFriendsStartM);
	}
}
```
```java
import java.util.function.Function;
import java.util.function.Predicate;

public interface differentName {
	//名前がHから始まるデータのみ抽出
	final Predicate<String> startsWithH = name -> name.startsWith("H");
	//様々な文字からスタートするデータを抽出
	//String型で受け取り、Predicate型で返す。
	final Function<String, Predicate<String>> startsWithLetter = (String letter) -> {
		Predicate<String> checkStarts = (String name) -> name.startsWith(letter);
		return checkStarts;
	};
}
```
## 検索結果、適当なデータが見つからない場合
```java
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Main {

	public static void main(String[] args) {
		final List<String> friends = Arrays.asList("Braian", "Mike", "Neal", "Hana");
pickName(friends, "Z");
	}
}
```
```java
public static void pickName(final List<String> names, final String startingletter) {
		final Optional <String>foundName = names.stream().filter(name ->name.startsWith(startingletter)).findFirst();
//指定の文字列を返すformatの%sを使用
		System.out.println(String.format("A name starting with %s:%s", startingletter, foundName.orElse("No name found")));
	}
```
## 文字数の合計を算出
```java
public class Main{
	public static void main(String[] args) {
		final List<String> friends = Arrays.asList("Braian", "Mike", "Neal", "Hana");
System.out.println(friends.stream().mapToInt(name ->name.length()).sum());
}
}
```
## 比較
```java
public class Main{
	public static void main(String[] args) {
		final List<String> friends = Arrays.asList("Braian", "Mike", "Neal", "Hana");
final Optional<String> alongName = friends.stream()
				.reduce((name1, name2) -> name1.length() >= name2.length() ? name1 : name2);
		alongName.ifPresent(name -> System.out.println(String.format("longest name is : %s", name)));
	}
}
```
## 結合
```java
public class Main{
	public static void main(String[] args) {
		final List<String> friends = Arrays.asList("Braian", "Mike", "Neal", "Hana");
System.out.println(String.join(",", friends));
```

## 参考資料
Javaによる関数型プログラミング ―Java 8ラムダ式とStream
加速度センサーとGooglefitについて

テスト担当した健康管理アプリで、**ユーザーの歩数を表示する機能**がありました。

表示するための歩数を取得するロジックについて、加速度センサーとGooglefitのどちらでも実装できるという話を聞いて、
何か違いがあるのかな？と疑問に思ったのでメモとして残します。

## 加速度センサーとは？
スマートフォンの動きを検知する仕組みのことです。
別名モーションセンサーとも呼ばれます。

例えば、スマホの傾きによる画面ON/OFFやなどにも使われています。
私がテストしたアプリだと、端末を軽く振るだけで歩数を増やすことができていました。

某歩数を使ったゲーム（〇〇　GO）などでも、GPSと組み合わせて使用されているそうです。


## GoogleFitとは？

oogleが提供しているスマートフォン向け健康管理アプリです。
Android・iOSのどちらでも使用可能で、運動データを記録することができます。
Google Fitが導入されたスマートフォンを持ち歩くだけで、主に以下の4つのデータを記録できます。

・1日の運動量
・睡眠データ
・心拍数
・体重の変動


開発アプリ内に歩数を測る機能を直接実装せず、Googlefitで記録された歩数を開発アプリ側で取得し、利用できます。

## それぞれの利点(テスト中に感じた私見も含みます)


先輩曰く、開発の際、お客様からどちらの方法で実装したほうが良いのか質問されることも多いようです。
それぞれのメリット、デメリットはおおまかに下記の通りです。

### 加速度センサー
**メリット**　
- わりとリアルタイムでアプリに歩数が反映できる。ほぼ万歩計。

**デメリット**　
- 端末の電池消耗が激しくなる。


### Googlefit
**メリット**
- お客様によっては申請したくない人もいる。
(社内用のアプリだったり、ストアに上げないもの）
 =>１００人までなら申請しなくても使える！

**デメリット** 
- 申請でごちゃごちゃすることが多い。
    - 実際、申請して1ヶ月以上かかりました。申請状況の連絡自体がなかなか来ない状態でした。

- 加速度センサーよりも歩数反映までにタイムラグが若干発生する



開発アプリの目的やお客様が重視する点を踏まえて、よりよい実装方法を選択する必要がありますね。
【SwiftUI】MenuBarExtraが開かれた事を検知する

# はじめに
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">MenuBarExtraがクローズした事を検知したいのにできない<br><br>onDisappearも効かない<br>scenePhaseで検知もできない<br>NSWindow.willCloseNotificationかと思ったけど違った<br><br>どうすればいいんだ</p>&mdash; Taishin Miyamoto (@SNQ2001) <a href="https://twitter.com/SNQ2001/status/1609819544117444610?ref_src=twsrc%5Etfw">January 2, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

`menuBarExtraStyle(.window)`で閉じたことを検知したかったのですが、未だに出来ていません。
わかる方いたらコメントください。

いろいろ試してたら開いたことを検知できたので記録しておきます。

# やりかた
```swift
import SwiftUI
import Combine
import AppKit

final class AppModel: ObservableObject {
    private var cancellable = Set<AnyCancellable>()

    init() {
        NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification)
            .sink { _ in
                print("✅")
            }
            .store(in: &cancellable)
    }
}

@main
struct swiftui_menubarextra_sampleApp: App {
    @StateObject private var appModel = AppModel()
    var body: some Scene {
        MenuBarExtra {
            ContentView()
        } label: {
            Image(systemName: "folder.fill")
        }
        .menuBarExtraStyle(.window)
    }
}
```

# おわり
https://developer.apple.com/documentation/uikit/uiwindow/1621607-didbecomekeynotification

`didBecomeKeyNotification`は監視対象のウインドウが一番前に来た時に通知するもの？？かな？？
GitHub Actions で Spell Checkを行う(aspell)

# 概要
aspellを利用してスペルチェックを行う
aspellとcspellどっちがいいんですかねえ…

# ファイル配置例
```
.github
|-aspell
| |-ignore.txt
| |-run.sh
|
|-workflows
  |-aspell.yaml
```

# github actionsの設定
・pull_requestのopen時とブランチが更新されたときに実行
・ubuntuで
　contentsはreadのみ
　長時間動いてしまうと怖いのでtimeoutは1min
・PR対象のブランチをチェックアウト
　元となるブランチもfetch（mainに固定してしまっているので、元ブランチが違う場合には記述を変える必要あり）
　aspellをインストールして実行

```.github/workflows/aspell.yaml
name: aspell

on:
  pull_request:
    types: [ opened, synchronize ]

jobs:
  main:
    runs-on: ubuntu-22.04  # runner OS version
    permissions:
      contents: read
    timeout-minutes: 1
    steps:
      - name: checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: Fetch base branch
        run: git fetch origin main
      - name: aspell
        run: |
          sudo apt install -y aspell aspell-en > /dev/null 2>&1
          sh ./.github/aspell/run.sh
```
# aspellの実行
設定ファイルをわかりやすくするために
・個人辞書は小文字でsortして格納するルールとする
・git diff で変更があった部分のみチェックをする

```.github/aspell/run.sh
tail -n +2 ./.github/aspell/ignore.txt > /tmp/trimmed_ignore.txt
tr A-Z a-z < /tmp/trimmed_ignore.txt > /tmp/lower_ignore.txt
diff /tmp/trimmed_ignore.txt /tmp/lower_ignore.txt
if [ $? -gt 0 ]; then
    echo 'There is upper case words in .github/aspell/ignore.txt. please fix lower case.'
    exit 1
fi

sort -u -f /tmp/lower_ignore.txt > /tmp/sorted_lower_ignore.txt
diff /tmp/lower_ignore.txt /tmp/sorted_lower_ignore.txt
if [ $? -gt 0 ]; then
    echo 'Please sort words in .github/aspell/ignore.txt'
    exit 1
fi
rm /tmp/trimmed_ignore.txt /tmp/lower_ignore.txt /tmp/sorted_lower_ignore.txt

cp ./.github/aspell/ignore.txt ~/.aspell.en.pws
git diff origin/main HEAD | grep "^+" | tr A-Z a-z | aspell list |sort |uniq > error_spells.txt
if [ -s ./error_spells.txt ]; then
    echo 'Check the spelling. Please store in .github/aspell/ignore.txt if needed.'
    cat ./error_spells.txt
    exit 1
fi
rm ~/.aspell.en.pws
```

# 個人辞書
aspellの個人辞書だが、無視する単語を格納しているので`ignore.txt`というファイルにして格納している
run.sh内でデフォルトのファイル名に変更している
これはaspell実行時のオプションでファイル名指定でもいいかもしれない…
先頭行だけ個人辞書を表すヘッダ。残りには無視する単語を入れていく

```.github/aspell/ignore.txt(例)
personal_ws-1.1 en 0
api
aspell
cp
```

# 雑感
使い始めは毎回スペルチェックに引っかかるのでちょっと面倒
辞書が整ってくるとtypoを見つけることができたりして便利になってくる
textlintやpullリクエストへの自動コメントも入れたかったがそれはまた今度ということでここまで

# 参考
http://aspell.net/

https://qiita.com/HeRo/items/935d5e268208d411ab5a

https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit

https://dev.classmethod.jp/articles/markdown-writing-with-textlint-ci/
Apple Silicon 上の Docker で bitnami の wordpress イメージを使うには

　基本的には https://hub.docker.com/r/bitnami/wordpress の情報通りにやればいいのだけれど、ここに書いてある docker-compose.yml 通りだと Apple Silicon では上手くいかなかった。
　根本原因は arm64 用のイメージが用意されていないことである。
　なので、これを解決するために以下の3つのことを行なった。

1. Rosetta2 をインストールした
1. 公式のdocker-compose.yml上に platform を用いて amd64 を明示した
1. apache に `Mutex posixsem` を設定する

## 1. Rosetta2 をインストールする

https://matsuand.github.io/docs.docker.jp.onthefly/desktop/mac/apple-silicon/

　こちらにある通り、Docker Desktop 4.3.0 からはインストール要件から Rosetta2 が外れている。
　が、これがないと動かないものもあると思われるため、念の為インストールしておく。

```sh
$ softwareupdate --install-rosetta
```

## 2. docker-compose.yml に amd64 を明示する

　bitnami の wordpress イメージは以下のコマンドでインストールする。

```sh
$ curl -sSL https://raw.githubusercontent.com/bitnami/containers/main/bitnami/wordpress/docker-compose.yml > docker-compose.yml
$ docker-compose up -d
```

　今のままで2行目の `docker-compose up -d` コマンドを実行しても、

```
mariadb The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
wordpress The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
```

というメッセージが出てくる。
　これを出ないようにするには、 docker-compose.yml の mariadb と wordpress に、以下の行を追加する。

```diff_yaml
mariadb:
  image: docker.io/bitnami/mariadb:10.6
+ platform: linux/amd64
```

```diff_yaml
wordpress:
  image: docker.io/bitnami/wordpress:6
+ platform: linux/amd64
```

　こうすると、上記のメッセージが出てこなくなる。

## 3. apache に Mutex posixsem を設定する

　2までの処理を行なっても、実は wordpress の方は起動後にエラーでコンテナが落ちてしまい、正常に起動しない。

```sh
$ docker compose logs wordpress
```

でログを見てみると、

```sh
wordpress 06:34:57.50 INFO  ==> ** Starting Apache **
[Wed Jan 04 06:34:57.621748 2023] [core:emerg] [pid 1] (95)Operation not supported: AH00023: Couldn't create the mpm-accept mutex 
(95)Operation not supported: could not create accept mutex
AH00015: Unable to open logs
```

というエラーを最後にコンテナが落ちている。
　この `Operation not supported: could not create accept mutex` でググると、最初に出てくるのが次のページである。
https://github.com/bitnami/bitnami-docker-wordpress/issues/316
ここにあるように apache2 の設定に `Mutex posixsem` を付け加えれば良い。
そのためには、Dockerfile の RUN コマンドを用いる。
なので、次の Dockerfile を追加し、更に docker-compose.yml を次のように変更する。

```Dockerfile
FROM --platform=linux/amd64 bitnami/wordpress:6

RUN echo 'Mutex posixsem' >>/opt/bitnami/apache2/conf/httpd.conf
```

```diff_yaml
wordpress:
-    image: docker.io/bitnami/wordpress:6
+    build: .
```

　これで Apple Silicon 上の Docker で bitnami の wordpress イメージが動くようになった。
　あとは[公式の説明](https://hub.docker.com/r/bitnami/wordpress)にある volumes の設定などを忘れずに行うといいだろう。
【車輪の再発明】Enum.reduceを使ってEnum.mapを作ってみよう

Enum.mapを作ってみましょう

# ルール
　・動けばよし、速度は無視

# 作ってみよう

```Elixir
defmodule Hoge do
  def map(x, fx) do
    Enum.reduce(x, [], fn x, acc -> acc ++ [fx.(x)] end)
  end
end
```

# 実行してみる

```Elixir
iex(3)> Hoge.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
```


```Elixir
iex(4)> Enum.map([a: 1, b: 2], fn {k, v} -> {k, -v} end)
[a: -1, b: -2]
```

Enum.mapのサンプルと同じ挙動したからよさげ
Xcodeのシミュレータの時刻を9:41に固定する（スクショ用）

# SSIA

```terminal
xcrun simctl status_bar "iPhone 14 Pro Max" override --time '9:41'
```

# 補足

1. 例では`iPhone 14 Pro Max`になってますが、ここは書き換えたいシミュレータのタイトルバーの名前で置き換えてください
1. 元に戻すにはシミュレータを閉じて、改めて開けばOK
gemとbundlerについて

# はじめに
gemとbundlerについて、
ちゃんと理解できていなかったので、備忘録としてまとめる。

## gemとは
gem形式にパッケージングされたRuby用の外部ライブラリのこと。


gem形式とは
外部ライブラリのフォルダやファイルをgem形式（.gem）という１つのファイルに（パッケージング）まとめたもののこと。
参考：
https://pikawaka.com/ruby/how-gem-works#gem(gemパッケージ)とは

ライブラリとは、汎用性の高い機能を他のプログラムで呼び出して使えるように部品化して集めたファイルのこと。
ライブラリには大きく分けて標準ライブラリ、組み込みライブラリ、外部ライブラリの3種類あり、
gemは外部ライブラリにあたる。

備考：
Railsもgemパッケージとして提供されている。
他にも有名なgemとしては、ユーザ認証を簡単に実装できる「devise」、ページネーションを簡単に実装できる「kaminari」がある。

## RubyGemsとは
Rubyのパッケージ(gem)を管理するシステムで、Ruby1.9以降から標準ライブラリとしてインストールされている。
「gemコマンド」を使うことでgemのインストール／アンインストールやインストールしたgemの一覧を表示することができる。

## bundlerとは
gemのバージョンやgemの依存関係を管理してくれる「gem」
bundlerでは、GemfileとGemfile.lockを使って管理する。

Gemfileは、Railsアプリで利用するgemの一覧が載っているファイルのこと。
Gemfile.lockはRailsアプリで利用するバージョンも含めたすべてのgemの一覧が載っているファイル。
インストールしたgemと、依存関係のあるgemのバージョンも記載してくれる。


参考文献：

https://pikawaka.com/ruby/how-gem-works

https://pikawaka.com/rails/bundler

https://and-engineer.com/articles/YUP-WBAAACMAu3gq

https://universato.hatenablog.com/entry/2021/07/18/234915#:~:text=gem%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A8bundle%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89,%E3%81%ABgem%E3%82%92%E7%AE%A1%E7%90%86%E3%81%A7%E3%81%8D%E3%82%8B%E3%80%82
Next.js (React) + typescript  + axios で Property 'xxx' does not exist on type 'never'.

# エラー

```
Property 'title' does not exist on type 'never'.
Property 'body' does not exist on type 'never'.
```

と言われる

# コード例

```js
import React, {useState, useEffect} from 'react'

function AxiosGet() {
  const baseURL = "https://jsonplaceholder.typicode.com/posts/1";
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    axios.get(baseURL).then((response) => {
      setPost(response.data);
    });
  }, []);

  if (!post) return null;

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
}
```

# 解決

プロパティではなくハッシュの値として書くととりあえず回避できた
たぶん本来であれば型を正しく指定したりする必要があるかも

```js

  return (
    <div>
      <h1>{post['title']}</h1>
      <p>{post['body']}</p>
    </div>
  );
```

# 参考

https://qiita.com/esoul/items/5ac4ae8260624dde135f

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
小説「流浪の月」を読んで業務でとても大事なことを教えてくれていると思った話

こんにちは。
ご興味をもってくださりありがとうございます。
社会人になって少しずつ読書量が
増えてきました。

そこでどうせならアウトプットしちゃおうということで、第一弾を書いていきます。

第一弾は小説です。

「え、小説？笑」
と思われた方もいらっしゃるかもしれません。

確かに実用書よりは学びの密度は
薄いかもしれませんね。

ですが学びは面白く、腑に落ちないと
自身の糧にならないと思っています。

第一弾は小説ですが、非常に学びのある
小説で、自身の言動を再確認したくなるくらい、なかなか考えさせられるものです。

まず本の紹介です。

# 流浪の月
凪良ゆうさんの作品で、2022年5月13日に映画も公開されているほどの有名作品ですね。
本屋大賞も受賞されているみたいです。

![51s6tvn+mBL._AC_SY1000_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627866/f9d0bdc3-3633-9e86-a940-619235260992.jpeg)
引用：https://www.amazon.co.jp/%E6%B5%81%E6%B5%AA%E3%81%AE%E6%9C%88-%E5%87%AA%E8%89%AF-%E3%82%86%E3%81%86/dp/4488028020?ref=d6k_applink_bb_dls&dplnkId=ade96df9-8e75-4d20-87c1-0969c3b4d8e3

ここから先、ほんの少しネタバレが含まれることをご容赦ください。

この本は、小学生の家内更紗ちゃん(後は「更紗」と記述)と大学生の佐伯文くん(後は「文」と記述)が近くの公園で出会うところから物語が大きく動きます。

更紗は家庭の事情で親戚の家に引き取られることになります。
親戚の息子が更紗に嫌がらせをよくする子で、更紗はそのことが原因の1つとなって家に帰りたくなくなってしまいます。

安心するはずの家で嫌がらせを受けていたら大の大人でも家に帰るのが億劫になってしまいますよね…。

そんな心境のまま更紗は近くの公園で放課後暇つぶしするんですよね。
帰りたくないから。


そんな最中更紗は文に会います。
結構省きますが、最終的に文は更紗に「うちに来る？」と言ってしまいます。
そして更紗の合意のもと二人は同じ屋根の下で住むことになります。

端から見たら明らかに誘拐ですよね。

二人での生活はとても羨ましいくらい
穏やかで和やかに続いていきます。

更紗は心の底からこの生活が続いてほしいと思っていましたが、もちろんずっと続くわけはなく、文は誘拐罪で捕まってしまいます。


文が捕まったあと、更紗の文に対する良い印象や主張は全て、世の中から「ストックホルム症候群だね、気の毒に…。」と跳ね除けられてしまうんですよね。

ストックホルム症候群とは、人質などの被害者が、犯人の小さな親切などによって好意を抱いてしまう心的外傷後ストレス障害のことです。

読んでいて本当にもどかしい思いでいっぱいになる瞬間です。

ただ世の中の人は悪気のない善意なのです。
だからとてもタチが悪い。

更紗ももどかしい気持ちと文への申し訳なさ(犯罪者にしてしまった後悔)を抱えたまま大人になります。

ひょんなことから
刑期を終えた文と再会するのですが、
この続きもドキドキハラハラもどかし展開なので、よろしければ実際に手にとってみてくださいね。


# 本人である更紗の意見が通らない原因
お待たせしました。
ここから本題です。

なぜ今回の件の被害者本人である更紗の意見が全く通らず、世の中の人の憶測だけで事件の真相(とされるもの)が決まってしまったのか。

この原因はコミュニケーションがとてもとてもとてもとても大事なエンジニアだからこそしっかり向き合う必要があると思います。


それでは私が考える当原因を3つ挙げます。
- 更紗が被害者本人であるにも関わらず、立場がとても弱い(今回は小学生)
- 世の中の人が自身の価値観(悪く言うと偏見)を持ちながら更紗の主張を聴いている
- 一次情報をもとに判断せずに感情で判断している

原因の本質は立場、偏見、多角的視点の欠如かと思われます。

# 原因から業務への応用を考える
本質まで立ち帰れば業務にも応用できますよね。

仕事でのコミュニケーションで活用するのであれば、
- 弱い立場であるために言いにくい環境、強い立場であるために言い過ぎる環境を作らないように仕組み化する
- 物事の相場はこう決まっているとある程度当たりをつけるのは良いが、決めつけずにその場その場で考え抜く
- 相手がどう考えた上でその言動をしているのか、目に見える以外になにか理由があるのかもしれないとあらゆる可能性を考える

以上3点ですが、エンジニアだけでなく全ての仕事でのコミュニケーションに非常に大切だと思います。

# おわりに
実用書ではめくりが進みにくい私ですが、とても面白い小説だったからか、摩擦ゼロでスルスルめくってしまいました。

今度から滑るのはバナナの皮ではなく流浪の月になります。

そんな面白い小説であり、
普遍的な学びを私たちに与えてくださる
流浪の月、そして凪良ゆうさんには
とても感謝しております。

今回の学びは学んですぐに出来るものではありませんが、日々頭の片隅にでも入れて徐々に100%に近づけていきたいです。

ここまでお付き合いありがとうございました。
最後に流浪の月のamazonリンクを貼っておきます。
よろしければ手にとってみてくださいね。
→[流浪の月はこちらから](https://amzn.to/3YDt6XO)