OmniAICreator/Qiita-1.07M huggingface dataset:
LazyColumn/RowでLazyListStateにアクセスするタイミングを間違えるとパフォーマンスが悪くなる

`LazyColumn` / `LazyRow` の引数である content の `LazyListScope` 内で `LazyListState` へのアクセスすると必要以上に recompose されるようになりパフォーマンスが悪くなる場合があります。

良くない実装と改善するとしたらのコードを書いていきます。  

## コード例

### 良くない例


```kotlin
@Composable
fun VerticalList(items: List<String>, onReachedBottom: () -> Unit) {
    val listState = rememberLazyListState()
    val currentOnReachedBottom by rememberUpdatedState(onReachedBottom)
    LazyColumn(state = listState) {
        items(items) {
            Text(text = it)
        }
        if (listState.firstVisibleItemIndex + listState.layoutInfo
                .visibleItemsInfo.size == listState.layoutInfo.totalItemsCount) {
            currentOnReachedBottom()
        }
    }
}
```

`LazyColumn` の中で `LazyListState` にアクセスして何かしらの処理をしているので、`LazyColumn` が何度も recompose され続けることになりパフォーマンスが悪くなります。


### 改善例

このコードを改善するには以下の例のように `LazyListState` の分岐処理を `LazyColumn` から出してあげる必要があります。


```kotlin
@Composable
fun VerticalList(items: List<String>, onReachedBottom: () -> Unit) {
    val listState = rememberLazyListState()
    val currentOnReachedBottom by rememberUpdatedState(onReachedBottom)
    val isReachedBottom by remember {
        derivedStateOf {
            listState.firstVisibleItemIndex + listState.layoutInfo
                .visibleItemsInfo.size == listState.layoutInfo.totalItemsCount
        }
    }
    LaunchedEffect(isReachedBottom) {
        snapshotFlow { isReachedBottom }
            .collect { isReached ->
                if (isReached) {
                    currentOnReachedBottom()
                }
            }
    }
    LazyColumn(state = listState) {
        items(items) {
            Text(text = it)
        }
    }
}
```

`LazyListState`　を使用した分岐処理を `derivedStateOf` で変数として取り出すようにしています。
`snapshotFlow` にした箇所は一番下までスクロールした時に発火する処理になっています。
これで `LazyColumn` 内に処理が入らないため必要以上に recompose されなくなります。

## なぜパフォーマンスが悪くなるのか

悪い例のコードの処理を詳しく追っていくと、

- `LazyColumn` の content が処理されて表示されるアイテムの数が確定してレイアウトされる  
  - アイテムの数が確定する時に `LazyListState` が更新される
- `LazyListState`　が更新されることで `LazyColumn` の content に変更が入ることになるので再度処理が実行される

```kotlin
@Composable
fun VerticalList(items: List<String>, onReachedBottom: () -> Unit) {
    // ２.アイテム数が確定することでLazyListStateが更新される
    // ４.contentが処理されることでLazyListStateが更新されることになる
    val listState = rememberLazyListState()
    val currentOnReachedBottom by rememberUpdatedState(onReachedBottom)
    LazyColumn(state = listState) {
        // 1.item/itemsの処理がされてアイテムの数が確定する
        items(items) {
            Text(text = it)
        }
        // ３.LazyListStateが更新されたことでここやcontentの処理も更新されることになる
        // ５.再びここが更新されることになって更新が繰り返される
        if (listState.firstVisibleItemIndex + listState.layoutInfo
                .visibleItemsInfo.size == listState.layoutInfo.totalItemsCount) {
            currentOnReachedBottom()
        }
    }
}
```


という感じになるので、`LazyColumn` の content の中で `LazyListState`　を参照している場合に、常に更新されることになってパフォーマンスが悪くなります。


`LazyColumn` / `LazyRow` のパフォーマンス改善には key を設定しておくとか、そもそも Jetpack Compose は `debuggable` が有効な時には挙動が遅くなっているといった話もあります。
CentOS 8にOpenJDK 11をインストール（Azul Zulu Builds of OpenJDK）

# はじめに

Azul Zulu Builds of OpenJDKを利用してCentOS8にOpenJDK11をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Azul Platform Core](https://docs.azul.com/core/zulu-openjdk/install/rpm-based-linux#install-from-azul-rpm-repository)

## サポート

有償版のみサポート期間が明記されている。[Azul Support Roadmap \- Azul \| Better Java Performance, Superior Java Support](https://www.azul.com/products/azul-support-roadmap/)
Zulu Community時代より、無償版のサポート期間は不明。

## LOG

### レポジトリ登録

```shell-session
# yum install -y https://cdn.azul.com/zulu/bin/zulu-repo-1.0.0-1.noarch.rpm
```

### インストール

```shell-session
# cat /etc/redhat-release
CentOS Linux release 8.5.2111

# yum install zulu11-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "11.0.13" 2021-10-19 LTS
OpenJDK Runtime Environment Zulu11.52+13-CA (build 11.0.13+8-LTS)
OpenJDK 64-Bit Server VM Zulu11.52+13-CA (build 11.0.13+8-LTS, mixed mode)
```
PHPのfile_get_contents()でプロキシを指定する

PHPのfile_get_contents()でプロキシを設定する方法。

```php:コード
$proxy = array(
    'http' => array(
        'proxy' => 'プロキシサーバーのホスト:プロキシサーバーのポート',
        'request_fulluri' => true,
    ),
);
$proxy_context = stream_context_create($proxy);
return file_get_contents('https://qiita.com', false, $proxy_context);
```
Rakeタスクのメソッドと定数はどこに定義するか

##経緯

Rakeタスクの中でメソッドと定数を定義していたためリファクタリングしたかったときに参考記事が少なかったため独自で調べたこととその方法について書こうと思います。


```ruby.rake
namespace :XXXXX do
  task YYYYY: :environment do
    #リファクタリングしたい定数の集団
    CONSTANT1 = hogehoge.freeze
    CONSTANT2 = hogefuga.freeze
    CONSTANT3 = fugafuga.freeze
    CONSTANT4 = fugahoge.freeze

    ################
    # rakeタスク処理 #
    ################
  end

  #リファクタリングしたいメソッドの集団
  private

  def method1(arg)
    ...
  end

  def method2(arg)
    ...
  end

  def method3(arg1, arg2)
    ...
  end

  def method4
    ...
  end
```

##調べた方法3つ

① namespaceの外に定義 →　メソッド数が少ないならいいかも

https://teratail.com/questions/140119

② Refinementsを使う　→　今回はやりたいことと違う気がする

https://qiita.com/hanachin_/items/6cf63dd3987a60e3d264

③ libの配下にクラスを作成し切り出す　→　リファクタリングとしてもスタンダード

https://techracho.bpsinc.jp/hachi8833/2018_04_12/54738


##採用した方法

今回は上記の参考記事をもとに③の方法でリファクタリングすることにしました！
自作したクラスを読み込む方法は過去記事を参照。




https://qiita.com/kat0/items/a8a903eec4373350da32
【javascript】クラス継承

# クラス継承
Prototype継承のクラス盤
`hogehoge.prototype = Object.create(Hage.prototype)`


## case：クラスに書き換えて継承をする。
Personクラスを継承した、Japaneseクラスを作成する。


```js
//元になるコード

function Person(name, age) {
  this.name = name;
  this.age = age;
}

function Japanese(name, age, gender) {
  Person.call(this, name, age);
  this.gender = gender;
}

Japanese.prototype = Object.create(Person.prototype);

Japanese.prototype.hello = function() {
  console.log('Konnichiwa ' + this.name);
}

Japanese.prototype.bye = function() {
  console.log('Sayonara ' + this.name);
}

const taro = new Japanese('Taro', 23, 'Male');

```

#### 書き換え
```js

class Person{
  constructor(name, age){
    this.name = name;
    this.age = age;
  }
  hello(){
    console.log('hello ' + this.name);
  }
}

// extendsの後に継承元を指定する。
//extendsは`Japanese.prototype = Object.create(Person.prototype);`にあたる。
class Japanese extends Person{
  constructor(name, age, gender){
    super(name, age);　//superでPersonクラスの引数を継承
    this.gender = gender　//Japaneseクラス独自のプロパティ,親のクラスをsuperで初期化した後に記述。
  }
  hello() {
        super.hello();//親のクラスのhelloが呼び出される。
        console.log('Konnichiwa ' + this.name);
    }
  bye() {
    console.log('Sayonara ' + this.name);
}
}


const taro = new Japanese('Taro', 23, 'Male');

```

<strong>PrototypeがPersonを継承しているのが確認できる。</strong>

![スクリーンショット 2021-11-18 19.48.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378066/ce103bb9-84ca-f69c-d85c-c057d337f544.png)

# superを使ったオブジェクトリテラルの継承
1. setPrototypeOf(第一引数：継承先,第二引数：継承元)を使用し、americanオブジェクトのhello()メソッドをbobが継承
1. bobオブジェクト内でsuperを使用し、継承先のhello()メソッドを呼び出している。

```js

const american = {
    hello() {
        console.log('hello ' + this.name);
    }
}

const bob = {
    name: 'Bob',
    hello() {
        super.hello();
    }
}

Object.setPrototypeOf(bob, american);
bob.hello();
```
CentOS 8にOpenJDK 8をインストール（Azul Zulu Builds of OpenJDK）

# はじめに

Azul Zulu Builds of OpenJDKを利用してCentOS8にOpenJDK8をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Azul Platform Core](https://docs.azul.com/core/zulu-openjdk/install/rpm-based-linux#install-from-azul-rpm-repository)

## サポート

有償版のみサポート期間が明記されている。[Azul Support Roadmap \- Azul \| Better Java Performance, Superior Java Support](https://www.azul.com/products/azul-support-roadmap/)
Zulu Community時代より、無償版のサポート期間は不明。

## LOG

### レポジトリ登録

```shell-session
# yum install -y https://cdn.azul.com/zulu/bin/zulu-repo-1.0.0-1.noarch.rpm
```

### インストール

```shell-session
# cat /etc/redhat-release
CentOS Linux release 8.5.2111

# yum install zulu8-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (Zulu 8.58.0.13-CA-linux64) (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (Zulu 8.58.0.13-CA-linux64) (build 25.312-b07, mixed mode)
```
UTC dateTimePicker

https://github.com/aizwellenstan/utc-schedule

```html
<link href="https://www.jqueryscript.net/demo/Datetime-Picker-jQuery-Moment/css/datetimepicker.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js" integrity="sha512-LGXaggshOkD/at6PFNcp2V2unf9LzFq6LE+sChH7ceMTDP0g2kn6Vxwgg7wkPP7AAtX+lmPqPdxB47A0Nz0cMQ==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://www.jqueryscript.net/demo/Datetime-Picker-jQuery-Moment/js/datetimepicker.js"></script>
<div style="width: 250px;">
    <div id="picker"></div>
    <input type="hidden" id="result" value="" />
    <input type="hidden" id="clone" name="schedule" value="" />
</div>
```

```js
$(document).ready( function () {
    $('#picker').dateTimePicker();
})

String.prototype.toDate = function(format)
{
  var normalized      = this.replace(/[^a-zA-Z0-9]/g, '-');
  var normalizedFormat= format.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-');
  var formatItems     = normalizedFormat.split('-');
  var dateItems       = normalized.split('-');

  var monthIndex  = formatItems.indexOf("mm");
  var dayIndex    = formatItems.indexOf("dd");
  var yearIndex   = formatItems.indexOf("yyyy");
  var hourIndex     = formatItems.indexOf("hh");
  var minutesIndex  = formatItems.indexOf("ii");
  var secondsIndex  = formatItems.indexOf("ss");

  var today = new Date();

  var year  = yearIndex>-1  ? dateItems[yearIndex]    : today.getFullYear();
  var month = monthIndex>-1 ? dateItems[monthIndex]-1 : today.getMonth()-1;
  var day   = dayIndex>-1   ? dateItems[dayIndex]     : today.getDate();

  var hour    = hourIndex>-1      ? dateItems[hourIndex]    : today.getHours();
  var minute  = minutesIndex>-1   ? dateItems[minutesIndex] : today.getMinutes();
  var second  = secondsIndex>-1   ? dateItems[secondsIndex] : today.getSeconds();

  return new Date(year,month,day,hour,minute,second);
};

function generateDateTime(date) {
  return date.toISOString().replace("T"," ").substring(0, 19);
}

function cloneUTC() {
    var localTime = $("#result").val();
    if (localTime != "") {
      var time = localTime.toDate("yyyy-mm-dd hh:ii");
      var utcString = generateDateTime(time);
      
      $("#clone").val(utcString);
    }
}
```
CentOS 7にOpenJDK 17をインストール（Azul Zulu Builds of OpenJDK）

# はじめに

Azul Zulu Builds of OpenJDKを利用してCentOS7にOpenJDK17をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Azul Platform Core](https://docs.azul.com/core/zulu-openjdk/install/rpm-based-linux#install-from-azul-rpm-repository)

## サポート

有償版のみサポート期間が明記されている。[Azul Support Roadmap \- Azul \| Better Java Performance, Superior Java Support](https://www.azul.com/products/azul-support-roadmap/)
Zulu Community時代より、無償版のサポート期間は不明。

## LOG

### レポジトリ登録

```shell-session
# yum install -y https://cdn.azul.com/zulu/bin/zulu-repo-1.0.0-1.noarch.rpm
```

### インストール

```shell-session
# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

# yum install zulu17-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment Zulu17.30+15-CA (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM Zulu17.30+15-CA (build 17.0.1+12-LTS, mixed mode, sharing)
```
Githubにプッシュする方法

#リモートリポジトリにファイルをアップロード

ターミナルでgitコマンドを入力してリモートリポジトリにファイルをプッシュします。


###前提として...
・ターミナルでgitインストール済み
・Github登録済み


<br>
Githubで新しいリポジトリを作成します。
リポジトリ名はmyblogにします。

ターミナルに以下を順番に実行していきます。
Gitで管理するディレクトリを作成して移動します。

```
$ mkdir myblog
```
```
$ cd myblog
```


Gitで管理できるように以下を実行します。

```
$ git init
```

先程Githubで作ったmyblogリポジトリのhttpsから始まるURLをコピーしてきて、コマンドを実行します。

```
$ git remote add origin　[URL]
```
プッシュ先のリモートリポジトリを指定する為に、
以下のように書きます。

```
$ git remote add origin https://github.com/Kaana0/myblog.git　　
```

ファイルを作成してコミットします。
以下のコマンドを順番に実行します。

```
$ touch index.html
```
```
$ git add index.html
```
```
$ git commit -m "Create index.html"
```
プッシュしていきます。

```
$ git push origin master
```


無事にプッシュ出来たので、 Githubのmyblogリポジトリを確認してみましょう！
TypeScriptで相対パスのモジュールをimportしたかった

相対パスでモジュールimportしたかったので、`ttypescript`と`@zerollup/ts-transform-paths` を利用していたけど、typescriptのアップデートで壊れちゃった。

`../src/lib/paresArgv`と書かなくても、こんなかんじのができてた。

```typescript
import { parseArgv } from 'lib/parseArgv'
```

調べてみたら、同じ目にあってる人もいた。

https://github.com/cevek/ttypescript/issues/122

## ts-patch
ts-patchを導入すれば、ttypescriptと同等のことをやってくれるっぽい。

https://github.com/nonara/ts-patch

## 対応方法
雑に直した差分を貼っとく
tsconfig.jsonにbaseUrl, paths, pluginsへの設定がない人は入れときましょう。


```diff
diff --git a/package.json b/package.json
index dcf37b8..276f3df 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,9 @@
   "scripts": {
+    "prepare": "ts-patch install -s",
-    "build": "ttsc -P ./tsconfig.json",
+    "build": "tsc -P ./tsconfig.json",
@@ -25,7 +26,6 @@
-    "@zerollup/ts-transform-paths": "^1.7.18",
+    "ts-patch": "^2.0.1",
-    "ttypescript": "^1.5.12",
+    "typescript-transform-paths": "^3.3.1"

diff --git a/tsconfig.json b/tsconfig.json
index 4a4cf58..a12c084 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,7 +7,7 @@
     "outDir": "./dist",
     "rootDir": "./src",
     "strict": true,
-    "plugins": [{ "transform": "@zerollup/ts-transform-paths" }],
+    "plugins": [{ "transform": "typescript-transform-paths" }],
     "baseUrl": "src",
     "paths": {
       "*": ["*"]
     },
```

# tsonfig.json
つかってる設定ファイルもペタリ

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "ES2021",
    "module": "CommonJS",
    "lib": ["es2021"],
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "plugins": [{ "transform": "typescript-transform-paths" }],
    "moduleResolution": "node",
    "baseUrl": "src",
    "paths": {
      "*": ["*"]
    },
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "noUnusedLocals": false,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true
  },
  "include": ["src/**/*"],
  "exclude": ["dist", "node_modules"],
  "compileOnSave": false
}

```
例外処理が発生するか確認するプログラムを実装(2021年11月18日現在)

# 例外処理が発生するか確認するプログラムを実装(2021年11月18日現在)
#### インスペクターウィンドウでbool値を変更すると、例外の切り替えができるプログラムを実装する。
#### 例外処理の基本を理解しやすくなると思ったので、作成してみました。

---

## 例外の切り替えができるプログラムの実装手順
### 1.スクリプトを作成する
```c#
using UnityEngine;
using System; // try/catchブロックの使用に必要

public class ExceptionThrow : MonoBehaviour
{
    public bool exceptionFlag = false; // インスペクターウィンドウで例外の切り替えをするフラグ

    void Start()
    {
        try
        {
            if(exceptionFlag) // 例外フラグがtrueのとき
            {
                throw new Exception(); // 例外を発生させる
            }

            Debug.Log("例外無し");
        }
        catch(Exception) // 例外が発生したら
        {
            Debug.Log("例外有り");
        }
    }
}
```

#### `using System`
try/catchブロックを使用する際に必要となるusingディレクティブ。

#### try/catchブロック
tryブロックで例外が発生した場合は、発生した時点でcatchブロックの処理に移行する。

tryブロックで例外が発生しなかった場合は、tryブロックの処理を継続して、catchブロックの処理は行われない。

catchブロックの引数には任意の例外クラスを設定する。

catchブロックの引数を`Exception e`のような形にして、catchブロック内で`e.Message`のように記述しても、Unityではc#の例外メッセージを取得できなかったので`e`は省いた。

#### throw式
`throw new [任意の例外クラス]();`の形で、任意の例外を発生させることができる。(上記ではExceptionクラスを使用)

#### Exceptionクラス
アプリケーションの実行中に発生したエラーを表示するクラス。

### 2.作成したスクリプトを設定する
①ヒエラルキーウィンドウで右クリックして任意のオブジェクトを作成する。

オブジェクト名は`ExceptionCheck`にしました。
![スクリーンショット 2021-11-18 19.04.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/062d5f3a-0c77-095c-787e-c086d27e3161.png)

②作成したオブジェクトに作成したスクリプトをアタッチする。

インスペクターウィンドウの`ExceptionCheck`に`ExceptionThrow`が表示されています。
![スクリーンショット 2021-11-18 19.05.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/feb93a7d-ab95-e2ce-05f7-47437f1edb03.png)

### 3.挙動を検証する
①シーンビューのプレイボタンをクリックすると、コンソールウィンドウに例外の有無が表示される。

インスペクターウィンドウのExceptionFlagにチェックを付けていないので、`例外無し`と表示される。
![スクリーンショット 2021-11-18 19.13.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/b2cac36a-a6bc-4774-c98c-a9a96d028385.png)

②ヒエラルキーウィンドウに作成したオブジェクトを選択して、インスペクターウィンドウのExceptionFlagのチェックを付ける。

シーンビューのプレイボタンをクリックすると、コンソールウィンドウの表示が`例外有り`と表示される。
(チェックを付けると例外発生、外すと例外未発生)
![スクリーンショット 2021-11-18 19.14.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/697aab05-07c2-e518-26cb-b8a1682f22ed.png)

---

#### 上記のスクリプトをコピーして、実装手順通り進めると試せるので、よろしければどうぞ。
ターミナルを使ってGitにプッシュする

自分用に備忘録として残します。
Gitをpushしようとしてかなりつまづいたのでここに残します。

#初期設定

 ```
$ git config --global user.name "XXXX"
$ git config --global user.email "XXXX@hogehoge.com"
```
初期設定としてユーザ名とメールアドレスを登録する。

#ディレクトリを移動する
```
Desktop % cd study-react
```
cdタグを使って移動してから下記を入力する

#リポジトリを作成し、プッシュする

```
$ git init
```
すでにあるリポジトリを初期化するためのもの！
git initを行うことでディレクトリ内に.gitファイルを作成する。
（隠しファイルなので見えない)
見るには shift + command + . で表示できる！！


```
$ git add .
```
変更した内容を追加するもの!

```
$ git commit -m "コメント"
```
さっきのaddで追加したものをGitに登録するためのもの
メッセージをつけることで管理しやすくする！

```
$ git remote add origin https://github.com/XXXX/XXXXXX.git
```
自分のGithubアカウントの登録したいリポジトリのURLをはる！

```
git branch -M main
```
main ブランチを作成


```
git push origin main
```

上記の形で無事アップされた。
React NativeのiOSビルドが突然できなくなった

## 現象

ついこの間までビルドやシミュレータでのデバッグができていたのに、週明けたらできなくなってた

シミュレータは立ち上がるが、コンソールには`BUILD FAILED`が(控えめに)出て、シミュレータ上でアプリが更新されない

TestFlightに上げるための、XCode上でのビルドも失敗する

## 環境

* MacBookAir 11.4
* react-native v0.63.2

## エラー内容

```
error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by opening [プロジェクト名].xcworkspace. Run CLI with --verbose flag for more details.

...

/[プロジェクトパス]/ios/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 15.0.99. (in target 'react-native-date-picker' from project 'Pods')

** BUILD FAILED **


The following build commands failed:
        PhaseScriptExecution [CP]\ Check\ Pods\ Manifest.lock /Users/takayukiono/Library/Developer/Xcode/DerivedData/[プロジェクト名]-ccqjxurifndgxheowdqriugyxlmf/Build/Intermediates.noindex/[プロジェクト名].build/Debug-iphonesimulator/[プロジェクト名].build/Script-4DD7404CB94F2720CFD58C9B.sh (in target '[プロジェクト名]' from project '[プロジェクト名]')
(1 failure)

```

[プロジェクト名] など伏せ字はありますが、このようなエラーが出ました

--verboseをつけて `react-native run-ios --verbose` とやったら

```
fatal error: 'React/RCTBridgeDelegate.h' file not found
```

も出てきた

## 試したこと

1 キャッシュクリア
よくあるエラーを解決してくれるそう

https://zenn.dev/taizo_pro/articles/c69a167f3d5bfd

https://qiita.com/tktktktk/items/5e5ab6ffa4d368cc5225

でも、同じくエラー…

2 `fatal error: 'React/RCTBridgeDelegate.h' file not found` でググった

https://teratail.com/questions/240436

`pod install` もう一回やった

キャッシュクリアしてたから出たエラーかな？（--verboseつけて再実行したのがキャッシュクリア後だったので…）

結果、ビルド成功！

### まとめ

```
watchman watch-del-all
lsof -n -P -i :8081 -t | xargs kill
rm -rf ios/build
rm -rf android/app/build
rm -rf node_modules && npm install
rm -rf ~/Library/Caches/CocoaPods
rm -rf Pods
rm -rf ~/Library/Developer/Xcode/DerivedData
cd ios
pod deintegrate
pod setup
bundle exec pod install
```

自分はpod install失敗してたっぽいので、その後に

```
pod install
```
Python ctypes 構造体 pragma pack (push,1)

本日はPythonのctypesに関する記事です。
実用的な内容ですので是非LGTM ストックお願いします ^__^

## ctypesとは

C言語のデータ構造をPythonで扱うことができるライブラリです。
Pythonをインストールするときにこちらのライブラリは標準でインストールされます。

Cの構造体をPythonでも扱いたいときなどに非常に便利です。

> [Python ctypes 公式ドキュメント](https://docs.python.org/ja/3/library/ctypes.html)

## 事例

今回紹介する例としては、

C側：構造体のデータをバイナリでログとして出力
Python：C側で吐き出されたバイナリのログデータを読み込んで表示

PythonでCのログを解析することで2次利用（可視化や機械学習）が各段にしやすいのでマスターしたい技術です。

# pragma pack (push, 1)

C側では構造体を定義するとき、 pragma pack をよく利用します。
これをPythonで定義するためには、下記が必要なので忘れないでください。

他のサイトにあまり書かれていないので、ここに書いておきます。

```python
import ctypes

class ST_DATA(ctypes.Structure):
    _pack_ = 1 # これが必須!!!
    _fields_ = (
        # 構造体データを自由に定義
    )
```

---

それではここから事例の内容をコードで紹介します。


## C側

かなり省略して書きますのでご了承ください。構造体の部分のみ抜き出し。

```C++
#pragma pack (push,1)

typedef struct {
    long ID;
    short result;
    double data[10];
} ST_DATA
```

## Python側

```python
import ctypes
import os

class ST_DATA(ctypes.Structure):
    _pack_ = 1 # pragma pack (push, 1) と同等. これ入れないとデータがパディングされてしまう。
    _fields_ = (
        ('ID', ctypes.c_long),
        ('result', ctypes.c_short),
        ('data', ctypes.c_double*10),
    )

dataList = []

def ReadData(logFilePath:str):
    global dataList
    
    if os.path.exists(logFilePath):
        with open(logFilePath, 'rb') as f:
            readBytes = bytearray(f.read())
            print(f"readBytes len: {len(readBytes)}")
            
            logCnt = len(readBytes) / ctypes.sizeof(ST_DATA) # 構造体データが何個存在するか算出
            print(f"logCnt:{logCnt}") 
            
            # 読みだしたデータから各構造体のデータに分割
            for no in range(logCnt):
                bytesArr = readBytes[no*ctypes.sizeof(ST_DATA) : (no+1)*ctypes.sizeof(ST_DATA)]
                datum = ST_DATA.from_buffer(bytesArr) # binaryデータを構造体データに変換
                dataList.append(datum)
    else:
        print("log is not exist")

if __name__ == "__main__":
    filename = "log.bin" # 構造体データがいくつも書かれたバイナリファイル

    # ログデータを読み込む
    ReadData(filename)

    # データの取得方法 例
    print(dataList[0].ID) # 1番最初のログのIDを表示
    print(dataList[0].result) # 1番最初のログのresultを表示
    print(dataList[0].data[0]) # 1番最初のログのdataの1要素目を表示
    print(dataList[0].data[9]) # 1番最初のログのdataの10要素目を表示

```

## Python ctypes Tips

### 構造体のサイズを取得

```python
print(ctypes.sizeof(ST_DATA))
```

### byte配列から構造体データに変換

```python
# bytesTmpにはbyte配列を準備
stData = ST_DATA.from_buffer(bytesTmp)
```

### 構造体のフィールドを全て取得

```python
print(ST_DATA._fields_)
```

---

以上で本日の記事は終了です。
是非参考にしてください！

## 更新履歴

* 2021/11/18 初版
Git Hubにファイルをアップロードする方法

##はじめに
Git Hubにファイルをアップロードしようとした際、<font color="red">「remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.」</font>というエラー文が出てきた。(このエラーで悩んでいる場合は、アクセストークンを作成し、「GitHubにアップロードする流れ」の4を見てもらえると解決できるはず・・・。)

2021年8月以降、仕様が変更されていたので、この機会に備忘録としてまとめてみた。

##実行環境 
macOS Big Sur 11.6 

##Git Hubにアップロードする流れ
####０．Git Hub ホームページでリポジトリを作成 ＆ アクセストークンを作成
リポジトリの作成方法については、各自で調べてください。
#####アクセストークンの設定方法については、[GitHub docs](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)を参照されたい。(URL:2021年10月現在)　　
####１．アップロードしたいファイルがあるディレクトリに移動
####２．リポジトリを新規作成、または既存のリポジトリを初期化
```
git init
```
#####ローカルリポジトリを構成する「.git」というサブディレクトリが作成される。(cd .gitで確認可能)
リポジトリ：ファイルや変更記録を保存しておく場所<br>ローカルリポジトリ：自分のパソコン内にある保存場所<br>リモートリポジトリ：複数人でファイルや変更記録を共有するために専用のサーバ（今回はGitHub）内にある保存場所
####３．ファイルをインデックスに追加（コミットの対象にする）
```
git add .   //カレントディレクトリにある全てのファイルが追加の対象
```
######特定のファイルを追加の対象としたい場合は、以下の様にする。
```
git add [ファイル名]
```
インデックス：バージョン管理する対象のファイルやフォルダを登録しておくためのスペース<br>コミット：ファイルの追加や変更の履歴をリポジトリに保存すること
####４．インデックスの内容をローカルリポジトリに保存（コミット）
```
git commit -m "[メッセージ]" 
```
「-m」オプションを指定すると、エディターを起動せず、コミットメッセージも指定してコミットする。

####５．リモートリポジトリを追加
```
git remote add [リモートリポジトリ名]　https://[アクセストークン]@github.com/[アカウント名]/[リポジトリ名].git
```
######リモートリポジトリ名を「origin」とすることが多いため、以下の記述も載せておく。
```
git remote add origin https://[アクセストークン]@github.com/[アカウント名]/[リポジトリ名].git
```
現在のローカルリポジトリに指定したリモートリポジトリを追加する。

####６．リモートリポジトリにローカルリポジトリの内容を反映
```
git push -u [リモートリポジトリ名] [ブランチ名]
```
######[リモートリポジトリ名]を「origin」、[ブランチ名]を「master」とすると、以下の様になる。
```
git push -u origin master
```
ブランチ：リポジトリの並列バージョンのこと。プライマリブランチには影響を与えず、自由に作業できるようになる。
#####ローカルリポジトリの「master」ブランチの内容が、リモートリポジトリ「origin」の「master」ブランチに反映される。

##補足
####リモートリポジトリを削除 
```
git remote rm [リモートリポジトリ名]
```
リモートリポジトリを再度追加する際、前回追加したリモートリポジトリは削除しておく必要がある
####現在のリモートリポジトリを確認
```
git remote -v
```
####次回の目標：GitHubの更新の流れを理解する
##参考ページ
#####[サル先生のGit入門](https://backlog.com/ja/git-tutorial/)
#####[GitHub Docs](https://docs.github.com/ja)
GitLab API returning "error":"The provided content-type '' is not supported." with 415

昔は動作していたGitLab操作スクリプトが、

```
HTTP code 415
body {"error":"The provided content-type '' is not supported."}
```

という状態になっていた。クエリ(というかリクエストボディ)はa=b&c=dみたいな普通のやつ。
[211119追記：メソッドはPOSTです。]

`curl --data`は依然として動作するのでどういうことだと思ったが、`Content-Type: application/x-www-form-urlencoded`ヘッダを付けることが必須になったようだった。

(いつから必要になったのかはわかりません。)
Prism コードサンプル学習：15-FilteringEvents

# Prism コードサンプル学習：15-FilteringEvents

## はじめに

以下の記事の続きです。
<https://qiita.com/mngreen/items/8d5b906833a53af9669f>

## 15-FilteringEvents

本サンプルは、互いに依存していないモジュール間でメッセージを送受し、送られたメッセージをフィルタリングして表示することを確認するサンプルとなっています。

原則、前回の記事とほとんど変わりませんが、ModuleBプロジェクトのMessageListViewModelクラスでの処理が一部変更されています。その変更部分の中に、フィルタリングする処理が追加されています。

```cs
using Prism.Events;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using UsingEventAggregator.Core;

namespace ModuleB.ViewModels
{
    public class MessageListViewModel : BindableBase
    {
        IEventAggregator _ea;

        private ObservableCollection<string> _messages;
        public ObservableCollection<string> Messages
        {
            get { return _messages; }
            set { SetProperty(ref _messages, value); }
        }

        public MessageListViewModel(IEventAggregator ea)
        {
            _ea = ea;
            Messages = new ObservableCollection<string>();

            // 以下に引数が追加され、"Brian"宛のメッセージでないと処理が実行されなくなっている
            _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived, ThreadOption.PublisherThread, false, (filter) => filter.Contains("Brian"));
        }

        private void MessageReceived(string message)
        {
            Messages.Add(message);
        }
    }
}
```

[Subscribeの実処理](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/PubSubEvent.cs#L231)では、前回の記事と同様にactionReferenceを生成しますが、その時に追加でfilterReferenceを生成します（実体はどちらも[DelegateReference](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/DelegateReference.cs)）。
その後、それぞれのオプションによって生成されるインスタンスが異なりますが、今回指定されているオプションが[ThreadOption.PublisherThread](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/ThreadOption.cs)のため、生成されるクラスである[EventSubscription](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventSubscription.cs)クラスに注目します。
前回同様必要に応じてアクションを実行するか否かを決める処理（[GetExecutionStrategy](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventSubscription.cs#L156)）が実行されます。
この中でフィルタ実行時・アクション実行時に必要となる引数を取得し、フィルタをかけてアクションを実行するか決めていました。

## おわりに

今回は前回記事の引き続きで、イベントをフィルタするサンプルを読んでみました。
前回と異なる点はフィルタのみで大きくサンプルも異なっていませんでしたが、ジェネリックのサポートがひとつだけであったのが気になりました。何となく、FuncやActionのようにジェネリックとして渡せるものが多ければ多いほど（特にフレームワークとして提供するのであれば）便利なように思っていたのですが、実際にはひとつあれば充分との判断でしょうか。確かに、複数の引数をやり取りしたいのであればクラス化したほうが良い気もします。そのあたりのバランス感覚を磨いていくことが良いアーキテクチャをつくれるか否かにつながっていくのかな、と思いました。
次回、[16-RegionContext](https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/16-RegionContext)について見ていこうと思います。
React Router使用時の　Module '"react-router-dom"' has no exported member 'Switch'.のエラーの解決

フロントエンドでページ遷移の実装時にReact Routerを用いたところ、

```
Module '"react-router-dom"' has no exported member 'Switch'.
```
というエラーが出て、Switchやexactが使用できませんでした。

#  解決法
ターミナルでreact-router-domのバージョンを下げることで解決できました。

```
npm install react-router-dom@5
Python　filter関数でリストから欲しい値を抽出その１ -初心者メモ

numbers = [1,8,-4,9,-3,2]
numbersリストから、偶数のみを抽出します。

偶数か判定するための関数を用意。

```
def guusuu(number):
    if number %2 ==0:
        print (f'この数字,{number}は偶数です ')
        return True

    else:
        print(f'この数字,{number}は奇数です')
        return False
```

動作確認

```
guusuu(3)

>>この数字,3は奇数です

guusuu(2)

>>この数字,2は偶数です

```



では、filter関数を使用しましょう

```
filter(guusuu , numbers)

```


おや、メモリの位置らしきものが出力されました

リストに入れて出力すると、

```
list(filter(guusuu , numbers))
```
出力結果

```
この数字,9は奇数です
この数字,8は偶数です 
この数字,2は偶数です 
この数字,0は偶数です 
この数字,-3は奇数です
この数字,-4は偶数です 
[8, 2, 0, -4]
```

guusuu関数が要素数の回数、実行されて、Trueとなる値のみを格納したリストが取得できました。
【Laravel】Laravel入門第2版をMySQLで環境構築

# 0. はじめに
こんにちは、[@kazuma_dev](https://twitter.com/kazuma_dev)です。
PHPフレームワークLaravel入門第2版(通称:青本)Chapter5で、SQLiteではなくMySQLで環境構築した際のエラー対処方法です。
レビューを見る限り、chapter5の環境構築でつまづく方が多かったので下記に記します。

## 0-1. 全体の流れ
> [1.エラー内容](#1-エラー内容)
> [補足](#補足)
> [Reference](#reference)

## 0-2. 本記事の対象者
- Laravel入門第2版でMySQLを使いたい人

# 1. エラー内容
## 1-1. 前提・実現したいこと
- Laravel6系とMySQL(MariaDB)の接続

## 1-2. 発生している問題・エラーメッセージ
```
sqlstate[hy000] [1045] access denied for user 'root'@'localhost' (using password: no)
```

## 1-3. 該当のソースコード

- 公式サイトのサンプルファイルにあるテストコードは下記の通りです。書籍の通り進めていくとSQLiteを使用するため、下記のコードになるかと思います。

``` /Applications/MAMP/htdocs/laravelapp/config/database.php
        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
===中略===
        ],
```

``` /Applications/MAMP/htdocs/laravelapp/.env
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=C:\Users\tuyano\Desktop\laravelapp\database\database.sqlite
DB_USERNAME=homestead
DB_PASSWORD=secret
```


## 1-4. 試したこと
- ユーザーを作る際にホスト名を``%``ではなく``localhost``で設定(phpMyAdminトップページ→ユーザアカウント→新規作成"ユーザアカウントを追加する")
- MAMP側のDBポートも``8889``に変更

``` /Applications/MAMP/htdocs/laravelapp/config/database.php
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', ''),
            'port' => env('DB_PORT', '8889'),
            'database' => env('DB_DATABASE', 'laravelapp'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', 'root'),
            'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',
===中略===
        ],
```

``` /Applications/MAMP/htdocs/laravelapp/.env
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=8889
DB_DATABASE=laravelapp
DB_USERNAME=laravelapp
DB_PASSWORD=password123
DB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock
```

```
$ php artisan cache:clear
```

```
$ php artisan config:cache
```

```
$ rm -f bootstrap/cache/config.php
```

```
$ php artisan migrate
```

# 補足
## 開発環境（FW/ツールのバージョンなど）
|ツール|バージョン|
|:--|:--|
|PHP|7.4.1|
|Laravel|6.20.38|
|MySQL|5.7.34|
|Nginx|1.18.0|
|Composer|2.1.9|
|MAMP|-|
|MacBook Air|M1,2020|
|macOS|Monterey 12.0.1|
|Homebrew|3.3.8|

# Reference

https://www.udemy.com/course/phpbeginnertolaravel/

https://yaba-blog.com/laravel-db/

https://qiita.com/Ping/items/10ada8d069e13d729701

https://zenn.dev/kawazhki/articles/d705728e5f7d7e

https://www.shuwasystem.co.jp/support/7980html/5258.html

https://www.shuwasystem.co.jp/support/7980html/6099.html

https://qiita.com/gaogaomango/items/933a1f55004920a4323d
NCMB Flutter SDKでクエリー検索を追加しました（v2.0.6）


Flutter/Dart SDKにいくつか機能を追加しました。また、2.0.6からNull Safetyに対応しています。これに伴い、Flutter 2.12.0以降の対応になりますので注意してください。

## OR検索

クエリーのOR検索に対応しました。

```dart
var query1 = new NCMBQuery('Item');
query1.equalTo('num', 1);
var query2 = new NCMBQuery('Item');
query2.equalTo('num', 2);
var query = new NCMBQuery('Item');
query.or([query1, query2]);
var ary = await query.fetchAll();
```

## パスワード再発行用メール送信

既存会員に対してパスワード再設定用のメールを送信します。

```dart
await NCMBUser.requestPasswordReset('info@mbaas.nifcloud.com');
```

## クエリー条件の追加

クエリーを利用する際の条件は以下のメソッドが用意されています。

```dart
void equalTo(String key, Object value)
void notEqualTo(String key, Object value)
void lessThan(String key, Object value)
void lessThanOrEqualTo(String key, Object value)
void greaterThan(String key, Object value)
void greaterThanOrEqualTo(String key, Object value)
void inValue(String key, Object value)
void notInValue(String key, Object value)
void exists(String key, {bool value = true})
void regex(String key, String value)
void inArray(String key, Object value)
void notInArray(String key, Object value)
void allInArray(String key, Object value)
void relatedTo(obj, String key)
void or(List<NCMBQuery> queries)
```

位置情報系検索はまだありませんのでご注意ください。次のバージョンで追加します。

## まとめ

Flutter SDKは全NCMB APIのうち、88.2%が実装済みです。残りはスクリプト、位置情報検索などになります。Flutterを使ったアプリ開発で十分利用できるようになっていますので、ぜひ活用してください。

[ncmb | Dart Package](https://pub.dev/packages/ncmb)
【javascript】Class

# case:クラスに書き換える。
* メリット
    * メソッドの追加が簡単
    * 簡潔に書ける 

```js

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.hello = function() {
  console.log('hello ' + this.name);
}
```

#### classに書き換え

```js
//クラスを定義

class Person {
  constructor(name, age){ //コンストラクタを用意
    this.name = name;
    this.age = age;
  }

  hello(){ //メソッドの追加 > 今まではprototypeで追加していた。
    console.log('hello' + this.name)
  }
}

//呼び出し方は同じ。
const bob = new Person('bob', 22)
console.log(bob) 
>> Person {name: 'bob', age: 22}
[devise]ログイン後に遷移するページを指定

# 解決したいこと
Railsのgemであるdeviseでユーザー管理を実装する際、
ログイン後に遷移するページを指定する方法。

# 結論
after_sign_in_path_forというヘルパーを利用する。
ヘルパー内で、ログイン後に遷移させたいパスを指定する。

[Githubリンク](https://github.com/heartcombo/devise/blob/dfbed22cee617992e5f846fdef58b724b6b32ff9/lib/devise/controllers/helpers.rb)
[Documentリンク](https://www.rubydoc.info/github/plataformatec/devise/Devise%2FControllers%2FHelpers:after_sign_in_path_for)

## 実装したコード
+ deviseは導入済みで、サインアップ・サインイン・ログアウト機能は実装済
+ rails g controller usersを実行して、usersコントローラーを作成済み


config/routes.rb

```
Rails.application.routes.draw do
  devise_for :users
  resources :users, only: [:show] #追加したルーティング
end

```


app/controllers/application_controller.rb

```
　private
  def after_sign_in_path_for(resource)
    user_path(resource)
  end
```

usersコントローラーのshowアクションを呼び出すパスを設定。
privateメソッドでも問題なく動作したため、こちらに定義した。


app/controllers/users_controller.rb

```
class UsersController < ApplicationController
  before_action :authenticate_user!

  def show
    @user = User.find(params[:id])
  end
end

```
マイページ(app/views/users/show.html.erb)で、ユーザー情報を使用するため、
usersテーブルから、該当idのユーザーレコードをとってくる様に設定。
また、ログインしていないユーザーを強制的にログインページへ飛ばすため、
usersコントローラー側でauthenticate_user!を設定した。


# ヘルパーの引数resourceは何か
**結論：「ログインユーザーのレコード(インスタンス)」**


実装コードで動作確認はできた。
しかし、「resourceには何が渡されているのか？」と気になった。

binding.pryで調べてみると
resourceには、ログインユーザーのレコードが入っていた。
paramsには、ログイン時に入力した情報が乗っていた。

```
    16: def after_sign_in_path_for(resource)
    17:   user_path(resource.id)
 => 18:   binding.pry
    19: end

[1] pry(#<Devise::SessionsController>)> resource
=> #<User id: 2, email: "test@test", nickname: "テスト", created_at: "~(省略)", updated_at: "~(省略)">
[2] pry(#<Devise::SessionsController>)> params
=> <ActionController::Parameters {
　　　　"authenticity_token"=>"~(省略), 
　　　　"user"=>{"email"=>"test@test", "password"=>"ttttt1", "remember_me"=>"0"},
　　 "commit"=>"Log in",
　　 "controller"=>"devise/sessions",
　　 "action"=>"create"
　　　　} permitted: false>

```

ちなみにuserコントローラーのshowアクションに飛んだときのparams。
ちゃんとidが飛んでいた。

```

    4: def show
    5:   @user = User.find(params[:id])
 => 6:   binding.pry
    7: end

[1] pry(#<UsersController>)> params
=> <ActionController::Parameters {"controller"=>"users", "action"=>"show", "id"=>"2"} permitted: false>
```

# ヘルパーは、誰が呼び出してるのか
**結論：「sessionsコントローラーのcreateアクション」**


次は、ヘルパーの呼び出しが気になった。
authenticate_user!とは異なり、
before_actionなどで、ヘルパーメソッドの呼び出しはしていない。


まずは、Gitでsessionsコントローラーのコードを見てみる。

devise/app/controllers/devise/sessions_controller.rb

```
  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message!(:notice, :signed_in)
    sign_in(resource_name, resource)
    yield resource if block_given?
    respond_with resource, location: after_sign_in_path_for(resource)
  end
```

最後行でafter_sign_in_path_forが呼び出されている。
つまり、sessionsコントローラーのcreateアクションを動かすと、
必ず呼ばれるメソッドだと解釈した。
そのため、before_actionのような呼び出しも不要だった。

# 感想
「ログイン後に、マイページへ遷移させたい」という機能は実装できたが、
devise側でどうなっているのか、については理解しきれなかった。

目的は達成したので、これ以上ここを掘り下げることに時間を使うべきではないが、
後々理解したいと思った。

特にRails側の機能であるrespond_with resourceとlocationオプション。
また、after_sign_in_path_forのオーバーライドと
deviseController、ApplicationControllerの関係性。
プラス、deviseコントローラーに定義されているhelper内の記述など。
CentOS 8にOpenJDK 17をインストール（AppStream）

# はじめに

Application Stream(AppStream)を利用してCentOS8にOpenJDK17をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[RHEL8のパッケージ構成 - BaseOSとApplication Stream - 赤帽エンジニアブログ]( https://rheb.hatenablog.com/entry/rhel8_baseos_and_appstream)

## サポート

本手法で導入した場合、[OpenJDK ライフサイクルおよびサポートポリシー - Red Hat Customer Portal] (https://access.redhat.com/ja/articles/1457743)より、2027-10がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

2021-11-18時点では[Red Hat Enterprise Linux 8 Application Streams Life Cycle - Red Hat Customer Portal](https://access.redhat.com/node/4079021)には記載されていない。

ただし、CentOS Linux8のEOLが大きく前倒しされたので、CentOS Linux 8にこの手法でインストールした場合は2021-12-31以降は更新されなくなる。

## note

- openjdkはmoduleではなく、今までのCentOSと同じようにバージョン+パッケージ名で別れているだけの模様

## LOG

### インストール

```shell-session
# cat /etc/redhat-release
CentOS Linux release 8.5.2111

# yum install -y java-17-openjdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment 21.9 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM 21.9 (build 17.0.1+12-LTS, mixed mode, sharing)
```
gsudoをつかってwingetを運用しよう

## 初期設定

### winget 初期インストール
Microsoft Storeで[アプリ インストーラー](https://www.microsoft.com/ja-jp/p/app-installer/9nblggh4nns1)を導入する。

### gsudo 初期インストールと更新
Powershellかコマンドプロンプトを管理者特権で開いて、

```diff_powershell
> winget install -e --id gerardog.gsudo
```

## 新規インストール
1. https://winget.run/ へアクセス。
1. お目当てのアプリを探す（ここではDocker Desktopをインストールするとして進める）。
1. アプリページのHow to installにコマンドが載っているのでそれをコピーする。
1. Powershellかコマンドプロンプトを開き（Windows Terminalを使っても良い）、以下のように入力する。 

```diff_powershell
> gsudo winget install -e --id Docker.DockerDesktop
```

このあとにユーザーアカウント制御の確認ダイアログが出るので、「はい」を押すと、あとはほぼ全自動で進む。

## 更新（一般アプリ編）
### アプリの更新リスト取得
※いわゆるapt update

```diff_powershell
> winget upgrade --all
```

### 一般アプリを一斉アップデート
※いわゆるsudo apt upgrade

```diff_powershell
> gsudo winget upgrade --all
```

:::note
一部に反応しないアプリがあります。
:::
::: note alert
下記の例外系が含まれている場合は、そちらの更新を優先してください。途中で止まることがあります。
:::

### 一般アプリを単発でアップデート

```diff_powershell
> gsudo winget install -e --id XXX.XXX
```

## 更新（例外編）
### Powershell
**コマンドプロンプト**を開いて、

```
> gsudo winget install -e --id Microsoft.PowerShell
```

::: note
当たり前ですが、powershellでやると途中でコケて更新できません。コマンドプロンプトをWindows Terminal上で開くぶんには問題なく更新できますが、その前にpowershellのウィンドウは全部閉じましょう。閉じていないと同様に途中で止まって更新できません。
:::

### Windows Terminal
※一度MS Storeでインストールすれば自動更新されるので基本は何もしなくて良いです。ここに記載の内容は、あくまで速攻で更新をかけたい場合用です。

**コマンドプロンプトまたはpowershell**を**単独アプリで開いて**、

```diff_powershell
> gsudo winget install -e --id Microsoft.WindowsTerminal
```
redux-toolkitをnextjsアプリに導入する

現状reactやnextでアプリを作成するときの状態管理としてreduxを利用することが多いが、redux-toolkitを使うと実装が簡単であった。

##redux-toolkitをインストール
導入したいプロジェクトにインストール
`npm install @reduxjs/toolkit`

##sliceを作成する
redux-toolkitはsliceの中でactionとreducerを同時に書くことができる。

今回は例として、ユーザー情報を管理するauthSliceを作成する

```authSlice.ts
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

export const authSlice = createSlice({
//sliceの名前
  name: "auth",
//初期値を設定
  initialState: {
    myprofile: {
      profile_id: "",
      nickname: "",
      profileUser: "",
      image: "",
    },
  },
  reducers: {
    setMyprofile(state,action) {
      state.myprofile = action.payload
    },
  },

//reducerをエクスポートし、コンポーネント内で使えるようにする
export const {
  setMyprofile
} = authSlice.actions;

//コンポーネント内のuseSelectorで呼び出せるようにする
export const selectProfile = (state) => state.auth.myprofile;

export default authSlice.reducer;

```

##storeを作成する
store.tsを作成して、作成したsliceをstore内で呼び出す。

````store.ts
import { configureStore } from "@reduxjs/toolkit";
import authReducer from "../features/auth/authSlice";


export const store = configureStore({
  reducer: {
    auth: authReducer,
  },
});
```

##_app.tsxでstoreを呼び出す
ComponetntをProviderで囲み、storeを適用する。

```_app.tsx
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { store } from "../src/app/store";
import { Provider } from "react-redux";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  );
}

export default MyApp;

```

あとは通常のreduxの時と同様に呼び出したいコンポーネントで
useSelectorやuseDispatchを使ってstoreにアクセスすることができる。
コンタクトレンズ取ったか？を忘れないように、IFTTTを使ってLINEで通知！

#久しぶりに怒られた・・・
コロナ禍もあり、3年ほど帰っていなかった実家に、
つい先日帰省しました。
その時に、母に久しぶりに怒られ・・・
<img width="300" alt=![0938d07b.png]" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2052662/932f8ac2-6687-7f32-aecd-c1246ff904bb.png>
30過ぎてからも怒られるとやっぱり恐い（笑）
その原因が、**コンタクトを外さずに寝る**ということ。
これまで2度ほど、コンタクトを外さないまま寝てしまい、
片目が見えなくなる（現在は回復）ことがあり、
心配だからこそ叱ってくれているのですが、
そこから毎日「コンタクト取った？」と聞かれるようになりました。

#IFTTTを使ってリマインドしよう！
<img width="500" alt=![original.png] src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2052662/3443983b-2f3a-61ef-0ed4-3b1720856136.png>

そこで、最近覚えた**IFTTTを使って、LINEでリマインドし、
コンタクトを夜になったら取る**習慣を身につけようと思いました。
（きっと、親に心配させないのも親孝行。）

#タイマーをセットし、コンタクト取った？の通知が来る
お風呂入って、ちょっとゴロゴロしたいい時間が
自分の中で22時なので、
**≪トリガー≫22時になったら
≪アクション≫コンタクト取るよ！！の通知がLINEで来る**（お母さんに取るよ！！と言われているイメージ）
というアプレットを作成しました。
<img width="500" alt=![IFTTT.jpg] src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2052662/963a251a-b67a-0446-79c7-4c43888bcffa.jpeg>
ノーコードなので、サクッと完成！
通知もばっちり来ました！
![LINE2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2052662/fb96435d-190c-63a2-aab4-4306cb52c49f.png)

#ただのアラームでいいんじゃないか・・・？
ふとそう思い、IFTTTの記事をいろいろと見ていたところ、
[薬の飲み忘れ防止！？1日3回「お薬飲んだ？」とLINEで確認してくれる](https://qiita.com/mnana/items/689b5b3b4f92830404fa)の記事をを見つけました。
この記事の中で、
>使ってみた
>父、母、私の3人に導入してみた。（主に使うのは父）
>使い方もシンプルなので、説明も特に不要で理解してくれた。
>（中略）
>初日以降、父から「薬飲んだ？」に対して返信が来るようになったので、ちゃんと利用してもらえている様子。
>家族から、えらい！スタンプを送ったりするとやる気に繋がりやすいかもしれない。
>あまりストレスにならない程度に継続して利用してもらうようにするのが今後の課題。

**なるほど、できたかできていないかを、誰かと共有することが大事なんだなと気付きがありました。**
最初は通知で自分の習慣になればと思っていたのですが、
お母さんに見張られていたら、確かに確実にやる・・・！

#早速お母さんに報告
通知とか言われる前にちゃんと取ってほしいんだけどね・・・と
ちょっと笑いながら飽きられました。

そこで受けたフィードバックは、
**・22時は寝ているので、もう少し早い時間にやってほしい
・もう1つ心配があって、使い捨てコンタクトを期限通り捨てているかということ**
でした。

#フィードバックをうけて
**時間は変えられそうなので、調整していきたい**と思います。
今回の場合は、私が忘れないようにするのはもちろんですが、
ちゃんと取ったよ！とお母さんを安心させるのが目的なので、
**使う人にとって最も効果的な時間を設定すること**

そして、30年以上見ているだけあって、期限を超えて使っていることもバレている・・・。
![original2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2052662/896ff3ba-9c92-d68a-3522-0f9b100de732.png)
ということで、**追加で毎週月曜日にコンタクト捨てた？の通知が来るように追加で作成**しました。

主題がしょうもないですが、健康第一にお母さんを心配させない！
というのと、ちゃんと親孝行していきたいと思います！
バリデーションでエラーが出た後モーダルを自動で表示

ブレード側

```php
    @if ($errors->any())
        <script src="{{ asset('js/modal.js') }}"></script>
    @endif
```

public/js配下にjsファイルを作成

```modal.js
$(function () {
    $('#exampleModal').modal();
});
```
Ubuntu 20.04にOpenJDK 17をインストール（OS標準）

# はじめに

Ubuntu20.04にOpenJDKを標準インストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)

## サポート

~~[Java Is Still Free](いくつかのベンダがOpenJDK17の長期サポートを表明しているため、OS EOLとなる2025-04まではサポートされると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。~~

[OpenJDK\-Updates \- Ubuntu Wiki](https://wiki.ubuntu.com/OpenJDK-Updates) より、TLSバージョンとしてOS EOLまで保守されると思われる。

Extended Security Maintenanceで保守されるか不明。（過去バージョンでは保守されなかった）
[SecurityTeam/ESM/20\.04 \- Ubuntu Wiki](https://wiki.ubuntu.com/SecurityTeam/ESM/20.04) に記載される見込み。


## LOG

### インストール

// 2021-11-18時点だとエラーが出る

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

# apt update;apt install -y openjdk-17-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment (build 17+35-Ubuntu-120.04)
OpenJDK 64-Bit Server VM (build 17+35-Ubuntu-120.04, mixed mode, sharing)
```
Ubuntu 18.04にOpenJDK 17をインストール（OS標準）

# はじめに

Ubuntu18.04にOpenJDKを標準インストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)

## サポート

いくつかのベンダがOpenJDK17の長期サポートを表明しているため、OS EOLとなる2023-04まではサポートされると思われる。


## LOG

### インストール

// 2021-11-18時点ではいくつかエラーが出る

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.6 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.6 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

# apt update;apt install -y openjdk-17-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment (build 17+35-Ubuntu-118.04)
OpenJDK 64-Bit Server VM (build 17+35-Ubuntu-118.04, mixed mode, sharing)
```
After Effects 文字を円に沿うように丸く

#■円に沿って文字表示
![スクリーンショット 2021-11-18 17.16.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/040ec4b8-d712-3a7e-eb7f-03790d64a5a9.png)

①テキストを書く
②テキストの中で円のマスクを作成
③文字を表示したい場所にマスクを移動
④パスのオプションを作成した円のマスクに設定
この時点で
![スクリーンショット 2021-11-18 17.46.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/e6bf986f-d961-b69a-4f1a-6775a7841de8.png)
⑤最初のマージンの数値をいらうと円を沿って文字が移動する。

参考サイト
https://www.curioscene.com/simple-logo-using-trim-path/
音声を再生したり、さらには録音したりするプログラムを何本か作った

---
### 音声再生、録音するプログラム

ずっと以前から、コマンドラインから呼び出せる音声再生、さらには録音するプログラムをいくつか作った。

ので・・・まとめてみた

- [IBM ProTalker97 ActiveX OCX を使った音声読み上げ ActiveX DLL](http://rocketeer.dip.jp/sanaki/free/free83.htm)
- [サウンド・ファイル(wav)を再生する ActiveX DLL & コマンド](http://rocketeer.dip.jp/sanaki/free/free65.htm)
- [WMPを使ったCUIなサウンドプレーヤー](http://rocketeer.dip.jp/sanaki/free/free161.htm)
- [NAudioを使ったコマンドラインで録音/再生をするプログラム sNAudioCUI](http://rocketeer.dip.jp/sanaki/free/free163.htm)
- [サウンドレコーダーの代替としての StreamRelay.jar](https://qiita.com/tomoki0sanaki/items/a18d7cd08f8c1c78692d)
- [サウンドレコーダーの代替としての StreamRelay.NET.exe](https://qiita.com/tomoki0sanaki/items/7b5260b09803ceee074b)
- [サウンドレコーダー/サウンドプレーヤーの代替としての StreamRelay.NET.exe(NAudio)](https://qiita.com/tomoki0sanaki/items/14233d101f970ee8bbd1)

---
### IBM ProTalker97 ActiveX OCX を使った音声読み上げ ActiveX DLL

昔、IBMがテキストを読み上げるActiveX(COM)を公開していて、そのラッパーです。
なので、WSH(Cscript.exe)から、CreateObjectすれば、コマンドラインからテキストファイルを読み上げる(音声再生する)ことができるというものです。

---
### サウンド・ファイル(wav)を再生する ActiveX DLL & コマンド

これは、VisualBASIC6.0のMCI コントロール、またはWindowsMediaPlayerコントロールをActiveX DLLとしてラップしたものです。
なので、WSH(Cscript.exe)から、CreateObjectすれば、コマンドラインからwave形式やMP3形式またはAudioCDの再生ができるというものです。
同梱しているもう一つのsComSoundPro.dllは、録音もできるようになっています。

---
### WMPを使ったCUIなサウンドプレーヤー

WindowsMediaPlayerのコンポーネントを.NET Framework2/4から呼び出しているだけです。
WMP経由なので、AudioCDや、音声ファイルのフォーマット自動判別なども可能です。

こちらは「[Windowsを目覚まし時計にする](https://qiita.com/tomoki0sanaki/items/06777109ea07243d8af6)」でも紹介しています。

---
### NAudioを使ったコマンドラインで録音/再生をするプログラム sNAudioCUI

[NAudio](https://github.com/naudio/NAudio)という.NET のサウンドライブラリを用いて音声の再生や録音を行えるコマンドライン形式のプログラムです。

---
### サウンドレコーダーの代替としての StreamRelay.jar

StreamRelay は[リンク先](https://qiita.com/tomoki0sanaki/items/a18d7cd08f8c1c78692d)を参照してほしい

---
### サウンドレコーダーの代替としての StreamRelay.NET.exe

StreamRelay.NET.exe は[リンク先](https://qiita.com/tomoki0sanaki/items/7b5260b09803ceee074b)を参照してほしい

---
### サウンドレコーダーの代替としての StreamRelay.NET.exe(NAudio)

StreamRelay.NET.exe は[リンク先](https://qiita.com/tomoki0sanaki/items/14233d101f970ee8bbd1)を参照してほしい

---
### 関係しそうなリンク

- [Windowsを目覚まし時計にする](https://qiita.com/tomoki0sanaki/items/06777109ea07243d8af6)

コマンドラインで音声再生したいってモチベーションって、スケジューラー(コマンドライン)で、音声ファイル(mp3ファイル)を再生したいだけだったりするんだな。

---
### 以上
WSL2（Ubuntu 18.04）でnpm installがfetchMetadataから進まなかった話

# はじめに

WSL2（Ubuntu 18.04）を自分のWindows 10環境に導入して、Node.jsのアプリの環境構築のために`npm install`をしたら、`fetchMetadata` と表示されてから処理が止まってしまう現象に遭遇しました。
私の場合は、（多分）DNSの名前解決が出来ていないことが原因でした。 

# 試すこと
- `registry.npmjs.org`にpingが通るか  
 →通らない場合、解決方法に進む

```
ping registry.npmjs.org
```

# 解決方法

名前解決が出来ていないので、下記の記事を参考にGoogle の DNS サーバー 8.8.8.8 を利用する設定する。
[WSL2 で dns の名前解決ができなくなって ネット接続できなくなった場合の対処方法](https://qiita.com/kkato233/items/1fc71bde5a6d94f1b982)

これでpingが通るようになって、npm installも実行できるようになるはずです。

```
$ ping registry.npmjs.org
PING registry.npmjs.org(2606:4700::6810:1b23 (2606:4700::6810:1b23)) 56 data bytes
64 bytes from 2606:4700::6810:1b23 (2606:4700::6810:1b23): icmp_seq=1 ttl=53 time=12.6 ms
64 bytes from 2606:4700::6810:1b23 (2606:4700::6810:1b23): icmp_seq=2 ttl=53 time=26.4 ms
```

**注意**
記事に書いてあるWSLのシャットダウンは必ずしてください。  私はこれを見落として（無視して）WSL側の設定だけをしてうまく行かず、時間を無駄にしました。
>コマンドプロンプトから WSL をシャットダウンさせる。
wsl --shutdown