OmniAICreator/Qiita-1.07M huggingface dataset:
STM32の開発環境を考える。

秋ロボアドベントカレンダ24日目の記事です。

こんにちは
やましょうです。


#STM32の開発環境について、
##1.有償コンパイラ+IDE
1-1.ARM MDK(マイクロVISON)
1-2.IAR W/B
1-3.その他 いっぱい

mdkもiarも50～100万くらいします。

##2.無償コンパイラ+IDE
2-1.MBED Studio
2-2.STM32 CUBE MX IDE
2-3.True Studio STM32
2-4.GCC+ECLIPSE(GNU MCU Eclipse)
2-5.その他

無償系の関して記載します。

#MBED Studio
ARMさんの提供してくれる無料開発環境です。
とても便利、でもデータ容量が。。
![SnapCrab_NoName_2020-12-25_9-33-31_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/e8f5fa9d-bc36-8885-a2d4-347541b2dce5.png)


#STM32 CUBE MX IDE
まず、注意ですが、STM32 CUBE MXとSTM32 CUBE MX IDEは別ものです。
STM32 CUBE MX はペリフェラルをGUIで設定して、コード生成してくれるツールです。(STM32 CUBE MX IDEには内包されています.)
STM32 CUBE MX IDEはEclipseの開発環境です。

![SnapCrab_NoName_2020-12-25_9-34-15_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/5ce0fa3c-1e68-0353-cff9-859f327e9b12.png)

#True Studio
Stさんが買収して無料となった元有料コンパイラideですが実際にはGCCでやっている様な気もします。（正確なところは調査していない。）
![SnapCrab_NoName_2020-12-25_9-49-17_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/bc8c7cd6-ee64-078e-74bf-37d5f4d8d260.png)


##コンパイラとしては
結局無償系のコンパイラはすべてGCCなのか？なぁ


#WINかMACか？
MBED Studio/STM32 CUBE MX IDEについてはMAC版もあります。
体感すればわかると思いますが、コンパイル速度から言うとMACの方が圧倒的に早いです。
（これは個人の感想です。）
ArudinoでもMACの方コンパイル速度爆速ですよね!
私は会社ではWINですが、M1 MACにしてもらおうか？考えています。
早くM1 4K iMacがでないかなと思っています。


#個人的な結論
MACの環境でSTM32CUBEIDEを使うのが一番簡単で早いかな。。と思いました。


以上
やましょうでした。
【#LINE】LINE Developers で作成できるプロバイダーやチャネル数に制限はあるの？

# 概要
LINE Developers 上で作成できるプロバイダーやその中で作成できるチャネル数に制限はあるのか検証＆調査してみました。


# 結論
あります。

## プロバイダ

１アカウントで作成できるプロバイダーは全部で 10個のようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/57f4d0bd-4d58-040a-975b-123b61b1bd25.png)

ただし、以下の画像のように
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/de8890f0-40d8-538a-b895-019cae750b71.png)

共有されているプロバイダ数は含まれないようです。
あくまで、１アカウント（１ビジネスID）で作成できるプロバイダー数は10個です。
10個以上作る場合は、アカウントを複数所有しての運用になりそうです。

## チャネル
１つのプロバイダー内では 100個までチャネルを作ることができます。
ただし、プロバイダーと違い権限には注意が必要ですね。
> 開発者AがMessaging APIのチャネルを100個管理している場合、ほかの開発者Bが作成したMessaging APIのチャネルの権限を、開発者Aに付与することはできません。

https://developers.line.biz/ja/faq/#how-many-channels-can-i-create


## プランによって、作成可能な最大数は変わる？
変わりません。
マルチスケールシミュレーション特論：第10回(Recursive)

# Fibonacci数列

再帰(Recursive)処理の練習に，Fibonacci数列の第n項を出力する関数fibを実装する．

```ruby:fibonacci.rb
def fib(n)
  if n == 0
    return 0
  end

  if n == 1
    return 1
  end

  return fib(n-1) + fib(n-2)
end
```

# 前回作ったassertを使ってテストする

```ruby:fibonacci.rb
require './assert'
[[0,0],[1,1],[2,1],[3,2],[4,3],
 [5,5],[6,8],[7,13],[8,21]].each do |index, expected|
  assert_equal(expected, fib(index))
end
```

# 参考文献

[チャート式ruby-V(Recursive Fibonacci)](https://qiita.com/daddygongon/items/1bb27b8920c201d5c520)

------
 - **source** ~/grad_members_20f/members/ryuta-kikuchi/qiita_articles/lecture10.org
M5Stackで非接触型体温計を作る

## はじめに

今年は、コロナウィルスの感染拡大防止のために、多くの店で入店時に検温を求められました。
ふと、手元に持っているもので自分でも`非接触の体温計`を作れるのでは!?と思ったので、試してみました。

お店で使われているものにどのような機能があるか調べていないですが、体温を素早く測ることができたら機能としては十分なのかなと思い、今回はその機能だけを実装しました。

|イメージ|できたもの|
|---|---|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128594/d0650165-f526-ec49-6133-805c16343edb.png" width="200">|![thermal2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128594/fa7a63b7-86ed-af87-08f1-8bf1aa817d8d.gif)|

## 利用したもの

|[M5Stack Gray](https://docs.m5stack.com/#/en/core/gray)|[M5Stack用ミニサーマルカメラユニット](https://docs.m5stack.com/#/en/unit/thermal)|
|---|---|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128594/bfb60436-08f0-3481-9eb8-e1a1c39828e0.png" width="300">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128594/f99d239e-a4b8-6165-0a54-8d424718c96a.png" width="300">|
|約3,500円|約10,500円|

## 作成手順
- まずは、M5Stack Grayの開発環境を構築します。環境構築手順は、[こちら](https://qiita.com/yamayoshii/items/9f74aadae2e5c2bd7850)が参考になると思います。
- 次に、サーマルカメラユニット[のサンプルプログラム](https://github.com/kdg-hacks/kdg-hacks-examples/tree/master/m5stack/Hello-MLX90640)を動かします。成功すると、以下のようにM5Stackのディスプレイにサーマルカメラの計測結果が表示されるようになります。　
    - <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128594/a9a79577-22be-8333-2759-5928b7601449.jpeg" width="300">
- このままだと測定結果がわかりにくいので、ボタンを押したときの体温を大きく表示するようにコードを修正しました。
    - 両面テープで壁に固定してみました。剥がすときに壁紙が剥がれそうになったので気をつけてください。
    
    ![thermal2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128594/fa7a63b7-86ed-af87-08f1-8bf1aa817d8d.gif)

## 終わりに
- 非接触型体温計を作ることができました。これで、簡単に体温測定することができます。
- 自作することで安価になると思っていたのですが、あとでググってみると市販しているものには数千円で購入できるものがあり、残念な感じになりましたが、自分でも作ることができるとわかったので、満足です。
- それでは、良いお年を。
他の要素と重ならないように、ヘッダーを上部に固定

スクロールした時、他の要素と重ならないように、ヘッダーを上部に固定したい。

``` ```:html

<header class-"header">
.
.
.
</header>
```

固定するためには position: fixedを使用し、
他の要素（文字など）と重ならないようにするためにz-indexを指定する。

``` ```:css

.header {
  position: fixed;
  z-index: 99;
  width: 100%;
  background-color: white;
}
```
Vee Validateのカスタムルールを作成する方法

## 概要
[Vee Validate](https://logaretm.github.io/vee-validate/)を用いて
バリデーションの設定を行う機会があった。
defaultで用意された[Validation Rules](https://vee-validate.logaretm.com/v2/guide/rules.html)ではなく、
独自のルールを設定したい場合の方法についてメモとして書き残しておく。

## 詳細

`/plugins/vee-validate.js`でカスタムルールを設定する

```javascript:vee-validate.js 
import Vue from 'vue';

// 使用する機能
import {
    ValidationProvider,
    localize,
    extend
} from 'vee-validate';

Vue.component('ValidationProvider', ValidationProvider);

// エラーメッセージの日本語化
import ja from 'vee-validate/dist/locale/ja.json';
localize('ja', ja);

// 使用するvalidation rules
import { numeric } from 'vee-validate/dist/rules';
extend('numeric', numeric);

// カスタムルールの設定
// validation-providerタグのrulesで指定する値を指定
extend('number', {
    // エラーメッセージを設定する
    message: '数値の先頭に0は不要です',
    validate(value) {
        if (value.match(/^([1-9]\d*|0)$/)) {
            return true;
        }
    }
});

// validation-providerタグのrulesで指定する値を指定
extend('larger', {
    params: [
        {
            name: 'minimum',
            isTarget: true
        }
    ],
    // エラーメッセージの{_field_},{minimum}にはvalidation-providerタグのnameで指定した文字列が入る
    message: '{_field_}は{minimum}より大きい数値を入力してください',
    validate(value, { minimum }) {
        return value > minimum;
    }
});
```

`/plugins/vee-validate.js`で設定したカスタムルールをvueファイルに適用する

```vue:input.vue
<template>
    <div>
        <label>最小文字数</label>
        <validation-provider
            v-slot="{ errors }"
            rules="numeric|number"
            vid="minimum"
            name="最小文字数"
        >
            <input type="text”>
            <p v-show="errors.length”>{{ errors[0] }}</p>
        </validation-provider>
    </div>
    <div>
        <label>最大文字数</label>
        <validation-provider
            v-slot="{ errors }"
            rules="numeric|number|larger:minimum"
            name="最大文字数"
        >
            <input type="text”>
            <p v-show="errors.length”>{{ errors[0] }}</p>
        </validation-provider>
    </div>
<template>

<!-- 省略 -->
```

### 参照

- [VeeValidate - Custom Rules](https://vee-validate.logaretm.com/v2/guide/custom-rules.html)
- [VeeValidateのクロスフィールドのカスタムルール設定方法](https://www.kabanoki.net/5136/)
マルチスケールシミュレーション特論：第8回(assert)

# assert

2つの引数をとり，それらが同じ値かどうかを出力するような関数assert\_equalを作る．同様に，それらが異なる値かどうかを出力するような関数assert\_not\_equalを作る．

```ruby:assert.rb
require 'colorize'

def puts_vals(expected, result)
  puts "expected :: #{expected}"
  puts "result   :: #{result}"
end

def assert_not_equal(expected, result)
  puts_vals(expected, result)
  if expected != result
    print "succeeded in #{__method__}.\n".green
  else
    print "failed in #{__method__}.\n".red
  end
end

def assert_equal(expected, result)
  puts_vals(expected, result)
  if expected == result
    print "succeeded in #{__method__}.\n".green
  else
    print "failed in #{__method__}.\n".red
  end
end

if $PROGRAM_NAME == __FILE__
  assert_equal(1, 1)
  assert_equal(1, 2)
  assert_not_equal(1, 2)
  assert_not_equal(1, 1)
end
```

# 他のソースコードからassertを利用する

```ruby:require_assert.rb
require './assert'

assert_equal(4, 2 * 2)
assert_not_equal('Muku', 'Miku')
```

# 参考文献

[チャート式ruby-IV(assert\_equal)](https://qiita.com/daddygongon/items/f6cea87314ee26e130ea)

------
 - **source** ~/grad_members_20f/members/ryuta-kikuchi/qiita_articles/lecture8.org
Amazon SES ってなに？

## 勉強前イメージ

AmazonSNSと似たような...通知送るシステムのイメージ
ただ何が違うのかがわからない

## 調査

### Amazon SESとは？

Amazon Simple Email Service の略で、メール配信サービスです。
独自ドメインの利用でも利用することができます。
また、他のメールサーバと違うのがAWSの他のサービスと連携することができます。

### Amazon SNS でもEメール使えるが、違いは何？

Amazon SNSでもEメールを使用することができますが、
SNSは通知をするためのサービスなので、HTMLなども使用することはできません。
メールでの設定を多くできるのがSESなのです。

### Amazon SESの特徴

- 導入のコストが低い

SESを利用するために必要なのが、AWSアカウント・メールアドレス・ドメインのみです。
すぐに始めることができます。

- 低価格

使用した分だけ発生するので、固定費などはありません。
ですので気軽に試すことができます。

- 高い配信性能

メールサーバではスパムメールを受信しない対策がされており、信頼性が低いメールは受信されません。
SESでは信頼性を高めて送信しているので、受信される率が高いです。


## 勉強後イメージ

SNSは通知、SESはメール。
ややこしい.....
けど、気軽にメール送れるサービス作れるのはよきー
メールサーバってめんどくさい・・・・

## 参考

- [Amazon SESとは？使いどころとSNSとの違い](https://tech-dive.xyz/2018/11/12/post-278/)
- [【AWS】メール配信サービスSESの概要から使い方まで](https://techplay.jp/column/614)
AWS Certified Solutions Architect Professional試験に合格しました

クリスマスイブ(2020/12/24)の日に、いつもの歌舞伎座テストセンターで受けてきました。
スコアは894点でした。
今回も英語で受けているので、参考にならないかもしれませんが、英語で受ける方は参考になればと思います。

# 試験の感想

ESL +30 MINUTESを使って、210分で75問を解くというハードな戦いでした。全部解いた時点で残り１５分だったので、これがないとかなりヤバかった。蓋を開けてみれば高スコアでしたが、試験を受けている最中は、時間が足りず、これは落ちたかもとかなり焦りました。
問題集で勉強していた問題がそのまま出ることはないと覚悟してましたがやはりそうでした。ほとんどが初めて見る問題で、想像していたとおりの難易度でした。シナリオベースの長文も多く、複数選択解答も多い。箇条書きで条件が羅列され、そのなかで最も適したものを選ぶというスタイル。
前回受けたDatabaseの試験と比べると、試験時間は同じにもかかわらず、１０問増えて、しかもこちらのほうが、長文、複数選択問題が多い。いかに３時間半集中力を持続させ英文を読み続けることができるかというのが一番のテーマでした。

# 勉強したこと
公式サンプル問題とExam Readinessは一通りやりました。
それ以外に繰り返し勉強したものは、

## Udemy

**1. Ultimate AWS Certified Solutions Architect Professional 2021**
https://www.udemy.com/course/aws-solutions-architect-professional/
500ページを超えるPDFのスライドがよくまとまっていてメイン教材でした。時間の都合もあり動画は見てません。iPad+GoodNotesでメモ書きしながら2回繰り返しました。

**2. Practice Exam AWS Certified Solutions Architect Professional**
https://www.udemy.com/course/practice-exam-aws-certified-solutions-architect-professional/
1と同じ方の問題集です。実質１回分（75問）しかないので量的には少ないですが、問題の形式や難易度は本試験に一番似ているように思いました。（内容が似ていたというわけではないです）
ちなみに本試験を受ける一週間前に初めて受けたら、65%で不合格判定でした。試験時間が170分というところもありましたが。これはヤバいなと最後１週間ラストスパートかけました。
私の場合は、本試験とまったく同じような問題は１０問くらいしかなかった印象ですが、この問題集で間違えたところで何が理解できていないのか最後に確認できたのが合格につながったと思います。

**3. AWS Certified Solutions Architect Professional Practice Exam**
https://www.udemy.com/course/aws-solutions-architect-professional-practice-exams-amazon/
2だけではあきらかに問題数が少ないので、こちらの問題集を使いました。基礎力アップを目的としました。
こちらは４セット(75x4)ありますが、３回くりかえしました。最後にはすべて９０%を超えました。難易度としては、２や本試験よりは易しい。問題文が短く、一つの知識だけで即答できるような問題もありました。本試験では一つの知識だけで即答できる問題は極めてまれです。ですが、シナリオベースの問題や複数選択の良問も多いので、繰り返して知識の定着をはかりました。

## 書籍

**4. ＡＷＳ認定ソリューションアーキテクト−プロフェッショナル 試験特性から導き出した演習問題と詳細解説**
https://honto.jp/netstore/pd-book_30341766.html
Udemyの教材をやる前に、日本語でこちらの書籍で勉強しました。日本語もちゃんとしていて読みやすく、キーポイントもよくまとまっていたと思います。最初から英語でうけるつもりだったので１回しかやりませんでしたが、時間があったら繰り返し勉強してもよかったと思います。

## 模試
本試験１週間前くらいに受けました。85%判定でした。
難易度も内容も本試験に似ているので絶対受けておいたほうがよいです。

# まとめ
実はSAPの勉強は2020年はいったころから始めてました。家庭の都合や、Databaseの試験先に受けたりと、中途半端な状態でした。日本語、英語問わずいろいろ教材にも手を出しましたが、本試験とまったく同じという問題集はまずないと思いました。（Databaseの試験は似たような問題結構ありましたが）
ですが、全く同じ問題など出ないとはじめから想定して試験対策をしていたので、本試験でも「そうだよな」とその点に関しては気持ちが乱れることはありませんでした。不安だったのは試験時間の方ですべて時間内に回答できるかどうかでした。
やはりこの試験のように、一発で正解を選ぶのが難しい場合は、明らかに間違っているものを確実にかつスピーディに消していける力が必要です。そのために教材をつかって繰り返し勉強して、自分の勘（フィーリング）を洗練させていく。AとDは明らかに違うとわかるけど、BとCは微妙、という場面が何度もありました。最後にBかCかどちらを選ぶかは、知識と経験に基づく勘になってしまうのだと思います。AとDを消せないのは明らかに勉強不足。本当の勝負は２択になってから。これを１問あたり３分でひたすら７５回繰り返す集中力と体力が必要です。
小手先のテクニックと言われてしまうかもしれませんが、BかCかだなってなるまでには相当な勉強が必要です（あくまで主観です）
Security、DevOps、Database、SAPと取得できたので、来年はData Analytics、ML、Networkingを目指していきたいです。

戦いはつづく。。。
Dockerをついに使ってみる:開発環境の起動、停止、削除編

前回で開発環境は整えることができた
[Dockerをついに使ってみる:用語、イメージ、立ち上げ編](https://qiita.com/pank24ever/items/9d3bf84462e5d28bbb5c)

この記事では、開発環境の起動、停止、削除の
方法をまとめる

##起動する
**docker-compose.yml**があるディレクトリ上で実行する

```
docker-compose up -d 
```

「-d」をつけずに起動させると
サイトのアクセスログ等が見ることができる

##停止する
下記のコマンドでコンテナを停止する

```
docker-compose stop
```

**停止状態**になっただけで、**コンテナ自体は存在する**
必要に応じて、このコマンドを実行して開発を進めていく

##削除する

コマンドの停止ではなく、コマンドごと削除したい場合は
下記のコマンドを実行する

```
docker-compose down
```

削除しても、`docker-compose up`コマンドで
再度コンテナが作成、起動する

また`Ctrl+C`で止めると、Railsがどのプロセス番号で起動しているかを
記録しているファイル(**server.pid**)が残ってしまう。
次回起動時にエラーが出てしまう

エラー内容

```:ターミナル
A server is already running. Check /app/tmp/servier.pid
```

もしおこなったら、`tmp/pids/server.pid`を削除、再起動
再起動は**docker-compose up**でできる
→`Ctrl+C`で実行してみたが、問題なく**docker-compose up**できたので
一応、備忘録として参考記事から参照

##参考記事
https://www.udemy.com/course/rails-kj
https://qiita.com/gold-kou/items/44860fbda1a34a001fc1
https://qiita.com/azul915/items/5b7063cbc80192343fc0
DBからデータを取得して返り値にするときに詰まったこと

(備忘録なので簡単に。より詳しい情報は[ドキュメント](https://docs.sqlalchemy.org/en/13/)などを参照ください）

##execute()の返り値

・sqlalchemyでDBに接続して、excute()でクエリを発行したとき、
　返ってくるのは'sqlalchemy.engine.result.ResultProxy'クラスの
　オブジェクト

・つまり、DBから取得した値をintやstrなどで返すためにはひと工夫が必要

↓↓↓例えばこんな感じ↓↓↓

~~~py
    from sqlalchemy import create_engine
    # 余談だけど型アノテーションはちゃんとしよう。この関数宣言をまねしちゃダメだぞ
    def fetchUserIdFromDB(userName):
        # DB接続
        engine = create_engine('sqlite:///app.db')
        
        userId = []
        with engine.connect() as con:
            # クエリ発行
            rows = con.execute("select USER_ID from user_table where USER_NAME='{}'".format(userName))
            print(type(rows)) # -> <class 'sqlalchemy.engine.result.ResultProxy'>
            for row in rows:
                # 一行ずつ辞書化して・・・
                userDict = dict(row)

                # valueをint化して配列にpush!
                userId.push(int(userDict['USER_ID']))

        return userId
~~~
SSH接続の設定

CentOS7を想定しています。
TCP wrapperとPAMを使用して簡素に設定。

####①クライアント側からのアクセスをTCP wrapperで設定する
/etc/hosts.denyに追記 (接続禁止リスト)

```
sshd:all　#全て拒否
```
/etc/hosts.allowに追記 (接続許可リスト)

```
sshd:192.168.0.10(許可するIPアドレス)
```
アクセスを全て拒否し、必要なものだけを許可する。

####②サーバー側のssh接続させるユーザーの設定


/etc/pam.d/sshの7〜8行目あたりに追記して許可ファイルを有効にする。

```
account    required     pam_access.so
```
                         
/etc/security/access.conf (⬆️のpam_access.soで有効にしたファイル)の最終行に追記

```
-:ALL EXCEPT sshgrp:ALL  #sshgrp(グループ名)以外は禁止。ユーザー名も指定可。
```
root昇格を許可する場合は/etc/pam.d/suの６行目あたり

```
auth            required        pam_wheel.so use_uid  #(コメント)を外して有効にする
```
/etc/login.defsの最終行に追記。wheelグループのみroot昇格を許可。

```
SU_WHEEL_ONLY yes
```
/etc/ssh/sshd_configの９７行目あたりを確認。

```
UsePAM yes　#UsePAM no だと上記の設定が反映されない
```
設定を反映させるためにsshdを再起動

```
systemctl restart sshd.service
```
ユーザーに必要なグループを追加する

```
gpasswd -a ユーザー名 グループ名
```
rails+devise+devise_token_auth



```ruby:model/cuustomer.rb
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable,
         :omniauthable
  include DeviseTokenAuth::Concerns::User
  
  serialize :tokens

  after_create :send_confirmation_email, if: -> { !Rails.env.test? && Customer.devise_modules.include?(:confirmable) }
  private
    def send_confirmation_email
      self.send_confirmation_instructions
    end

end
```

##このserialize :tokensのおかげでPostmanでログインしようとしてもできませんでした。ありがとうございます。



```ruby:model/cuustomer.rb
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable,
         :omniauthable
  include DeviseTokenAuth::Concerns::User
  
  # serialize :tokens

  after_create :send_confirmation_email, if: -> { !Rails.env.test? && Customer.devise_modules.include?(:confirmable) }
  private
    def send_confirmation_email
      self.send_confirmation_instructions
    end

end
```


# devise_token_auth# パスワードを忘れた時
![スクリーンショット 2020-12-25 8.24.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239663/13181f7a-6457-a7af-e109-2784824d1749.png)

# devise_token_auth# ログイン
![スクリーンショット 2020-12-25 8.25.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239663/54e5cbef-8d37-e2f3-c4bf-c5b3f58eeff5.png)
簡易輪郭シェーダー

モデルに輪郭をつける場合、
もっぱらイメージベース＋深度で行いますが、
モバイルではイメージベースの処理や
深度バッファが使用できないことがまだまだあります。
そんなときは、昔ながらの拡大＆反転法線を使った
輪郭描画が便利です。

```oldStyleEdgeDetect.shader
Shader "Custom/oldStyleEdgeDetect" {
    Properties {
      _Color ("MainColor", Color) = (1,1,1,1)
      _Amount ("Edge Width", Range(1,2)) = 1.1
    }
    SubShader {
      Tags { "RenderType" = "Opaque" "Queue" = "Geometry-10"}
      Pass{
        Cull Front
        ZWrite Off
      }
      CGPROGRAM
      #pragma surface surf Lambert vertex:vert alpha

      struct Input {
          float4 screenPos;
      };
      
      float _Amount;
      float4 _Color;
      sampler2D _MainTex;
      
      void vert (inout appdata_full v) {
          v.vertex.xyz *= _Amount;
      }
      void surf (Input IN, inout SurfaceOutput o) {
          o.Emission = _Color.rgb;
          o.Alpha = _Color.a;
      }
      ENDCG
    } 
    Fallback "Unlit"
}
```
「それなりの輪郭」がまた懐かしい感じでいいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/dc6f8fb2-6e96-301c-31a6-f79f8f00e62d.png)
Mapbox-GL.js用に用意したglyphのpbfを活用出来ないか調べている話 Part2

メリークリスマスイブ
MIERUNEアドベントカレンダーの12月24日分の記事です
Part1はこちら
https://qiita.com/northprint/items/b5c48a02b9ae83a4d0a7
前回、うまくいかなかったので、引き続きチャレンジ中です

## 取得できたBitmapを表示してみる
色々調べていたのですが、どうやら1チャンネルのデータになっているようで、これを4チャンネルのデータに変換してあげる必要があることまでたどり着きまして、以下のような関数を用いることで画像の出力はできました
dataに、Part1で取得したbitmapを指定してあげます
（mapboxだとtestに書いてありました）
https://github.com/mapbox/mapbox-gl-js/blob/main/test/integration/lib/render.js#L192

``` javascript
function displayBitmap(width, height, data) {

  let pixel = width * height;

  // 4チャンネルのデータを生成
  const arrayData = new Uint8ClampedArray(pixel * 4);
  for (let i = 0; i < pixel; i++) {
    arrayData[4 * i + 3] = data[i];
  }

  // canvasに描画
  var canvas = document.getElementById('target');
  const ctx = canvas.getContext('2d');

  let imageData = new ImageData(arrayData, width, height);
  ctx.putImageData(imageData, 0, 0);

}
``` 
画像は出せたのですが、文字？とは言い難い、よくわからない画像が出力されます

と、ここまできて、全ての事が載っている記事を見つけました
https://observablehq.com/@jjhembd/mapbox-glyph-pbfs

こちらの記事を踏襲し、この記事を更新していきます
Ruby学習#8 Working With String

"を出力する場合、バックスラッシュ　\
  mac だと　Option　＋　￥マーク
#8 Working With String
puts "Giraffe\" Academy"
    # Giraffe" Academy

phrase = "Giraffe Academy"
puts phrase
  #Giraffe Academy  
puts.upcase()
   #GIRAFFE ACADEMY
puts.downcase()
   #giraffe academy
phrase = "    Giraffe Academy    "
puts phrase.strip()
   #Giraffe Academy
   #スペースとれる
puts.phrase.length()
  #15
puts phrase.include? "Academy"
  #true
puts phrase.include? "Academys"
  #false
puts phrase[0]
  #G
puts phrase[3]
  #a
puts phrase[0,3]
  #Gir
puts phrase.index(G)
  #0
puts phrase.index(ffe)
  #4
puts "programming".upcase()
  #PROGRAMMING
OCamlでオーバーロード！？


# OCaml でオーバーロード

前回の記事 ([HListをOCamlで: 型クラス無しで作る異種混合リスト (heterogeneous list)](https://qiita.com/keigoi/items/4fe2c511a09d2fcfac77)) の続き．

なんと次のコードが合法である：

```ocaml
open HList
open Stdlib

let x = List.nth [1;2;3] 1
(* val x : int = 2 *)

let y = HList.nth [1;"a";false;0.1] _1
(* val y : string = "a" *)
```

一見して違和感があるのは，後者は**型エラー**になるようにも見えることだ． つまり，上で `open Stdlib` で `list` 型のリストがスコープに入っているので，[1;"a"] のようなリストは型がつかないのではなかろうか？

これがなぜ合法かといえば，後者の `[1;"a";false;0.1]`　は型 `_ HList.t` と推論されるため，もっといえば `open HList` したあとに `1 :: "a" :: false :: 0.1 :: []` と書いたのと同じ効果を持っているためだ．
つまり，リストのコンストラクタ `::` と `[]` が，状況によって**異なるコンストラクタ**として解釈されている．

なぜそのような恣意的な選択が可能なのか？そのからくりは `HList.nth` が書かれていることである．このため，型推論の過程で，`HList.nth` の引数は `_ HList.t` でしかありえないと推論される．そこで，直前に `open` していた HList のほうの `::` と `[]` が選ばれた，というわけだ．

私の理解では，このような **コンストラクタのオーバーロード** はレコードの使い方に端を発する．

レコードのフィールド名は重複することが多い．空間の一点を表すのに x, y, z, ... のような名前を使いたかったり　(`{x:float; y:float}` と `{x:float; y:float; z:float}` )，様々なレコードで name とか id とかいう名前のフィールドを共用したいと思うことは頻繁にある．しかしだいぶ古い時代の OCaml ではそういうことはできなかった．

OCamlのどこかのバージョンでレコードのフィールド名のオーバーロードが型推論ベースで解決されるようになった．

つまり，重複するフィールドラベルをもつ型を `open` 等でスコープに入れておけば，レコードの構築 `{f1=e1;..;fn=en}` においては，その式を 囲む文脈から生成される型が決まり，フィールド参照 `e.fi` においては，式 `e` の型からどの `fi` が参照されるかが決まる．

これと同様に，スコープ内で衝突する同名のコンストラクタを持つヴァリアント型についても，型推論の結果を用いて型が選ばれるオーバーロードができるようになっていたわけだ．

# 以下雑多な内容

上も含め，知っている人にとっては当たり前なのだが，ざっと知っている限りの状況を書き出してみる．

# プログラミング言語におけるオーバーロード

このように同じ記法や名前を異なる型において何度も使うことをオーバーロードという．
関数や演算子のオーバーロードはプログラミング言語において普遍的な機能で，思いつく範囲でも以下のものを並べることができる：

* 古くは **C言語**の算術演算子は各種数値型についてオーバーロードされている．おかげで OCaml のように `1.0 +. 2.0` のように型によって異なる演算子を使う必要がない．
* **C++** の関数/演算子オーバーロード．テンプレートと組み合わせれば呼び出し先を型の構造に従って選択できる．
* **Java** のメソッドオーバーロード．単に同じ名前を異なる関数につけられるだけだが例えば System.out.println など使う部分がなくはない．（当時、C++の演算子オーバーロードは邪悪だと思われていたためか Java には入らなかったが、データサイエンス全盛の今となってはちょっとしたハンデのような気がする．）

関数型言語のグループにも次のものがある．

* **Haskell** の型クラス．静的型付き関数型言語の**型推論**との相乗効果でプログラムの**書きやすさ**が飛躍的に増大する．
* **Scala** の implicits．型クラスのインスタンスのスコープを制限できる．
* 他の言語の事情はそこまでよく知らない．**Standard ML** では `=` を使える型の上を動く型変数を `''a` のように特別視するようだ．(数値型に限ってはオーバーロードがあるんだっけ？)


## OCamlにおけるオーバーロードの未来

上でも少し触れたように **OCaml** にはオーバーロードが**まだ**ない (Standard ML でもユーザー定義オーバーロードはできなかったような)． これは非常に残念なことで，例えば OCaml で数値計算を書いたりモナドを使ううえでの足枷にもなっている．
一応，オーバーロードを使うには次のような道がある：

* **Modular implicits**． ML Family Workshop 2014 で[提案された (arXiv)](https://arxiv.org/abs/1512.01895)．Scala の implicits にインスパイアされた機能で，モジュールを介して実現できる．が，最近なかなか動きが見えない．OCaml コミュニティでは Multicore OCaml の update は頻繁にやってくるので，今後に期待したいところだが…
* **ppx_implicits**． 古瀬淳さん aka camlspotter が開発した，プリプロセッサで型推論の結果を利用して型クラス辞書を挿入する超スゴイ実装だが，今は公開されていないのかググると fork が最初にヒットする．

OCamlカルチャーとしては、[ppx_deriving](https://github.com/ocaml-ppx/ppx_deriving) などで自動生成したコードを型名のサフィクスを付けて使うようになっている(らしい)．
大学に行った途端にオンライン授業になったので、囲碁サービスを突貫工事した話。

この記事は[N高等学校 (2) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/n-highschool-2)の後出しじゃんけん24日目です。

N高を去年卒業(2期生)して、東京理科大学の理工学部 数学科に今年入学した[@kakudo415](https://twitter.com/kakudo415)と申します。
8年の不登校期間を超えて、ついに大学でのリアル授業だと意気揚々としていたらパンデミックの影響でほぼ全ての授業がオンラインになってしまいました。その中で生まれた不便を解消し**かけた**話を書きます。

# なぜ作るか

理科大の人気授業(多分)に「囲碁で養うコミュニケーション力」があります。
本来は教室に行って実際に対局をするのでしょうが、このご時世でそうもいかなくなってしまいました。
少なくとも僕が受講した前期においては、全てZoomと画面共有した棋譜ソフトによって授業が行われていて、ブレークアウトルームに分かれた学生同士が口頭で打ちたい手を相手に伝えると言った状況でした。

# 作る

世の中には既にいくつもの素晴らしい対局サイトがあります。にもかかわらず、あえて不便な方法を取っているということは大学という組織で利用することの面倒さ(手続きとか)などがあるのだろうと思いました。ならば、学生が作ったサービスなら使ってもらえるだろうと思ったわけです。

## 何で作るか

僕のスキル的にWebアプリ一択でした。2021年はネイティブアプリにも手を出したいものです。
GoでいくつかしょうもないWebサービスを作ったことがあったので、自信満々で作り始めました。

## サービスの概要

学生同士がただ対局できればそれで良いので、それ以外の機能をなるべく省きました。
具体的には、個々の対局にIDが振られていて、対局作成時に自動生成されるパスワードを入力することで対局に参加できるようにしました。パスワード無しに対局にアクセスした場合は石を置くなどの操作ができないようにして、観戦ができるようにしました。
対局はWebSocketを使って実装しました。囲碁のようなボードゲームでWebSocketを使うのは過剰だと思いますが、サーバー側からクライアント側への通信を簡単に行いたかったので使うことにしました。

## 実装

以下のような順に作っていきました。全てが整わないと動かないようにするのではなく、それぞれの段階である程度の動作が確認できるようにしました。

1. 簡単なフロントエンドUI
2. 対局作成UIとハリボテAPI
3. 石を置くなどのフロントエンド(通信なし)
4. フロントエンドからの通信を受け取れるように、ハリボテAPIを本実装
5. バグ潰し + リファクタリング

[https://github.com/kakudo415/online-igo](https://github.com/kakudo415/online-igo)
(現在進行形で動いているサービスのコードを公開するのは少し気が引けますね。セキュリティ上マズいことなどあれば教えてください)

# できた

[Online 囲碁](https://igo.kakudo.app/)

# しかし

担当の教授の先生にメールをお送りしたところ、授業の中でサービスを発表する機会を頂きました。
残念ながら、不便さが生むコミュニケーションもあるらしく授業での採用は見送りとなってしまいました・・。(先生が付けた注文の全てに応えられなかったというのも大いにあると思います。)

ニーズがあるか事前に把握しようというのが教訓ですね。(とはいえ提案するには動くプロトタイプが必要というジレンマ)

# 終わりに

2枚目のAdvent Calendarが埋まってないので、卒業生のみんなでがんばって埋めましょう！！！
明日(今日)は[K4133](https://qiita.com/K4133)さんの「僕自身今年一年プログラミングをやってみた学び、振り返りをします。」です！お楽しみに！

[N高等学校 (1) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/n-highschool)
[N高等学校 (2) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/n-highschool-2)
GoogleFormをチョット理解してガワだけオリジナルフォームにする

#ガワだけオリジナルフォーム？？
画面だけを自分の好きなデザインのフォームにしたいけどGoogleFormみたいな機能使いたいという時に使うちょっとした小技です。

#下準備
適当にGoogleFormを作ります
適当に入力形式の項目などを追加します
適当に解答集計用のスプレッドシートを作っておきます
適当なところから叩けるようにログインが必要のない設定にしておきます


#Chrome Developer Tool
GoogleFormを開いたまま、ChromeのDeveloperToolを開きます
※option + command + i (Macの方は)


#テキストフィールドに割り当てられたフィールド名を確認する
![スクリーンショット 2020-12-25 6.00.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84002/e2455b87-bc73-4790-154c-db01210c447f.png)


#実はこっちの方が楽説・・・・
昔こんなのあったけ？みたいな気持ちですが、もっと楽な方法がありました。
この左上にあるメニューをクリックすると、
「事前に入力したURLを取得」というのがあるのです。

![スクリーンショット 2020-12-25 6.02.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84002/dd2cabcd-8d79-6585-b5c5-311b99b46071.png)

回答入力し左下にある、「リンクを取得」をクリック
すると、フォーム左下に大きくリンクをコピーできる場所が出現します。

![スクリーンショット 2020-12-25 6.03.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84002/70b83368-0806-9202-8cd1-82e25fccf7f1.png)

#メモかなんかにコピペすると・・・？

```
https://docs.google.com/forms/d/e/1FAIpQLSehA2MP3C87InvPlNcSGH2I00Bs3BSHDH53Sd0pI4sNVv3w0A/viewform?usp=pp_url&entry.829023143=%E3%82%82%E3%81%AE%E3%82%82%E3%81%AA%E3%81%84&entry.76589297=+(%CB%98%CF%89%CB%98)%EF%BD%BD%EF%BE%94%EF%BD%A7
```
いい感じにidがついたままのURLを取得できます。

#とりあえずテストとしてcurlにしてみる

```
curl https://docs.google.com/forms/d/{You are Google Form ID}/formResponse --data-urlencode ifq --data-urlencode entry.829023143=ものもない  --data-urlencode entry.76589297=5000兆円欲しい -d submit=Submit
```

#結果を確認してみる

![スクリーンショット 2020-12-25 6.05.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84002/ebef5701-8656-f784-0d07-7671e35b5445.png)


#どうやってモバイルアプリに活かすのか？
1. 適当にテキストが打てるレイアウトを作ります
2. Androidなら`EditText`・iOSなら`textField.text`などで入力された文字を適切に取得します
3. 取得した文字を、Post時のパラメータとして突っ込みます。
4. 最後にライブラリでも標準のやつでもなんでもいいのでPOSTします。
5. 終わりです。


#iOSなら

```swift

let parameters = [
    "entry.829023143": "勝ち取りたい",
    "entry.76589297" : "５０００兆円欲しい",
    "submit"         : "Submit"
    ]

AF.request("https://docs.google.com/forms/d/{You are Google Form ID}/formResponse", method: .post, parameters: parameters)
```

#Androidなら

```kotlin

 val client:OkHttpClient = OkHttpClient()
            val url:String = "https://docs.google.com/forms/d/{You are Google Form ID}/formResponse"
            val body:FormBody = FormBody.Builder()
                  .add("entry.829023143", textfield1)　/// "勝ち取りたい"
                  .add("entry.76589297", textfield2)  /// "5０００兆円欲しい"
                  .add("submit", Submit)
                  .build()
            val request = Request.Builder().url(url).post(body).build()
            
            client.newCall(request).enqueue(.......


```
最近、微妙にOldな感じになりかけたりしてるので、誤っている可能性もあります。。。
UnityでEZ DO DANCEする(お手軽マイリアルアバター召喚：概要編)

# はじめに
この記事は[KDDI Engineer Advent Calendar 2020](https://qiita.com/advent-calendar/2020/kddi_engineer)の最終日の記事です。
最終日なので何か万人に役立つ素晴らしい記事を！と意気込んでみたものの、そんなネタを持っていなかったので、ゆるい感じでお届けしたいと思います。

今年はいろいろあって、3Dスキャナー使って様々な人のリアルな3Dアバターを作成しまくりました。また、アバターにお手軽に動きを追加して、Unityで動かす方法を学んで、ARアプリを作りました。
チームの同僚や先輩から頂いた`アバタースキャンエンジニア`という称号に恥じないよう、ARアプリ開発で得たおもしろノウハウを記事にしていこうと思います。

この記事では、3Dスキャンからのアバター作成、 `EZ` にアバターに対してボーンとモーションの追加・設定し、Unityに取り込んで `DO DANCE` するまでの概要と開発環境・利用した3Dスキャナーを紹介していきます。

# 作ったもの
![ez-do-dance-qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536303/4e3c2593-c299-e701-b80a-4c8844488917.gif)
この記事用にQiitaのキャプチャ画像を背景にして3DアバターがUnity内で`DANCE`するだけのシンプルなサンプルを作りました。

# おおまかな作業の流れ
- iPad+Structure Sensorで全身を3Dスキャン
- itSeez3Dでクラウドで3Dモデルを書き出し・ダウンロード
- 3DモデルをBlenderで読み込み・整形・ファイル形式変換
- Mixamoで3Dモデルにボーンとアニメーションをつける
- Unityに3Dモデルを読み込み
- UnityでAnimator、Prefabを設定
- UnityでEZ DO DANCEしてみる

# 開発環境
普段利用しているMac Book Proに外付けGPUを接続して利用しています。
![スクリーンショット 2020-12-25 午前5.28.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536303/0f8a7fa6-324e-ec8a-e9bb-9c93e242e3c1.png)
(https://www.apple.com/jp/shop/product/HM8Y2J/A/blackmagic-egpu より画像を引用)


- Mac Book Pro 13(Catalina 10.15.5) +  [Blackmagic eGPU](https://www.apple.com/jp/shop/product/HM8Y2J/A/blackmagic-egpu)
- Unity(2018.4.12f1)
- Blender(2.82)

# 3Dスキャナー構成
- iPad Pro 11 + [Structure Sensor mark Ⅱ](https://structure.io/structure-sensor/mark-ii)
    - iPadに外付けの赤外線デプスカメラを接続して利用しています。
- itSeez3D
    - スキャン用のアプリです。

![スクリーンショット 2020-12-25 午前5.39.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536303/902f6c5a-47db-02eb-e5ae-d99c2db65135.png)
(https://store.structure.io/buy/structure-sensor-mark-ii より画像を引用)

        

# 利用したサービス
- [Mixamo](https://www.mixamo.com/) 
    - 3Dモデルに簡単にボーンを設定し、モーションを付けることができるAdobeの無料サービスです。
    - 2020/12現在ではこのサービスを通して作成したモデルの[商用利用も可能](https://helpx.adobe.com/jp/creative-cloud/faq/mixamo-faq.html)ということになっています。

![スクリーンショット 2020-12-25 午前5.43.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536303/e8609e59-afe0-be80-5890-784cb3c4c1e0.png)


# まとめ
全体では結構なボリュームになりそうなので、まず今回は作ったもの、大まかな作業の流れ、使用したツールやデバイスを概要編として紹介しました。
そこからUnityで`EZ`に`DO DANCE`するまでの全体像をざっくりイメージいただければ幸いです。
今後、シリーズものとして各作業工程の詳細な内容をコツコツと記事化していく予定です！
Expo webで環境ごとに設定を切り替える

本番、ステージング、開発環境などで設定を切り替えたいシーンは多くあると思います。
Expoでアプリを作るときは`release-channel`を使っていたのですが、Webのときはどうすればいいのかな？と思い調べてみました。

Expo、特にExpo webを使ったときに、以下のようにして設定を切り替えました。

# app.config.jsを使う

Expoの設定周りは通常`app.json`を使うと思います。
実はそれを`app.config.js`というファイルでさらに拡張できます。

`app.config.js`はJSのファイルなので、内部で環境変数`process.env`を使えるのが特徴です。

https://docs.expo.io/workflow/configuration/#dynamic-configuration-with-appconfigjs

今回はこれを利用します。

# 実装

ルートディレクトリに`app.config.js`を作ります。
環境変数`process.env.MY_CUSTOM_ENV`によって、本番/開発の`apiKey`を切り替えています。

```js:app.config.js

export default ({ config }) => {
  const apiKey =
    process.env.MY_CUSTOM_ENV === "production"
      ? "prod-api-key-xxxxxx"
      : "dev-api-key-oooooo";

  return {
    ...config,
    extra: {
      apiKey,
    },
  };
};
```

使う側の例です。
`Constants.manifest.extra.apiKey`で取得できます。

```js
import Constants from "expo-constants";

console.log(Constants.manifest.extra.apiKey);
```

# 切り替えの方法

例えばwebビルドの場合、以下のように環境変数を指定してexpoコマンドを叩くことで、先程の`app.config.js`の切り替えが有効になります。

```bash

# production用のAPI KEYを使うとき
MY_CUSTOM_ENV=production expo build:web

# 何も指定しなければdev用
expo build:web
```

同様に各種expoコマンドで切り替えが使えます。

```bash
# 開発サーバー起動
MY_CUSTOM_ENV=production expo start

# iosのリリースビルド
MY_CUSTOM_ENV=production expo build:ios
```


# 補足: release-channel

アプリの環境切り替えはrelease-channelを使うときが多いと思います。

例えば `expo publish --release-channel production` で本番にpublishするなど。

release-channelによる切り替えも考慮して、以下のようにしておくとより便利かもしれません。

```js:app.config.js

export default ({ config }) => {
  const apiKey =
    process.env.MY_CUSTOM_ENV === "production"
    || Constants.manifest.releaseChannel === "production"
      ? "prod-api-key-xxxxxx"
      : "dev-api-key-oooooo";

  return {
    ...config,
    extra: {
      apiKey,
    },
  };
};
```
Lightningにメニュー項目を追加(function.php/header.php)

#wordpressの無料テーマLightining
管理画面で設定できるメニュー箇所を追加する方法をご紹介

完成系は
有料版にあるヘッダー右上のヘッダーサブメニューを無料版Lightningに追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/01e90c14-9686-813c-7e59-a4bf44f01b42.png)

ダッシュボードにも、ちゃんとメニューバーの設定項目が出力されます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/1e3ebeab-3ecf-ef92-4da7-011b25163c1f.png)


#functino.phpに追記
以下を追記
・header_sub :　任意の文字列
・ヘッダーサブメニュー : 外観＞メニューで表示される任意の文字列

```php

register_nav_menus(array(
		'header_sub' => 'ヘッダーサブメニュー'
	)
);
```

多言語化しているサイトなので、英語と2種類出力されていますが、ヘッダーサブメニューが追加されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/9e9abba1-27ba-dcb5-e0da-d793cedbaec2.png)

#出力場所の指定
管理画面で設定が出来るようになったので、今度は設定したメニューを出力させる設定が必要です。

cromeのディベロッパーツールで解析した所、以下の赤線の箇所に入れたいので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/010b3564-83ff-637e-80e7-bdfdc7241f8f.png)

header.phpファイルを編集します。
(子テーマを作成して編集をしてください)

1.44行目と45行目の間に45行目～55行目をコピーして貼り付けます。
その際に
gMenu ⇒ sMenu
と名前を変えます。
'theme_location' => 'Header',　⇒　'theme_location' => 'header_sub',
先ほどfunctionで設定したIDに変えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/cd8a4a1e-11e3-8d54-72a4-b5051fbe3eb3.png)

２．53行目に54行目～60行目をコピーして追記します。
その際に
gMenu　⇒　sMenu
と変更を忘れないように

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/5c90d81e-4682-9e26-0849-a2ec91206cfc.png)

#Lightningのヘッダー上にメニューを追加
通常のメニューバーの上にメニューバーを増やす事が出来ました。
【お問い合わせフォーム、お申し込みフォーム、ご利用について】
この3つのメニューの箇所です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/01e90c14-9686-813c-7e59-a4bf44f01b42.png)

管理画面からメニューバーの項目が変えられるので、メンテナンス性に優れています。
header.phpファイルにメニュー項目を直接htmlで入力するのではなく、制作を受注している人などは是非、ひと手間かけて欲しいですね！
DockerのLXDEデスクトップ環境で再ログイン時にファイルマネージャが起動しない件



サイト( https://qiita.com/FukuharaYohei/items/a6c1e1a2ba8d1285cfa5 )
を参照して、EC2上のdocker上に、LXDEのデスクトップ環境を作成した。
１度ログアウトして再度ログオンすると、スタートメニューのデフォルトのファイルマネージャPCManFMが起動しない問題発生。

![lxdedesktop1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/979266/b57b0c45-34d6-38a2-4fd4-2ccd3a1120e6.jpeg)

色々調べてみたが、~/.cache/pcmanfm-socket-nnというキャッシュ的なファイルがあり、それを削除すると再ログイン時にも起動できることがわかった。ただ、ログアウト時やログイン時にそのファイルを削除したいが、いまいち良い方法がわからない状況。

一旦pcmanFMの対応は保留し、別のファイルマネージャである、nautilusをinstallして、スタートメニューにpcmanFMに代えて設定。

![neutlius1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/979266/18fe93e3-1d38-1de0-3a69-885d123c7937.jpeg)


再ログイン時にも起動することは確認できた。
Red Hat OpenShift on IBM Cloud on VPCで3台以上のノード構成時にロードバランサーのヘルスチェックに失敗するノードがある場合がある件への対応

# 事象

※2020年12月25日時点、OpenShift 4.5で確認しています

Red Hat OpenShift on IBM Cloud on VPCでクラスターを3台以上のノードで構成した際、デフォルトルーターのロードバランサーでヘルスチェックに失敗するノードがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/3213c9b4-271f-8c3c-6afc-c05170e328b1.png)

# 原因

ルーターのPodはレプリカ数2でデプロイされており、これが2つのノードに分散しています。つまり3台以上のノードがある場合は、Podがデプロイされないものが出てきます。

```
$ oc get pods -n openshift-ingress -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP             NODE
router-default-cf87dd6d-6s8xf   1/1     Running   0          2d19h   172.17.58.4    10.244.0.17
router-default-cf87dd6d-d2b7k   1/1     Running   0          2d19h   172.17.42.94   10.244.64.9
```

サービスのexternalTrafficPolicyを見てみます。

```
$ oc get svc router-default -n openshift-ingress -o yaml | grep " external"
  externalTrafficPolicy: Local
```

ここがLocalであることが原因です。このとき、ノードに到達したリクエストを転送するPodが同一ノードにないため、応答を返すことができません。

ちなみに該当ノードに直接リクエストを飛ばしてみると、次の挙動となりました。

```
$ curl 10.244.128.5:32727 &
[1] 4648
$ netstat -ano | grep 10.244.128.5:32727
tcp        0      0 10.244.10.7:49460       10.244.128.5:32727      ESTABLISHED keepalive (51.96/0/0)
$ kill %1
```

ソケットがESTABLISHEDかつkeepalivedになっているのがいまいちですね。これが何を意味するかというと、クライアント側またはサーバ側で明示的に通信を切断してくれないと、永遠に接続し続けてしまいます。

# 影響

結論からすると実影響はありません。該当ノードはヘルスチェックに失敗したことでロードバランサーから切り離されていますので、ユーザーからのリクエストが該当ノードに直接到達することはないからです。

影響があるとすれば、該当ノードのNodePortに直接接続したいケースですが、実運用でそのような構成をとることはないでしょう。何かしらのロードバランサーを経由するはずなので。

# 対応

実影響はありませんが、気持ち悪いので対応したい場合は、サービスのexternalTrafficPolicyをLocalではなくClusterに変更します。

```
$ oc patch svc router-default -n openshift-ingress -p '{"spec":{"externalTrafficPolicy":"Cluster"}}'
service/router-default patched
$ oc get svc router-default -n openshift-ingress -o yaml | grep " external"
  externalTrafficPolicy: Cluster
```

少し待つとロードバランサーのプールがヘルシーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/e61dd1f2-f3c9-fae7-6497-c82a5675b254.png)

ノードへの直接接続もできるようになります。

```
$ curl 10.244.128.5:32727
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
```

ただし、これによって通信の挙動が変わってしまうことは理解しておく必要があります。Localの場合、ロードバランサーから割り振られたノードへの通信はそのノード上のルーターPodが処理することになります。Clusterの場合、通信が割り振られたノードとは異なるノード上のルーターPodが処理をする場合があります。そのため、通信的にはわずかな遅延が発生することになります。

また、手動でサービスのマニフェストを変更していますが、OpenShiftの更新の際に戻ってしまう可能性もあります。しばらく様子を見たいと思います。
Notionで継続的なKPTを行う

アルプ株式会社でエンジニアをしています、集約のエンティティ@pictinyです。
これは[Notion Advent Calendar 2020](https://qiita.com/advent-calendar/2020/notion) 24日目のエントリです。
23日目は[Notionでガントチャートを作る](https://qiita.com/pictiny/items/b6a45b5d689a6fd013e2)でした。

# 継続的なKPT
KPTを継続的に行いたいことがあります。
2回目以降のKPTをNotionの[KPTボード](https://qiita.com/pictiny/items/d2a3774d6eeadcb2c2e5)で実施することを考えてみます。

## データベースのコピー
Notionのデータベースは、中のデータごと複製することができます。
左メニューのページタイトル横からメニューを開き、 `Duplicate` を選択するとデータベースがコピーされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/fe90c002-27b6-abc5-0120-e31ad295aa38.png)

Statusプロパティに `前回のTry` を追加し、前回のKPTの `Try` からカードを移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/bb7127cb-9c20-372f-4c47-3a40be04fb38.png)

`Keep` と `Problem` のカードは、KPTボードを作り直すたびに削除します。
これで前回のKPTの結果を引き継ぎながら、新しいKPTが行えるようになります。

# まとめ
KPTボードを継続的に運用する方法を紹介しました。
前回のTryを振り返ることで、継続的に改善していきましょう！
pChart を PHP7 対応させる方法

#概略
pChart を、PHP7 で動かすとエラーが出て正常に動いてくれません。これの暫定的な対応策です。とりあえず動いてくれればいいや、という状況向け。

#詳細

こんな感じのエラーが出ます。

```php
Fatal error: Uncaught Error: Cannot use string offset as an array "pchart"
```

エラーの原因としては、変数を後から配列扱いすると PHP7 でエラーが出るようになったのが原因なので、pChart.class と pData.class を何箇所か修正すると正常に動くようになります。

```php
$this->Data = "";
$this->DataDescription = "";
```

↓　以下のように初期化宣言を直す。

```php
$this->Data = array();
$this->DataDescription = array();
```

以上。
Ruby on Rails概要(初心者まとめ)

#はじめに
プログラミングを初めて２ヶ月の駆け出しエンジニアが文字通り初心者目線で、かつ初心者でもできるだけ分かりやすいようにRuby on Railsについてまとめてみました。
間違いなどありましたらご指摘いただけると幸いです。
#Ruby on Railsとは
Rubyを元に作られたアプリケーションフレームワークです。
そもそもフレームワークとは簡単に言い換えると「枠組み」や「骨組み」「雛形」のことで、アプリを作る際に必要となる基本的なものがあらかじめ準備してくれているものになります。
ゼロから開発する必要がないため、開発にかかるコストを減らしてくれるとても便利なものです。
##Rails Way
Railsはフレームワークというある種固定的なレールに柔軟で自由なRubyを使い、「フレームワークの良いところ」と「自由に自分のコードを書けること」を両立させたものと言えるでしょう。
これを踏まえてRailsらしく考えRailsらしいコードを書くことが大事になってきます。
そうすることで綺麗な読みやすいコードになっていき自ずと生産性も上がっていくはずです。

##Railsの哲学
上記でも触れたRailsらしいコードにあたる共通理念のようなもので、代表的なものを二つ紹介します。

__DRY (Don't Repeat Yourself)__
繰り返しや重複はコードとして美しくない

__設定より規約__
従来のフレームワークのように大量に設定を記述するのでは無く、規約に乗っ取とることでシンプルなコードにする。
##MVCとは
Railsについて簡単に説明したところで、最後にMVCについて解説します。
MVCとはソフトウェアをどのような構造にするかの考え方のパターンの一つです。
さまざまな処理によって構成されるアプリケーションの中でも、UI(ユーザーインターフェース)の部分は性質が異なるため、一緒くたにして記述するとコードが複雑になってしまいます。そのため『__UIに関わる部分(view)__』と『__アプリケーション固有の処理やデータの扱いを(model)__』、『__この二つの橋渡し的な立ち振る舞いをする(controller)__』の三つの役割に分けて管理しやすくしたのがMVC(__Model__ __View__ __Controller__)というわけです。

橋渡し役であるコントローラの中にはルーティングがあります。これはブラウザから受け取ったURLやHTTPリクエストを元に、__どのコントローラ(クラス)の、どのアクション(メソッド)が処理を担当するのかを決めるところ__です。
図にすると次のようになります。
![スクリーンショット 2020-12-25 2.36.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871987/ed7cdeac-7d4f-7939-8e08-0d0e373421f7.png)

それぞれの番号に対応する処理を説明します。
①ブラウザ(クライアント)からのリクエストがwebサーバを介して受け渡されます。
②ルーティング機能が受け取ったURLなどを元に処理するべきコントローラとアクションを特定しアクションを呼び出します。
③アクションでは必要に応じてモデルを利用します。(データベースからデータを取得するなど)
④必要に応じてモデルはデータベースへ書き込みや呼び出しなども行います。
⑤アクションごとに対応するviewテンプレートを用いてHTMLを作成します。
⑥コントローラがレスポンスを作成し、ブラウザに返します。

RailsにおいてこのMVCはとても大切な概念なのでしっかりと理解しておきましょう。
##参考図書
現場で使えるRubyonRails5速習実践ガイド5.2対応
【Raspberry Pi Zero W】FFmpegでハードウェアエンコーダーを使う＋動体検知カメラを動かす

#概要
Raspberry Pi Zero WでOSがbusterという組み合わせでの参考サイトが見つからなかったので覚え書きとして記録
明確な記載は見つからなかったが最新のFFmpegはRaspberryPiのハードウェアエンコーダに対応済み？
motionからFFmpegに渡す際、```h264_omx```を指定してもエラーが起きず。今後調査。

#作業環境
* ボード：Raspberry Pi Zero W
* OS：Raspberry Pi OS Lite v5.4(buster 2020-8-20)
* ストレージ：32GB
* カメラ：Raspberry Pi Camera Module V1.3

#参考サイト
https://ki-chi.jp/?p=769
http://akahana-1.hatenablog.jp/entry/2017/10/29/132822
https://www.kaoriya.net/blog/2017/10/07/
https://hombre-nuevo.com/microcomputer/raspberrypi/raspberrypi0030/

#Raspbianのインストール、初期設定
※詳細は省略

1. Raspberry Pi Imagerを使用してSDカードにOSを書き込み
2. Raspberry Pi Zero WにSDカードを挿入して起動
3. 初期設定
4. SSHの有効化
5. Windows PCからSSH接続
6. sudo apt update & sudo apt upgrade

#カメラの有効化
raspi-configで設定

```terminal
$ sudo raspi-config
～　別画面が開く　～
3.Interface Options -> P1.Camera -> yes
```

#FFmpegのインストール

```terminal
$ sudo apt install ffmpeg
～　省略　～
$ ffmpeg -encoders 2> /dev/null | grep omx
 V..... h264_omx             OpenMAX IL H.264 video encoder (codec h264)
```

#motionのインストール

```terminal
$ sudo apt install motion
```

#motionの設定
###録画条件等の設定
録画ファイルの保存先ディレクトリのパーミッションは適宜変更
今回はテストのため制限なしとする

```terminal
$ mkdir motion
$ chmod -R 777 motion
$ sudo nano /etc/motion/motion.conf
```

今回は以下の内容で設定

```
daemon on  # サービスとして実行
norm 1     # NTSC
width 640  # 記録する映像の幅
height 480  # 記録する映像の高さ
framerate 30  # フレームレート(性能が足りなければこれより低くなる)
threshold 1500  # 動体検知の閾値。変化のあったピクセル数。適宜調整しつつ運用。

ffmpeg_video_codec mp4 # mp4で出力

use_extpipe on  # 記録した動画を外部プログラムに渡す
extpipe ffmpeg -y -f rawvideo -pix_fmt yuv420p -video_size %wx%h -framerate %fps -i pipe:0 -vcodec h264_omx -preset ultrafast -f mp4 %f.mp4  #FFmpegにrawvideoを投げつけてh264_omxでエンコード。

locate_motion_mode on  # 認識した動体の位置を示す。デフォルトでは長方形で図示。

target_dir /home/pi/motion  # 保存先ディレクトリ

stream_maxrate 30  # ストリーミングで滑らかに動くため(性能が足りなければこれより低くなる)
stream_localhost off  # localhost以外からでもストリーミングにアクセスできるようにする
stream_auth_method 1  # ストリーミングにBasic認証をかける
stream_authentication username:password  # 認証時のIDとPass
```

###motionの動作テスト

```terminal
$ sudo motion -n
[10995336:motion] [NTC] [ALL] conf_load: Processing thread 0 - config file /etc/motion/motion.conf
[10995336:motion] [NTC] [ALL] motion_startup: Motion 4.1.1 Started
[10995336:motion] [NTC] [ALL] create_path: creating directory /var/log/motion
[10995336:motion] [NTC] [ALL] motion_startup: Logging to file (/var/log/motion/motion.log)
～　以下省略　～
```

ブラウザで```http://[RaspberryPiのIPアドレス or ホスト名]:8081```　にアクセス、
事前に設定した ```username``` ```password``` を入力するとカメラの映像が表示される。
ターミナルでCtrl+Cを押すと終了。

###動作確認
今回の環境では4fps前後しか出なかった。
ググった結果、近い環境で画質とフレームレートが高い状態で撮影している事例が見つかったため、
設定の追い込みが足りないと思われる。引き続き調査。
個人用Googleアカウントを作成する

超初心者向けのGoogleアカウント作成手順です。

## 必要なもの
- ChromeやFireFox、IEなどのブラウザでインターネットに接続できるパソコン（Windows/Mac/ChromeBookなどブラウザが開けるならどのOSでも同じ手順でできるはず）
- （任意）電話番号
- （任意）受信可能なメールアドレス

## アカウント登録手順

[Googleアカウントログインページ](https://accounts.google.com/signup/v2/webcreateaccount)にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/1c26f4b3-4b28-d5d4-4e1c-7ed62685c3fd.png)

左下の[**アカウントを作成**]をクリックし、表示されるプルダウンの項目から[**自分用**]をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/343002d0-b15b-0fd9-cc17-126e96808e98.png)

名前とメールアドレスにするユーザー名とパスワードを入力し[**次へ**]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/7c6b1d5e-dc66-57a7-0bdd-6aff13891a10.png)

必要項目を入力して[**次へ**]をクリックします。画像では電話番号やメールアドレスは入力していませんが、セキュリティを高めるためには入力することをおススメします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/2b95e1d6-70ae-3828-bf74-005080c16212.png)

利用規約を確認し[**同意する**]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/23c28d30-9b1a-cb97-f886-732adf4df13e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/044fb215-6e67-3aea-7f87-934c105d28ed.png)

なんとこれだけで完成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/22573f51-4e6b-9d79-3914-aa423b0f0d0e.png)

こんだけのサービスが使えるのすごいよね？色々いじって使ってみなきゃ損でしょ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/071c2b22-2a83-a11f-545c-644c7facabfb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/2a648668-c663-fc5c-d20d-81223bb906f1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178016/83fb3bcc-56f2-fe74-2234-a79b88357afa.png)
Blenderのカメラのスクリプトの試作2種

ADVENTARのBlender Advent Calendar 2020の23日の記事として登録します
https://adventar.org/calendars/5212

チャットで漫画の下絵に使うためのカメラ操作をする機能が欲しいって話題があったので
ちょっと機能を試作してみました。　どちらも試作で機能としてはメモ書きに近い程度です

# 目的の位置が中心になるようにカメラをシフトする
カメラシフト（カメラビューのままで平行移動したように表示を変更する機能）の数値を
より簡単にするためにするためのスクリプトです

カメラビューで見た３Dカーソル位置が中心になるようにシフトの数値を設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/24cfef63-63b1-9a6d-9487-d4e0c4b95273.png)

```py:CameraShift/py
import bpy
import math
from mathutils import Vector, Matrix

scene = bpy.context.scene
camera = scene.camera
camera_data = camera.data

matrix = camera.matrix_world
camera_angle = camera_data.angle
print(camera_angle)


target_location = scene.cursor.location - camera.location
loc = target_location@camera.matrix_world

print(loc)

x_tan = loc[0]/loc[2]
y_tan = loc[1]/loc[2]
angle_tan = math.tan(camera_angle/2)
print(angle_tan)
camera_data.shift_x = -x_tan /(2*angle_tan)
camera_data.shift_y = -y_tan /(2*angle_tan)
```


逆にカメラでの中心を３Dカーソル位置に移動させる場合には
シフトが0の状態で　最後の２行を

``` py
camera_data.shift_x = x_tan /(2*angle_tan)
camera_data.shift_y = y_tan /(2*angle_tan)
```
と符合を逆転したものを実行するだけです
既にシフトが設定されている状態からは　もう少し調整が必要になりますね。

## 画像の一部分に合わせる形でカメラを設定
漫画の１コマに合わせる形でのレンダリング画像を作りたいといった時に使うスクリプトです

カメラの下絵と画像エディッタに表示する画像を同じにしておいて
画像エディッタ上のアノテーションでカメラに収めたい範囲に印をつけることで
表示範囲とレンダリングの解像度を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/5a377477-e1e7-83fa-f28d-668724a93a07.png)

```py:GpenCrip.py
import bpy
scene = bpy.context.scene
#strokes = bpy.context.annotation_data.layers.active.active_frame.strokes
strokes = bpy.data.grease_pencils[0].layers[0].active_frame.strokes
# アノテーションは3Dビューに使われるものと3Dビューに使われるのがあるのでフィルタリング
strokes_2d = [ s for s in strokes if s.display_mode == '2DSPACE']
x_list = []
y_list = []
for stroke in strokes_2d:
    x_list += [pos.co[0] for pos in stroke.points]
    y_list += [pos.co[1] for pos in stroke.points]

bbox = [min(x_list),min(y_list), max(x_list), max(y_list)]
#カメラの下絵画像の情報を取得
camera = scene.camera
bg_image = camera.data.background_images[0]
bg_size = bg_image.image.size

# 下絵の表示される範囲の設定
bg_image.frame_method = 'CROP'
crop_size = [(bbox[2] -bbox[0])*bg_size[0], (bbox[3] -bbox[1])*bg_size[1]]
# 背景のトリムは背景画像の比率と比べて大きい方を基準にフレームに収めて切り抜く
if bg_size[0] * crop_size[0] > bg_size[1] * crop_size[1]:
    bg_scale = bg_size[0] / crop_size[0]
else:
    bg_scale = bg_size[1] / crop_size[1]
bg_image.scale = bg_scale
# 下絵の中心位置を設定
bg_image.offset = ((bbox[0] + bbox[2] -1) *-0.5 *bg_scale, (bbox[1]+ bbox[3] -1) *-0.5 *bg_scale) 
# レンダリングの画像サイズの設定
scene.render.resolution_x = crop_size[0]
scene.render.resolution_y = crop_size[1]
```
まだ試作なので　アノテーションは最初の１しか取得できないし
下絵と画像エディッタで表示する画像をそろえておく手間はありますが
何かしらの手助けになれば幸いです
いつかTomcat10を使用する……気になれないパッケージ名変更の闇

※この記事12/23が空いていたので、代わりに投稿しました。ライトなものです。

# Tomcatの最新バージョンは9.0

現在の Apache Tomcat の最新メジャーバージョンは9.0です。
https://tomcat.apache.org/
を見ると、2020/12/25 現在

* Apache Tomcat 9.0.41
* Apache Tomcat 8.5.61
* Apache Tomcat 7.0.107

が更新されています。2011/1にリリースされたTomcat7.0もようやく2021/3/31にEOLを迎えると発表されています。
http://tomcat.apache.org/tomcat-70-eol.html

いつかは、いま運用保守したり開発しているアプリケーションをTomcat10に乗り換える必要がありますが、ここに頭の痛い問題があります。Jakrta EE 9 のパッケージ名変更の影響です。

「Java EE 8 から Jakrta EE 9 になるとき、javax.\* だったパッケージ名が jakarta.\* になる話ですよね、たしか Big ban と呼ばれてた。**でも私たち Glassfish のような Java EE 使ってないから関係ないですよ」って、私も以前誤解していました。そうではないのです……**
（知っている皆さんからあたり前じゃないか！と突っ込みがたくさん来そう💦）

# Tomcat10.0に載せ替えるときのパッケージ名変更の問題

Tomcat 10.0.0 は 2020/12/8 にリリースされたばかりですが、サイトに「えっ？」となることが書いてあります。
https://tomcat.apache.org/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314396/b2290a47-d950-29cb-f5c9-fcb98c78371c.png)

> the primary package for all implemented APIs has changed from javax.\* to jakarta.\*. This will almost certainly require code changes to enable applications to migrate from Tomcat 9 and earlier to Tomcat 10 and later.
適当訳：パッケージ名が javax.* から jakarta.* になったから、Tomcat9（とそれ以前）から10に移行するときは、動かすためにコードの変更が必要ですよ。

そうでした、Servlet も Jakarta EE (Java EE) を構成する一つでした。なので、**手元で**
> import javax.servlet.\*

**と書いてあるコードは片っ端から**
> import jakarta.servlet.\*

**に変更する必要があります。**

### 10.0で動くバージョンは9.0では動かないのが面倒で

今回の変更で厄介なのは、Tomcat10で動くようにした Servlet は Tomcat9 では動かない、という点ですね

# JavaMail などのライブラリも変更

https://jakarta.ee/specifications/ に Jakarta EE (Java EE) の構成要素が並んでいます。

* Java Activation Framework → Jakarta Activation 
* JavaMail → Jakarta Mail
* Java Message Service → Jakarta Messaging
* JSON-B → Jakarta JSON Binding
* JAXB → Jakarta XML Binding
* Java Server Pages → Jakarta Server Pages
* Java Servlet → Jakarta Servlet

あたりは、いわゆる Glassfish、JBoss Application Server のような Java EE コンテナ と関係ない、Tomcat 上のWebアプリケーションやCLIなコマンド実装・バッチ処理でも使用されるケースが多いと思います。これらも Jakarta EE (Java EE) の構成要素ですので、パッケージ名が jakarta.\* になっています。
 
例えば、「JavaMail → Jakarta Mail」も2.0からしっかりと jakarta.mail になっています。
https://jakarta.ee/specifications/mail/2.0/ の先にある javadoc ( https://jakarta.ee/specifications/mail/2.0/apidocs/  ) はこの通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314396/88c99fc3-2762-c98d-23b0-ce285f85ca8e.png)

このため、JavaMailの最新バージョンでBugFixがあったとき、いままでの 1.6.x から 2.0.y にジャンプするには、Java（Scala, Groovy）ソースのimport文を javax.mail.\* から jakarta.mail.\* に変更する必要があります。 

-------

**長期的にはメリットも出てくると思うので、時間をかけて地道に対応するしかないですね。**
[Rails]超簡単なRailsAPIを作ってみる

##はじめに
railsAPIを作ってみたので備忘録として残す。
次回はswaggerなどのAPIドキュメントの導入をやってみる


##Rials APIの作り方
rails newに--apiを付ける

```
rails new rails-test-api --api
```

##簡単な使い方
CRUDを生成する
今回は掲示板CRUDを作成

```
rails generate scaffold Board title:string text:string
rails db:create
rails db:migrate
```

アプリケーションを起動

```
rails s
```

http://localhost:3000/boards に接続

[]が表示されるCurlでPOSTを叩く

```
curl -X POST -H "Content-Type: application/json" -d '{"title": "test", "text": "テストです"}' http://localhost:3000/boards
```
※Curlの叩き方は[こちら](https://qiita.com/hanata-el/items/d96d84d1889b495aca00)


再度 http://localhost:3000/boards に接続するとデータが作成される

```
[{"id":1,"title":"test","text":"テストです","created_at":"2020-12-24T17:27:15.312Z","updated_at":"2020-12-24T17:27:15.312Z"}]
```

これで完成


##参考
https://railsguides.jp/api_app.html
https://qiita.com/hanata-el/items/d96d84d1889b495aca00