OmniAICreator/Qiita-1.07M huggingface dataset:
git pushできない。エラー：remote: Permission to [ユーザ名]/[プロジェクト名].git denied to [ユーザー名]. fatal: unable to access 'https://github.com/[ユーザー名]/[プロジェクト名].git/': The requested URL returned error: 403

git push -u origin main
で下記のエラーが発生。

remote: Permission to [ユーザ名]/[プロジェクト名].git denied to [ユーザー名]. 
fatal: unable to access 'https://github.com/[ユーザー名]/[プロジェクト名].git/': The requested URL returned error: 403

解決策：アクセストークンの発行画面でrepoにチェックが入っていなかった。

![githubアクセストークン.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055916/6638fb92-fc73-96ac-7f4b-5970ee08aeb1.png)
【Playdate】Spriteをアニメーションさせる

Playdateではマトリクス状にレイアウトしたスプライト画像を用いてコマ送りアニメーションができます。
しかし、アニメーションするSpriteを作るのは色々と実装を行わなければならないため中々面倒です。
そこで[AnimatedSprite](https://github.com/Whitebrim/AnimatedSprite)という拡張クラスを使って簡単にコマ送りアニメーションするspriteを作ります。
今回も[こちら](https://qiita.com/sada_lp1/items/1751040555361bae33b7)を改造して作ります。

以下のリポジトリから`AnimatedSprite.lua`をダウンロードします。

https://github.com/Whitebrim/AnimatedSprite

更に今回使用するスプライト画像を用意します。
player-table-32-32.png
![player-table-32-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/85e840e9-067d-2ac2-9306-49f0c44d5a94.png)

`AnimatedSprite.lua`と`player-table-32-32.png`をダウンロードしたら以下のようにファイルを追加します。

```
myProjectName/
    source/
        main.lua
        Images/
            player-table-32-32.png ← 追加
            playerImage.png
            background.png
        Plugins/
            AnimatedSprite.lua ← 追加
```

`main.lua`は以下のように修正します。

```main.lua
import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"
import "CoreLibs/timer"

import 'Plugins/AnimatedSprite.lua' -- AnimatedSprite読み込み

local gfx <const> = playdate.graphics

local playerSprite = nil

function myGameSetUp()

    -- local playerImage = gfx.image.new("Images/playerImage")
    -- assert( playerImage )
    local playerTable = gfx.imagetable.new("Images/player") -- imagetable追加

    -- playerSprite = gfx.sprite.new( playerImage )
    playerSprite = AnimatedSprite.new(playerTable) -- AnimatedSpriteインスタンス作成
    playerSprite:moveTo( 200, 120 )
    playerSprite:add()
    playerSprite:addState('idle',1,4,{ tickStep = 4 }) -- カスタムアニメーションステートの追加
	playerSprite:playAnimation() -- アニメーション再生

    local backgroundImage = gfx.image.new( "Images/background" )
    assert( backgroundImage )

    gfx.sprite.setBackgroundDrawingCallback(
        function( x, y, width, height )
            backgroundImage:draw( 0, 0 )
        end
    )

end

myGameSetUp()

function playdate.update()

    if playdate.buttonIsPressed( playdate.kButtonUp ) then
        playerSprite:moveBy( 0, -2 )
    end
    if playdate.buttonIsPressed( playdate.kButtonRight ) then
        playerSprite:moveBy( 2, 0 )
    end
    if playdate.buttonIsPressed( playdate.kButtonDown ) then
        playerSprite:moveBy( 0, 2 )
    end
    if playdate.buttonIsPressed( playdate.kButtonLeft ) then
        playerSprite:moveBy( -2, 0 )
    end

    gfx.sprite.update()
    playdate.timer.updateTimers()

end
```

`AnimatedSprite.lua`のドキュメントは以下にあります。

https://github.com/Whitebrim/AnimatedSprite/wiki
New Relic-Flexを使用した🦍ゴリ押し🦍構成管理 

# 課題

運用チームがメインで管理している構成管理データベースだが、セキュリティ調査や商用環境の状態確認ということで開発や営業から情報を聞かれることがよくある。
その度に運用側で情報を確認して伝達するというフローが発生し、非常にボトルネックとなっていた。
しかし、自社サービスは諸事情でオンプレ稼働しており、簡単にサーバ情報を外に出すことができない。
営業・開発・運用のどのチームでも見られることができるスマートなプラットフォームが無いだろうか。。。

と思っていたら、New Relicにそれっぽい機能があった。

# New Relicの構成管理機能とその問題

New Relicにはどのミドルウェアがどのサーバで使われているかが一目瞭然となる機能がInfrastructureにある。
↓こんな感じで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957034/6e25b042-9f45-6a88-b01f-8d78c60548cb.png)
これをダッシュボードに載せればと思ったが、NRQLで引くことがなんと不可能であった。Graphqlを通して無理やりダッシュボードに載せても閲覧することができなかった。
チームメンバ全員にFull userアカウントを買うのは非現実的すぎるし、この機能のためだけにというのはあまりに無駄である。

こうなったらもはやゴリ押しするしかない！　ということで、New Relic-Flexを使用して情報を収集する。

# New Relic-Flexで構成情報収集

## New Relic-Flexの仕様
New Relic-Flexについては、[こちら](https://docs.newrelic.com/jp/docs/infrastructure/host-integrations/host-integrations-list/flex-integration-tool-build-your-own-integration/) を参照
要約すると、「コマンドの実行結果をNew Relicに転送して任意のDBテーブルとして保存する」という機能である。データカラムを定義してコマンドの出力結果を区切り文字で区切ることで、カラムに対応するデータとして保存する。
この機能を利用するにあたって壁となったのは、「コマンドの出力結果は行単位でデータとして保存される」という仕様。コマンドの出力結果が複数行に分かれると1行ごとに別データとして保存されてしまう。
例えば、Apache_versionというカラムを定義して`httpd -v`の結果を収集しようとすると
```
Server version: Apache/2.4.37 (centos)
Server built:   Jun  8 2020 20:14:33
```
これは、
|Timestamp  |Apache_version |
|---|---|
|2022-12-11 HH:MM:ss  |Server version: Apache/2.4.37 (centos)  |
|2022-12-11 HH:MM:ss  |Server built:   Jun  8 2020 20:14:33  |

このように別のイベントデータとして収集されてしまう。そのため、複数行のデータを1行にまとめる必要があり、ここが一番苦戦した。

## ゴリ押し構成情報出力シェル

結論として、以下のように*xargsとechoを利用して1行にまとめつつ改行コードを文字列化する*というあまりにゴリ押しの実装を行った。
```
httpd -v | xargs -I{} echo -n {}\\r\\n; echo -ne "\t"
```
これを実行すると
```
Server version: Apache/2.4.37 (centos)\r\nServer built:   Jun  8 2020 20:14:33
```
というように改行が改行コードの文字列に変換され、末尾にタブを追加した文字列が出力される。


さらにechoのnオプションで末尾は改行されないので、
```
#!/bin/bash

httpd -v | xargs -I{} echo -n {}\\r\\n; echo -ne "\t"
openssl version | xargs -I{} echo -n {}\\r\\n; echo -ne "\t"
```
というようにxargsとechoを追加したコマンドを並べたシェルを実行すると、
```
Server version: Apache/2.4.37 (centos)\r\nServer built:   Jun  8 2020 20:14:33[タブ]OpenSSL 1.1.1f  31 Mar 2020\r\n[タブ]
```
という1行でタブ区切りのコマンド結果が出力できる。

あとは、integration.d配下に以下を記載したymlを置いて、
```
integrations:
  - name: nri-flex
    interval: 21600s
    timeout: 900s
    config:
      name: collectCMDB_Integration
      apis:
        - name: middleware
          commands:
            - run: 'sh [構成情報収集シェルのパス]'
              split: horizontal
              split_by: \t
              timeout: 60000
              set_header: [Apache_version,OpenSSL_version]
```
先ほどのシェルをInfraエージェントに実行させると、New Relicにmiddlewaresampleという以下のようなテーブルが作成される。

|Timestamp  |Apache_version  |OpenSSL_version  |
|---|---|---|
|2022-12-11 HH:MM:ss  |Server version: Apache/2.4.37 (centos)\r\nServer built:   Jun  8 2020 20:14:33  |OpenSSL 1.1.1f  31 Mar 2020\r\n  |

他の構成情報もまとめたければ、シェルに好きなコードを書いて同様のパイプを噛ませることで自由に構成情報を収集できる。

# まとめ

必要な情報をgrepして1行ごとに情報を出力すればいいのではと思うかもしれないが、10行程度の出力全てが必要な構成情報というパターンもあり得る。
New Relicデータベース上に記録される文字列としては1行にまとめられているせいで改行コードなどが不細工だが、GASでGraphqlを叩いてスプレッドシートに成形するなどすれば、見栄えはどうとでもなる。
New Relic使用中でかつオンプレなどで構成情報収集が面倒だという方は参考にしていただけると。
Googleカレンダーの当日予定をSlackに通知する

# まえがき
株式会社ピーアールオー（あったらいいな！を作ります） Advent Calendar 2022 の5日目になります。

# 背景
開発チーム30人程度になるプロジェクトでかれこれ5年近くSlackを無料プランで使わさせていただいています(本当にお世話になっております:pray:)
Googleカレンダーに登録してある当日予定をSlackに通知する機能がとても便利だったのですが、Slackのアップデートにより無料プランでは使えなくなるとのこと
有料プランにする？代替アプリを探す？と検討したが、エンジニアなのだから作ってしまおうということで本記事になります

# 実現方法
毎朝9:00に定期実行(GAS)　→　Googleカレンダーから当日の予定を入手　→　Slackに通知
定期実行かつ(無料で)サーバ立てずに手っ取り早くということでGAS(GoogleAppsScript)を利用する

# 準備
+ GoogleカレンダーのCalendarIDを取得しておく
+ Slack APIにSlack投稿の権限付与
+ Slack APIでWebhook URL取得しておく

### GoogleカレンダーのCalendarIDを取得しておく
カレンダーを開いて、設定からCalendarIDを取得

### Slack APIにSlack投稿の権限付与
* Slack APIを作成
* OAuth & Permissions -> Scopes -> Bot Token ScopesにSlackのチャンネルに投稿する権限「incoming-webhook」を追加
詳しくはこちら
https://api.slack.com/scopes
* OAuth & Permissions -> OAuth Tokens for Your WorkspaceでInstall to Workspace
エラーが出た方はこちらが参考になりました
https://the-simple.jp/slack-nobotuser

### Slack APIでWebhook URL取得しておく
* Incoming Webhooks -> Webhook URLs for Your Workspace

# GASで実装する
https://script.google.com/home
カレンダーに登録してあるタイトルのみをSlackに通知しています
他の情報まで通知したい場合、カスタマイズしてご利用ください

```hoge.gs
// カレンダー
const calendarID = "準備で取得したCalendarID";
// slack
const slackWebHook = "準備で取得したWebhook URL";

// 予定を取得
function getEvents(calendarID) {
  var date = new Date();

  // カレンダーから当日予定を取得
　var events = CalendarApp.getCalendarById(calendarID).getEventsForDay(date);

  return events;
}

// Slackに送信
function sendSlack(message) {
  // Webhook URL
  const postUrl = 'https://hooks.slack.com/services/'+slackWebHook;
  const json = {
    'text': message
  };
  const payload = JSON.stringify(json);
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': payload
  };
  UrlFetchApp.fetch(postUrl, options);
}

// 定期実行
function myTasks() {
  // slack投稿メッセージ
  let message = "";

  // カレンダー情報取得
  var events = getEvents(calendarID);

  // 予定が存在する場合
  if (events.length !== 0) {
    message += "■本日の予定\n";
    for(let event of events){
      message += '[' + event.getTitle() + ']\n';
    }
  }
  // 何らかの予定がある場合、(休日でも)slack投稿
  message !== "" && sendSlack(message);
}

// トリガー用(必要であればここで日時指定するとか)
function setTrigger(){
  const date = new Date();
  ScriptApp.newTrigger('myTasks').timeBased().at(date).create();
}
```

# 実装したGASを定期実行に設定する
毎朝9:00(ぐらい)に定期実行
カレンダーに予定があれば、休日でも投稿する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320579/aedf52e4-830d-4ca0-15e8-04af81fb2b36.png)

# これで何とか元通り
Slack通知がされなくなるのはチーム的に困りそうなので、突貫で作ってみました
9:00ぐらいというアバウトな状態ですが、厳密じゃなくても困らなそうなので、このままにします

しばらく運用しながらカスタマイズしていく予定です

# 全体的に参考(感謝)
https://liginc.co.jp/584979
PL-900：Dataverseの概要

この投稿はMicrosoft PL-900の受験に向けた勉強資料をMS Learnページを参考にして作っています。
一発合格に向けて頑張りましょう！

[公式ページ: Dataverse の概要][MS-Learn]

[MS-Learn]: https://learn.microsoft.com/ja-jp/training/modules/introduction-common-data-service/2-overview

# Dataverseの概要
* クラウドベースのソリューション
* さまざまなデータとビジネスロジックを簡単に構成して、相互に接続されたアプリケーションとプロセスを安全にサポートする
* 世界中で利用可能だが、潜在的なデータの場所を地理的に考慮して展開する
* サーバー上にスタンドアロン環境で使用するようには設計されていないため、アクセスして使用するにはインターネット接続が必要
* ビジネスデータ用の集中型データリポジトリとして設計されている
* Field Service、Marketing、Customer Service、Sales など、多くの Microsoft Dynamics 365 ソリューションに利用されている
* 機能
    * セキュリティ：AzureADにより条件付きアクセスと多要素認証を使用、行レベルおよび列レベルまでの許可をサポート、豊富な監査機能を提供
    * ロジック：ビジネスロジックをデータレベルで簡単に適用
　　　　　ユーザーがデータを操作する方法に関係なく、同じルールが適用される
　　　　　重複の検出、ビジネス ルール、ワークフローなどに関連するルールを使用できる
    * データ：データの整形を制御でき、データの検出、モデル化、検証、レポート作成を行える
　　　　データの使用方法に関係なく、データを希望どおりの形にできる

    * ストレージ：物理データはAzureクラウドに格納される
    * 統合：API、Webhook、イベント、データのエクスポートにより、データを柔軟に格納したり取得したりできる

# Dataverseの定義
* Microsoft Dataverse の1つのインスタンス
* テーブルと呼ばれる一連の標準およびカスタムのデータ構造にデータが格納される
テーブル　→　データを格納するために使用される行の論理的なセット
　　　　　　　１行に対して個別の情報を管理するための多数の列が含まれている
* ビジネスソリューションをホストするために１つ以上のデータベースのインスタンスを作成できる
* Microsoft Dataverseの各インスタンスはデータが格納されるテーブルのセットは最初は同じだが、特定のビジネスニーズに合わせて拡張もしくはカスタマイズができる
→　つまり、組織全体でおよび世界中の他の組織と標準テーブルを参照するビジネスソリューションを共有できる

## スケーラビリティ (Scalability)
* Largeデータセット(large data set)と複雑なデータモデル(complex data model)がサポートされる
* テーブルは数百万のアイテムを保持できる、また各データベースのインスタンスのストレージは４テラバイトまで拡張可能
→　関連つけられているライセンスの数と種類によって利用できるデータの量が異なる
* データストレージはライセンスを持つユーザー間にプールされるため、構築したソリューションごとに必要に応じてストレージを割り当てることができる
* 標準ライセンスで提供されているストレージの量以上が必要な場合、追加購入可能

## Common Data Model vs Microsoft Dataverse
* Microsoft Dataverseデータベースでの標準テーブルの設計はCommon Data Modelと呼ばれるオープンデータモデルの標準に基づいている
* オープンソース、標準化、拡張可能なデータテーブルとMicrosoftとそのパートナーがオープンデータイニシアチブと呼ばれる業界全体のイニシアチブで発表した一連の関係を含む論理的な設計
* この定義済みテーブル、カラム、セマンティックメタデータ、およびリレーションシップのコレクションは共通データモデルの基礎を形成する

## Microsoft Dataverseの構造と利点
* Microsoft Dataverseデータベースの構造はCommon Data Modelでの定義とスキーマに基づいている
* 利点
    * ソリューションの標準テーブルが同じであるため、Common Data Modelのスキーマを使用するすべてのソリューションを間単に統合できる
    * ベンダーがCommon Data Modelを使用して構築したソリューションの豊富なエコシステムを利用できる
    * 何より、実質的に際限なく拡張できる
勉強が苦手でもプログラミング学習を継続できる方法3選


# はじめに/前提

今回の記事では、本職を継続しながらプログラミング学習を行う会社員の方を対象にした「勉強が苦手でもプログラミング学習を継続できる方法3選」という記事を書いていきたいと思います。

個人的な意見満載なので、その点ご容赦頂けると幸いです。
人それぞれ自分に合った学習方法は異なるので、参考程度に読んでいただければと思います。

# 1. 1日2回勉強を開始する

勉強が苦手な方でも継続できる大事なこと1つ目は、「1日2回勉強を開始する」です！
勉強をする時間帯は朝と夜で、朝は「復習」、夜は「予習」を心掛けます。
ここでの注意点は、夜更かしし過ぎないことです。
開始できる時間が遅くなってしまい日付が変わりそう・・・よくありますよね。
そのような時間になってしまった場合は、学習時間は「10分」でもいいので、まずは始めることが大事です。
短時間の学習でも、向き合う時間が少しでもあれば学習には大きな差が生まれます。


# 2. 月間の目標を決める

勉強が苦手な方でも継続できる大事なこと2つ目は、「月間の目標を決める」です！
人間は目標を持っていないと、だんだん怠けていってしまう生き物です。
そうならないように、自分自身を制御する必要があります。そのために行うのが目標設定です。


目標は、週ごとや日ごとで設定すればより細かく習慣化を促すことができますが、
場合によっては細かくしすぎることによって管理が大変になってしまい、逆効果になることもあります。
最初のうちは月間目標だけを決めて、達成できていれば十分だと思います。あくまでも大事なことは達成し続けることです！

目標を設定する上でのポイントは、箇条書きチェックボックス形式で目標を「具体的に書く！」です。
目標が曖昧だと、月半ばなどで進捗を確認するときに出来ているのか出来ていないのか判断が難しくなってしまい、やる気が削がれてしまいます。

**良い目標の例**

- [ ] HTML/CSSを使って模写コーディング3サイト完成（Codestepから3つ選択）
- [ ] e-typing スコアS、正確率90%以上を達成

**悪い目標の例**

- [ ] HTML/CSSを使って模写コーディング
- [ ] e-typingでタイピングを極める

# 3. Twitterを活用して仲間を作る

勉強が苦手な方でも継続できる大事なこと2つ目は、「Twitterを活用して仲間を作る」です！

Twitterでは「#プログラミング学習初心者」や「#駆け出しエンジニアとつながりたい」などのハッシュタグで検索すると同じように
学習し始めて間もない方がたくさんいらっしゃいます。
色々な人のプロフィールに飛んでみて、自分と同じところを学習している方などをフォローして仲間を作るといいかと思います。
Twitterは、通勤時間などのすきま時間を活用してみるのがいいかと思います！
たっぷり時間が取れるときは、なるべく学習時間にあてましょう！

**仲間を作ることでのメリット**
- プログラミングについての有益な情報が得られる可能性がある
- 分からないことを聞ける（通知があるので即レスの可能性も高い）
- 逆に人に教えることで知識定着を促せる
- モチベーションに繋がる

# さいごに

今回の記事は以上となります。

これから学習を始める方、学習を始めたけどモチベーション維持に悩んでいる方などにとって
参考になる記事になっていれば嬉しく思います。



# プログラミング学習サイトおすすめ

無料コンテンツ

https://ninjacode.work/

有料コンテンツ

https://koga.ninjacode.site/?ni=q_8
RailsでITF規格のバーコードを生成する方法

## 前置き
メタップスアドベントカレンダー 5日目ということで投稿させていただきます。
[RailsでITF規格のバーコードを作ろうとした話](https://qiita.com/k5yoshidq/items/2ffad71194fef9df3593)にて一度は断念したITF規格のバーコードの生成が可能だということを上司が発見してくれたので僭越ながら紹介させていただきます。

# ITF規格のバーコードとは
> ITFは、インターリーブド2of5（Interleaved Two of Five）の略で、主に段ボールに印刷されている物流商品コード用のバーコードとして利用されているコードです。
[引用...ITF | バーコード講座 | キーエンス](https://www.keyence.co.jp/ss/products/autoid/codereader/basic_itf.jsp)


余談にはなりますが、今回バーコードの生成にあたり沢山バーコードについて調べたのでその辺りの予備知識的なところが増え楽しかったです。

## 実装
Railsにおけるバーコード生成としてよく聞く`Barby`を用いると驚くほど簡単に実装ができます。

```gem:Gemfile
gem "barby"
```
まずはgemをinstallします。

```ruby:barcode.rb
    require "barby/barcode/code_25_interleaved"
    def get_barcode
      content = "0123456789"
      xdim    = 3
      height = 150
      barcode = Barby::Code25Interleaved.new(content)
      barcode.to_image(xdim: xdim, height: height).to_data_url
    end
```
出力結果
![qiita_barcode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603884/941a3aea-551e-d73d-4f19-164bcb8113a3.png)

読み取り結果
![E1E6216B-6BF9-44A3-9485-60221FFE3172.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603884/ce24f90b-c9e1-89a2-0599-b163c64cbe0c.jpeg)

### 注意
※ITF規格のbarcodeを生成する場合は、埋め込む値は偶数である必要があります。

## 最後に
方法を模索してる間、どれだけ調べても出てこずGitHubで全リポジトリに`ITF`で検索をかけたりしてましたw
ITFという略語に固執して「`Barby`にITFはないか...」となっていたのが時期尚早でした。
`Interleaved Two of Five`こっちで探す必要があったということですね。
これからも精進します。
勉強への意識を見つめ直してみると世界が拓けるかも

# はじめに

これから社会人エンジニアとして一歩を踏み出す皆さん、または、エンジニアとして一歩踏み出してまさにニ歩目を踏み出す皆さん、はじめまして。

当方は長いこと技術者の末席に居座っており、僭越ながら、一番感触が良かった方法を伝授できればと思っております。

# いきなり本題

何を伝授したいのかと思いますと…

それはズバリ、**勉強する際の意識** について！

それについては、私がお勧めする勉強法としては、別のアドベントカレンダー用に用意した記事を読んでいただければすべて解決します！

https://qiita.com/cyross4vocaloid/private/35bece727ff081c6e89e

…というわけには行きませんよね。ごもっともです。

とはいえ、何らかの形でアウトプットしないと、勉強したことが身につかないのは事実です。学校のテストも良いアウトプットの機会と考えれば、テストも楽しくなることでしょう。**知らんけど**。

# 勉強するときの意識

おそらくですが、皆さんは社会人となるために高校や大学、専門学校に入って勉強をしていたと思います。
その際、その目的は「入試に受かりたい」「学期テストでいい点を取りたい」など、関門をクリアする目的（目標と言っていいかも）で必死に（嫌々ながら？）勉強していたと思います。

そこで一つ気になっていたのですが、さっきあげた「**目標**」に対して視点を変えてみたことは無いでしょうか？

目標をクリアするということは、学校の先生や入試の担当者に対して質の高いアウトプットを出す、と考えられないでしょうか。

こうすることで、テストをする際に何を意識して立ち回るのかが変わってきます。
相手は何を期待しているのか、どのようにすれば解決への道筋が見えてくるのか。
ただ単に公式を覚えるだけでは見えてこない世界を自ずと垣間見ることが出来るようになってきます。

さらに、苦行のような訓練を受けることなく、頭に解法が残ってきます。
結果が伴うと、ストレスを感じなくなって、勉強するのが楽しくなってきます。

これは、エンジニアの世界でも同じです。
この世界でも、会社の同僚や先輩、上司、お客さんの担当者、不特定多数の技術者、一般ユーザーなど、相手はごまんと居ます。
でも、視点の捉え方を見極める工程は必ず通ります。

違うのは、説明する粒度だけです。本筋はすべて同じです。

ここまで説明して、おそらく勘の良い読者ならお気づきだと思います。

**アウトプットすることを前提に勉強をする**、これが質の良い勉強への第一歩です。

# 勉強の土台

さて、アウトプット前提ということで、何をすればいいのか？　はい、**インプット**です。

ITの世界の場合、直接人から聞くこともありますが、ネット上の情報をかき集めることも大事です。
当方の場合、以下の手法で土台を構築しています。
もちろん、アウトプットする意識を忘れずに。

- Twitter
- 技術記事・ブログ
- Amazonマーケットプレス
- Github

これらについて少し細かく解説していきます。

## Twitterの活用

Twitterでは、ちょくちょく技術解説のサイトや記事のツイートをよく拡散しています。
そこで、リスト機能を使って、そういうアカウントをリスト化しておいてちょくちょく見るようにしています。
気になった記事があればブックマーク（Twitterの機能）して、溜めておいて、あとでチェックします。

## 技術記事・ブログの活用

国の内外問わず、各種新技術や技術解説を行うサイトがたくさんありますので、自分の感性に合ったサイトをピックアップしてRSSリーダーで管理したり、Chromeのタブグループ化（サードパーティーの拡張で、タブグループを管理するものがありますので、それも活用します）しておいて、いつでも参照できるようにしています。

技術に特化した会社では、社外向けにテックブログを公開しているところがあります（有名なところではクラスメソッド社の[DevelopersIO](https://dev.classmethod.jp/)ですね）から、有効活用しちゃいましょう。

[お勧めのテックブログをまとめているブログ記事](https://codelearn.jp/articles/tech-media-blog-feed)もありますので、これも便利です。

最近、[Zenn](https://zenn.dev/)という技術共有サイトもあります。技術者が書いた電子書籍も頒布されています。
お金を出して活動をサポートすることもできますし、こちらもチェックしています。
(余談ですが、先日、UnrealEngine5の入門書を買ったので参考にします)

もちろん、Qiitaも活用できますね。

### 技術記事・ブログのPDF化

しかし、こういう記事には弱点があります。
その記事が**いつの間にか消えてしまう**リスクがあるということです。

取り返しのつかない状態になる前に、印刷機能を使ってPDF化することをおすすめします。
これなら万が一、消えてしまったとしても、いつでも参照できるようになります。

## Amazonマーケットプレイスの活用

ここはちょっと特殊ですが、古いIT本を購入する際に便利です。
ITは日進月歩、目まぐるしく発展していってますが、根本となる技術は抑えておかないと足元を掬われかねません。
古い本には、枯れた技術を手頃な値段で吸収するチャンスがあります。

ちょっとずれますが、マネジメントする側の考え方を理解するための本は、技術書ではなくビジネス書として扱われることが多く、非常に安い金額で絶版本が手に入ったり出来るのでお勧めです。

## Githubの活用

Githubは、大体はオープンソースソフトウェアの管理のために使用されています。
ですが、中では、ITで活用するためのドキュメント群がリポジトリとして存在しています。

たとえば、「[システム設計入門](https://github.com/donnemartin/system-design-primer/blob/master/README-ja.md)」は、設計としての基礎知識を蓄えるのに十分なプロジェクトです。

### 自分用知識の溜め場としてGithubを活用

Githubの**プライベートリポジトリ**を使用して、今までにまんだ知識を管理する方法もあります。

Markdown形式でその知識をまとめておけば、いつでもどこでもその知識をきれいな書式で閲覧できるため便利っです。

当方も、これまでに読んだ本をまとめる際に活用しています。

# とっても大事なこと

ここまで、勉強への意識や、当方の勉強の土台をお伝えいたしましたが、非常に大事なことは一つです。

繰り返しになりますが、「**後でアウトプットしよう**」という意識です。
これが有ると無いとでは、頭に入る濃度が大きく違います。

興味を持ったらすぐに調べて、調べたらそのままにせずにアウトプットする、その習慣で大きな学びが得られると思います。

さて、書きたいことを書き尽くしました。

エンジニアとしての道を突き進んでいくのか、マネジメントの立場に鞍替えするのか、それは読者さん次第だとは思いますが、あなたに合った勉強法を身に着けて、豊かなエンジニアライフを祈念いたします。

それでは、このへんで筆を置きたいと思います。
アイスタイル通知基盤のクラウド移行で学んだ教訓たち

この記事は[アイスタイル Advent Calendar 2022](https://qiita.com/advent-calendar/2022/istyle) 6日目の記事です

アイスタイルにて主にバックエンドのサービスを担当しているusuitです。
今年は私が担当している通知基盤というサービスのクラウド移行を行いました。
この記事ではその経験から学んだ教訓たちを紹介していきたいと思います。

# 通知基盤って何？
通知基盤は[@cosme](https://www.cosme.net/)のスマホアプリに表示されるお知らせやPush通知の配信を行っているサービスです。
今回のクラウド移行では外部MAツールにそれらのデータを連携するよう作り変えを行いました。
その作り変えの中感じたことを以下にまとめました。

# 急がば回れ
クラウド移行開始時、それまで私はAWSはチュートリアル程度しか触ったことがありませんでした。
ネットで調べながらなんとかサービスをリリースしましたが、その中で感じたことが以下になります。

### AWSの公式ドキュメントはいきなり読んでも知らない単語ばかりで分からない
- まずはDevelopersIOやQiitaから入るのもアリ
- でもそこで終わらないでしっかり公式ドキュメントを読むべき
- **公式ドキュメントの情報量に勝るものはない**

### チュートリアルだけでなく、公式ドキュメントだけを参考に作ってみたりするとベター
- やるのはミニマムな内容でいい
- **書いてある内容をトレースするのと、自分で調べて実践するのでは理解度が全く違う**
- 料金がかかってもそれくらい怒られない(はず)
   ※ 怒られた場合は自己責任でお願いします

### スタートダッシュはできないが最終的には役に立つ
- **プロジェクト初期の余裕がある時期の方がしっかりドキュメントを読める**
- プロジェクト後半の修正ほどスケジュールがタイトになるもの
    - 焦って調べたら変なやり方を採用してしまうかも
    - 後で直せばいいと思っても結局そのまま何年も経過してしまうかも
- 1度ドキュメント読んでいればどこに何が書いてあるか大体覚えてる
- 結果的に修正時間を短縮できたりする
- 間違ったやり方を選んでしまう可能性も低くなる

**→遅かれ早かれドキュメントと格闘するときはやってくる！だったら最初からやっておこう！**

# ｢おや？｣を見逃してはいけない
クラウド移行後2週間くらい経ったときの出来事でした。
ユーザーからお知らせのページから遷移した際に操作ができないという問い合わせがありました。
原因はアプリの遷移処理の実装不備だったのですが、今回そこは問題ではありません。

### 実はテスト時にページの表示が変わったなとは思っていた
- 実装変わったからデザインも変わったのかなくらいにしか思ってなかった
- 実際は遷移時に必要な処理が抜けていたため表示が変わっていた

### この｢おや？｣をそのままにしなかったらこの障害は発生しなかった
- とりあえず聞いておけばアプリチームが見てくれて事前に発覚できたはず
- 問題なかったならなかったでOK
  - 質問と回答くらいなら工数は数分
  - バグの可能性が確実に1つ潰せる

**→疑問や気になった点は小さなことでもそのままにしない姿勢が大事**

# やっぱり世の中うまくは行かない
AWS移行後にけっこうトラブルを起こしてしまいました。
その中には事前に防げたものもあるし、防げなかったものもありました。

### 防げたものこそ次に活かせる学び
- 次は絶対起こさない
    - テスト時のチェック観点
    - 実装時に注意する点
- 他のチームとの連携
- **こういう学びの１つ１つが自分の引き出しになる**

**→しっかり反省する姿勢は大事**

### じゃあ防げなかったものは？
- 起きたものは仕方がない
- ミスは誰にでもあるのだから
- 大切なのは報連相と迅速な対応
    - ユーザー影響はどれくらい？
    - 回避策はある？
    - 原因は分かってる？
    - いつ対応できる？
    **→ しっかり対応することで企画側との信頼関係も築ける**

- 知識をつけておけば対応もはやくなる
    - 最初の急がば回れの話に戻る
- [コンティンジェンシープラン](https://www.newton-consulting.co.jp/bcmnavi/glossary/contingency.html)は用意しておかないといけない
    - 切り戻し方法
    - そもそも切り戻せる設計

# まとめ
### ドキュメントを読もう！
- まずは知識を身につける
- めんどくさがったら後から自分に返ってくる
### 疑問はしっかり解消しよう！
- テスト時の挙動だけにあらず
- 設計、実装で迷ったときも有識者に確認しておけば技術的負債も発生しない
### しっかり反省して自分の引き出しを増やそう！
- ミスは誰だってするもの
- １度目の失敗は仕方がない
- でも２度目はないぞ


#
以上になります。
今回私がクラウド移行を経験して学んだ教訓を紹介させていただきました。

最後まで目を通していただきありがとうございました！
【underscores】WordPressカスタマイズ専用テーマで自作テーマ作成

## underscoresテーマ

WordPressで自作テーマを作る場合はスターターテーマと呼ばれるカスタマイズ専用のテーマを使うと便利です。

スターターテーマとして有名なのが「アンダースコア（_s,underscores）」です。

https://underscores.me/

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/718184/aaa7030f-48e9-010f-4953-dda87bf7ce65.png)


### 使い方

1. [underscores](https://underscores.me/)サイトへアクセス
2. ThemeNameを入力しGenerateを実行しダウンロード
3. Downloadされたzipファイルを解凍し、`wp/wp-content/themes/`ディレクトリ内に配置
4. テーマを有効化
    
    WordPressの管理画面から、画面左のメニューバー内の外観 > テーマを選択します。
    
    themeフォルダに配置していたunderscoresのテーマ（自分でつけたThemeName）が表示されていると思います。
    
    カーソルを合わせると有効化というボタンが表示されるので選択し、テーマを有効化します。
    

あとは、設置したthemeディレクトリでオリジナルテーマを作成します！
ウホウホプラグウホ🦍

ウホ、2021、ウホウホカスタウホ。
[ウホウホウホー2021 ウホウホカスタウホ](https://qiita.com/juri_don/items/1f175e40f45a41092c40)

## ウホ2022、ウホプラグウホ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/78dd58b3-b10f-5d95-16a1-4a55d852bed8.png)

※ウホ↓
https://icone.unique-work.com/

## ウホ🦍

ウホ、ウホ。ウホウホウホー。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/cceeb83e-002b-4fb0-a4fe-30cb3ad0468d.png)

ウホホウホホ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/3e1d4315-4e36-f9d0-3849-ed397da48a0c.png)

## ウホホホウホホ🦍

ウホホホウホ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/2846a879-4241-95d8-a3ff-e1772d6dd9fc.png)

🙅ウホ↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/8578c481-50aa-3585-3743-4949040f0195.png)

ウホッ😭

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/9bf29039-2caa-0ad1-8453-972d16a2bb4d.png)


## ウホホ

ウホホ、ウホ、ウホホホホ。

|ウホ|ウホホ|
|--|--|
|1ウホ|10,000ウホン|
|12ウホ|100,000ウホン|


※ウホホ（ウホホホ版）1ウホ、0ウホン。

ウホホウホホ、Telウホ🙆‍♀、Faxウホ🙆
ウホウホウホホ！
実装したコードが2ヶ月で90%消えた話

## はじめに

タイトルどおり、2ヶ月で90%くらいのコードが消えた。

アドバイスもらうのは重要だねって話。

技術的な話ではなく、メンタル的な学びを共有します。

## 頑張って**自分だけ**で実装した

9月、本番データベースからシードデータを作るってタスクを割り振ってもらった。

ざっくりと書くと

1. RDSでDBのスナップショットをとる
2. AWSのGlueでDBのスナップショットからテーブル構造を取得
3. 2を元にGlueでデータをCSV出力
4. CSVをローカルに落とし、seedデータとして整形

みたいな流れだ。


1,2の部分は良かったのだが、3のCSV取得で大変冗長なコードを書いていた。

以下の画像みたいにテーブルごとにGlueのJobを書いて、一つずつ回していたのだ。


![Glue_Studio_-_Jobs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581713/9b6a765f-f051-376f-7242-031c4399ab89.png)

一応for文で回してみたのだが、なぜか空のCSVしか出力されない。

「仕方ない。。。それぞれJob作るか。」

そう思って、テーブルごとにコードを書いたわけだ。

しかし、コードは冗長だったものの、
その後無事に、目的の要件「本番データベースからシードデータを作る」は達成できた。


## その後先輩エンジニアにアドバイスを貰った

それから1ヶ月位経ってから、
**「AWSのコンソール上ではなく、Docker上で動くようにする」**
というタスクが動き始めた。

いい機会だったので、上述の顛末を相談しよう。
そう思って、docker基盤を作ってくれた先輩エンジニアに、
色々と今までの話を共有して、アドバイスを貰った。

「ん。これって、JobBookmarkのせいじゃない？ ほら、ここをdisableにすれば良さそう。」

![Glue_Studio_-_Editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581713/0ddfafb2-b67c-bf1c-47cd-6f6eb7a2c128.png)


「え、、、」

そう聞いて、上の画像のページを見ると、**JobBookmark**という項目がある。

まじか。コンソール上で変更できることを完全に見逃していた。

実はJobBookmarkに原因があることは分かっていたため、lambdaで一つずつdisableにしていたのだ。

実際にここを変更したところ、for文でつつがなく回せるようになった。
そして、上記のlambdaの関数も不要になった。

「まだ、いらない部分あるよ。」

「え、、、」

そんなこんなで、2ヶ月で9割のコードが消えたのである。


## まとめ

個人的には、コードの綺麗さよりも、期間内に実装できるかが大事だと思っている。

しかし、今回の場合、アドバイスを貰っていれば、大幅に実装時間を減らすことができたはずだ。

特に新人エンジニアは自分を過信しないようにしよう。
そして、積極的にアドバイスをもらおう。

自分の知らない知識も増える。
私のように、「この時間なんだったんだ。。。」と思うことも減る。

ということで、周りを頼ろうという話でした。
ITエンジニアの心の地図

[山陰 Advent Calendar 2022](https://adventar.org/calendars/8245)の12/5エントリー投稿です！

---

我々ITエンジニアは、次々と現れる新技術に翻弄されながら、顧客に価値を提供し続けるために学び続ける存在です。
エンジニアとして学ぶ＝成長するためには、自分の強み弱みを理解してテーマ設定すると効率的です。

テーマ設定の一助として、エンジニアの能力を大きく3つに分類して自分を棚卸しする方法を紹介します。
この3つの能力を表現する言葉が見つからないので、聞き慣れたワードで代用しますが、役割・役職と混同しないようにご注意ください。

なお、この3分類は私の持論なので、異論は歓迎します。
この持論が呼び水になって、活発な議論が行われることを期待します。


# 3つの能力

## 技術的な力

エンジニアと言えば技術！プログラミング言語！をイメージすることが多いと思います。
実際、ITエンジニアのキャリアは（ほとんどの場合）プログラミングから始まります。
諸先輩方のプログラミング能力に圧倒されて、自分ももっと色んな言語を覚えなきゃ、って焦ったりもします。

しかしここには落とし穴があります。

顧客目線だと、システム開発会社にいる人は全員、プログラミングができると思っている一方で、顧客が求めていない技術に関する知識の有無には興味がありません。

プロに求められるプログラミング能力は（宮本武蔵の五輪の書ではないですが）「作れる程度にできれば十分」なものです。

エンジニアに囲まれていると世間の基準を見失いがちですが、技術を学ぶ際はプログラミング言語だけに特化するのではなく、「作れる程度」にネットワーク、ミドルウェア、最近だとクラウドの知識など、引き出しの幅を広げることを意識すると良い顧客提案ができるようになります。


## 保守運用的な力

顧客はシステムが欲しいのではありません。
システムを使って、ビジネスがしたいのです。
顧客のビジネスが回る＝収益を産み続けている状態を健全に維持する活動を保守運用と言います。

では、エンジニアの能力としての保守運用的な力とは何を指すのでしょうか？

これはシステムの品質です。
私はよく「強い実装」と表現するのですが、以下のような特徴を備えたシステムです。

- 例外的な状況でも（データ破壊など）破綻せず、正しくエラーが発生する
- コードから仕様が読み解きやすく、修正が容易
- テストコードが揃っており、デグレードの不安が少ない
- ログ出力の内容とタイミングが適切で、必要十分な情報が得られる

一度作ったシステムは、長年にわたって顧客に使用され続けます。
そして使用されるシステムには必ず改修要望があります。

日々使用されるシステムの声なき声はログという形で出力されており、これはシステム改善のタネです。
読み解くには相応のスキルが求められますが、ログを元にシステム観点から改善提案ができると、顧客との信頼関係を強固にすることができます。

初期開発の時点で強い実装を意識するのは簡単ではありませんが、保守運用のフェーズでより強い実装に鍛えていくのはさらに高度な作業になります。


## マネージメント的な力

プロのエンジニアは納期を守らねばなりません。
要件や設計、実装も納期に大きく影響しますが、時には現実を踏まえて妥協する判断も必要になります。
要は仕事をやり切る力なのですが、ただ終わらせるだけでは不十分です。

顧客と合意した内容が満たされていること、自社の収益が確保されていること、そして何より仲間たちの心身の健康を維持したままゴールすること。
これらが揃ったとき、プロジェクトが成功したと胸を張ることができます。

もう一つ、コミュニケーションもマネージメントの範囲に含めたいと思います。
顧客との交渉ごと、仲間との情報共有、どちらもコミュニケーションです。
正しく動機付けできなければ各人のゴール意識が揃わず、プロジェクトを成功させることが難しくなります。

誰が相手であっても、コミュニケーションは相互の働きがなければ成立しません。
相手を尊重し、理解し、言葉を引き出すのは技術でもありますが、ハートも重要になります。

こう考えると、マネージメントの力は「プロとしての振る舞い」と言えるかもしれません。


# 全部必要

これら3つの能力は（割合の差はあっても）全てのエンジニアの中に必要なものです。
役割によって強く求められる能力は異なりますが、それぞれの能力は相互補完的なので、どれかをゼロにすることも、何かに全振りすることもできません。

プロジェクトが成功した時、上手くいかなかった時、これらの要素の何が影響したのかを振り返れば、どこに空地があって次に何を学ぶべきかが見えてくると思います。
また、目指す道があるのであれば、意識して学ぶこともできると思います。

バランスよく身に付くとゼネラリストの道、どれかに注力するとスペシャリストの道に続いていますが、どの道を目指すのかは自分の気持ちと、与えられた環境、いただいたご縁によって変わってくるのかなと思います。

ITエンジニアの心の地図は人それぞれ、心の中にあるのです。
【SiteSetup】Bulk User Import using CSV list

This time, I would like to try a method to add multiple users at once to [Sharperlight](https://www.sharperlight.com/).
Among them, let's try adding users using a **CSV list**.
Launch **Site Setup** from the Sharperlight application menu.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/fc4022dc-2c48-a40d-b6c1-411dc9e1f87b.png)
After the site setup window opens, review your existing users and user groups.
In particular, check users in detail.
The reason is that when adding multiple users, you need to specify which user to use as a template.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4758297a-d543-b8e6-68fa-b0a69dba98a3.png)
Select the user node and select **Import Users** -> **CSV** from the right-click menu.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/8ab25acc-6d1a-63fa-260f-139b1baa80ef.png)
A dialog prompts for user input to be used as the initial setting.
This time, specify the **guest** user. Proceed with the `OK` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/9d495e5d-55ca-dfb5-1500-1e464163e097.png)
A dialog appears describing the list of users to add.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/d76d4c48-11dc-7f1c-2daf-ef1a0724dbbb.png)
Only one line of the template is displayed, so fill in according to it.
**Username** and **User Group** are mandatory fields, `Description`, `Email` and `Password` are optional.
I made a user list like this. I tried specifying a template for only one **admin** user.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/9cfe126f-94fe-6b06-c2bb-9a766382f3de.png)
```
[WindowsDomain\WindowsUser or UserName],[UserGroup],<Description>,<Email>,<Password>
EthanT,guest,Ethan Thomas,EthanT@company.com
ChloeH,guest,Chloe Hall,ChloeH@company.com
HarperW,guest,Harper Williams,HarperW@company.com
AvaM,guest,Ava Miller,AvaM@company.com
CadenB,guest,Caden Brown,CadenB@company.com
AriaS,admin,Aria Smith,AriaS@company.com
```
Confirm with the `OK` button.
You should see a message that it has been imported.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/854c784d-a557-0f56-09c5-d655df214deb.png)
You can see 6 new users in the user node. And `Aria Smith` is properly assigned to the **admin** user group.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/571d3e0e-68d5-9787-79d2-da5e59c8a1ed.png)
That's all for how to add multiple users at once using a **CSV list**. Please try it.

Thank you for reading this article.
mail gem を 2.8.0 にしたら LoadError が出た件

Rails でメールを扱うのに ActionMailer が大活躍するが，この [actionmailer](https://rubygems.org/gems/actionmailer) gem は [mail](https://rubygems.org/gems/mail) という gem に依存している。

mail gem は 2022 年 12 月 3 日にバージョン 2.8.0 がリリースされた。

早速 mail を 2.8.0 に上げたところ，Rails アプリが起動しなくなった。エラーメッセージには

```
Error: The application encountered the following error: cannot load such file -- /usr/local/rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/mail-2.8.0/lib/mail/indifferent_hash.rb (LoadError)
```

とある。

なかなか原因が分からなかった。「cannot load such file」（んなファイル，ロードできねえよ）と言われた indifferent_hash.rb は，ちゃんと存在しているし。

mail gem のリポジトリーを見に行くと，既に issue が上がっていた。

https://github.com/mikel/mail/issues/1516

要するに一部のファイルの読み取りパーミションが適切でなかったために LoadError が出る，ということらしい。user は読取可だが，group と other は読取不可になっていた。

当該のファイルは三つあり，それらに読取パーミションを付加してやれば，とりあえずエラーは出なくなる（具体的な方法は上記 issue 参照）。

修正版がすぐにリリースされるんじゃないかとは思うけど。

# 追記 2022-12-28

ファイルのパーミションだけの問題だからすぐに修正バージョンが出るんだろうと思ってたけど，そんなことはなかった。

3 週間以上経つが気配もない。
こちらの issue
https://github.com/mikel/mail/issues/1541
を見ると，悲痛な叫びと言外のいらだちが感じられなくもない。

# 追記 2023-01-13

バージョン 2.8.0.1 がリリースされ，本件は解決したようだ。長かった。

関係者のみなさまに感謝。
先読み/後読みの覚え方【正規表現】

# 先読み 眼帯セイウチ

セイウチが眼帯をしてるように見えますね。

![output-onlinestringtools.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/64b1aa36-7b44-6d5c-7f58-d0e038205c16.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/1fea9523-1392-f033-f31e-cdcbb44d0f6d.png)

# 後読み 鼻あり眼帯セイウチ

セイウチに鼻がつきました。これで呼吸できます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/a6561211-39d7-d803-fe8c-03c3fa0ba1a0.png)
【AWS Lambdaテスト】sinonで1つのLambdaで複数のDBを参照しているときのLambdaTest

# Lambda Testこんなときどうするの
シリーズ化できたらいいな～

# AWS Lambdaで複数のDBをscanしてる、このDBをstubにしたい
以下のようなケースについて☟

```JavaScript:Lambda.js
//aws-sdkを定義
const AWS = require('aws-sdk')

//dynamo-DBを定義
const dynamo = new AWS.DynamoDB.DocumentClient()

// 野菜DBから全取得
    // Dynamoの野菜DBの内容をscan
    var yasaiDB = await dynamo.scan({ TableName: 'vegitable' }).promise()
    // 八百屋DBから全取得
    var yaoyaDB = await dynamo.scan({ TableName: 'Yaoya' }).promise()

```

野菜DB、八百屋DBそれぞれから情報をscanしてきて、その情報をほにゃほにゃしてる状況。

このLambdaをsinonやchaiでTestするとき、
この野菜DBと八百屋DBをstubするには、stubを2つ設定しないといけない？

ふつうにdynamo-DBのscanのstubつくるときはこんな風に書くけど…
```JavaScript:Test_instance.js
    // スタブでdb-scanしたとき、このアイテムを返すと約束する
  const dynamoDBScan = sinon.stub(proxyDynamoDB.prototype, 'scan')
    .returns({
      promise: () => {
        return Promise.resolve({
          Items:
            vegitableInfo

        })
      }})
```

どうしたらいいのだろうか…

# sinonの公式ドキュメントにいい使い方が
[Stubs - Sinon.JS](URL "https://sinonjs.org/releases/v15/stubs/")

sinon.stub.withArgs(***)で引数変えたときの返してほしい値を設定できるそう。
これが使える。

# 実際に書いたテストコード

```JavaScript:Test.js
describe('yasai kounyuu system Lambda', () => {
  let event
  let context
  let lambda

  // it毎に毎回呼ばれる
  beforeEach(() => {
    event = {routeKey: 'GET'}
    context = {}
  },

  // DynamoDBのstubを作成
  proxyDynamoDB = class {
    scan (params) {
      return {
        promise: () => {}
      }
    }
  },

  // テストしたいソースをここで定義
  lambda = proxyquire('./Lambda.js', {
    'aws-sdk': {
      DynamoDB: {
        DocumentClient: proxyDynamoDB
      }
    }
  })
  )

  // スタブでdb-scanしたとき、このアイテムを返すと約束する
  //　★ここからstubの引数による使い分け箇所★
  const dynamoDBScan = sinon.stub(proxyDynamoDB.prototype, 'scan')
  dynamoDBScan.withArgs({ TableName: 'vegitable' }).returns({
    promise: () => {
      return Promise.resolve({
        Items:
            vegitableInfo

      })
    }})
  dynamoDBScan.withArgs({ TableName: 'Yaoya' }).returns({
    promise: () => {
      return Promise.resolve({
        Items:
              yaoyaInfo

      })
    }})


 // テストしたいコードを書き足すときは、asyncにしないとバグる（まだデータないよってなる）
  it('yasai TEST', async function () {
    // ここでREST APIのCRUDをrouteKeyに設定する
    var event = {routeKey: 'GET'}

    // テストしたいソースを呼び出す
    const resp = await lambda.handler(event, context)

    // Stringできてるrespをparseする
    const respBody = JSON.parse(resp.body)

    // dynamoDBscanは2回呼ばれてるので、calledTwice(Onceではない)ですよー
    assert.equal(dynamoDBScan.calledTwice, true)
})
```

# sinonの公式ドキュメントはすごく親切
みんな読もう…！
エクセルの基本的な使い方

## 機能名
リボン：表機能を作る際に使用する各機能の一覧
タブ：リボンの上に位置する部分。
ダイアログボックス：関連した機能が集まるグループ
ミニツールバー：文字の種類やサイズ、色などを設定できるボタンが備わっている部分
フィルハンドル：アクティブセルの右下にある■。
オートフィル機能：フィルハンドルにマウスインターを合わせ、ドラッグし、同じデータを入力できる
オートフィルオプション：オートフィルで入力したデータの入力方法を変更出来る。
B:太文字
I:斜体
U:下線
条件付き書式：選択したセルに自動で書式を設定する機能。例えば、棒グラフ等で表すことができるようにしたり、指定の値より大きいセルのみ文字の色を変更させたりすることができる。
オートSUM：合計、平均、数値の個数、最大値、最小値を求める関数が備わっている。
オートフィルター：データを抽出する機能。
数値グループ：選択したセル内の数字に通貨やパーセントを追加したりすることができる機能。
データの入力規則：入力をスムーズに行うための機能。
テーブル：選択したセルをテーブル表記に変更する。デザインからテーブルの色等を変更できる。
ふりがなの表示/非表示：選択したセル内の文字のふりがなを編集したり、設定したりすることができる。
検索：入力した文字を検索できる機能
置換：セルに入力した文字列を別の文字列に変更する機能。
重複の削除：重複しているデータを削除する機能
書式：選択した列を表示したり、非表示にしたりすることが出来る機能
シート保護：入力欄以外を編集不可にする。
ウインド枠の設定：指定した行や列を常に表示できるようする機能。
分割：離れた場所を同時に表示する機能。
新しいウインドを開く：1つのファイルにある2つのワークシートを比較できる。
折り返して全体を表示する：文字列を複数行にする。
図形：選択した図形を挿入する機能
スマートアート：図表を簡単に作成できる機能
貼り付け：コピーした値や文字列を選択したセルにペーストできる。
書式のコピー/貼り付け：セルに設定した書式を別のセルにも設定する
新しいコメント：セルにメモを付けられる。
コメントの編集：メモを編集する
テンプレート：文書のひな形。
操作アシスト：目的操作が不明なとき、操作に関する機能やヘルプが表示される。
クイックツールバー：よく使う機能を登録できるもの

## 関数
SUM関数：数値を合計する。=SUM(数値1,数値2．．．）

ROW関数：セルの行番号を求める。=ROW(参照)

PHONETIC関数：文字列の読みを取り出す。=PHONETIC(氏名)

ROUNDDOWN関数：指定した桁数に切り捨てる。=ROUNDDOWN(数値,桁数)

VLOOKUP関数：範囲を縦方向に検索して指定した列の値を抽出する。=VLOOKUP(検索値,範囲,列番号,検索方法)

IFERROR関数：数式のエラー値を別の値に置き換える。=IFEFFOR(値,エラーの場合の値）

TODAY関数：現在の年月日を表示。=TODAY()

IF関数：条件を満たす場合はTRUE、満たない場合はFALSEで返す関数。=IF(論理式,真の場合,偽の場合)
t3-stack入門 (3) T3-appにMantineを導入する

CSS弱者なので、tailwindだけで画面を作るのは厳しいです。React コンポーネントライブラリのMantineを使って画面を作成します。
https://mantine.dev/
Mantineを使うのはudemyでちょうど講座がセールしてたというだけの理由です。
https://www.udemy.com/course/mantine-react-complete-guide-nextjs/
内容は非常にわかりやすくで実践的だったのでお勧めです。
ただし、udemyは普段の値段と、セールの値段が違いすぎるのでセールを待つのがめんどくさいですが。

## mantineを追加
```
npm install @mantine/core @mantine/hooks @mantine/form @mantine/next tabler-icons-react
```

## mantineの設定
https://mantine.dev/guides/next/
を参考に、src/pages/_app.tsxにMantineの設定を追加します。

```diff_typescript
  return (
    <SessionProvider session={session}>
+      <MantineProvider
+        withGlobalStyles
+        withNormalizeCSS
+        theme={{ colorScheme: "dark" }}
+      >
        <Component {...pageProps} />
+      </MantineProvider>
    </SessionProvider>
  );
};

```

## Layoutを作成
src/components/Layout.tsxを作成します
https://github.com/GomaGoma676/mantine-lesson/blob/main/components/Layout.tsx
udemy
からコピペしただけです。
```typescript
import Head from "next/head";
import type { FC, ReactNode } from "react";

type Props = {
  title: string;
  children: ReactNode;
};

export const Layout: FC<Props> = ({ children, title = "T3 Todo Example" }) => {
  return (
    <div>
      <Head>
        <title>{title}</title>
      </Head>
      <header></header>
      <main className="flex flex-1 flex-col items-center justify-center p-4">
        {children}
      </main>
      <footer></footer>
    </div>
  );
};

```

Webアプリの開発していたころはまだflexは使えなかったため
https://www.webcreatorbox.com/tech/css-flexbox-cheat-sheet
のチートシートを見て勉強しました。
flex-colが子要素を上から下に配置する指定。
flex-1クラスを使用すると、初期サイズを無視して、必要に応じてフレックスアイテムを拡大および縮小する指定。
justify-centerが主軸（flex-colなら縦）方向で中央に配置
items-centerがクロス軸（flex-colなら縦）方向で中央に配置
だそうです。


## Todo画面を更新

```typescript
import { ActionIcon, Card, Group, Text } from "@mantine/core";
import { type NextPage } from "next";
import { Trash } from "tabler-icons-react";
import { Layout } from "../components/Layout";

import { trpc } from "../utils/trpc";

const Todo: NextPage = () => {
  const todos = trpc.todo.getAll.useQuery();
  const utils = trpc.useContext();
  const deleteTodo = trpc.todo.delete.useMutation({
    onSettled: () => {
      utils.todo.getAll.invalidate();
    },
  });
  return (
    <Layout title="Todo">
      <h1 className="">Todo</h1>
      <div>
        {todos.data?.map((todo) => (
          <Card withBorder key={todo.id} mt={"sm"}>
            <Group position={"apart"}>
              <Text>{todo.name}</Text>
              <ActionIcon
                onClick={() => {
                  deleteTodo.mutate({ id: todo.id });
                }}
                color={"red"}
                variant={"transparent"}
              >
                <Trash />
              </ActionIcon>
            </Group>
          </Card>
        ))}
      </div>
    </Layout>
  );
};

export default Todo;

```
Groupは要素を縦に並べるFlex Boxで、position={"apart"}を指定すると、要素同士ができるだけ離れるように配置します。

今回の変更は以下の通りです。

https://github.com/bioflowy/t3-todo-example/commit/c3f8aca5b69312fabacc4e90d8c74353ceb27a2f
①SpringBootプロジェクト作成方法 【Vue.js+SpringBootでアプリケーション作成】

# ①SpringBootプロジェクトを作成方法
## 環境
    OS : Windows 11 Home
    システム種類 : 64 ビット
    プロセッサ : i7-10510U
    メモリ : 16.0 GB 
    統合開発環境 : VSCode

1. Javaの拡張パックを導入
    「Extension Pack for Java」で検索しインストールします。
    Visual Studio CodeでJavaの開発を可能にするため、必要な拡張機能です。

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/15386e72-929a-d080-60a0-3dd373d83d69.png)

2. Spring Bootの拡張パックを導入
「Spring Boot Extension Pack」で検索しインストールします。
Spring Boot プロジェクトの作成や実行、デバッグなどができるようなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/cd8481d0-6a74-5497-ec83-23fa0b6cf404.png)

## SpringBootプロジェクト作成
1. Ctrl+Shift+Pでコマンドパネルを開いて「Spring」で検索。
1. 「Spring Initializr: Create a Maven Project」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/35810b0e-ac65-7c17-dd47-f79160f45648.png)

3．Spring Bootのversionを選択。
今回は、「3.0.0」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/42d145e7-a66a-5f53-8914-140678f6d316.png)

４．言語の選択。
Javaで開発を行いため、Javaを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/a1bc6204-bbe3-d8ff-5304-f78827780fa1.png)
5. グループIDは任意で指定します。
今回は、そのまま使用しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/31235a94-a2ba-e031-36d0-47bee11c328c.png)
6.自分のプロジェクトの名前を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/927632fb-a6dc-3cfa-e962-f08d9521d5e4.png)
7. 実行ファイル形式の選択
「Jar」ファイルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/24651dce-fe81-1fe5-7678-18c51ea1ba59.png)
8. JavaVersionの選択。
17を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/4963ab30-3cd4-1b01-25f2-3e698c9129b8.png)
9.拡張機能の選択。
Spring Boot DevTools
Spring Web
Lombok

:::note info

Spring Boot DevTools
Tomcatを再起動せずにアプリケーションだけを再起動する機能があり、コードの修正、確認のサイクルを速めることができます。
:::
:::note info
Spring Web
サーブレット API に基づいて構築されたオリジナルの Web フレームワークです。
:::
:::note info
Lombok
Java言語におけるボイラープレートコードをソースコードから排除するために使用するライブラリです。
[ボイラープレートコードとは](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%82%A4%E3%83%A9%E3%83%BC%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%B3%E3%83%BC%E3%83%89)
:::
を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/015c257b-a61e-8d27-1b55-9502bf9b4faa.png)
10. プロジェクトの完成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/01f87b14-560e-f5e9-1a44-ff1ba18ad012.png)
11.実行してみます。

デバッカー選択を聞かれたらjavaを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/489e3cda-3786-606c-1506-155f6a3a8fa1.png)

## 起動しました!!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918186/477e2b71-a694-fc94-3b6b-ec4398f0a589.png)
bash: !.xls: event not found

# 事象 : S3に格納されている「!」がファイル名にあるファイルをダウンロードできない

```bash
$ aws s3 ls s3://sample-bucket-name/dir-path/ --profile chovin
2022-11-29 09:31:46      34304 file_name!.xls

$ aws s3 cp s3://sample-bucket-name/dir-path/file_name!.xls ~/Downloads/ --profile chovin
bash: !.xls: event not found
```

## 原因 : Bashのヒストリ展開が行われているから

> **!**
> 履歴置換を開始します。ただし、 ブランク文字、 改行文字、 = 、 ( (シェルオプション extglob が組み込みコマンド shopt によって有効になっている場合) のいずれかが後に続く場合は除きます。
> [Man page of BASH](https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html#lbCX)

1. 「!.xls」でヒストリ展開が行われる
1. 「.xls」で始まるコマンドで実行された履歴を探す
1. ないからエラー

参考 : [[Bash] ダブルクォートで囲んだコマンド置換中で!を使うとエラーになる（例: echo &quot;$(echo &#39;!&#39;)&quot;） - Qiita](https://qiita.com/anqooqie/items/785f46a8cc5f10ba7abb)

### 対応 : 「'」だけで囲う

```bash
# 成功パターン : パス全部を「'」で囲う
$ aws s3 cp 's3://sample-bucket-name/dir-path/file_name!.xls' ~/Downloads/ --profile chovin
download: s3://sample-bucket-name/dir-path/file_name!.xls to C:\Users\chovin\Downloads\file_name!.xls

# 成功パターン : ファイル名を「'」で囲う
$ aws s3 cp s3://sample-bucket-name/dir-path/'file_name!.xls' ~/Downloads/ --profile chovin
download: s3://sample-bucket-name/dir-path/file_name!.xls to C:\Users\chovin\Downloads\file_name!.xls

# 失敗パターン : パス全部を「"」で囲う
$ aws s3 cp "s3://sample-bucket-name/dir-path/file_name!.xls" ~/Downloads/ --profile chovin
bash: !.xls: event not found

# 失敗パターン : ファイル名を「"」で囲う
$ aws s3 cp s3://sample-bucket-name/dir-path/"file_name!.xls" ~/Downloads/ --profile chovin
bash: !.xls: event not found

# 失敗パターン : ファイル名を「'」と「"」で囲う
$ aws s3 cp s3://sample-bucket-name/dir-path/'"file_name!.xls"' ~/Downloads/ --profile chovin
fatal error: An error occurred (404) when calling the HeadObject operation: Key "dir-path/"file_name!.xls"" does not exist

# 失敗パターン : パス全部を「'」で囲う and ファイル名を「"」で囲う
$ aws s3 cp 's3://sample-bucket-name/dir-path/"file_name!.xls"' ~/Downloads/ --profile chovin
fatal error: An error occurred (404) when calling the HeadObject operation: Key "dir-path/"file_name!.xls"" does not exist
```
【サイトセットアップ】CSVリストを利用したユーザーの追加

今回は、[Sharperlight](http://www.sharperlight.jp/)にユーザーを一度に複数追加する方法を試してみたいと思います。
その中でも**CSVリスト**を利用したユーザーの追加を試してみます。
Sharperlightアプリケーションメニューから**サイトセットアップ**を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/23a507b2-e0e6-2296-ea10-2b6c4287674e.png)
サイトセットアップウィンドウが開いたら、既存のユーザーとユーザーグループを確認します。
特にユーザーを詳しくチェックしておきます。
その理由は、複数のユーザーを追加する際に、テンプレートとしてどのユーザーを使用するかを指定する必要があるためです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/3c4cd3cb-b090-5936-7abf-da1d5a454d0c.png)
ユーザーノードを選択し、右クリックメニューから**ユーザーのインポート** -> **CSV**を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/e1034425-e0bd-9911-ba34-894f539c7674.png)
初期設定として使用するユーザー入力を促すダイアログが表示されます。
今回は**guest**ユーザーを指定します。`OK`ボタンで先に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/f4d6a237-62b8-82e4-f950-aa0a4c439768.png)
追加するユーザーの一覧を記述するダイアログが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/d76d4c48-11dc-7f1c-2daf-ef1a0724dbbb.png)
一行だけテンプレートが表示されているので、それに従って記入していきます。
**ユーザー名**と**ユーザーグループ**は必須項目で、`説明(Description)`、`電子メール(Email)`、`パスワード(Password)`はオプションです。
このようなユーザーリストにしてみました。一人だけ**admin**ユーザーのテンプレートを指定してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/eedcc57c-56b9-8ab9-5d40-5995d2116e58.png)
```
[WindowsDomain\WindowsUser or UserName],[UserGroup],<Description>,<Email>,<Password>
YoshinoriK,guest,久保 美則,YoshinoriK@company.com
HideyukiA,guest,秋元 英幸,HideyukiA@company.com
MisatoH,guest,浜田 美里,MisatoH@company.com
NobutoN,guest,新田 信人,NobutoN@company.com
EriF,guest,藤田 恵理,EriF@company.com
HideshiH,guest,原口 秀志,HideshiH@company.com
HitomiI,admin,井上 ひとみ,HitomiI@company.com
```
`OK`ボタンで確定します。
インポートされましたというメッセージが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/e419f283-8bd3-2b53-392f-762de5514847.png)
ユーザーノードに7人の新規ユーザーが確認できますね。そして`井上ひとみ`さんには**admin**ユーザーグループがきちんと割り当てられています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/18019257-413f-d312-8a3b-7e4af7f213b1.png)
以上が、**CSVリスト**を利用して一度に複数のユーザーを追加する方法でした。どうぞお試しください。

では、失礼します。
SBT：譲渡不可 NFT の紹介

譲渡不可 NFT については、[NTT](https://qiita.com/blueplanet/items/89c9af6bf0ad836d9272) を紹介しましたが、今年話題になっているもう１つ `SBT` があります。SBT とは、 `SoulBound Token` の略語であり、Vitalik の提案から広がっています。

名前の由来は、人気オンラインゲーム「World of Warcraff」からアイデアを得ています。
そのゲームの道具アイテムには、任意で他人に譲ったり売ったりものはもちろんありますが、もう１つの種類として、一度拾うと他人に譲ったり売ったりすることができないアイテムがあり、ゲームの中では `魂に紐付けいたアイテム（SoulBound Item）` と呼ばれています。Vitalik はこの発想をブロックチェーンに持ってきた経緯です。

## 最初は vitalik のブログ記事でした
- 2022 年 1 月 26 日、vitalik が、[Soulbound](https://vitalik.ca/general/2022/01/26/soulbound.html) タイトルの記事を発表しました。
- ゲームの soulbound アイテムのお話しからはじめ、譲渡不可な NFT・譲渡不可なガバナンス権利の可能性を言及しました。

## 論文発表
- 2022 年 5 月 11 日、[Decentralized Society: Finding Web3's Soul](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4105763) 論文を他の二方と発表しました。SBT で分散型社会を構築する構想になります。
- 詳細の実装のお話はないですが、それなりのボリュームがあるので、いろいろ議論されています。
[![Screen Shot 2022-12-05 at 10.28.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4777/43c303f6-793e-61d2-ceaa-f01367e25eb4.png)](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4105763)
- それ以来はいろいろ議論されて注目されています

https://twitter.com/AkioHoshi/status/1528330197342117888?s=20&t=AnDRXdrEcZdNMhC8kS7Y5g

https://www.xross-dx.com/article/aboutSBT-byGG-vol1.html

https://www.sbbit.jp/article/fj/93134

https://note.com/shinkinjo/n/nd968502eee99

https://coinpost.jp/?p=353189

## 実装について
SBT は、現状まだ決めた EIP がなく、[NTT：譲渡不可の NFT の紹介](https://qiita.com/blueplanet/items/89c9af6bf0ad836d9272) 記事で紹介した NTT や下記の EIP があります。

No |作成日付|ステータス|内容
---|---|---|---
[EIP 4973 (Account Bound Token)](https://eips.ethereum.org/EIPS/eip-4973)|2022-04-01|Review|転送のための標準的なインタフェースを実装していない。このEIPは、ABTの造成、割り当て、取り消し、追跡のための基本的な機能を定義しています。
[EIP 4974 (Experience Token Standard)](https://eips.ethereum.org/EIPS/eip-4974)|2022-04-02|Draft|ビデオゲームの経験値、学術論文の引用、Redditのカルマのように、有用な貢献に対して与えられ、区別できない単位で蓄積され、権限を与えられた信頼できる当局によってのみ再割り当てまたは破棄されるべきポイントのようなもの
[EIP 5114 (Soulbound Token)](https://eips.ethereum.org/EIPS/eip-5114)|2022-05-30|Draft| mint 時に他の NFT と結合し、その後譲渡/移動ができないトークン
[EIP 5192 (Minimal Soulbound NFTs)](https://eips.ethereum.org/EIPS/eip-5192)|2022-07-01|Final|ERC721 を拡張して、トークンをソウルバウンドさせるための最小限のインタフェースを提案し単一のアカウントにバインドされた非可溶性トークンである
[EIP-5516: Soulbound Multi-owner Tokens](https://eips.ethereum.org/EIPS/eip-5516)|2022-08-19|Review|これまでのアカウントバインドトークン標準は、ユーザーがアカウントキーを紛失したり、回転させたりすることで、その過程でトークンを紛失するという問題に直面している。このEIPは、この問題に対して、SBTのリサイクルを可能にする解決策を提供する

## 事例
2022年8月18日、千葉工業大学で学修歴証明書をNFTで発行と発表されました。
Soulbound トークンに通じる譲渡不可な NFT となっています。

![Screen Shot 2022-12-05 at 13.28.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4777/752ee65e-2722-8009-ded1-69fcafcc9c4b.png)


## まとめ
ブロックチェーンは、ビットコイン・暗号化通貨のおかげでよく知られるようになってきたと同時に、金臭いと感じられてしまっています。取引を目的とするものではなく、分散型社会を構築するためにブロックチェーンを活用する SBT はすごく期待できると思います。
ReactのReduxTolkitの練習にて、Prettierのエラーを解消した方法のメモ


## 初めに
Reactを用いたWebアプリ開発中にエラーが起こりました。
多分、フレームワークに関係なく、VSCodeniteにて、Prettierを使って自動でコード整形をしようとした時にエラーが起こりましたので、eslint-config-prettierのバージョンが7以下の方はぜひ参考ください。


## エラーについて
実行すると、`[eslint] Cannot read config file: `という以下のようなエラーがターミナル上に出てきます。

```
[eslint] Cannot read config file: 
/Users/ホームディレクトリ名/React/toolkit-todop/node_modules/eslint-config-prettier/@typescript-eslint.js
```

## 解決策
`.eslintrc.json`ファイルのバージョンに関するエラーのようでした。Version 8.0.0 (2021-02-21)では、以下のように書かないとエラーになるようです。

eslint-config-prettierのバージョンを8.0.0以上に上げた人は注意が必要です。


```.eslintrc.json
{
    "extends": [
      "eslint:recommended",
      "plugin:@typescript-eslint/recommended",
      "prettier",
      "prettier/@typescript-eslint"
    ],
    "plugins": ["@typescript-eslint"],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
      "sourceType": "module"
    },
    "env": { "browser": true, "node": true, "es6": true },
    "rules": {
      // 適当なルール
    }
  }
```

以下のように変更するとエラーが解消されます。


```.eslintrc.json
{
   "extends": [
    "some-other-config-you-use",
    "prettier"
  ],
    "plugins": ["@typescript-eslint"],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
      "sourceType": "module"
    },
    "env": { "browser": true, "node": true, "es6": true },
    "rules": {
      // 適当なルール
    }
  }
```


ぜひ、同じ境遇でお困りの方は、参考にしていただければと思います。

参考記事
* [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md#version-800-2021-02-21)
* [Prettierの設定に躓いたので解消した方法をメモ](https://zenn.dev/yantera/articles/52866646181aea)