OmniAICreator/Qiita-1.07M huggingface dataset:
Kindle × notion 連携

# 初めに
Kindleとnotionを連携することで、マーカーした部分をまとめてnotionにまとめてくれたりとめちゃ便利ですが、設定がわかりにくいのが難点。
今回は写真付きでまとめてみました。
スマホのスクショなのでみずらいかもです。。

# booknotionのインストール
Kindleとnotionを連携してくれるアプリ
https://apps.apple.com/tt/app/booknotion/id1619994087

# インテグレーショントークンを発行
### 「インテグレーショントークンを設定する」をクリック

![IMG_1990.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/92047c78-ac67-5db0-bf1a-138a8ecdf710.jpeg)


### 「新しいインテグレーション」をクリック
（スマホレスポンシブ対応してないっぽいので、横にするのがおすすめ。。）
![IMG_1992.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/9c312d59-0009-44d3-ff18-6edaf5885116.jpeg)

### 名前の入力と、ワークスペースの選択　の2点で、他はそのままで、送信。
![IMG_1993.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/9e4c8839-c63a-37c0-d7b3-c6f2cb071134.jpeg)
![IMG_1994.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/e42c5388-698e-f394-ce03-ff7324799cec.jpeg)
### すると、トークンが発行されるのでコピーする。
![IMG_1996.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/e0b97e71-28d5-4c0e-0575-372ba4c0f3bc.jpeg)
### コピーしたトークンを貼り付けて保存
![IMG_1997.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/5b0caff7-3e6b-afef-ead8-dacc157bb844.png)

# notionとKindleの連携
### notion側で新規ページを作成し、右上の辺りのアイコンを押す
![IMG_2004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/e919a754-9c34-28b9-dc50-d90eea093de9.jpeg)

### 自分ユーザー名を選択し「招待」をクリック
![IMG_2002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/98020f9a-f9a6-8d50-bff3-309e90c76bbe.jpeg)

### 同じページから、ページリンクをコピーする
![IMG_2005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/85d4def2-d7ba-302c-14a3-95a0c5855b78.jpeg)
![IMG_2006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/6af6dad3-af1a-2e2b-72ef-50d9eb1caa5d.jpeg)

### 「データベースを作成する」をクリックし、先ほど「コピーしたリンクのURL」に含まれている、**作成したページ名以降の32文字**を入力して完了

![IMG_1998.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/06994fbb-1f79-f88a-58b4-7bef4f1d7a6d.jpeg)
![IMG_2008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/b5680f05-cfd1-fb5d-3e29-6f8cd63ee107.jpeg)

# 終わりに
Twitterでも情報発信しておりますので、ぜひフォローお願い致します!
https://mobile.twitter.com/tatsuki_kt
ネットワーク構築 #2(OSPF設定)

# 今回の内容
･R1とR2をospfで繋げる
実施日:2022/06/11～2022/06/25
# 1.設定項目(R1)
```
R1(config)#int fa 1
R1(config-if)#ip address 192.168.2.254 255.255.255.0
R1(config-if)#exit
R1(config)#router ospf 1
R1(config-router)#netowrk 192.168.2.254 0.0.0.0 area 0
R1(config-router)#router-id 1.1.1.1
R1(config-router)#exit

R2(config)#int fa 0
R2(config-if)#ip ospf priority 255
R2(config-if)#end
R2#clear ip ospf process fa 0
R1(config-if)#ip ospf priority 255
R1(config-if)#end
R1#clear ip ospf process

R1(config)#int loopback 0
R1(config-if)#ip address 1.1.1.1 255.255.255.255
R1(config-if)#exit
```
# 2.設定項目(R2/R3)
※R3も同じ設定、値に関しては192.168.3.0/24でセグメント作成
```
R2(config)#int fa 0
R2(config-if)#192.168.2.253 255.255.255.0
R2(config-if)#exit
R2(config)#router ospf 1
R2(config-router)#netowrk 192.168.2.253 0.0.0.0 area 0
R2(config-router)#router-id 2.2.2.2
R2(config-router)#exit

R2(config)#int fa 0
R2(config-if)#ip ospf priority 255
R2(config-if)#end
R2#clear ip ospf process

R2(config)#int loopback 0
R2(config-if)#ip address 2.2.2.2 255.255.255.255
R2(config-if)#exit
```
# 3.結果
R1とR2でDRとBDRが選出されていることを確認しました。
確認したコマンド
```
R1#show ip ospf neighbor
Neighbor ID     Pri   State           Dead Time   Address         Interface
2.2.2.2         255   FULL/DR         00:00:39    192.168.2.253   FastEthernet1
R2#show ipospf neighbor
Neighbor ID     Pri   State           Dead Time   Address         Interface
1.1.1.1         255   FULL/BDR        00:00:37    192.168.2.254   FastEthernet0
```
もう1台ルーターがないと、ospfのNW環境の構築が不十分ですので、近日中にもう1台用意して
構築してみたいと思います。

2022/07/10追記
ルーターを1台追加し、3台となりました。
以下、それぞれのルーターから見たneighborの状態です。

```
R1#show ip ospf neighbor
Neighbor ID     Pri   State           Dead Time   Address         Interface
2.2.2.2         255   FULL/DR         00:00:32    192.168.2.253   FastEthernet1
R2#show ipospf neighbor
Neighbor ID     Pri   State           Dead Time   Address         Interface
3.3.3.3         255   FULL/DR         00:00:31    192.168.3.253   FastEthernet1
1.1.1.1         255   FULL/BDR        00:00:34    192.168.2.254   FastEthernet0
R3#show ip ospf neighbor
Neighbor ID     Pri   State           Dead Time   Address         Interface
2.2.2.2           1   FULL/BDR        00:00:37    192.168.3.254   FastEthernet0
```

LSAが格納しているリンクステートデータベース（LSDB）の要約情報
```
R1#sh ip ospf database
            OSPF Router with ID (1.1.1.1) (Process ID 1)
                Router Link States (Area 0)
Link ID         ADV Router      Age         Seq#       Checksum Link count
1.1.1.1         1.1.1.1         631         0x80000004 0x005EF5 1
2.2.2.2         2.2.2.2         1551        0x80000009 0x002939 2
3.3.3.3         3.3.3.3         1552        0x80000002 0x00D173 1
                Net Link States (Area 0)
Link ID         ADV Router      Age         Seq#       Checksum
192.168.2.253   2.2.2.2         724         0x80000002 0x002497
192.168.3.253   3.3.3.3         1552        0x80000001 0x00515E
```

# 更新履歴
**2022/07/10**
･ルーターR3を追加
･設定項目をR2と同じに設定

**2022/07/31**
･ルーターR4を追加
･設定項目をR3と同じに設定
R2とR3のエリア間をエリア0からｴﾘｱ1に、R3とR4のエリア間をエリア2に変更
Vueper Slides(Vue3)でasync使用のautoplay(fade)でハマった件

setupにasyncを使用している場合は問題なくautoplayが使用できるけど、onMountedでasyncすると、下記エラーで自動再生できなかったので解決までの半日を記録しておきます。（Vue3の知識も浅いので、組み方がうんこすぎて他の人には再現できないかもね！）

```javascript:error
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'duration')
```

# autoplayをscript内で実行
上記エラーよりdurationの値を設定してみたが全く変化なし。
ドキュメントを確認して「resumeAutoplay」なるものの存在を確認。（ここまで2時間）
https://antoniandre.github.io/vueper-slides/

```vue:template
<button @click="$refs.myVueperSlides[`${autoPlaying ? 'pause' : 'resume'}Autoplay`]();autoPlaying = !autoPlaying">
  {{ autoPlaying ? 'Pause' : 'Resume' }}
</button>
```
script内で実行する必要があるので、refを使用することでtemplate内の$refsと同じことが出来る事を知る。（ここまで3時間）
サンプルソースを書いておきます。（一部抜粋）
```vue:script
<script>
import { reactive, onMounted, ref } from "vue";
import "vueperslides/dist/vueperslides.css";
import { VueperSlides, VueperSlide } from "vueperslides";

export default {
  name: "HomeView",
  components: {
    VueperSlides,
    VueperSlide,
  },
  setup(props, context) {
    const { getJson } = ComFunc();
    const myVueperSlides = ref(null); //autoplay対策
    const reacObj = reactive({
      mainSlider: {},
    });

    onMounted(async () => {
      //JSON取得
      const json = await getJson();

      //メインスライダー
      reacObj.mainSlider = Object.keys(json.main_slider).map(function (key) {
        return {
          img_path: json.main_slider[key].img_path,
          href: json.main_slider[key].href,
        };
      });
      myVueperSlides.value.resumeAutoplay();//ここがポイント
    });
    return {
      myVueperSlides,
      reacObj
    };
  },
};
</script>
```
この段階でautoplayが動作して一件略着かと思いきや、一枚しか再生されないというトラップが発動。（ここまで4時間）
Verが<b>3.4.０</b>だったので、最新の<b>3.4.2</b>がめっちゃ最近リリースされてたので、package.jsonを修正して、npm install。その後、template内の記述にも<b>autoplay</b>を追記することで、無事に機能しましたとさ。

```vue:template
<vueper-slides ref="myVueperSlides" fade autoplay>
```
以上、参考になれば幸いです。

追記：fadeを指定した時の現象みたいです。
Laravel タスクスケジュールを使う

## はじめに
毎日0時にある処理をしたい、といったような時に使えるのがLaravelのタスクスケジュールです。
このタスクスケジュールの使い方について記載します。

## 参考にしたページ
- [Laravel 8.x タスクスケジュール　-ドキュメント](https://readouble.com/laravel/8.x/ja/scheduling.html)

## 環境
- Laravel 8.x

## スケジュールの定義の仕方

スケジュール（時間指定）するタスクは`App\Console\Kernel`クラス（ファイル）の`schedule`メソッドで定義できます。

```php
class Kernel extends ConsoleKernel
{
    /**
     * アプリケーションのコマンド実行スケジュール定義
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
           // ここにスケジュールしたいタスクを記入
           // 例: messageテーブルを削除する
           DB::table('message')->delete();
        })
        -> // ここに指定間隔を記載
           // 例: 毎日深夜12時に実行 
          daily();
    }
}
```
- イベントもタスクに指定できます。
```php
event(new イベント名())
```

### タスクスケジュールを指定するメソッド
- [繰り返しのスケジュールオプション -ドキュメント](https://readouble.com/laravel/8.x/ja/scheduling.html#schedule-frequency-options)
ドキュメントにまとめて記載してあります。

ここではよく使うと思われるものを抜粋して記載します。

| メソッド | 説明 |
|:-:|:-:|
|  ->everyMinute(); |  毎分タスク実行 |
|  ->hourly(); | 毎時タスク実行  |
|  ->daily(); |  毎日深夜12時に実行 |

時間、曜日等を指定して、細かく調整したスケジュールを作成できます。
詳しくはドキュメントを参照ください。

## スケジュールをローカルで実行
下記コマンドでスケジュールを実行することができます。
コマンドを終了するまで1分ごとにスケジュールを呼び出すことができます。

```bash
php artisan schedule:work
```
## おわりに
毎日0時にある対象が指定の条件を満たす場合に通知メールを送りたい！といったときに、タスクスケジュールが使えました。
Laravelの機能を余すことなく使いこなせるようになりたいです。
Windowsで文字コード変換

Windowsで文字コード変換するクラス。探したらいっぱい出てくるやつです。

```C++:EncodingConverter.h
#pragma once
#include <string>

class EncodingConverter
{
public:
	static std::string SJISToUTF8(std::string src);
	static std::string UTF8ToSJIS(std::string src);
};
```

```C++:EncodingConverter.cpp
#include "EncodingConverter.h"
#include <Windows.h>
#include <string>
#include <vector>

static std::wstring ConvertToUnicode(UINT cp, std::string src)
{
    const DWORD dwFlags = 0;
    const int srcLength = static_cast<int>(src.length());
    const int dstLength = MultiByteToWideChar(cp, dwFlags, src.c_str(), srcLength, NULL, 0);
    if (dstLength <= 0) return L"";

    std::vector<wchar_t> dst(dstLength + 1);
    MultiByteToWideChar(cp, dwFlags, src.c_str(), srcLength, &dst[0], dstLength);
    return std::wstring(&dst[0], dstLength);
}

static std::string ConvertFromUnicode(UINT cp, std::wstring src)
{
    const DWORD dwFlags = 0;
    const int srcLength = static_cast<int>(src.length());
    const int dstLength = WideCharToMultiByte(cp, dwFlags, src.c_str(), srcLength, NULL, 0, NULL, NULL);
    if (dstLength <= 0) return "";

    std::vector<char> dst(dstLength + 1);
    WideCharToMultiByte(cp, dwFlags, src.c_str(), srcLength, &dst[0], dstLength, NULL, NULL);
    return std::string(&dst[0], dstLength);
}

std::string EncodingConverter::SJISToUTF8(std::string src)
{
    std::wstring unicode(ConvertToUnicode(CP_THREAD_ACP, src));
    return std::string(ConvertFromUnicode(CP_UTF8, unicode));
}

std::string EncodingConverter::UTF8ToSJIS(std::string src)
{
    std::wstring unicode(ConvertToUnicode(CP_UTF8, src));
    return std::string(ConvertFromUnicode(CP_THREAD_ACP, unicode));
}
```
【#11 エンジニア転職学習】Linux基礎  シェルスクリプト基礎 if / for

# はじめに
富山県に住んでいるChikaといいます。
毎日投稿を目標に、バックエンドエンジニア転職に向けた学習内容をアウトプットします。

連日になりますが、Linuxの基礎を進めましたので自分なりに気になったポイント等をまとめていきます。

バックエンドエンジニアになるまでの学習内容は以前投稿した以下の記事を基にしています。


https://qiita.com/Chika110/items/ef54dddd565a0193ef44

# 本日の学習内容
本日はシェルスクリプトの基礎を学習しました。実行方法や基本文法と、制御構文のifとfor文でした。

* シェルスクリプト基本
* **if文・for文　←Topic!!**


# if文・for文
#### そもそもシェルスクリプトとは
コマンドラインをあらかじめ記述しておくファイルのことです。そのため**同じ処理を何回も実行**したり、**他人に同じ処理を共有**するときに、**作業ミスすることなく**実行できるメリットがあります。
また、サーチパスを通しておけば通常のコマンドと同様に、ファイル名を入力するだけでコマンド実行が可能です。

ファイル内に複数行分のコマンドを組み合わせて、一連の処理が行えるためプログラミング言語のような**制御構文が存在**します。
以下本日学習したif・for文の気になった点をまとめました。

* **ifの後ろにはコマンド**を書く必要がある
* 記号に見える`[]`も中に**条件式を記入するコマンドの1つ**
* ifはコマンドの終了ステータスをもとに、真か偽のどちらの処理をするか判断している(正常に終了すれば0が返る)
* `for i in $(seq 0 5)`で0から5までの**for range文と同じ処理**ができる

使用している書籍はこちら↓

https://www.amazon.co.jp/%E6%96%B0%E3%81%97%E3%81%84Linux%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E4%B8%89%E5%AE%85-%E8%8B%B1%E6%98%8E-ebook/dp/B072K1NH76/ref=sr_1_1?adgrpid=113196705062&gclid=Cj0KCQjwzLCVBhD3ARIsAPKYTcR4WAb_4QVrwuBM_1mIPMFsQ6kNDJ-o4yIofVSAI7_eHpWCeva8kKwaAstgEALw_wcB&hvadid=489559881279&hvdev=c&hvlocphy=1009363&hvnetw=g&hvqmt=e&hvrand=10125867468998217428&hvtargid=kwd-1152146940662&hydadcr=21814_10996132&jp-ad-ap=0&keywords=%E6%96%B0%E3%81%97%E3%81%84+linux+%E3%81%AE+%E6%95%99%E7%A7%91%E6%9B%B8&qid=1655473534&sr=8-1




# おわりに
最後までお読みいただきありがとうございました。
明日もLinuxシェルスクリプトの続きを行います。
アドバイス・応援コメント等いただけますと幸いです。
StackBlitzの導入からGitHub同期まで

## StackBlitz アクセス

<https://stackblitz.com/>  
![image](https://user-images.githubusercontent.com/38905609/175761711-bb471212-737f-4d23-abf8-b39434808113.png)

## StackBlitz の特徴

- Webブラウザ上の開発環境
- 環境構築が不要
- Angularに対応

## StackBlitz設定

- GitHubサインイン  
プロジェクト情報を保存するにはGitHubサインインが必要
![image](https://user-images.githubusercontent.com/38905609/175762836-b3c308fb-f4dc-4a4b-9ce4-7c65aa8cd4c2.png)

- プロジェクトの作成
![image](https://user-images.githubusercontent.com/38905609/175762349-c9482a59-415c-4342-8dd3-7ea053f91f41.png)
![image](https://user-images.githubusercontent.com/38905609/175762417-682de366-759f-4c6b-88a1-2df6fdf3a2da.png)

- テーマ設定  
![image](https://user-images.githubusercontent.com/38905609/175762514-c6ac62fc-7856-43fb-aa54-2ea58f90bde9.png)
![image](https://user-images.githubusercontent.com/38905609/175762541-5495b721-b925-4b22-9602-92421a96ae6e.png)
☝私はこちらの方がしっくり来ます。

## 既存GitHubリポジトリのオープン

下記URLで既存GitHub登録プロジェクトをStackBlitzから開くことができます。  
`https://stackblitz.com/github/___YOUR_PATH___`  

例)  
<https://stackblitz.com/github/jun-knd/material.angular.github/tree/material>  
"Open in StackBlitz" のリンクを付ける場合は以下  

```html
<a href="https://stackblitz.com/github/___YOUR_PATH___">
  <img
    src="https://developer.stackblitz.com/img/open_in_stackblitz.svg"
    alt="Open in StackBlitz"
  />
</a>

👇例  
<a href="https://stackblitz.com/github/jun-knd/material.angular.github/tree/material">
  <img
    src="https://developer.stackblitz.com/img/open_in_stackblitz.svg"
    alt="Open in StackBlitz"
  />
</a>

```

👇例  
[![image](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/jun-knd/material.angular.github/tree/material)

![image](https://user-images.githubusercontent.com/38905609/175762960-cfc55b38-550b-4666-a18f-d4f6c3dc22bb.png)

## Fork してローカルリポジトリを生成

![image](https://user-images.githubusercontent.com/38905609/175763011-3be8d7e6-ed66-463a-a97f-ff21e15710b1.png)

## GitHubリポジトリを作成し接続

- Connect Repository  
![image](https://user-images.githubusercontent.com/38905609/175763065-472ae66b-5476-4423-9642-8bd6f6384664.png)

- Create repo&push  
![image](https://user-images.githubusercontent.com/38905609/175763134-47f378d2-d392-4346-9787-69d0e725db4d.png)

- GitHubに同期されたプロジェクトになる
![image](https://user-images.githubusercontent.com/38905609/175763288-ad2427af-b5e4-4d91-8ce1-a8276839e8bd.png)

- トップページにアクセスすると、作成したProjectがPROJECTSに表示される。
![image](https://user-images.githubusercontent.com/38905609/175763355-f483a113-c0ea-4a49-abe6-b4cda57cd035.png)

## 👇参考

- <https://developer.stackblitz.com/docs/guide/open-from-github/>
Spring Boot Controller呼び出し時のログ出力をInterceptorで共通化する

# Controller呼び出し時にログを出す処理を共通化する
Interceptorを利用します。

### 環境
- Spring Boot
- Kotlin

## 手順1
Interceptorを実装

- `HandlerInterceptor`インターフェースを実装
- `preHandle`メソッドをOverride
    - HandlerMethodクラスを利用して、呼び出し元のクラス名、メソッド名を取得しています
    - handlerは、静的コンテンツの場合に`ResourceHttpRequestHandler`型になるのでその場合はreturn trueしている。
    

```kotlin:LoggerInterceptor
class LoggerInterceptor : HandlerInterceptor {
    private val logger = LoggerFactory.getLogger(LoggerInterceptor::class.java)

    override fun preHandle(request: HttpServletRequest,
                           response: HttpServletResponse,
                           handler: Any): Boolean {

        if (!HandlerMethod::class.java.isInstance(handler)) {
            return true
        }

        val handlerMethod = HandlerMethod::class.java.cast(handler)
        logger.info(request.requestURL.toString())
        logger.info(handlerMethod.beanType.name + "::" + handlerMethod.method.name )
        return true
    }
```

## 手順2
Interceptorを登録します

```kotlin:WebMvcConfig
@Configuration
class WebMvcConfig: WebMvcConfigurer {
    @Bean
    fun getLoggerInterceptor(): LoggerInterceptor {
        return LoggerInterceptor()
    }

    override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(LoggerInterceptor())
    }
}
```

#### 出力結果
```terminal:出力結果
http://localhost:8080/index
2022-06-25 20:46:09.044  INFO 50604 --- [nio-8080-exec-6] c.a.m.a.interceptor.LoggerInterceptor    : com.test.controller.IndexController::index
```


以下を参考にさせていただきました。
https://qiita.com/kyabetsuda/items/78a61bfff859fbc9c63f

以上です。
rebase したらちょっと前に入れた修正が巻き戻ってた

# 先に結論（という名の戒め）

- こまめにローカルブランチとリモートブランチを同期しましょう
- 特に、PR/MR の suggested changes を適用した時は必ずその修正をローカルに反映しましょう
- `force push` は**歴史の改変**なのだということを**強く**意識しましょう

# 事の発端

〜とある MR[^1] のレビュー中〜

[^1]: 現在関わっているプロジェクトでは GitLab を利用しています。MR = Merge Request です。GitHub の PR（Pull Request）とほぼ同じです。

私「そろそろこの MR も終わりに近づいてきたなあ。他の人の MR がマージされて develop ブランチが先に進んだようだし、develop ブランチのコミットを取り込むか」

私「コミットの履歴は１本にしたいし、rebase でやろう。`git fetch` でリモートの状態を手元に取り込んで、`git rebase origin/develop` っと。」

私「お、コンフリクトした。いい感じに修正して・・・このままだと push で弾かれるから、`git push origin branch1 -f` でリモートに反映！」

私「`@レビュワーのみなさま` develop ブランチの修正を取り込み、コンフリクトを解消しました。ご確認お願いします :smile:  」


〜〜その後しばらくして〜〜
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908526/10a70cbc-e779-56ed-15e1-975792b7ad32.png)
私「は・・・？」

私「色々と戻ってる・・・？？？そんなはずは・・・」

私（コードを確認）

私「ほんとに戻っちゃってる・・・・:cry: なんで・・・？？？」

# 時系列の整理

1. 私、MR を出す
1. いくつか修正コメントをいただいたので修正して push
1. suggested change に書くには多すぎる量の修正提案があったので、レビュワーが修正案を別の MR として作成
    - このとき、作成いただいた MR のマージ先ブランチは元の MR の source branch
1. レビュワーが作成した MR をマージ
1. この間に、別のメンバーが進めていた MR が develop ブランチにマージされる
1. `git fetch` して最新の状態をローカルに取得後、`git rebase origin/develop` で別メンバーの修正を自分のブランチに取り込み
1. コンフリクトしていたのでローカルで修正
1. `git push -f` でリモートに反映
1. レビュワーからのコメントで巻き戻りに気づく

# 何が悪かったのか？？

やらかしの原因は、ここ。

↓ ↓ ↓ ↓ ↓ ↓ ↓
`git fetch` して最新の状態をローカルに取得後、`git rebase origin/develop` でマージされた修正を自分のブランチに取り込み
↑ ↑ ↑ ↑ ↑ ↑ ↑

## もうちょっと詳しく

時系列 1〜4 の時点で、私のローカルの作業ブランチは MR の source branch（= ローカルの作業ブランチをリモートに push したもの）よりも遅れている状態になっていました。

その後、時系列 5〜7 で **MR の source branch（= ローカルの作業ブランチをリモートに push したもの）に入った修正をローカルの作業ブランチに取り込まないまま、作業ブランチを force push してしまった** ために、MR 上で修正が巻き戻った状態になってしまいました。

## 本当はどうすべきだった？

時系列 4 の後すぐに、MR の source branch の修正をローカルの作業ブランチに取り込むべきでした。

# 結論という名の戒め、再掲

- こまめにローカルブランチとリモートブランチを同期しましょう
- 特に、PR/MR の suggested changes を適用した時は必ずその修正をローカルに反映しましょう
- `force push` は**歴史の改変**なのだということを**強く**意識しましょう
  - force push に慣れちゃうとなんかあったら脳死で `-f` つけちゃうの、ほんと良くない
ffmpegで連番画像からGIFを作成 / 解像度変更 / 逆再生

# 連番画像からGIFの作成
手元にあるファイルが`file1.JPG`, `file2.JPG`, `file3.JPG`のような連番画像の場合
```Terminal
$ ffmpeg -i file%d.JPG -vf palettegen palette.png
```
のように入力し`palette.png`を作成し，それをもとにGIFを作ります．
```Terminal
$ ffmpeg -f image2 -r 15 -i file%d.JPG -i palette.png -filter_complex paletteuse mixed_15fps.gif
```
※`-r`の後がFPSになるので上記の場合だと15fpsということになります．

## 参考
https://kimizuka.hatenablog.com/entry/2018/05/26/204618

# 解像度変更
素材のアスペクト比を維持して解像度を変更する場合，widthかheightのどちらかを指定して，もう一方を`-1`にすることで自動で調整してくれます．
```Termianl
$ ffmpeg -i mixed_15fps.gif -vf scale=720:-1 mixed_15fps_720.gif
```
※上記ではwidthを720で指定しています．

# 逆再生

```Terminal
$ ffmpeg -i mixed_15fps.gif -vf reverse -an mixed_15fps_720_reverse.gif
```

# おわり
ffmpegを久しぶりに使うと毎回使い方を忘れているので今回はメモ感が...
wsl2を使用したDockerがアップデートでUIが起動しない場合の修正

# 前書き
前提条件として、今までなぜかアップデートするとうまく動かなくなっていたので、動く中で一番新しい4.3.2を使用していた。
多分記事的にあると思うが、自分の検索力では見つけられなかったので投稿。

## 前準備
もしdocker全体を入れなおす人は現在使用しているdocker imageを
>docker save レポジトリ名:タグ名 > backup_image.tar

でバックアップを取っておくことをお勧めする。
(イメージによってはかなり重いので注意。)

# 状況
アップデート前はうまく動いていたのに、
アップデート後はUIが表示されず、うまく動いていないのかと思ってdocker desktopを再度起動しても

>failed to initialize 
>docker desktop is shutting down 

みたいな感じのエラーが出て起動しない。

ネットで調べても
Roamingのdockerを消して~とかしか出てこずやっても意味がなかった。

一からインストールしても、同じ現象が起こる。
(wsl2の設定はされているにも関わらず、wslで実行のチェックボックスがでない...)

4.3.2くらいであれば今まで通りインストールしたら起動したのでそれで放置してた。

しかし、さすがにversionが4.9まで増えているとちょっとアップデートした方がよさそうな気がしてきたのと少しだけ時間ができたので、気になってたこちらの問題を解決することにした。



# 解決策
気になった[issue](https://github.com/docker/for-win/issues/12746)が出ていて、そちらで今までは削除を求められてこなかった
>C:\Users\<ユーザー名>\.dockerの削除

をするのを求めていたので実行したら起動した。
おそらくだが、ログを見たところ署名か何かが変わって読めていなかったらしい。
しかもdockerのアンインストールでも消去されずに結果的に起動しなくなっていたと思われる。


また、wsl仕様でインストールができていなかったため当然hyper-vで動く仕様になっておりstoppedのまま動かない。

そちらについては[参考](https://remix-yh.net/2139/)を元に
>C:\Users\<ユーザー名>\AppData\Roaming\Docker\settings.json

の<b>wslEngineEnabled</b>が<b>false</b>になっているのを<b>true</b>にすることできちんとwsl経由で起動することに成功した。

あとは、もし再インストールなども行っていれば
> docker load --input backup_image.tar

などで入れていたimageを復元すればOK。
【セグメンテーション】ラベルデータをインデックスカラーのpngファイルとして保存・読込みする

# はじめに

ニューラルネットを用いた機械学習の中でも、セグメンテーションは1ピクセルごとのラベルが必要になることから、ラベルのインプットを工夫しないと学習のボトルネックになることがあります。
整形してあるデータセットであれば良いですが、KaggleなどはCSVファイルでラベルが配布される場合がある為、学習時に都度CSVからラベルを作成してモデルにインプットした場合、学習が非常に遅くなります。
そこで予め全てのラベルをインデックスカラーのpngファイルとして保存しておき、学習時には読込みだけを行う方法を調べたので、備忘録として残します。

# 環境
- Google Colaboratory Pro

# コード
モジュールのimport
```python:
import numpy as np
from PIL import Image
import torch
from matplotlib import pyplot as plt
```

初めに与えられたデータからインデックスカラーのNumPy配列を作成します。
以下は例で、背景を0、2番目に大きい四角を1、最も小さい四角を2と指定しています。
この時データ型をintあるいはuintで指定する必要があります。
```python:
label = np.array(
    [[0,0,0,0,0,0],
    [0,1,1,1,1,0],
    [0,1,2,2,1,0],
    [0,1,2,2,1,0],
    [0,1,1,1,1,0],
    [0,0,0,0,0,0]], dtype = 'int8'
)

print("label_shape:", label.shape)
plt.imshow(label)
plt.axis("off")
```
```
実行結果
label_shape: (6, 6)
```
![label.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2657466/f9cf8f77-1157-cfcb-a83e-adf5011b279d.png)
画像をPILのパレットモードで保存
```python:
label = Image.fromarray(label, mode = "P")
label.save("./label.png")
```
画像を読み込む。ワンホットエンコーディングは分類したいクラス数+1で実行する。
例では分類したいのが2種の四角なので、2+1（1は背景分）で実行しています。
```python:
label = Image.open("./label.png")
label = np.asarray(label)   #NumPy配列に変換
label_tensor = torch.from_numpy(label.astype(np.float32)).clone()   #tensorに変換
label_onehot = torch.nn.functional.one_hot(label_tensor.long(), num_classes=3)
```
```python:
print("label_shape:",label.shape)
print(label)
plt.imshow(label)
plt.axis("off")
```
```
label_shape: (6, 6)
[[0 0 0 0 0 0]
 [0 1 1 1 1 0]
 [0 1 2 2 1 0]
 [0 1 2 2 1 0]
 [0 1 1 1 1 0]
 [0 0 0 0 0 0]]
```
![label.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2657466/cf2142aa-3de3-995c-2501-05586a7f43bf.png)
```python:
print("label_tensor_shape:",label_tensor.size())
print(label_tensor)
plt.imshow(label_tensor)
plt.axis("off")
```
```
label_tensor_shape: torch.Size([6, 6])
tensor([[0., 0., 0., 0., 0., 0.],
        [0., 1., 1., 1., 1., 0.],
        [0., 1., 2., 2., 1., 0.],
        [0., 1., 2., 2., 1., 0.],
        [0., 1., 1., 1., 1., 0.],
        [0., 0., 0., 0., 0., 0.]])
```
![label.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2657466/db53c6e9-9b75-5ca0-4a2a-27a6eba2dc84.png)

```python:
print("label_tensor_shape:",label_onehot.size())
print(label_onehot)
```
```
label_tensor_shape: torch.Size([6, 6, 3])
tensor([[[1, 0, 0],
         [1, 0, 0],
         [1, 0, 0],
         [1, 0, 0],
         [1, 0, 0],
         [1, 0, 0]],

        [[1, 0, 0],
         [0, 1, 0],
         [0, 1, 0],
         [0, 1, 0],
         [0, 1, 0],
         [1, 0, 0]],

        [[1, 0, 0],
         [0, 1, 0],
         [0, 0, 1],
         [0, 0, 1],
         [0, 1, 0],
         [1, 0, 0]],

        [[1, 0, 0],
         [0, 1, 0],
         [0, 0, 1],
         [0, 0, 1],
         [0, 1, 0],
         [1, 0, 0]],

        [[1, 0, 0],
         [0, 1, 0],
         [0, 1, 0],
         [0, 1, 0],
         [0, 1, 0],
         [1, 0, 0]],

        [[1, 0, 0],
         [1, 0, 0],
         [1, 0, 0],
         [1, 0, 0],
         [1, 0, 0],
         [1, 0, 0]]])
```
後はreshapeやcropなどを行いモデルにインプットするだけです。
個人アプリを React Native 0.69 にアップデートしたが、今回もすんなり行かなかった

こんにちは、エモトです。家に巣をかけていたツバメの雛が順調で成長して、間も無く巣立ちしそうです。仕事の合間に、気分転換に見ていたので、寂しくもあります。外敵に襲われずに、無事に巣立ってほしい。

さて、React Native で開発してる個人アプリを [React Native 0.69](https://github.com/facebook/react-native/releases/tag/v0.69.0) にアップデートしました。何かとアップデート時に困らされる React Native、さらに今回の 0.69 は React Native で初めて React 18 に対応するバージョンです。何も起こらないはずはない！ある意味楽しみ ( ꒪⌓꒪)

（参考）過去にアップデートで困らされたときの記事

- [React Native 0\.67\.x にアップデートしようと思ったら、Expo 44\.x の対応でいろいろあった件](https://qiita.com/mitsuharu_e/items/3d840fdf313e862de6bd)

## 起きた問題

私のアプリは、SQLite で保存したデータを条件によって一覧で表示する、または地図上に表示するという簡単なアプリです。

さっそく [React Native Upgrade Helper](https://react-native-community.github.io/upgrade-helper) に従って更新してビルドすると、いくつか導入しているライブラリで問題が起こりました。

### react-native-vector-icons

- クラッシュする
- 使用箇所で以下のようなエラーメッセージ

> Unrecognized font family 'Ionicons'

### react-native-sqlite-storage

- クラッシュする
- 関数 `openDatabase ` を呼ぶと例外発生

> [TypeError: null is not an object (evaluating 'NativeModules["SQLite"][method]')]
	
### react-native-maps

- クラッシュする

> ViewPropTypes will be removed from React Native. Migrate to ViewPropTypes exported from 'deprecated-react-native-prop-types'. #33557

あわわ

## 原因とその修正方法

今回の変更は React 18 に注目してましたが、他にも変更点（[a](https://reactnative.dev/blog/2022/06/21/version-069), [b](https://github.com/facebook/react-native/blob/main/CHANGELOG.md#v0690)） があります。今回起きた問題はそれが原因でした。


- react native cli が変更された
- deprecated になっていた型 react-native-prop-types が取り除かれた

react native cli が変更になったことにとり、Native Modules の Autolinking の機能が強化されて一方、以前の設定のままでは失敗するようになりました。

- [refactor\(breaking\): remove deprecated \`link\`, \`unlink\` and associated code by grabbou · Pull Request \#1537 · react\-native\-community/cli](https://github.com/react-native-community/cli/pull/1537)
- [cli/autolinking\.md at master · react\-native\-community/cli](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md)

ざっくり言うと、autolinking に関しては `react-native.config` で不要になった項目を取り除けば大丈夫です（今回、私が遭遇した内容では）。

型エラーに関しては、適切な型に関する修正することになります。また、React Native 0.65 から deprecated になっていた `removeListener` が削除されたので、ワーニングのまま未対応にしていた場合、面倒になことになります。お気をつけて。



## 対応

自分のコードならともかく、ライブラリ側で改修が必要になると、大変だな・・・。


### react-native-vector-icons

対応した [9.2.0](https://github.com/oblador/react-native-vector-icons/releases/tag/v9.2.0) が直様リリースされたので、アップデートしたら終了です。`react-native.config` で assets を設定して箇所が削除されています。


### react-native-sqlite-storage

対応したバージョンがリリースされていないので、パッチファイル [react-native-sqlite-storage+6.0.1.patch](https://github.com/mitsuharu/Ubepedia/blob/20220625/app/patches/react-native-sqlite-storage%2B6.0.1.patch) を自分で作成して patch-package で対応しました。なお、これらの issue と PR を出しておきました。本家で対応してもらえば嬉しい。

	
### react-native-maps

対応した [0.30.2](https://github.com/react-native-maps/react-native-maps/releases/tag/v0.30.2) が既にリリースしてあったので、アップデートして完了です！簡単。

## まとめ

本当は `useEffect` などの動作変更で何か意図しない動作をする問題を楽しみにしていたのですが、ライブラリの導入方法に関するエラーでした。今週末は、コードに間違いないけど期待動作が違うという、終わらないデバッグを期待してました。


まあ、私が作ったアプリの規模が小さいので、問題が観測できていないだけかもしれません。引き続き、細かい動作検証や React Native 0.69 関連の issue を見ていこうと思います。
gitの使い方を考えてみた。

# 目的
gitを使ってプログラムを管理したい。

## 環境　
os: windows10 

## git flow
git flowを参考に開発してみたかったので、試してみました。git flowとは、[こちらのサイト](https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow)では下記のように説明されています。
> Gitflow とは、フィーチャー ブランチと複数のプライマリ ブランチを使用する代替 Git ブランチ モデルです。nvie の Vincent Driessen 氏が初めて公開して有名になりました。トランクベース開発と比較して、Gitflow には永続的なブランチと大規模なコミットがあります。

git flowとは、Gitのリポジトリを使ったブランチモデル(分岐モデル)の一つで。複数人での開発している場合、変更点、リリースなどの状況をブランチで分けられています。そうすることで、プログラムの変更状況を管理しやすいと考えており、活用することにしました。

git flowのブランチの説明については、下記サイトが詳しく書かれていましたので省略します。
[Git-flowをざっと整理してみた](
https://dev.classmethod.jp/articles/introduce-git-flow/)

## 今回行ったフロー

mainには、最新の状態を入れておきます。developには、リリースまでにアップデートした機能、featureには、リリースまでに新たに追加した機能やバグを修正した作業を入れています。

使用しているコマンドは、下記にまとめてます。
https://qiita.com/yutaka_m/items/55fd9120bf2886ba6e83

### featureの作成
maimからdevelop、fuatureの順に作成します。developのブランチ名には、revの番号(xx)、featureには、作業内容のタイトル(yy)をつけて置くことにしました。

```github
# ブランチがmainにいることを確認する。
git branch

# develop/rev0.xを作成し、ブランチを切り替える。
git checkout -b develop/rev0.x

# develop/rev0.xをコピーし、feature/rev.0.x_yyを作成する。
git checkout -b feature/rev.0.x_yy develop/rev0.x または git checkout develop/rev0.x -b feature/rev.0.x_yy 

```

### featureをoriginへ反映
featureの変更後、commitし、originまでアップロードします。

```
# 変更内容をステージングエリアへ
git add .
# 変更内容のコミット
git commit -m "メッセージ"
# featureの内容をoriginへ反映
git push origin feature/rev.0.x_yy
```

### mainをoriginへ反映
featureの内容をdevelop、main、originへと反映させます。

```
# developブランチへ切り替え
git checkout develop/rev0.x 
# featureの内容をdevelopへmergeして反映
git merge feature/rev.0.x_yy
# featureブランチの削除
git branch -d feature/rev.0.x_yy
# mainブランチへ切り替え
git checkout main
# developブランチの変更内容をmainへmergeして反映
git merge develop/rev0.x 
# mainの変更内容をoriginへ反映
git push origin main
```

## 差分比較
gitの差分比較を行う場合、同じファイルの変更が少量であれば```git diff```で確認できますが、大量に変更した場合見えにくくなります。なので、私は、winmergeを用いて比較することにしました。横並びで変更点がハイライトされるので便利です。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176158/2cdc3054-55d2-956f-844d-8abe2c730970.png)

設定については、[こちら](https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2)の記事を参考にさせていただきました。gitconfigファイルがある場所は、[こちら](https://qiita.com/shionit/items/fb4a1a30538f8d335b35)の記事が参考になります。

また、コミットID同士で履歴を指定して、比較することもできます。
```
git windiff コミットID_A コミットID_B
```


### 参考URL
[いまさらだけどGitを基本から分かりやすくまとめてみた](https://qiita.com/gold-kou/items/7f6a3b46e2781b0dd4a0)
[リリースまでの流れ](https://gist.github.com/fujimaki-k/21196aa7cdad40a6e6e5b323c73fa714)
[git develop, feature branch作成からmergeするまで　(自分用メモ)](https://qiita.com/Naoki206/items/e5520453f92dcd4274f1)
[Git-flowって何？](https://qiita.com/KosukeSone/items/514dd24828b485c69a05)
[git の差分比較・マージを WinMerge で行う](https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2)
論理演算子のメモ

論理演算子&,&&,|,||について、
&&､||はショートサーキット演算子と呼ばれ、左オペランドの結果によって後続処理が不要な場合は処理を省略する。

後続処理というのはショートサーキット演算子以降のすべてに対してなので、以下のような条件も省略される。


~~~java
public class Main {
    public static void main(String[] args) throws Exception {
     int a = 1;
     int b = 1;
     if(a == 2 & b++ == 1&& a++ == 3 & a++ == 4){    	  
     }
     System.out.println(a+":"+b);
    }
}
~~~

>1:2

もちろん手前で結果未定になる場合は後続も実行される。
~~~java
public class Main {
    public static void main(String[] args) throws Exception {
     int a = 1;
     int b = 1;
     if(a == 2 & b++ == 2|| a++ == 1 & a++ == 4){
     }
     System.out.println(a+":"+b);
    }
}
~~~
>3:2

｜と｜｜が混在したりするようなプログラムがあったらこういう目的なんだろうとは思うが…そんな可読性低そうな方法使うか？
LineBotから自分にメッセージを送信する(python)

# 概要

LineBotで自分にメッセージを送信する方法を簡単にまとめました。

# 手順

### ①LineDeveloperのサイトでチャネル(公式アカウント)を作成   
   https://developers.line.biz/ja/docs/messaging-api/getting-started/
に従って自分のBotのチャネル(Lineアカウント)を作成する。
そして、自分のLINEアカウントで友達登録しておく。

### ②使用するpython環境で、line-bot-sdkをインストール
```
$ pip install line-bot-sdk
```

### ③Botから自分にメッセージを送信するコードを作成

以下テストコード。
これを実行するとLINEBotから自分のLINEアカウントにメッセージが来ます。

```python:test.py
from linebot import LineBotApi
from linebot.models import TextSendMessage
from linebot.exceptions import LineBotApiError

channel_access_token = ‘<チャネルアクセストークン>’
my_user_id = ‘<自分のユーザID>’

line_bot_api = LineBotApi(channel_access_token)

try:
    line_bot_api.push_message(my_user_id, messages=TextSendMessage(text='Hello World!'))
except LineBotApiError as e:
    #エラー処理
```

チャネルアクセストークンは、「Messaging API設定」タブから確認可能。
自分のユーザIDは、「チャネル基本設定」タブの「あなたのユーザーID」で確認可能。
[Power BI] Field Parameter フィールドパラメーターのTips① メジャー切り替え時の色を固定する🎊

# はじめに

2022年にプレビューリリースされたフィールドパラメーター。プレビュー機能とはいえ、描画されているメジャーをスライサーで切り替えることができたり、日付の粒度（年、月、日）を**簡単に**切り替えることができるのがとても便利でレポートを作成しているとよく使う機能になってきています

https://docs.microsoft.com/ja-jp/power-bi/create-reports/power-bi-field-parameters

https://marshal115.hatenablog.com/entry/2022/05/20/192120

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/020b487b-dab6-ea20-6efa-17b6e8bfdf73.png)

# フィールドパラメーターを作成する

Power BI Desktopのモデリングタブからパラメーターボタンを押します。

ここで**フィールド**と書いてあるのがフィールドパラメーターです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/6c3eef6c-1075-2016-6d2f-d55b731b6a19.png)

適当に作成したメジャーを何個か選んでみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/4b3f0780-912b-c944-62bd-d720511be863.png)

# フィールドパラメーターを試す

X軸は日付列を設定し、フィールドパラメーターをY軸に設定して折れ線グラフを描画してみます。
メジャーを選択するスライサーを任意にクリックすると期待通りの動き😁
メジャーが切り替わることによって、レポートを見るユーザーがよりデータ探索をしやすくなりますよね。

![2022-06-25_17-18-55.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/8c44a472-be67-d59c-d5b2-b54d88114c8a.gif)

# グラフ描画時の色を固定したい

3つのメジャーすべてが描画してあるときは、オレンジ、紫、水色と3色の表示になっているけど・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/008e986e-8745-9d80-ab6d-a5bbd4b14cc4.png)

## スライサーで1つのメジャーを選んだときに色が同じになる🤔

メジャーひとつずつを選択したときには、ビジュアルの仕様で色が1色になり、どのメジャーを選択しても同じ色が使われます。**オレンジ色で表示されていたものはオレンジ色でそのまま表示されてほしい！**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/fd371f80-1b5b-48d6-4535-fe9d2a9ea8c2.png)

# 現時点での解決策😊

フィールドパラメーターに、各メジャーの名前を表示するだけの列を追加します。

```DAX
Measure Name = 'Chosen Measure'[Chosen Measure]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/42d239ed-7324-5171-e0fb-cb883af9c245.png)

## 作成したカラムを凡例に追加する

凡例に追加するのですが、スライサーでメジャーがすべて選択されている状態では追加をすることができません。
1つだけメジャーを選択した状態にすると、凡例に追加することができます😅

![2022-06-25_18-14-01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/6c10a5a8-af8a-72e5-d0a5-e7fe7ee5f86d.gif)

## 予期せぬ動作も

ここまでやっていると、期待した動作をするように思えますが、うまくいかない部分もあります。メジャーを複数選択すると正しく描画されず、一つのグラフにまとまってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/9ed3cdde-a529-7da2-1486-ac923d6cf4f1.png)

## 回避策

メジャーが複数選択されると描画がおかしくなってしまうので、スライサーを単一選択に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/14faf648-3542-c0a6-07f3-1ebfb69839f6.png)

# まとめ

使えるシーンがあるような、ないような😅要件によってはOKな場合もあると思うので、試してみてください～！とはいえ、プレビュー機能ですから、ご利用は計画的に。ありがとうございました～😀
adbから好きなアプリ起動

`adb shell am start HOGE` でアプリ起動できるのでHOGEの部分を調べる。

調べ方はいろいろあるけど、一覧から探すの辛い。
好きなアプリを起動しておいてlogcatで確認するのが簡単そう。
ActivityManagerの「pre-top-activity」を含むログだけ表示する。

`adb logcat -d -s ActivityManager:I -e pre-top-activity`

```sh
$ adb logcat -d -s ActivityManager:I -e pre-top-activity
--------- beginning of system
06-25 18:27:26.535  1797  1892 I ActivityManager: Start proc 25440:com.google.android.calculator/u0a143 for pre-top-activity {com.google.android.calculator/com.android.calculator2.Calculator}
06-25 18:29:01.483  1797  1892 I ActivityManager: Start proc 25751:com.google.android.dialer/u0a114 for pre-top-activity {com.google.android.dialer/com.google.android.dialer.extensions.GoogleDialtactsActivity}
06-25 18:29:03.593  1797  1892 I ActivityManager: Start proc 25867:com.google.android.GoogleCamera/u0a158 for pre-top-activity {com.google.android.GoogleCamera/com.android.camera.CameraLauncher}
06-25 18:29:07.478  1797  1892 I ActivityManager: Start proc 25911:com.google.android.youtube/u0a161 for pre-top-activity {com.google.android.youtube/com.google.android.youtube.app.honeycomb.Shell$HomeActivity}
06-25 19:18:25.464  1797  1892 I ActivityManager: Start proc 29544:com.google.android.deskclock/u0a159 for pre-top-activity {com.google.android.deskclock/com.android.deskclock.DeskClock}
06-25 19:23:30.853  1797  1892 I ActivityManager: Start proc 30185:jp.co.shueisha.youngjump.android/u0a218 for pre-top-activity {jp.co.shueisha.youngjump.android/jp.co.shueisha.youngjump.android.MainActivity}
```

最後の{}で囲まれてる部分をam(Activity Manager)に投げればおっけー。

```sh
adb shell am start 'jp.co.shueisha.youngjump.android/jp.co.shueisha.youngjump.android.MainActivity'
```

# 参考

https://developer.android.com/studio/command-line/adb?hl=ja#am
DockerでEC-CUBEの環境構築を行う

※本記事は、Docker Desktopをインストールしている前提です

## ローカルにEC-CUBEファイルデータを落とす
ターミナルで任意のディレクトリに移動してください
```
cd ~/Documents
```
ec-cube公式が提供しているgitからファイル一式をcloneします
```
git clone https://github.com/EC-CUBE/ec-cube.git
```

## Dockerを立ち上げてEC-CUBEを起動する
先ほどcloneしたディレクトリに移動してください
```
cd ec-cube
```
dockerを立ち上げます。下記コマンドを実行すると、各コンテナが起動します。
```
docker-compose up -d
```
ec-cubeを起動するための初期スクリプトを実行します。
```
docker-compose exec -u www-data ec-cube bin/console eccube:install
```
※上記コマンドを実行すると、5つぐらい質問が出てきます。
　全てenter keyを押下してください。

再度に緑色の背景で下記のように表示されれば、
```
 [OK] EC-CUBE installation successful.  
```

## EC-CUBEをブラウザで開く
下記サイトにアクセスしてください。
```ruby:フロント
http://localhost:8080 
```
```ruby:管理
http://localhost:8080 
ID: admin
PASS: password
```


以上で、完了です。
React: React Router の使い方 (その 2)

こちらのページを参考にしました。
[【最新バージョン対応】React Routerの使い方を解説](https://ralacode.com/blog/post/how-to-use-react-router/)

プロジェクトの作成

```bash
create-react-app ex02
cd ex02
yarn add react-router-dom
yarn start
```

src のツリー構造

```text
$ tree src
src
├── App.css
├── App.js (修正）
├── App.test.js
├── Home.js (追加)
├── Login.js (追加)
├── NotFound.js (追加)
├── Register.js (追加)
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
```

```src/Home.js
/*  Home.js */

import { Link } from "react-router-dom";

const Home = () => {
  return (
    <>
      <h1>ホーム</h1>
<blockquote>
      <div>
	ログインは<Link to={"/login"}>こちら</Link>
      </div>
<br />
      <div>
        新規登録は<Link to={"/register"}>こちら</Link>
      </div>
</blockquote>
    </>
  );
};

export default Home;
```

```js:src/Login.js
/* Login.js */

import { Link } from "react-router-dom";

const Login = () => {
  return (
    <>
      <h1>ログインページ</h1>
<blockquote>
      <div>
        新規登録は<Link to={"/register"}>こちら</Link>
      </div>
<br />
      <div>
        <Link to={"/"}>ホームに戻る</Link>
      </div>
</blockquote>
    </>
  );
};

export default Login;
```

```js:src/Register.js
/* Register.js */

import { Link } from "react-router-dom";

const Register = () => {
  return (
    <>
      <h1>新規登録ページ</h1>
<blockquote>
      <div>
        ログインは<Link to={"/login"}>こちら</Link>
      </div>
<br />
      <div>
        <Link to={"/"}>ホームに戻る</Link>
      </div>
</blockquote>
    </>
  );
};

export default Register;
```

```js:src/NotFound.js
/* NotFound.js */

import { Link } from "react-router-dom";

const NotFound = () => {
  return (
    <>
      <h1>お探しのページは見つかりませんでした。</h1>
<blockquote>
      <div>
        <Link to={"/"}>ホームに戻る</Link>
      </div>
</blockquote>
    </>
  );
};

export default NotFound;
```

```js:src/App.js
// ---------------------------------------------------------------
//	App.js
// ---------------------------------------------------------------
/* App.js */

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./Home";
import Register from "./Register";
import Login from "./Login";
import NotFound from "./NotFound";

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path={"/"} element={<Home />} />
        <Route path={"/register"} element={<Register />} />
        <Route path={"/login"} element={<Login />} />
	    <Route path={"*"} element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
};

export default App;
```

ブラウザーで、http://localhost:3000　にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f9b76959-5ec6-5525-050b-bbf86bed1be4.png)

## 関連情報 ##
[React: React Router の使い方](https://qiita.com/ekzemplaro/items/5e6f83f482fbbdd825ce)
if文についてのメモ

javaのif文についてよく解説書では
処理が1行のものであれば｛｝は省略できる。
というような記載になっている。

実際以下のようなプログラムはコンパイルも実行もできるし、
if文も想定通り動く。

~~~java
public class Main {
    public static void main(String[] args) throws Exception {
     int a = 1;
      if(a == 1)
       System.out.println("aは"+a+"です");
    }
}
~~~~

だが以下のif文ではコンパイルエラーが発生する。

~~~java
public class Main {
    public static void main(String[] args) throws Exception {
     int a = 1;
      if(a == 1)
    	int b = 1;
    }
}
~~~

エラー文
>Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	構文エラーがあります。". class" を挿入して Expression を完了してください
	構文エラーがあります。"AssignmentOperator Expression" を挿入して Assignment を完了してください
	構文エラーがあります。";" を挿入して Statement を完了してください
	代入の左側は変数でなければなりません
	b を変数に解決できません
	at Main.main(Main.java:5)

こちらは正常にコンパイルも実行も可能
~~~java
public class Main {
    public static void main(String[] args) throws Exception {
     int a = 1;
      if(a == 1){
    	int b = 1;
      }
    }
}
~~~

クラスのインスタンス宣言等他にもできない事はいくつかあるようだが、
新しく何かを宣言する処理というのは｛｝を省略しては実行することができないようだった。
調べても詳細にたどりつけなかったが、メモリ領域の取得とかの処理が挟まって実質1行で動いていないとかそういうことなのかもしれない。

時間があんまりないので今日はこの辺りで。
グループ機能全般で利用できるサイト

★グループ作成実装-アソシエーションメイン！ Viweは簡単！

https://qiita.com/ki_87/items/5add92e34c639fe13ef0

★グループへの入退会機能-ネストがメイン！ Viewの記述に注意！

https://qiita.com/ki_87/items/eb2d073c2dccbed42c5a

★グループメンバーへのメール送信機能-全体的に難しい！ 覚えるしかない！

〜実装時は↓こっちの方が良い！〜

https://qiita.com/ki_87/items/67f8965e8de17e95ac1c

〜解説重視なのは↓こっちの方が良い！〜

https://qiita.com/annaaida/items/81d8a3f1b7ae3b52dc2b

※どちらのページも素敵なまとめ方でした！！！ Ψ(☆ω☆)Ψ

★環境変数についてのサイト！　簡単・便利！

https://qiita.com/ki_87/items/82b28f89a8552506a169

https://qiita.com/yuichir43705457/items/7cfcae6546876086b849
niceコマンド

#### niceコマンドとは
プロセスの相対優先度を変更して実行するコマンド


```:書式
nice [オプション] [実行したいコマンドとそのオプション]
```


・優先度(nice値)は-20から19の値で調整でき、マイナスに行くほど優先度が高くなり、プラスに行くほど優先度が低くなる

・優先度を高くするにはroot権限が必要

| 優先度 | 値 | 備考 |
| --- | --- | --- |
| 高　| -20 | rootユーザでのみ変更可能 |
| ↕︎ | 0 | 初期値 |
| 低 | 19 | rootユーザ、一般ユーザで変更が可能 |




```:使用例
nice -n -5 /opt/hogehoge.sh

#変更できたか確認
ps -l 
PID  USER PR NI VIRT  RES  SHR  S %CPU %MEM TIME+   COMMAND 
2818 root 15 -5 13004 1416 1208 S 0.0 　0.3 0:00.05 /bin/bash /opt/hogehoge.sh

#NIが-5になっていれば変更完了
```

※ -n 優先度を指定する　


大量のデータをエクスポートしたりバッチ処理の時にしようするとよさそうですね。
リモートサーバーでのシェルをrbashに変更してJenkinsからSSHしたときに実行できるコマンドを制限する

JenkinsからSSHしてリモートサーバーでコマンド実行したりしているのですが、ユーザー権限で使えるコマンドは自由に実行できてしまうので、一応安全のために利用できるコマンド制限しておこうと思います。

Linuxでコマンドを制限する場合は rbash が使えるようです。

bash にシンボリックリンクをはって rbash をシェルとして使えるようにする。

```
# ln -s /bin/bash /bin/rbash
# echo /bin/rbash >> /etc/shells
```

Jenkinsユーザーのシェルを rbash に変更。

```
# usermod -s /bin/rbash jenkins
```

利用できるコマンドはホームディレクトリの bin ディレクトリのみのコマンドに制限。

```
# echo "PATH=\$HOME/bin" > /home/jenkins/.bash_profile
# echo "PATH=\$HOME/bin" > /home/jenkins/.bashrc
```

利用できるコマンドを設定。(例えば git だけにする)

```
# mkdir /home/jenkins/bin
# ln -s /bin/git /home/jenkins/bin/
```

ユーザー自身で設定を変えられないようにパーミッション変更。

```
# chown root:root /home/jenkins/.bash_profile
# chown root:root /home/jenkins/.bashrc
# chown -R root:root /home/jenkins/bin
```

設定は以上です。

Jenkinsから余計なコマンドが実行できないことを確認しておきましょう。
Windows10 + Python3 + BeautifulSoup4 を試してみる

# 目的
[Yahoo!ニュース](https://news.yahoo.co.jp/)の主要トピックスに対してBeautifulSoupを使って以下を試したときのメモ
・Copy selectorの出力
・Copy XPathの出力
・find、find_allを使った例
検索結果で記述した日付が記述されていない記事は注意が必要
Yahoo!ニュースの構成が変更される頻度が多い??ようなので、まずはtagを検証する

## 使用するパッケージのインストール
```
PS > pip3 install BeautifulSoup4
PS > pip3 install lxml
```

## サンプルコード

```python
# ここからは共通コード。
# Windows Add env PYTHONIOENCODING = UTF-8 & restart vscode
# coding:utf-8

from bs4 import BeautifulSoup
import urllib.request
import re
from lxml import etree
from lxml import html

url = 'https://news.yahoo.co.jp/'

with urllib.request.urlopen(url) as response:
    res = response.read()
    url = response.geturl()
    info = response.info()

# ここまでは共通コード。以下パターンごとに記述する

# 指定した１項目を表示する
soup = BeautifulSoup(res, 'html.parser')
# print(soup.prettify())    # 整形された書式で出力を確認
# 以下はいずれでも良いようだ
# elems = soup.select('#uamods-topics > div > div > div > ul > li:nth-child(1) > a')
elems = soup.select('#uamods-topics > div > div > div > ul > li:nth-of-type(1) > a')

for elem in elems:
    print(elem.contents[0])
    print(elem.attrs['href'])

# tag を対象にした検索
# 全８項目＋もっと見る＋全カテゴリのトピックス一覧を表示する
soup = BeautifulSoup(res, 'html.parser')
# 主要トピックの抽出
sect = soup.find("section", attrs ={"id":"uamods-topics"})
# print(sect.prettify()) # 整形された書式で出力を確認

# 主要トピッ内の a tag の抽出
elems = sect.find_all("a")

for elem in elems:
    print(elem.contents[0])
    print(elem.attrs['href'])

# news.yahoo.co.jp/pickup を対象にした検索
# 全８項目＋もっと見る＋全カテゴリのトピックス一覧を表示する
soup = BeautifulSoup(res, 'html.parser')
elems = soup.find_all(href=re.compile("news.yahoo.co.jp/pickup"))

for elem in elems:
    print(elem.contents[0])
    print(elem.attrs['href'])

# XPathを使用してトピック全８項目を表示する
soup = BeautifulSoup(res, 'html.parser')
xmldat = html.fromstring(str(soup))
elems = xmldat.xpath('//*[@id="uamods-topics"]/div/div/div/ul/li[1 or 8]/a')

for elem in elems:
    print(elem.text)
    print(elem.attrib['href'])

```

# 参考にしたサイトはこちら
[Beautiful Soup 4.9.0 documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
[Beautiful Soup 4.2.0 Doc. 日本語訳](http://kondou.com/BS4/)
[【Python】スクレイピングにおける要素特定は、XPathかCSSセレクターか](https://posipochi.com/2021/05/22/python-xpath-css-selector/)
[図解！Python BeautifulSoupの使い方を徹底解説！(select、find、find_all、インストール、スクレイピングなど)](https://ai-inter1.com/beautifulsoup_1/)
[図解！XPathでスクレイピングを極めろ！(Python、containsでの属性・テキストの取得など)](https://ai-inter1.com/xpath/)
[beautifulsoup4 Xpath指定で要素を取得](https://qiita.com/ritumutaka/items/464233b2f78a267348be)
GPIOのALT機能(alternate function)を使う


大学の課外活動で開発していて、こんな問題に遭遇しました。

「ラズパイ使うのはいいけどさ、PWMピンが足らなくない…？」

どうしたものかと思って色々探していたらALT(alternate function)というものを使えばいいらしいということを知りました。
これを使うとピンの機能を変更できるらしい。

https://raspberry-pi.ksyic.com/page/page/pgp.id/8

ただこのALT、いまいちやり方が分からない。

ということで、調べた結果を記事にいたしました。qiitaに記事を書くのは初めてな上、そこまで詳しいわけでも無いのでミス等は多めに見ていただけると助かります…。

使用したのはraspberrypi4 modelBでOSはraspbianです。

# ALT機能の使い方
今回は例として12番ピンをALT5に変更します。

ターミナル開いて
```
$ gpio -g mode 18 ALT5
```

これで終わり。
ここで、modeの次に打ち込む値(今回は18)はBCMの番号で、ハードのピン番号ではないことに注意してください。

ALT3なら、
```
$ gpio -g mode 18 ALT3
```
にすればokです。

BCMの確認は
```
$ gpio readall
```
で見ることができます。
Oops 18だかなんだかと出てきたらwiring.piを更新してあげれば解決します。更新の方法は熟練者たちが丁寧に解説してくださっているので、ここでは割愛します。

調べるのに一日近くかかってこれだけ…？
解決したから良いですが…。

変更できたか不安だったら、先ほどと同様に
```
$ gpio readall
```
を打ち込んで、確認しましょう。

# 起動時に自動実行させる

ただ、このままでは起動時に毎回コマンドを打ち込む必要があります。
面倒ですね。
そこでrc.localを用いて起動時に自動で打ち込むように指示します。
```
$ sudo nano /etc/rc.local
```
を入力し、
```
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

exit 0
```
のexit 0の前の行に利用したいALTのコマンドを入力してください。
打ち込んだら、ctrl+Oで保存。

再起動し、gpio readallで適応されているか確認してください。

お疲れ様でした。
【TypeScript】in演算子を使った型による条件分岐の方法

## やりたかったこと
↓のような、型とメソッドが既存のソースにありましたが、このメソッドに対し、似てるけどちょっと違う型も引数に渡せるようにする必要がありました。（プロパティ名が異なる）
理由としては、型が違ってもほぼ同じ処理なので、わざわざ別々のメソッドを作るのも気が引けたためです。
```typescript
interface IfX{
 propA: string;
 propB: string;
}

func(param: IfY) {
 // なんらかの処理
}
```


そのため、このような感じで型の追加と、引数の修正を行いました。

```typescript
interface IfA{
 propA: string;
 propB: string;
}

interface IfB{
 propC: string;
 propD: string;
}

func(paramX: IfX | paramY: IfY) {
 // なんらかの処理
}
```

ただ、このメソッドは、プロパティに依存した処理を行なうので、このままでは使用することができませんでした。
そのため、型による条件分岐をする必要がありました。

## 方法
以前、たまたま見かけた下の記事のことを記憶していたので、見返してみましたが、型名用のプロパティを追加して、タグのようなものとして使用し、それにより条件分岐する方法でした。

https://qiita.com/Yametaro/items/e75d5c520b0f30c4db28


しかしながら、今回の場合は、既に設計書があり、プロパティを追加することができないため、この方法は使用できませんでした。

で、調べた結果、in演算子でできそうということで、inを使って実装しました。

## 具体例
```typescript
func(paramX: IfX | paramY: IfY) {
  if('propA' in paramX ) {
    // 型IfX用のなんらかの処理
  } 
  if('propC' in paramY) {
    // 型IfY用のなんらかの処理 
  }
}
```

`'propA' in paramX`の意味ですが、paramXの型がIfXで、propAというプロパティをもっていればtrue、もっていなかければfalseとboolean型で返します。これで型による条件分岐ができました。


https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/in
Salesforceインテグレーションに幅広く使用するOAuthの仕組みを理解しましょう

Hello！ 大家好！ こんにちは！ PanguのChoです。 社内勉強会のネタを掲載させていただきます。基本的にネットに既存でわかりやすい記事を探して、それを繋がせるかたちで編集させていただいております。ご参考になったら幸いです。

近年、新規会員登録する際にGoogle、Facebook、Twitterなどでログインのサイトは増えているようです。そのセキュリティーは大丈夫ですか？　心配したことはあるかと思います。また、Amebaブログなどを投稿の同時にFacebookなどに代理投稿もやってくれます。かなり便利な機能ですが、それはなんの仕組みですか？たくさんのネット記事の中、私は以下の記事はとても分かりやすい解説しているかと思い、リンクを掲載させていただきました。

## 代理投稿の仕組みよりOAuthを理解しましょう
https://tech-lab.sios.jp/archives/25470

いかがでしたか？OAuthの仕組みもよく理解出来たでしょうか？
## 応用でFacebookなどでログインの仕組みを想像して行きましょう
##### 1. 初回登録
運用サイトより遷移されたFacebookのログイン画面にログイン情報を入力、次に「名前、アイコンなど情報の取得権限を運用サイトへ付与して大丈夫ですか？」旨のメッセージが提示され、承認した場合は運用サイトへ戻ります。その後に、運用サイトの裏にユーザIdを作成、アクセストークンよりFacebookのId（例：メールアドレス）を取得、自サイトのユーザIDと紐付ける。
##### 2. 次回（以降）のログイン
セッションが切れった場合、再びFacebookのログイン画面へ遷移されます。ログイン後にFacebook用のアクセストークンが返ってきます。アクセストークンよりFacebookのId（例：メールアドレス）を再度取得し、それを利用して自サイト内に作成したユーザを特定出来、ログイン成功とみなします。
※Facebookログインの2回目以降は、「名前、アイコンなど情報の取得権限を運用サイトへ付与して大丈夫ですか？」旨のメッセージが表示されません。

## Salesforce OAuth 2.0 Web Server Flow を理解しましょう
Web アプリケーションインテグレーションの OAuth 2.0 Web サーバフロー
https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_web_server_flow.htm&type=5
オフィシャルサイトにはとても丁寧に説明しているかと思います。さらに下記を図を参考しながら、理解を深めましょう！
![web.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129251/4a4bf376-a6fc-dceb-3136-d53124aa7a91.png)
##### ↑図の元サイト：
https://architectxchange.com/oauth-2-0-web-server-flow-with-implementation/

## Salesforce OAuth 2.0 User-Agent Flow を理解
デスクトップまたはモバイルアプリケーションのインテグレーションの OAuth 2.0 ユーザエージェントフロー
https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_user_agent_flow.htm&type=5
同じく下記を図を参考しながら、理解を深めましょう！
![app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129251/f6c4c9e7-4735-61a2-59a2-161c41821fdc.png)
##### ↑図の元サイト：
https://architectxchange.com/oauth-2-0-username-password-flow-with-implementation/

## 補足：
OAuth認証はセキュアな通信プロトコルhttpsを土台としています。httpsは盗聴、改ざん、なりすますを防ぎます。httpsの仕組みも理解しましょう！

https://medium-company.com/ssl-%E4%BB%95%E7%B5%84%E3%81%BF/
sshでログインしたあとにsudoを自動でしたい


- -t で仮想端末を割り当てるのだけどこれが必要っぽい（ターミナルの中にターミナルが必要なイメージ？？）

```bash
ssh -t ec2-user@${ID} -i ~/.ssh/vampire.pem "sudo su - ec2-user"
```