OmniAICreator/Qiita-1.07M huggingface dataset:
【rails】modalを出現させてデータの「更新」をajaxで実装する方法

##自己紹介
rails学習約4ヵ月です。
bootstrapでmodalウィンドウを出現させ、編集⇒更新をajax処理で行いたいと思いましたがなかなかうまくいかずに悩んだので備忘録として記録しておきます。
##やりたい事
1.左上の「・・・」を押すとモーダルが出現。
![スクリーンショット (88).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/f94bd714-c75e-212a-a68a-df6852e78fde.png)
2.続けて「編集」を押すとデータが編集画面のモーダルが出現
![スクリーンショット (89).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/df68382c-b474-4b17-5e3c-35a4f91f77ae.png)
3.「更新」を押すとmodalがすべて閉じて、変更した部分だけが変わるようになる
![スクリーンショット (90).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/4af7f405-01ed-499c-5223-f5280d9f8c7b.png)
こんな感じ。（リロードではなく非同期通信で行えている）
![スクリーンショット (88).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/497a4d66-0ca9-6392-122f-1a1934d93b9f.png)
#起こった問題
「更新」を押すと以下のようになり、スクロールなど何もできない。「更新」の処理は思惑通りにうまく処理できている。
![スクリーンショット (91).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/913893bc-6a18-46e3-95ff-6887e94679ef.png)
##この時のjqueryのコード

>```
2番目に開いたモーダルを閉じる処理↓
$("#modal-e"+"<%= @menu_list.id %>").modal('hide');
1番目に開いたモーダルを閉じる処理↓
$("#modal-"+"<%= @menu_list.id %>").modal('hide');
変更したいところをshow_menuクラスで囲み、それをrenderでmenu_list_showに置き換える処理↓
$('.show_menu').html("<%= escape_javascript(render 'menu_list_show', menu_lists: @menu_lists, families: @families ) %>");```

##モーダルが完全に閉じていない
![スクリーンショット (93).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/bde2abd4-379c-d5e6-0cbd-89f6ddde387b.png)
googlechromeの検証ツールで見てみると

>class="modal-backdrop fade show"

が消えていないのが確認できました。
試しにこの状態でこれを消してみると、、、
![スクリーンショット (94).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/646e724a-5da6-6813-5d7a-14cf282860e5.png)
暗い部分が消えました！
ですが、この状態では**まだスクロールはできません。**

##つづいてmodal-openも消してみる
検証ツールを引き続きみてみると、「modal-open」というクラスがあることが確認できます。
左側を見てみると

>modal-open {
    overflow: hidden;

「modal-open」クラスは「overflow: hidden;」になっています。
これを消してみると、、、
![スクリーンショット (88).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1245620/0311912e-62ea-e853-e7e4-dd8ff9eba43c.png)

無事に動きました！これで想定した動作ができたことになります。
##まとめ
今回問題だったのが、
>class="modal-backdrop fade show"

>modal-open {
    overflow: hidden;

が**モーダルを閉じたときにも残っていた**ことが問題だったことがわかりました。

なので、jqueryで以下を付け足します。
>```
modal-backdropクラスを削除する処理↓
$(".modal-backdrop").remove();
modal-openクラスを削除する処理↓
$("body").removeClass("modal-open");
```


これで無事に実装ができました。
今回の事が同じような状況に遭遇している方の参考になれば幸いです♪
JIRAカスタムフィールドIDの調べ方

# カスタムフィールドとは
最初からJIRAに存在するシステムフィールドとは違い、自分で作成するフィールド。
作成毎にカスタムフィールドIDが振られる。(`customfield_00001`など)

# カスタムフィールドIDってどこに書いてるの？
これ、実は見つけるのがちょっと大変。
前提として、自分のJIRAアカウントに管理画面へのアクセス権がないと調べられません。
以下、カスタムフィールドIDの調べ方です。
<br>
該当のプロジェクトに移動
↓
`プロジェクト設定`をクリック
↓
`フィールド`をクリック
↓
歯車マークの`アクション`をクリックし、フィールドの編集をクリック
↓
調べたいフィールドの`編集`をクリック
↓
表示された画面のURLをチェック。
<br>
末尾に
`orderableFieldId=customfield_00001`
といった文言がありませんか？
この`customfield_00001`の部分がカスタムフィールドIDです。
`custom～`で始まってないよという方、それはカスタムフィールドではなくシステムフィールドで、そのIDがそのままフィールドIDです。
PHP8 と Laravel8 で league/flysystem-aws-s3-v3 をインストールするときにハマった

## Laravel で AWS S3 を操作したい時

- https://github.com/thephpleague/flysystem-aws-s3-v3

AWS S3を操作する時はこの `thephpleague/flysystem-aws-s3-v3` ライブラリを利用します。

## 環境

- PHP: 8.0.2
- Laravel: 8.34.0

## league/flysystem-aws-s3-v3 インストール時にエラー

```shell-session
$ composer require league/flysystem-aws-s3-v3
Using version ^2.0 for league/flysystem-aws-s3-v3
./composer.json has been updated
Running composer update league/flysystem-aws-s3-v3
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - league/flysystem-aws-s3-v3[2.0.0, ..., 2.x-dev] require league/flysystem ^2.0.0 -> found league/flysystem[2.0.0-alpha.1, ..., 2.x-dev] but the package is fixed to 1.1.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    - league/flysystem-aws-s3-v3[2.0.0-alpha.1, ..., 2.0.0-RC1] require php ^7.2 -> your php version (8.0.2) does not satisfy that requirement.
    - Root composer.json requires league/flysystem-aws-s3-v3 ^2.0 -> satisfiable by league/flysystem-aws-s3-v3[2.0.0-alpha.1, ..., 2.x-dev].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.
```

- https://github.com/thephpleague/flysystem-aws-s3-v3/releases

リリースを見てみると、現在の最新バージョン(2021.03.27)は、2.0.4です。
`thephpleague/flysystem-aws-s3-v3`のv2系を利用する場合、`thephpleague/flysystem`の2系をインストールする必要があるようです。

- https://github.com/thephpleague/flysystem/releases

`thephpleague/flysystem`の現在の最新バージョン(2021.03.27)は、2.0.4です。

Laravelフレームワークが利用している`thephpleague/flysystem`のバージョンを見てみましょう。

- https://github.com/laravel/framework/blob/8.x/composer.json#L26

```composer.json
    "require": {
        "league/flysystem": "^1.1",
    },
```

Laravelフレームワークが`league/flysystem`の1系を参照しているので、`thephpleague/flysystem-aws-s3-v3`の2系をインストールしようとするとエラーになってしまうという原因でした。

## league/flysystemのv2はいつ対応されるのか？

- https://github.com/laravel/framework/pull/33612

Laravel9.xから`league/flysystem`のv2がサポートされます。

## 公式ドキュメント

https://readouble.com/laravel/8.x/ja/filesystem.html#composer-packages

- Amazon S3: `league/flysystem-aws-s3-v3 ~1.0`

公式ドキュメントを見ると1系をインストールするようにとのこと。
(まぁ最初に見ろよって話ですが...)

## 解決

```shell-session
$ composer require league/flysystem-aws-s3-v3:^1.0
```
Springよくあるエラー 「Error during execution of processor... SpringInputFileFieldTagProcessor」

##環境
macOS
STS
spring-boot 2.4.3
Thymeleaf


##Error during exception of processor...とは？

エラーコード

```
Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputFileFieldTagProcessor'
```

##よくある原因

よくある原因としては

・Thymeleafオブジェクトの値を正しく参照できていない
・Thymeleafオブジェクトがそもそも存在しない

が挙げられる。

例えばth:objectで参照したオブジェクトがControllerから引き渡せていなかったり、参照したクラスフィールドが存在しない場合である。

###  ${} と *{} の違い
このSpringInputFileFieldTagProcessorのエラーを引き起こす際に良くある原因として、オブジェクトの表記方法に原因がある。

thymeleafのオブジェクトの値を参照する時

```
th:value="${test.hoge}"
```
ダラー($)で表記することが良くある。
ただ、値を参照する際もう１つの表記方法がある。
それが

```
th:value="*{hoge}"
```
という表記である。

このアスタリスク(*)は、オブジェクトのフィールド名を指定する際に用いられる記号である。

つまり

```
<form th:object="${test}">
  <input th:value="${test.hoge}">
</form>
```
と

```
<form th:object="${test}">
  <input th:value="*{hoge}">
</form>
```
は同じ結果になる。


よくある間違いで、このように記述してしまうと今回のエラーになる。

```
<form th:object="${test}">
  <input th:value="${hoge}">
</form>
```
PostmanからJIRA REST APIを叩いてみた（POSTメソッド）

PostmanからJIRA REST APIを叩いてみた。
GETについてはすでに色々に記載が見られるので、
POSTやPUTでフィールド連携するときのbodyの中身についてまとめてみた。

#JIRA REST APIとは

他システムなど、外からJIRA REST APIを経由してJIRAの課題の「追加、更新、検索、削除」ができる。<br>
HTTPメソッドの、追加=POST、更新=PUT、検索=GET、削除=DELETEでリクエストを送る。
<br>※今回は、JIRAバージョンの制約のためAPIはver2（2021/3現在の最新verは3）

# 早速叩いてみよう
とりあえずPOSTのリクエストを載せます。bodyに関してはPUTも同じなので参考になるのでは？
加えて、

* [フィールドの連携](#フィールドの連携)
* [ステータスの連携](#ステータスの連携)
* [コメントの連携](#コメントの連携)

はエンドポイントが別。それぞれ内容を以下に記載。

<a id="anchor1"></a>
## フィールドの連携

ヘッダーは以下
![ヘッダー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227763/7041b35d-39eb-c060-472d-44584bf0d524.png)

AuthorazationにはJIRAアカウントのIDとパスワードを入力。

エンドポイント↓

```json:endpoint
https://[自分のJIRAのホスト名]/rest/api/2/issue
```
<br>

そして肝心のbody↓

```json:body
{
    "fields": {
        "project": {
            "key":"ABC"
            },
        "summary": "TEST_JIRA_API",
        "issuetype": {
            "name":"task"
            },
        "labels": ["テスト", "管理"],
        "priority": {
            "name": "Medium"
            },
        "duedate": "2020-02-02T02:02:02.000+0900",
        "customfield_12345": "test",    
    }
}
```

1. `key`：自分のJIRAのプロジェクトキー。課題番号が`ABC-1`, `ABC-`の場合`ABC`がプロジェクトキー。
2. `summary`：システムフィールド(最初から存在するフィールド)の1つ。課題の要約、題名にあたり、たいていの場合入力必須なので、これを空欄にして送るとエラーが返ってくる。
3.  `issuetype`：システムフィールドの1つで、課題タイプのこと。taskの他に、incident, storyなど
4.  `labels`：システムフィールドの1つで、ラベル。,(カンマ)で区切って複数設定が可能
5.  `priority`：システムフィールドの1つで、優先度。
5.  `duedate`：システムフィールドの1つで、期日。<br>値のタイムスタンプは自身の環境によって異なるので、要確認。GETでリクエスト送ってレスポンスで返ってきた日時のタイムスタンプを確認するのが一番早い。
6.  `customfield_12345`：カスタムフィールド(自分でカスタマイズして作成したフィールド)のIDを入れる。<br>
カスタムフィールドとはなんぞ？カスタムフィールドIDはどうやって調べるの？っていう方はこちらの記事を参照ください↓　<br>
[JIRAカスタムフィールドIDの調べ方](https://qiita.com/Chiri_Tsumo/items/b88764a1e89bd13d57a3)


## ステータスの連携

ヘッダー、認証はフィールド連携と同じ。
エンドポイント↓

```json:endpoint
https://[自分のJIRAのホスト名]/rest/api/2/issue/ABC-1/transitions?expand=transitions.fields
```
`ABC-1`の部分にコメントを追加したいJIRAの課題番号を入れる。
<br>

body↓

```json:body
{
　　 "transition": {
         "id": "[トランジションID]"
         },
     "fields": {
          "resolution": {
               "name": "Done"
               }
          }
 }
```
`resolution`：システムフィールドの1つで、解決状況のこと。Done, Unresolvedなど。
<br>トランジションIDってなに？？IDの調べ方わからんよという方、こちらの記事を参照ください↓
[JIRAトランジションIDの調べ方](https://qiita.com/Chiri_Tsumo/items/1c8dc7237e6d64dc5b1a)

## コメントの連携

ヘッダー、認証はフィールド連携と同じ。
エンドポイント↓

```json:endpoint
https://[自分のJIRAのホスト名]/rest/api/2/issue/ABC-1/comment
```
`ABC-1`の部分にコメントを追加したいJIRAの課題番号を入れる。
<br>

body↓

```json:body
{
    "body":"テスト"
}
```
これで"テスト"というコメントが追加されているはず。
CupertinoPageRouteで前画面に戻るときだけスワイプ可能にする

# やりたいこと

iOSアプリでよく見る、前画面に戻る際にスワイプで戻れるようにしたい。

ただし、前画面に戻る以外の画面遷移はスワイプしないようにする。

# 解決策

1. CupertinoPageRouteクラスを作成

    ※引数がいくつか入っていますが、適宜変更してください

2. CupertinoPageRouteにDurationを設定
3. 次の画面に進む処理を0秒に設定
4. クラスを任意の画面遷移処理の部分で呼び出す

```dart
// スワイプバック可能にする
class MyCupertinoPageRoute<T> extends CupertinoPageRoute<T> {
  MyCupertinoPageRoute({ WidgetBuilder builder, RouteSettings settings })
    : super(builder: builder, settings: settings);
  
  // 次の画面に進む処理
  @override
  Duration get transitionDuration => const Duration(seconds: 0);

  // 前の画面に戻る処理
  @override
  Duration get reverseTransitionDuration => const Duration(seconds: 1);
}
```

実際は全ての画面遷移時にもスワイプしてますが、遷移時間を0秒にすることで

スワイプには見えない処理にすることができました。


もっと良い方法があればぜひ教えて下さい。。。

# 参考サイト

[https://api.flutter.dev/flutter/material/MaterialRouteTransitionMixin/transitionDuration.html](https://api.flutter.dev/flutter/material/MaterialRouteTransitionMixin/transitionDuration.html)

[https://medium.com/flutterdevs/page-transitions-in-flutter-5236a8afae92](https://medium.com/flutterdevs/page-transitions-in-flutter-5236a8afae92)
Docker基本コマンド

#Dockerの基本的な流れ
アプリコード
Dockerfile

↓作成

イメージ

↓作成・起動

コンテナ

↓停止
↓削除

#コマンド
* イメージを作成

```
docker image build
```

* イメージが作成できたかの確認

```
docker image ls
```

* dockerコマンド一覧

```
docker --help
```

* コンテナの作成・起動

```
docker container run
docker container run -d (バックグラウンドで実行される)
```

* コンテナの起動状態の確認

```
docker container ls
docker container ls -a
```

* コンテナの停止

```
docker container stop
```

* コンテナの削除

```
docker container rm
```

* ログの確認

```
docker container logs
```

* 実行中のコンテナで別のコマンドを使う

```
docker container exec
```

* 後片付け

```
docker system prune -a
```
[iOS]プロジェクト内のJSONファイルを取得する方法

#概要
自分が直近やったことを備忘録として書きます。
iosアプリで事前に準備したJSONファイルを読み込んで、表示するということをやったのでまとめます。

#環境
・mac
・Xcode(Version 12.0.1)
・Swift UI


##JSONファイルを準備
今回は下記のJSONを用意して使用しました。

```
{
  "GoodMorning":"good morning",
  "Hello":"hello",
  "GoodEvening":"Good evening",
  "Test": {
      "Name":"name",
      "PassWord":"password"
  }
}
```
JSONファイルを作成したらプロジェクト内に配置します。

##データモデルを作成
用意したJSONファイルにあったデータモデルを作成します。

```
import Foundation


struct SampleModel: Codable {
    let goodMorning, hello, goodEvening: String
    let test: Test

    enum CodingKeys: String, CodingKey {
        case goodMorning = "GoodMorning"
        case hello = "Hello"
        case goodEvening = "GoodEvening"
        case test = "Test"
    }
}


struct Test: Codable {
    let name, passWord: String

    enum CodingKeys: String, CodingKey {
        case name = "Name"
        case passWord = "PassWord"
    }
}
```

このデータモデルですが簡単に作ってくれるサービスがあるので、今回はそれを使って作成しました。
https://quicktype.io/

##JSONから取得したデータをオブジェクトに変換
JSONファイルとそのJSON用のデータモデルが用意できたら、JSONを呼び出して、実際に使用できる様にするための処理を書いていきます

```
import Foundation
func ReadJson() throws -> SampleModel?{
    //①JSONファイルのパスを取得
    guard let path = Bundle.main.path(forResource: "sample", ofType: "json") else {
        return nil
    }
    //②パスからJSONファイルのデータを取得
    let url = URL(fileURLWithPath: path)
    
    //③JSONDecoder()を使用してデータモデルのSampleModelオブジェクトに変換する
    let sampleData = try? JSONDecoder().decode(SampleModel.self, from: Data(contentsOf: url))

    return sampleData
}
```
ReadJson()という関数を作成して、returnとしてデータモデルで作成したSampleModelオブジェクトに変換して返すようにしています。

①で書いたパスの取得ですが、
```Bundle.main.path```で取得できるのはアプリケーションバンドルにあるものしか取得できない様です。
テストコードを書いている際に、テストバンドル内のJSONのパスを取得したいってなった時は

```
let testBundle = Bundle(for: type(of: self))
let path = testBundle().url(forResource: "sample", withExtension: "json")
```
の様に書くと取得できます。

③で使用しているJSONDecoder()は、JSONから取得したデータをデータモデルで書いたオブジェクトのかたちに変換してくれるらしいです。



##画面上に表示してみる
今回はJSONからちゃんと取得できているかというところだけを確認したかったのでTextとして羅列させてみました。

```
struct ContentView: View {
    let text: SampleModel = try! ReadJson()!
    var body: some View {
        Text(text.goodMorning)
            
        Text(text.hello)
            
        Text(text.goodEvening)
        
        Text(text.test.name)
        
        Text(text.test.passWord)
    }
}
```
上記を追加した後にビルドしてみると
![スクリーンショット 2021-03-27 15.40.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948599/9fc61384-ed48-95ce-d89a-3cd5ef25d0f3.png)
ちゃんと取得できてますね。

#最後に
今回初投稿です。
自分の備忘録のつもりで書いていますが、自分以外の人が読んでもわかる記事になっているかが正直不安です…
今後も定期的に書いていくつもりなのでその都度精進していきます。
javascriptのネストしていないオブジェクトを比較する

javascriptのオブジェクトを比較する時に、等価演算子(===)を使ってはだめというのは良く知られています。(たぶん)

https://developer.mozilla.org/ja/docs/Web/JavaScript/Equality_comparisons_and_sameness

"JS オブジェクト 比較"とかをキーワードにぐぐると、deep-equal使えとか、JSON.stringifyして比較すると順序が一致しないから駄目とかそういう情報がすぐに見つかることでしょう。

https://www.npmjs.com/package/deep-equal


でも実際には、次のような __ネストの無い__ オブジェクト同士の比較ができれば十分ということが多々あります。

```
const foo={hoge:"hoge", huga:"huga"}
const bar={hoge:"hoge", huga:"huga"}
const baz={hoge:"piyo", huga:"poyo"}
```

こんな作業にわざわざパッケージを導入するのは、鶏を捌くのに牛刀を持ち出すようなもの。
というわけで、JSのビルドイン関数だけでなんとかしてみましょう。

```
function shallowEqual(l,r){
 if(l===r){
   return true
 }
 
 const lKeys=Object.keys(l)
 const rKeys=Object.keys(r)
 if(lKeys.length !== rKeys.length){
   return false
 }
 return !lKeys.some( (key)=>{
  return  typeof r[key] === "undefined" || l[key] !== r[key]
  }) 
}
```


最初は、`Object.entries`でプロパティと値をとってきて、someに渡せば一発でできるかと思ってたんですが、keyの数が違うケースとか片方のオブジェクトだけに含まれるkeyのこととか考えていくと意外と面倒ですね。

最後にもう一度書いときますが、この関数で比較できるのは、全ての列挙可能なプロパティの値が `===` で比較できるオブジェクト同士の時だけです。
ネストしたオブジェクトが渡されても、特にエラーは返さず、誤判定することがありますので気をつけてください。



<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="クリエイティブ・コモンズ・ライセンス" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />この 作品 は <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンスの下に提供されています。</a>
忘備録_Logic_BubbleSort_1

理解度がかなり中途半端なので理解が進む毎に更新していく。
かなり分かりにくい説明ですが自分なりの理解は進みました。

###少し長いですが、自分なりの復習して理解できた

```BubbleSort4.java


public class BubbleSort_4 {
	public static void sort1(int[] a) {
		int buf;//i,jの並び替えの為bufを用意
		for (int i = 0; i < 10; i++) {//全体の要素数10(0~9)
			for (int j = 0; j < 9; j++) {//最後は比較しないので全体の要素数から-1した数(0~8)
				if (a[j] > a[j + 1]) {//1と1の場合は比較されないのでスルーflase/条件分岐a[j]の次の要素a[j+1]が大きかったらtrue
					// j ループの時のa[j]を一旦bufに格納
					buf = a[j];
					//格納して空になったa[j]に次の要素のa[j-1]を格納する
					a[j] = a[j + 1];
					//次の要素のa[j-1]に一旦格納したbufを再度格納
					a[j + 1] = buf;
				}
			}
		}
		for (int b : a) {
			System.out.println(b);
		}
	}

	public static void main(String[] args) {
		var r = new Random();
		//要素数の初期化d
		int[] a = new int[10];
		int i;
		for (i = 0; i < 10; i++) {
			//a[i]番目に要素を入れていくr.nextInt(30)の代入
			a[i] = r.nextInt(30);
			System.out.println(a[i]);
		}
		//		int[] a = {1,1,13,57,8,2,54,3,5,33,};
		System.out.println("-------");
		sort1(a);
		}
	}



```

###例として
1回目のループ0~9 i → 0
2回目のループ0~8 j → 0
例 num a{⑤,①,⑨}

```s.java
if(a[j]//index[0num⑤]番
>
a[j+1])//index[1num①]番を比較
//この時trueになり
int buf = a[j]//⑤を代入
a[j] = a[j +1]//①を代入
//次の要素に
a[j+1] = buf //⑤を再度代入
//次の i → 0 j →　１ ループ時に a[j + 1]⑤はa[j]となり
//a[j]⑤とa[j+1]を再度比較するその為
//例 num はa{①,⑤}と入れ替わっている
```
###次に
例 num a{①,⑤,⑨}
1回目のループ0~9 i → 0
2回目のループ0~8 j → 1

```s.java
if(a[j])//a[index番号1 j ]⑤
>(a[j+1])//次の要素 ⑨
//を比較し式が成立しないのでfalse
///a{①,⑤,⑨}
```
この繰り返し



###比較の時
昇順(1,2,3)>
降順(100,99,98)<

```s.java
(a[j] > a[j + 1])
(a[j] < a[j + 1])
```



###分かりやすかったので参考にしました

```BubbleSort3.java

public class BubbleSort_3 {

	public static void main(String[] args) {
		int[] a = {5,3,9,1,8};
		int i, j,buf;

		for( i = 0; i < 5; i++) {
			for(j = 0; j < 4; j++) {
				if(a[j] > a[j + 1]) {
					buf = a[j];
					a[j] = a[j + 1];
					a[j + 1] = buf;
				}
			}
		}
	}
}

```


```BubbleSort.java
public static void sort1(int[] a) {
//外側のループは大きな数字を確定させていくループ
//ループ変数iは0,1,2,3 = 4回ループが実行される
		for (int i = 0; i < 4; i++) {
//要素数から１引いた数
			for (int j = 0; j < 4 - i; j++) {
				if (a[j] > a[j + 1]) {//隣り合う要素との大小判定を行う
//a[j]の方が大きいので交換を行う
					int tmp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = tmp;
				}
			}
		}
		for(int b : a) {
			System.out.println(b);
		}
	}
	public static void main(String[] args) {
		int[] a = {10,4,5,6,1};
		sort1(a);

	}
実行
1 4 5 6 10
				}
			}
		}
	}
```
Raspberry Pi OS 2021-03-04 Release-note 翻訳

(追記: 2021/5/29にRaspbian OS 2021-05-07がリリースされています)
https://qiita.com/utaani/items/826db0d06b505613aa3c

https://downloads.raspberrypi.org/raspios_full_armhf/release_notes.txt

2021-03-04：

  - Thonnyがバージョン3.3.5にアップグレードされました
  - SD Card CopierはGTK+3ツールキットを使ってビルドされ、NVMeデバイス互換になりました
  - Raspberry Pi 4において、Raspberry Pi Configurationからコンポジットビデオオプションが削除されました
  - raspi-configの起動順序オプションが柔軟性を高めるために調整されました
  - Recommended SoftwareがGTK+3ツールキットを使ってビルドされました
  - ボリュームプラグインでキーボードを使用すると値が範囲外にできクラッシュするバグが修正されました
  - ファイルマネージャーでキーボードを使用してディレクトリビューをナビゲートするときにウィンドウ間でフォーカスが変更される問題が修正されました
  - 起動ウィザードでRaspberryPi400キーボードの国が正しく読み取られない問題が修正されました
  - アルメニア語と日本語の翻訳がいくつかのパッケージに追加されました
  - ARM64にaes-neon-bsを自動的にロードして、OpenSSLを高速化します
  - RaspberryPiファームウェアfcf8d2f7639ad8d0330db9c8db9b71bd33eaaa28
  - Linuxカーネル5.10.17
A-Frame: 8bitゲーム機の世界を体験するVR

１年ほど前に A-Frame のライブラリを色々試してみたので、ここいらで何か作ってみるかと思い、簡単なインタラクションを楽しめる [VRコンテンツ](https://k38.github.io/aframe/8bit/index.html) を作成して放置していたので、ブログに上げてみます。

8bitゲーム機を彷彿とさせる世界の中で、アイテムを見つけてパワーアップし、ブロックを壊したりできます。

このへんの記事で試したライブラリを利用しました。

- [A-FRAME: 物理演算でボーリングっぽい動きを実現してみる１１（これまでのまとめ）](https://qiita.com/matsukatsu/items/8de043abd3bae0a28ffb)
- [VR滑走路を作ってみた](https://qiita.com/matsukatsu/items/7544307deb02a927bc17)



### 楽曲素材
こちらのサイトの楽曲を利用させて頂きました。

- [(C)PANICPUMPKIN](http://pansound.com/panicpumpkin/music/kiyaku.html)
- [(C)OtoLogic](https://otologic.jp/free/license.html)
- [OPENGAMEART.ORG](https://opengameart.org/content/512-sound-effects-8-bit-style)
Egress-Only Internet Gateway とは

## 勉強前イメージ

インターネットゲートウェイでもEgress-Only・・・？
わからん

## 調査

### Egress-Only Internet Gateway とは

IPv6を使用してインターネットに出たいときに使用するもの。
しかし、IPv6はインターネットへのEgress(送信)のみでIngress(受信)はできません。
NATゲートウェイのIPv6バージョンのようなもの

### 違い

- NATゲートウェイとは？

プライベートIPとパブリックIPを `多対1` で変換するもの
プライベートサブネットからネットワークに通信したい際に使用する
※事前にVPCにインターネットゲートウェイがアタッチされてることを確認

- インターネットゲートウェイとは？

プライベートIPとパブリックIPを `1対1` で変換するもの

![2021-03-24 インターネットゲートウェイ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/bddf156e-129f-7307-722b-7f3d344e7de0.png)

### マネジメントコンソールではどこで確認できるか

Egress-Only Internet Gateway はVPCから設定することが出来ます

![2021-03-24 VPC.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/554ba4ea-1fd2-33cf-5f35-028bf6e8e470.png)


## 勉強後イメージ

あんまりIPv6が必要になる時ないから知らなかった・・・
覚えておこう

## 参考

- [Gatewayが多過ぎて何がなんなのかわからない？AWSのGateway全種類解説！ーその１](https://blog.serverworks.co.jp/aws-gateways-1)
- [【図解/AWS】インターネットGWとNAT-GWの違い〜各メリット、パブリックサブネットとは〜](https://milestone-of-se.nesuke.com/sv-advanced/aws/internet-nat-gateway/)
pͪoͣnͬpͣoͥnͭpͣa͡inͥを支える技術 のWebサービスを少しだけ改良した

##この記事に登場するWebサービスの話

https://qiita.com/ykhirao/items/9ca1fbd294883e06dbd6

##実際に使ってみた

こちら

https://ykhirao.github.io/qiita/ponponpain/dist/

##最初にミスると後で困る
![ponponpain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122701/100c033d-0a08-0a1f-c5b8-f84d6d51134a.png)
`moudame~` って入力しようと思ってたのに序盤に顔文字入れたせいで入りきらない！ってなっている場面😿
前方から削除できないから全部消してやり直しだ❗️😾

##左右にシフトできるようにした

![qwaae-bhshe.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122701/ffb72c02-98f4-8482-0a70-29a4da026f06.gif)

左右に動かせるから編集しやすいぞ❗️😸

##成果物
https://emoshare.net/ponponpain

##おわりに

一応レスポンシブ対応したけど1画面に収まってないので普通に使いづらい😿
先頭に文字追加できないので実は全然便利になっていない説😿

ほぼ丸パクリなので原作者に怒られたら消します🐱
【Ruby】writeメソッドの使い方

#プログラミング勉強日記
2021年3月27日

#writeメソッドとは
　Rubyで指定したファイルを読み込むときに使うメソッド。指定したファイルがない場合には新しくファイルを作成して書き込むが、すでにファイルがあった場合は内容がすべて上書きされる。

```ruby:書き方
File.write("ファイル名","書き込む内容")
```

#サンプルプログラム

```ruby:sample.rb
# sample.txtのファイルを作成し、「Hello World」を書き込む
File.write("sample.txt", "Hello World")  
#文字を書き込んだファイルを開き変数に代入
file = File.open("sample.txt")  
#コンソールにファイルに書かれた内容を表示する
puts file.read  
file.close  #ファイルを閉じる
```

#参考文献
[Rubyのwriteメソッドの使い方を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/50292)
[ファイルに文字列を書き込む（出力する）には？](https://www.buildinsider.net/language/rubytips/0022)
heroku上で画像が表示されなったので対処

ってかそもそもの手順を知らないから、この事象が当然起こる事なのか、イレギュラー的事象なのかすら分からない・・・
![スクリーンショット 2021-03-27 14.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/893740/d95186be-de58-733f-2857-7290f1bb3114.png)
もうちょっとなんか必要だろう・・・ってのは気付いてますよ？
なので・・・
![スクリーンショット 2021-03-27 15.00.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/893740/b0d1f3d5-0aec-df04-b9ed-a9fae10211ba.png)
これで解決！
「謎のコマンド」については後々理解しよう。

色々解決策を探して記事を読み漁ったから・・・
おそらくこの後、一定時間経過すると画像が表示されなくなる問題が発生するのは分かってる。
忘備録_Logic_Randomのint型値格納

8つの箱にランダムに値を入れます

```RandomInt.java

	var r = new Random();
		int[] array = new int[8];
		for(int i = 0; i < array.length; i++) {
			array[i] = r.nextInt(30);
		}
実行(例)
28
 10
 9
 2
 0
 23
 21
 26

```
なんでUnityWebGLを無理矢理モバイルで動かすとメモリ効率が悪いのかの考察

UnityWebGLでテクスチャを扱うとメモリ消費がえぐいことで知られているがモバイル向けに無理矢理表示すると
普通のPC以上に消費する傾向があるように見えたので文献をいくつか見て考察したい、
ちゃんとパフォーマンストレースできる手法を確立できてないので辛いところ・・・

# UnityWebGLのテクスチャ圧縮
https://docs.unity3d.com/ja/2018.4/Manual/class-TextureImporterOverride.html

>高速テクスチャサンプリングに最適化された専用の形式でテクスチャを圧縮する必要があります。異なるプラットフォームとデバイスにはそれぞれ独自のフォーマットがあります。

Unity側でテクスチャを圧縮してくれる機能があってWebGLはWebGLで専用の圧縮形式があるんですね

>ノート: sRGB DXT をサポートしないウェブブラウザーの リニアレンダリング では、テクスチャはランタイムに RGBA32 に解凍されます。


RGBA Compressed DXT・RGB Compressed DXTでWebGLの場合圧縮してくれてるんですがこれがブラウザー依存の挙動になります


# ブラウザー側の対応状況
WebGL APIでDXT形式は定義されているんですが `WEBGL_compressed_texture_s3tc`
の実装がブラウザーによって違うみたいです
## WEBGL_compressed_texture_s3tc
https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_compressed_texture_s3tc
MozillaのWebGLリファレンスで対応状況が書かれていますが
2021/03/27現在 現状ではFirefoxだけ言及がないですが（Mozillaさん・・・自分のですよね・・・）
モバイル版ブラウザでは対応がない状況です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/64665a84-bda1-aef4-9f79-d61ae5ae89bd.png)

# 所感
DXTアルゴリズムの圧縮率は6/1:8/1と結構高いのでただでさえメモリ消費にギャアギャアうるさいモバイルブラウザでは致命傷になる気がします　※圧縮率に関してはWikipedia引用

# 今後やってみたいこと
ブラウザごとの挙動をトレースして実際にどのようなパフォーマンスなのか把握してみたい

# 参考文献
https://ics.media/entry/17863/
https://ja.wikipedia.org/wiki/DXTC


本当のところはよくわからないから変なこと言ってたら指摘お願いします
mutate_allを使って空文字を置換する【R】

Rでデータハンドリングをする際に空文字の置換に関する情報が少なかったので記事にしました。
困っている方の参考になれば幸いです。

# データ作成

```r
library(tidyverse)
gender <- c("F", "F", "M", "M", "M")
answer_1 <- c('', 'x', '', '', 'x')
answer_2 <- c('x', '', 'x', '', 'x')
answer_3 <- c('', '', '', '', 'x')
df <- data.frame(GENDER=gender
                  , ANSWER_1=answer_1
                  , ANSWER_2=answer_2
                  , ANSWER_3=answer_3)
```

|  gender |  ANSWER_1 |  ANSWER_2 |  ANSWER_3 |
|  ----   |    ----   |    ----   |    ----   |
|    F    |           |     x     |           |
|    F    |     x     |           |           |
|    M    |           |     x     |           |
|    M    |           |           |           |
|    M    |     x     |     x     |     x     |

上記のようにnullではなく空文字が入っている処理の対応に苦戦しました。
もしnaであればmutate_all(~ifelse(is.nan(.),0,.))とすれば良いというのはいくつか見ましたが、空文字の場合どうすればよいのかというのがわからず時間がかかりました。

# 空文字の置換
is.nan(.)の部分を.==''にすることで対応できました。

```r
df_fix <- df %>%
  mutate_all(~ifelse(.=='',0,.)) 
```

|  gender |  ANSWER_1 |  ANSWER_2 |  ANSWER_3 |
|  ----   |    ----   |    ----   |    ----   |
|     F   |     0     |     x     |     0     |
|     F   |     x     |     0     |     0     |
|     M   |     0     |     x     |     0     |
|     M   |     0     |     0     |     0     |
|     M   |     x     |     x     |     x     |

ついでにxを1に変換する処理を追加する場合はこちら

```r
df_fix <- df %>%
  mutate_all(~ifelse(.=='',0,.)) %>%
  mutate_all(~ifelse(.=='x',1,.)) 
```
|  gender |  ANSWER_1 |  ANSWER_2 |  ANSWER_3 |
|  ----   |    ----   |    ----   |    ----   |
|    F    |     0     |     1     |     0     |
|    F    |     1     |     0     |     0     |
|    M    |     0     |     1     |     0     |
|    M    |     0     |     0     |     0     |
|    M    |     1     |     1     |     1     |

個人的にはこちらの記事が参考になりました。

- https://www.javaer101.com/ja/article/41801655.html
- https://blog.okazuki.jp/entry/2015/12/09/204959


ifelseの使い方を知っていればすぐに解決しそうでした。
ERROR: Service 'web' failed to build を解決する

Dockerを使っていて、font-awesomeを使っていこうと思い、
`docker-compose run web bundle install`をしたあとに、
`docker-compose build`を実行しようとしたところ、タイトルのエラーとなってしまいました。今回は自分の解決した方法とそ子に行き着くまでの過程を話していきたいと思います。

まず最初にやってみたこととして、エラーメッセージに出てきたコマンドを打ってみました。それがこちらです

```
/bin/sh -c bundle install
```
しかしこれでも同じエラーになってしまいました。調べてみるとbundlerもrubyもインストールされていないことが原因だと思うと書いてあったteratailのものがありました。
ここでピーンときたのが、一つありました。それは、
・バージョンの違いが起こしているエラー(何かしらの)
と思いました。
エラー分を改めてよく見ていると、

```
Your bundle is locked to mimemagic (0.3.5), but that version could not be found
in any of the sources listed in your Gemfile. If you haven't changed sources,
that means the author of mimemagic (0.3.5) has removed it. You'll need to update
your bundle to a version other than mimemagic (0.3.5) that hasn't been removed
in order to install.
```
要するに、`mimemagic(0.3.5)`なんてバージョンこのジェムにはないぞってことらしいのですが、これ書いてあった場所Gemfile.lockでした。
ってことは、それがないと言うのはおかしいということになります。最初から入っているものなわけだから。
後々入れていったgemのバージョンが求めているものと一致していないのかなと思ったので、とりあえずこれを実行してみました

```
docker-compose run web bundle update
```

そしたら無事通りました!!
やったぜ。
この仮説は間違っているかもしれません。ですので、突っ込みたいところなどありましたらガンガン教えて下さい。
何分初心者なので
【React】ActionsとReducersを図でまとめてみた

React学習を始めておよそ１週間ほど経ちますが、Vueと比べるとやはり難しいですね。

今、``router``と``redux``を学習しているのですが、どうも感覚がつかみづらい。

Vueではこれらすべて自動で作成してくれたのでてっきりReactもそうなのかなと思っていました。

こういう時はインプットよりもアウトプットを優先。

ということで図にまとめてみた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954754/1320d99e-4689-79f4-e812-5ca108c1e633.png)

イメージ的にはこんな感じだと思う。。。

#Action#

```javascript
export const textInputAction = (state) => {
  return {
    type: 'TETX_INPUT',
    payload: {
      text: state.text
    }
  }
}
```

``type``でどのようなアクションを起こすのかを定義。

``payload``で変更する値を決める。

#Reducers#

```javascript
export const UsersReducer = (state = {}, action) => {
  switch (action.type) {
    case 'TEXT_INPUT':
      return {
        action.payload
      }
    default: 
      return state
  }
}
```

Actionsで定義した``type``と合致するアクションを起こす。

とりあえずはこんな感じで``store``の内容を変更できる。

他にも非同期処理などを加えるがやり方はまだわからないので割愛。

いや～むずい！
【Swift】Main.storyboard起動をやめる

#はじめに
自分用メモです。

#やりたいこと
XcodeはデフォルトでMain.storyboardを作成してくれ、何もしないとこのstoryboardが初めの画面になります。
これを、storyboard referenceなどを使った時に違うstoryboardを初期画面に設定することです。

#実装
Info.plistを開くと、Application Scene Manifestの階層にStoryboard Nameがあり、Mainになっています。
![スクリーンショット 2021-03-27 14.45.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/ed65159d-82ba-1667-2de9-827bca634359.png)

これを例えば、First.storyboardを初期画面にしたければ、MainをFirstにします。
そして以下の`Main storyboard file base name`もMainになっているのでFirstに変更してあげましょう。
![スクリーンショット 2021-03-30 14.08.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/28f3b1d0-0860-9f2c-5e4c-057881c6fb99.png)

#おわりに
おわりです。
シンプルで使いやすいIPアドレス確認ツールを作ってみた

# はじめに

こんにちは、システム開発チーム「presto」です。
開発業務（プログラミング中）に「こんなツール、あんなツールが身近なところにあったらいいなぁ」と思ったことはありませんか？

ここではそんなツールをVuetifyを使って作ってみたので紹介させてください。

# IPアドレス確認ツール

今回紹介させていただくのは、[IPアドレス確認ツール](https://web-tools.presto-service.com/ip-address)です。

画面は以下の通りです。
![IPアドレス確認ツール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/fedc00ca-fe49-573d-14c4-2600a54adf7e.png "IPアドレス確認ツール")

# 使い方

使い方は簡単、[IPアドレス確認ツール](https://web-tools.presto-service.com/ip-address)を開くだけでOKです。
接続した端末のグローバルIPアドレスを表示されます。

IPアドレス表示エリアをクリックするとコピーできます。
![IPアドレス表示エリア](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/d7afde5d-ff1a-c540-6085-ede836f0eaf7.png "IPアドレス表示エリア")

# まとめ

今回は、[IPアドレス確認ツール](https://web-tools.presto-service.com/ip-address)の紹介をさせていただきました。

他にも、私達が作った[presto web tools](https://web-tools.presto-service.com/)の紹介もしていますので、良ければ合わせてご覧ください。

https://qiita.com/presto/items/cd5f4cd6e3f364025606

https://qiita.com/presto/items/2d79f8208f78685ff990

https://qiita.com/presto/items/21a6713a108da35075c0

https://qiita.com/presto/items/e8e1d6fa5b07306937d9

https://qiita.com/presto/items/8dfa800eb8d3008686b1


今後もよろしくお願いします。
ありがとうございましたー！
[Android]Vector Assetに枠線をつける方法

初めに
===
AndroidのVectorDrawableを利用することであらかじめ用意されている画像を簡単に利用できます。
そのVectorDrawableに枠線をつける方法をまとめていきます。

VectorDrawableの作成
===
Android StudioのVector Assetでデフォルトで作成されるのは以下のようなxmlになります。

```xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:tint="#FFFFFF"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"
 />
</vector>
```
このxmlによって作成されるDrawableリソースは以下のようになります。
![device-2021-03-20-204356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487320/420f5a4c-be34-25ec-73f8-d90e6b0d192c.png)
枠線をつける
===


以下のように変更することで枠線をつけることができます。

```xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"
        android:strokeWidth="1"
        android:strokeColor="@android:color/holo_red_dark" />
</vector>
```

変更後のDrawableリソースは以下のようになります。
![device-2021-03-20-204748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487320/290dfcb7-eca8-d505-9e45-26178db56605.png)

変更箇所
===
枠線をつけるにあたり変更した個所について説明します。
tint:リソース全体を着色
strokeWidth:枠線の太さをFloat型で指定
strokeColor:枠線の色を指定

参考
===
[Add multi-density vector graphics](https://developer.android.com/studio/write/vector-asset-studio?hl=ja)
ターミナルでjupyter notebookするとcommand not foundと言われる（pip3インストール)

macのターミナルでjupyter notebookをインストールしたのち、`$ jupyter notebook`すると`-bash: jupyter: command not found`が返ってきた。

#インストール
`$ pip install --upgrade pip`(pipを最新のものにする）してから`$ pip3 install notebook`を実行した（と思う）。

#pip list:インストール済パッケージのリスト
`$ pip list`するとどどんとリストが出てくる。jupyterとかnotebookが入ってるから、インストールはできているっぽい。
参考：[Python, pip list / freezeでインストール済みパッケージ一覧を確認note.nkmk.me](https://note.nkmk.me/python-pip-list-freeze/)

#フォルダにパスが通っていないのではないか？

[pipでインストールしたjupyter notebookを起動しようとして「command not found」と言われたらPATHを通せばいけるっぽい。](https://qiita.com/midonon/items/96acbf3aacdebe38f96c)ってことなので、まずはパスが通っているかいないかを確認。

**1. パスが通っているフォルダはどこ？**　`$ echo $PATH`すると表示される
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:

**2. jupyterがいるフォルダはどこ？**`$ pip3 show jupyter`すると表示される`/usr/local/lib/python3.9/site-packages`

結論：通ってない。

#パスを通す

[Python - terminalからjupyter notebookが起動しない｜teratail ](https://teratail.com/questions/251164)の回答を参考にパスを通す！

1. ターミナルを開き`$ vi .zprofile`-->viで.zprofileが開く
２.`export PATH=$PATH:~/Library/Python/バージョン/bin`を入力して閉じる（escキー→`:wq`→returnキー）。当たり前だが、バージョンのところは自分のバージョン
3. 設定反映のために`$ source .zprofile`
4. `$ jupyter notebook`で成功


ちなみにパスを通すって何？→[「PATH を通す」の意味をできるだけわかりやすく説明する試み - Qiita ](https://qiita.com/sta/items/63e1048025d1830d12fd)

---
jupyter notebookを使う必要はないんだけど、「あああああ、パスを通すって、前もやったのに全部忘れてるーーー。通したいーーーー」と思ったからムキになってやっちゃった。

ターミナルのコマンドも、viエディタの使い方も忘れていた。偉大なる先人たちよ、ありがとう…。

足の上で寝ている犬が重い。
【Next.js】Next.jsで作ったアプリのVercelへのデプロイ方法【React】

##はじめに
VercelとはNext.jsを開発している会社で静的サイトとサーバレス機能のホスティングを提供するクラウドプラットフォーム。
JAMStackなWebサイトやサービスをGUIで簡単にデプロイできる。
Next.jsに至っては、ウチでデプロイしないと本領発揮できませんよー的なノリでVercelがデプロイを推奨している。
料金プランは三つあるが、非営利の個人運用とかポートフォリオ用なら無料のHobbyプランでOK。
従量課金でもないので、基本無料で使える。
##デプロイ方法
まず作ったアプリのリポジトリをGitHubに作成する。![スクリーンショット 2021-03-27 13.41.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076062/aafd12f0-eb9b-3fb2-4832-3611d96384c7.png)
赤丸をクリック。
次にここにリポジトリ名を入力する。
なんでもいいが、基本作ってるアプリのディレクトリ名とか。
入力したら他は全部飛ばして一番最後の「Create repository」をクリック
![スクリーンショット 2021-03-27 13.42.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076062/021f3757-88be-2237-ca71-6b3a0343387c.png)
出来たらvscodeのここからコミットメッセージを入れて赤丸をクリック。
コミットメッセージは何でも良いが、最初なら「initial commit」とか。
![スクリーンショット 2021-03-27 13.47.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076062/23184f4a-949d-8070-75d7-be8187debad0.png)

githubの作ったリポジトリのページに行って、コマンドラインからソースコード上げるならこれしろ。みたいなノリで書いてあるソースコードを打ち込む

````ターミナル
~$ git remote add origin https://github.com/ユーザー名/リポジトリ名.git

~$ git push -u origin main
````

ここまでやってGithubをリロードするとファイルがちゃんと上がってるはず。
それから[Vercel](https://nextjs.org/)にログインして、New Projectをクリック
![スクリーンショット 2021-03-27 14.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076062/33a4705a-0b4d-26ad-8394-b74063fe30b1.png)
Import Git RepositoryのデプロイしたいアプリのImportをクリック。
個人の場合はPERSONAL ACCOUNTをクリック
![スクリーンショット 2021-03-27 14.03.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076062/c016845b-ddfe-3ddc-2c11-847720ff2e3d.png)
この画面で、RESTAPI等を作ってそこからAPIでやりとりしたり環境変数が必要な場合は、Environment Variablesに入力していく。完了したらAddをクリック
![スクリーンショット 2021-03-27 14.04.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076062/16c29eea-2f45-9979-295c-f5a526da7b86.png)
環境変数周りをOKならDeployをクリックで正しくデプロイ出来れば紙吹雪が舞います！！
##デプロイ後の更新
更新はvscodeでcommitして、ターミナルでgit push -u origin mainでデプロイが走り即時反映される。
RFID RC522でのFirmware Version: 0x0 = (unknown)について


##はじめに

ESP32 or ArduinoにてRFID-RC522を動作させようとしたらエラーが発生して結構つまづいたので共有します。
機材：ESP32 DevkitC
RFIDリーダモジュール:RC522 Amazonで評価いいものを選んだつもり
##エラー内容
***Firmware Version: 0x0 = (unknown)***
***WARNING: Communication failure, is the MFRC522 properly connected?***

上記エラーはSPI通信がそもそもできていないことを示しています。
ググってもなかなかまとを得た回答がありませんでした。

##原因は？
考えられる原因は
①コードミス、配線ミス
②接続不良
③製品不良　⇦私はこれでした・・・

###①コードミス・配線ミス
RC522のサンプルコードを使って動作させる場合、**SS_PIN**と**RST_PIN**がデフォルトではArduino用(unoかな?)になっています。
自分の使用するマイコンに適用したピン番号に変えてあげる必要があります。

###②接続不良
こちらは意外と見落としがち半田不良です。私は不器用なので下手くそですが、下記画像の半田でも動作したので最低限これくらいであれば問題なく動作すると思います。画像は実際に動作した基板です。

<img src= "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342722/a6e72e06-9320-917e-532a-42b19a346c24.jpeg" width=50%>

###③製品不良
私はこれでした。Amazonで1枚600円か、2枚800円かで迷って、結局1枚の方を買いました。
今思えば、予備で2枚買っておけばよかったと思います。
数日いろいろ試して、何も進捗しなかったので別メーカのものを買い直してあっさり動作しました。

①と②を試してダメなら再度購入した方が無難のようです。もったいないけど。
Pythonからシンプルにslackにアラートを飛ばす（2022新方式版）

# はじめに
現場ではこの手の「ログをslackに投げる」みたいなのはすでに出来上がっていることが多いが実際にやったことあるかないかでは大きく違うので、メモみたいなものだが書いておく

# 参考
アプリケーションのテーマ自体はこっち:point_down:だけどslackの設定の仕方が古いので、

https://developers.wonderpla.net/entry/2020/06/18/11000

設定の仕方はこっち:point_down:の新方式で

https://zenn.dev/hotaka_noda/articles/4a6f0ccee73a18

# slack側準備
https://api.slack.com/apps/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/b5553b21-72aa-99af-9653-3a80de74e38c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/7a331cd7-7e4d-f65a-9fd4-5bdb6426749a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/ffe7ae5a-a384-ad59-f415-dcc437a2b0a6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/fcb22107-ff68-d102-29ef-ff7c76864ad6.png)

Webhook URL をコピーしといてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/f708b125-69dd-cd08-a42e-4f6b57972696.png)



# source
```python
import json
import requests


def send_message(message: str):
    response = requests.post(
        # webhook urlを貼る 
        'https://hooks.slack.com/services/cool/slack/endpoint',
        data=json.dumps({
            "channel": "random",
            "text": message,
            "icon_emoji": ":mostly_sunny:",
            "username": "weather_bot"
        })
    )
    print(response)


if __name__ == '__main__':
    TODAY = 0
    TOKYO = 130010
    url = f'https://weather.tsukumijima.net/api/forecast/city/{TOKYO}'
    weather_data = requests.get(url).json()
    txt = weather_data["title"] + '\n'
    txt += weather_data["forecasts"][TODAY]["date"] + '\n'
    txt += weather_data["forecasts"][TODAY]["telop"] + '\n'
    send_message(txt)

```

# 確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/c89ee995-cc0b-4d5f-a8d3-6c3231896cba.png)
AccessVBA備忘録(レポートでのグループ化)

AccessVBAのレポートで集計をしようとした際、グループ化が必要、ということはわかったのですが、グループ化の方法がわからなくてしばらく詰まったので、備忘録として書いておきます。

##レポートで項目のグループ化
```
Dim NewGroupLevel As Variant
NewGroupLevel = CreateGroupLevel(NewReport.Name, 基準とする項目名, グループヘッダーを作成するかどうか, グループフッダーを作成するかどうか)
```
基準とする項目名
グループ化する際にまとめる項目の名前
指定した項目の同じ値のものがグループ化される

グループヘッダーを作成するかどうか
True 作成する
False　作成しない

グループフッダーを作成するかどうか
True 作成する
False　作成しない

***
##その他AccessVBAメモ

###Excelインポート
```
DoCmd.TransferSpreadsheet acImport, , インポート後のテーブル名, インポートファイル名, 一行目をフィールド名として使用するかどうか
```
インポートファイル名
インポートするExcelファイルのパスを""で囲って指定

一行目をフィールド名として使用するかどうか
True 使用する
False　使用しない

###レポート作成
```
Dim NewReport As Report
Set NewReport  = CreateReport()
DoCmd.Restore
```

###レポートのレコードソースを指定
```
NewReport.RecordSource = "sample"
```
"sample"
レコードソースとするテーブル名など



###レポート上でのラベル作成
```
Dim NewLabel As Label
Set NewLabel  = CreateReportControl(NewReport.Name, acLabel, acPageHeader, "", "", x, y, w, h)
NewLabel.Caption = "ラベルに表示する文字列など"
```
acPageHeader
ラベルを作成する箇所
<details><summary>その他の箇所の指定</summary>
　acDetail 詳細 
　acFooter フッター
　acGroupLevel1Footer グループ レベル 1 フッター
　acGroupLevel1Header グループ レベル 1 ヘッダー 
　acHeader ヘッダー
　acPageFooter ページ フッター
　acPageFooter ページ ヘッダー
</details>

x(ラベルの横位置),y(ラベルの縦位置),w(ラベルの幅),h(ラベルの高さ)
1cm = 567

###レポート上でのテキストボックス作成
```
Dim NewTextBox As TextBox
Set NewTextBox = CreateReportControl(N_Report.Name, acTextBox, acDetail, "", "", x, y, w, h)
NewTextBox.ControlSource = "レポートソースとしたテーブル内の項目名"
```
.ControlSource 
関係ない文字列を指定すると他のビューでエラーになる？ため、表の項目などはラベルで作成する

###グループ化した表の集計
```
Dim TotalTextBox As TextBox
Set TotalTextBox = CreateReportControl(N_Report.Name, acTextBox, acGroupLevel1Footer, "", "", x, y, w, h)
TotalTextBox.ControlSource = "=Sum([集計を行う項目名])"
```
acGroupLevel1Footer
作成したグループのフッターにテキストボックスを作成して集計
Laravelで作成したAPIをJSON形式で返すときに文字化けする

APIを作成がなんのこっちゃな初学者が[この記事]('https://qiita.com/mdrq/items/a5a5d33e30ef1108c54e')を参考にAPIを作成したら、JSON形式で返すときに文字化けして、それを解決したので書きました。

# 文字化け
こんな感じの文字化けです。
![スクリーンショット 2021-03-27 13.26.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706118/bd911a1d-09c6-f4a2-7953-dd583e6ab622.png)
実際には`{"result":true,"title":"テスト","naiyo":"テストです。"}`と出力されてほしい。

# 解決
`response()->json()`のオプションに`JSON_UNESCAPED_UNICODE`を追加するだけです。
あらかじめ、`JSON_UNESCAPED_SLASHES`というオプションを入れているため、
`JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`と繋げてあげます。

## JSON_UNESCAPED_SLASHES とは
/ のエスケープをしないようにするオプションです。
これを設定しておかないと、/ の前に \ が入ってしまいます。（今回の場合だと無くても良い）
例） `https:\/\/hogehoge.com` → `https://hogehoge.com`


参考：[PHP の json_encode で変換後の文字列を僕が読みやすいようにする](`https://s4-ba.hatenablog.jp/entry/2019/02/28/110105`)
xmlでやりとりしているAPIをSpringに移植してみた

# 更新履歴

|日付|内容|
|:--|:--|
|2021.03.27|初版|

# はじめに

xmlでやりとりしている既存のAPIの置き換えの検証をしている。
API仕様書がエクセルだったりするので仕様書から作った方がいいかな、と考えている。
ひとまず[この仕組み](https://qiita.com/mabubu0203/items/2278a9a36b92f0a2e07d)をパクり、以下の方針で作成してみた。
・xmlでやりとりという部分は変えない
・OpenAPIから色々自動生成する
・Springで作る、もちろんJava11

# OpenAPIGenerator

使用したバージョンは `5.1.0`
Gradleから利用し、モードは `openapi` 、 `spring` を使用した。

## mode:openapi

OpenAPIをrefを駆使して色々とファイルを分割し、`mode:openapi`でひとつのファイルに統合した。

## mode:spring

`mode:openapi` で生成した`openapi.json`からインターフェースとモデルを自動生成させた。
今回はxmlでやりとりするので、

```json:openapi-generator-config.json
{
  "withXml": "true",
  "jackson": "false"
}
```

の設定を追加した。
※　`"jackson": "false"` は不要かも?

## 自動生成コードについて

生成されるモデルのクラスに `@XmlRootElement(name = "{classname}")` が付与されるのだが、
{classname}箇所が一律UpperCamelCaseとなっている。
※　読んで字のごとく、クラス名となっている。
期待していた値はOpenAPIで定義しているプロパティだっただけに残念。
[OpenAPIGeneratorのテンプレートを確認](https://github.com/OpenAPITools/openapi-generator/blob/v5.1.0/modules/openapi-generator/src/main/resources/JavaSpring/xmlAnnotation.mustache#L5)したところ、こうなっていた。

```groovy:xmlAnnotation.mustache#L5
@XmlRootElement({{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}name = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{classname}}{{/xmlName}}")
```

このままだと使い物にならないので、テンプレートを自作(いうてもコピーですが)して、`@XmlRootElement`のみ出力し、Spring(JAXB?)の設定でSnakeCaseになるようにやってみたがうまくスネークケースにならなかった。:scream:

やりたいことが叶えられないことに六時間ぐらい割きましたが、
時間がもったいないので**自動生成コードは使わない**としました。
※　モデルを使わないので、**インターフェースも使わない**となりました。
※　英断になるのでしょうか？

# Spring

SpringMVCではなく、SpringWebFluxで実装してみました。
xmlを受け取ってxmlで返却するので、SpringWebFluxである必要はないです。書いてみたかっただけ。

## セットアップ

build.gradleに下記の依存関係を別途、追加しました。

```gradle:build.gradle
dependencies {
    // SpringBoot Projects
    implementation("org.springframework.data:spring-data-commons")
    implementation("org.springframework.boot:spring-boot-starter-hateoas")
    implementation("org.springframework.boot:spring-boot-starter-validation")
    implementation("javax.xml.bind:jaxb-api")
    implementation("org.glassfish.jaxb:jaxb-runtime")
    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
}
```

## Controller

自動生成したインターフェースのdefaultメソッドをスクラッチしたControllerにコピペして、
`default` -> `public` に置換した後中身を実装しました。
SpringFox向けのアノテーションは手動でSpringDoc向けのアノテーションに置換しました。
リクエストボディとレスポンスボディのいわゆるモデルについては、自作クラスに置換する必要があります。

## Model

リクエストボディとレスポンスボディに相当する箇所については、
自動生成したモデルを参考に、コピペ作業などを実施しました。
0から作るよりは、OpenAPI Generator で自動生成したものを使い回すことで労力は削れたかと思います。
ただし、メンバ変数がLowerCamelCaseなのですが、後述するWebClientでうまくマッピングできなかったので、
メンバ変数も手作業でSnakeCaseに書き換えています。

自動生成したモデルにはJAXBのアノテーションが付与されていました。

## WebClient

API呼び出しをWebClientを使って実装してみました。
リクエストで受け取ったxmlをそのまま外部APIにたらい回すような作りにしました。
問題があって、
SnakeCaseで定義されたプロパティはJavaのメンバ変数でもSnakeCaseとなっていないとまともに動作しませんでした。
SpringとJAXBの仕様と思いますが、僕には解決できませんでした。:worried:

# おわりに

既存API(xml)をOpenAPI化と自動生成&Springの仕組みに乗っけるのは辛かったです。
そもそも既存が `RestWebAPI` もしくは `OpenAPI Specification　3.x.x` の仕様からかけ離れすぎている:worried:

とはいえ、`xmlでやりとりする` ってことも Spring でできることを確認できたのはお勉強になりました。
cypressを使ってsalesforceのlwcのE2Eテストをしたい

## cypressとは

E2Eテストのためのツールです。
cypress自体の説明は検索すればたくさん出てくるので割愛します。

https://www.cypress.io/

## cypressのインストール

自分はnpmを使用しているので、以下でインストールしました。

```bash
npm install --same-dev cypress
```
以上！なのですが、`code ENOENT`のエラーでインストールに失敗しました。
VSCodeを起動していると、失敗することがあるみたいです。VSCode閉じてから実行したらうまくいきました。

## LightningWebComponentのDOMの取得

LightningWebComponentはshadow DOMになっている影響で、そのままDOMの取得ができません。
色々調べた結果、`shadow()`を用いることで取得ができました。

```js
cy.get('custom-component').shadow().find('lightning-button').last().shadow().find('button')
```

自作コンポーネントを使用する場合もshadow DOMになっているので、上記のようにカスタムコンポーネントを取得してあげてから`shadow()`を用いることで操作が可能になります。
あとは、通常のcypressのテストと同様にテスト可能になります。
年金事務所が使用する日付形式を'yyyymmdd'形式に変換する

年金事務所が発行する公文書（PDF形式）をOCRで読み取り、
社内システムに格納されているデータと一致しているかをチェックする作業をしています。

年金事務所の用いる日付形式は「元号コード-yymmdd」となっており、
例えば昭和50年12月31日であれば、「3-501231」と表されています。
一方社内システムは「yyyymmdd」形式のため、その形式に変換する必要があります。

元号コード
昭和：3
平成：4
令和：5

元号年から西暦を求めるには下記の計算を行います。
昭和：元号年に25を足し、さらに1900を加える
平成：元号年から12を引き、2000を加える
令和：元号年に18を足し、さらに2000を加える

上記を踏まえて、リストに格納した年金事務所日付データを変換します。

```py
date_list = ['3-501231','4-101231','5-021231']
for cnt in range(len(date_list)):
    eracode = date_list[cnt][0]
    eray = int(date_list[cnt][2:4])
    if eracode == '3':
        yyyy = int(eray) + 25 + 1900
    elif eracode == '4':
        yyyy = int(eray) - 12 + 2000
    else:
        yyyy = int(eray) + 18 + 2000
    yyyymmdd = str(yyyy) + date_list[cnt][4:8]
```

関数化する場合

```py
def gengo(erayymmdd):
    eracode = erayymmdd[0]
    eray = int(erayymmdd[2:4])
    if eracode == '3':
        yyyy = int(eray) + 25 + 1900
    elif eracode == '4':
        yyyy = int(eray) - 12 + 2000
    else:
        yyyy = int(eray) + 18 + 2000
    yyyymmdd = str(yyyy) + erayymmdd[4:8]
    return yyyymmdd

gengo('5-030101')
## 20210101
```

なお、このコードでは存在しない日付、例えば昭和64年1月10日（3-640110）であっても
特に判定は行わずに西暦に変換しています。

期間計算等を行うためにPython日付形式で取得したい場合は、
datetimeを使用しています。

```py
from datetime import datetime as dt #datetimeをインポート

date_list = ['3-501231','4-101231','5-021231']

for cnt in range(len(date_list)):
    eracode = date_list[cnt][0]
    eray = int(date_list[cnt][2:4])
    if eracode == '3':
        yyyy = int(eray) + 25 + 1900
    elif eracode == '4':
        yyyy = int(eray) - 12 + 2000
    else:
        yyyy = int(eray) + 18 + 2000
    yyyymmdd = str(yyyy) + date_list[cnt][4:8]
    modify_yyyymmdd = dt.strptime(yyyymmdd,'%Y%m%d') #python日付形式に変換
    print(modify_yyyymmdd)
```

和暦・西暦の相互変換や大正以前の元号年を扱いたい場合は、
slangsoftさんのjeraconvを利用させて頂いております。
https://pypi.org/project/jeraconv/
令和になってもUbuntuでNot Tetrisがしたい

#これは何?
以下2つの場合に読む備忘録
1. 新しいUbuntuに古いLove2Dを入れる
2. Ubuntuでtar ballをビルドする

#導入
Not Tetrisは一見するとTetrisのように見えるクソゲー。
クロスプラットフォームなフレームワークLove2D上で動作する。

https://dic.nicovideo.jp/a/not%20tetris

Linuxでもできる落ちゲーと聞いてプレイしようとした……が、動作せず。
どうやら`apt install love`で取得したLove2Dと、当時のバージョンに互換性がないらしい。仕方がないので、tar ballからビルドすることにした。

#前準備
###ビルド環境
+ OS: Ubuntu 18.04.5 LTS
+ ビルドツール一式は`apt install build-esseitial devscripts`でまとめて入っているものとする。
+ buildflags.confを以下の内容で作成するのがおすすめ。

```sh:$HOME/.config/dpkg/buildflags.conf
APPEND CFLAGS -march=native -pipe
APPEND CXXFLAGS -march=native -pipe
```
###ソースコード
[リンク](https://github.com/love2d/love/releases/tag/0.7.2)からソースコードlove-0.7.2-linux-src.tar.gzを入手する。その後、作業用ディレクトリに展開する。

#仮ビルド
###仮Configure
1. `./configure --help`を実行して、利用可能なオプションを眺めてみる。  
1. `./configure`を実行する。
1. おそらくSDLが無い事で怒られるので、依存パッケージを入れる  
configure.inや`apt show love`等の内容を参考に、libdevil-dev, libfreetype6-dev, liblua5.1-0-dev, libsdl1.2-dev等々を入れていく。
1. configureが成功するまで頑張る。  
結果論だが`./configure --enable-luajit`したらハマったので断念。


###仮Make
1. 以下の内容でcfg0.sh(修正前)を作成して、実行する。  
1. make する。
1. OpenGL周りでコンパイルエラーが出るので、以下のようにcfg0.shを修正する。
1. `./cfg0.sh`→`make`の順に実行し、コンパイルが通るまで頑張る。

```bash:cfg0.sh(修正前)
#!/bin/bash
export CFLAGS="-pipe -O0"
export CXXFLAGS="-pipe -O0"
./configure
```
```bash:cfg0.sh(修正後)
#!/bin/bash
export CPPFLAGS="-DGL_GLEXT_PROTOTYPES"
export CFLAGS="-pipe -O0"
export CXXFLAGS="-pipe -O0"
./configure
```

#本番ビルド+インストール
1. `make clean`する。
1. `dpkg-buildflags --export > cfg1.sh`とする。
1. cfg1.shの適切な箇所に、`-DGL_GLEXT_PROTOTYPES`と`./configure --prefix=/opt/love --program-suffix=-0.7.2`を追記する。
1. cfg1してmakeして…(以下参照)

```bash
./cfg1
make
sudo make install
make clean
```

#やったぜ
![Screenshot from 2021-03-25 21-00-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159333/69e4813b-4882-4e09-2e80-a85111dc61dc.png)
debuild の使い方

こちらのサンプルと同様のことを行いました。
[Debianパッケージを作成してみた](https://armadillo.atmark-techno.com/blog/53/2927)
[debパッケージ作成方法をステップバイステップでまとめました](https://eng-entrance.com/linux-package-deb-create)
>どちらの例も、
>debian/compat
>を加える必要があります。

ファイル構成

```text
$ tree testpkg
testpkg
├── debian
│   ├── changelog
│   ├── compat
│   ├── control
│   ├── copyright
│   └── rules
└── testpkg
```

copyright は空のファイルです。

```text:testpkg/debian/changelog
testpkg (0.1) unstable; urgency=low
 
  * initial release
 
 -- User <sample@sample.com>  Mon, 04 Dec 2017 06:15:27 +0900
```

```text:testpkg/debian/compat
9
```

```text:testpkg/debian/control
Source: testpkg
Maintainer: ekzemplaro <sample@example.com>
Build-Depends: cdbs, debhelper
Standards-Version: 0.1
 
Package: testpkg
Architecture: all
Description: sample
```

```text:testpkg/debian/rules
#!/usr/bin/make -f
 
include /usr/share/cdbs/1/rules/debhelper.mk
 
install/testpkg::
	install -d $(DEB_DESTDIR)/usr/bin
	install -pm 755 testpkg $(DEB_DESTDIR)/usr/bin
```

```text:testpkg/testpkg
#! /bin/bash
 
echo 'Hello World!'
echo 'Good Afternoon!'
echo 'Mar/27/2021 PM 13:20'
```

パッケージの作成

```bash
debuild -uc -us
```

パッケージのインストール

```bash
sudo dpkg -i testpkg_0.1_all.deb
```

インストールされたプログラムの実行

```text
$ testpkg
Hello World!
Good Afternoon!
Mar/27/2021 PM 13:20
```

パッケージのアンインストール

```text
$ sudo dpkg --remove testpkg
(Reading database ... 101209 files and directories currently installed.)
Removing testpkg (0.1) ...
```