OmniAICreator/Qiita-1.07M huggingface dataset:
【Ruby のまずいコード】文字列連結

# お題

何かのデータファイルから情報を抜き出してテキストファイルに書き出すというお仕事です。
データファイルはテキストファイルで，どの行も先頭が `A` から `Z` までのいずれかの文字になっています。
こんなふうに：

```txt:data.txt
H 9032,4232
G PXPP
A 123:A-G3
L FO,WE
C 1..9X
G LOPX
```


この中から，A の行だけを（順序を変えずに）抽出して結合し，また B の行だけを同様に抽出して結合し，この二つを A→B の順に結合したものを result.txt に書き出してください。

データファイル data.txt は何百万行もあるので，`File.read` で一気にまるごと読み込むということはせず，`File.foreach` で 1 行ずつ読み込んで処理するようにしましょう。

なお，データファイルの末尾には改行が入っているものとします。よって，`File.foreach` で取り出した「行」は，最終行まですべて改行が入っていると仮定できます。

# コード

```rb
text_a = ""
text_b = ""

File.foreach("data.txt") do |line|
  case line
  when /^A/
    text_a += line
  when /^B/
    text_b += line
  end
end

File.write "result.txt", text_a + text_b
```

# 講評

速度面では，A の行，B の行の判定に `case/when` と正規表現を用いるのをやめて，`if` と [String#start_with?](https://docs.ruby-lang.org/ja/3.0.0/method/String/i/start_with=3f.html) を用いるのがよさそうですが，この記事で伝えたい点はそこではないので，この点に関しては上記コードのままでよいことにします[^sm]。

[^sm]: お題をシンプルにするために「A で始まる行」「B で始まる行」としましたが，正規表現を使わないと判定できないようなケースを想定してください。

このコードのまずい点は，見出された A の行，B の行を次々と結合していくのに

```rb
text_a += line
```

のようなやり方をとっていることです。
これは，自己代入式の形で書かれていますが，要するに

```rb
text_a = text_a + line
```

のことですね。
ローカル変数 `text_a` に代入されている String オブジェクトと，ローカル変数 `line` に代入されている String オブジェクトとを結合した String オブジェクトを新たに生成し，それを `text_a` に代入しています。

この式が実行（評価）される前に `text_a` に代入されていた String オブジェクトは，実行後にどうなるのでしょうか？
これは，もうどこからも参照されないオブジェクトになります。永遠に使われることはないのです。こういったオブジェクトをガーベジ（garbage）といいます。

もし，A で始まる行が百万行あったとすると，最終的に百万個のガーベジが出来ます。
ガーベジは際限なく溜まり続けるわけではなく，Ruby の処理系が適当なタイミングで消していきます。そうしないとメモリーが足りなくなりますから。この処理をガーベジコレクションといいますが，場合によってはこれがプログラムの効率に無視できない影響を与えることもあります。

ところで，

```rb
text_a = text_a + line
```

のような処理を繰り返していくと，生成する文字列はだんだん長くなりますね。
あとになればなるほど大きなガーベジができるわけです。

以上から，連続する文字列結合で，上記のような書き方は避けたほうがよいことが分かります。

# 改善

文字列結合に [String#<<](https://docs.ruby-lang.org/ja/3.0.0/method/String/i/=3c=3c.html) を使って

```rb
text_a << line
```

とすれば解決します。
`String#<<` は破壊的に文字列を結合するメソッドです。
この場合，`text_a` に代入されている文字列自身がずんずん伸びていきます（`line` に代入されているオブジェクトは変化しません）。
この操作では新たな String オブジェクトが出来たりはしません。

なお，スクリプト先頭に

```rb
# frozen_string_literal: true
```

と書いた場合は，

```rb
text_a = ""
text_b = ""
```

で得られる String オブジェクトが凍結されているので，`<<` による破壊的操作ができません。
この場合は

```rb
text_a = +""
text_b = +""
```

のようにして，凍結されていない空の String オブジェクトを作ればいいでしょう。
Java 例外を投げ直せ

[Javaのカレンダー | Advent Calendar 2021](https://qiita.com/advent-calendar/2021/java)の14日目の記事です

※ 北斗の拳のようなタイトルになってしまって申し訳ありません

# 概要

`@SneakyThrows` を使って検査例外(チェック例外)を非検査例外(非チェック例外)?に投げ直すやり方
Stream API では、検査例外は try - catch で握る必要があるので、非検査例外にすることでコードをシンプルに保ちます

## 参考

- [@SneakyThrows](https://projectlombok.org/features/SneakyThrows)
- [Lombokの@SneakyThrowsを使うとSpring Bootの@Transactionalはロールバックされるのか調べる](https://www.greptips.com/posts/1320/)
- [jOOQ/jOOL： jOOλ](https://github.com/jOOQ/jOOL)

# やり方

## before

```java
    void tryCatch() {
        Stream.of("2021/12/22", "2021/12/23", "a").map(s -> {
            try {
                return new SimpleDateFormat("yyyy/MM/dd").parse(s);
            } catch (ParseException e) {
                return new RuntimeException(e);
            }
        }).forEach(System.out::println);
    }
```

## after

```java
    void sneakyThrows() {
        Stream.of("2021/12/22", "2021/12/23", "a").map(this::parse).forEach(System.out::println);
    }

    @SneakyThrows
    Date parse(String s) {
        return new SimpleDateFormat("yyyy/MM/dd").parse(s);
    }
```

# 説明

Stream API の中間操作で検査例外が発生する場合は、try - catch で例外を受け付ける必要があるため、冗長な例外処理を書く必要があります。
これに対応するため、検査例外を投げる処理を別のメソッドに抽出して、`@SneakyThrows` アノテーションをつけることで検査例外の例外処理のコードを省略するテクニックです。

## ポイント

- 別メソッドに抽出しているため、コードの行数は変わらない。もしくは増える場合がある。が、可読性は増す。
- 必要に応じて、呼び出しの大元で適切な例外処理を書くことは当然必要。スタックトレースを出せば、どこで発生したかはわかるため不安はない。
    - SpringBoot であれば `@RestControllerAdvice` がオススメ
- 中間操作で例外を握りつぶす(イレギュラーな状態でも処理を継続したい)必要がある場合は、 try - catch を利用して例外処理を書きます
- `@SneakyThrows`　は、検査例外を非検査例外に詰め直しているわけではない(javac 時に一時的に検査例外として認識されないようにしている)ので、投げられる例外は、検査例外になっている（そして、UndeclaredThrowableExceptionになってしまう？ちょっと自信なし）
- 別メソッドに切り出す必要もないほどのコード(例のコードもそうではあるが) `jOOQ` の Unchecked.throwChecked() を検討してもよい
Win10 から ubuntu20にssh自動ログイン

■Win10側
powershell起動

C:\Users\your_account\.sshに移動する。

```powershell
> cd C:\Users\your_account\.ssh
```

keyを作成する

```powershell
> ssh-keygen
```

The program will ask you for a file name, just press enter
It will then ask you for a passphrase, press enter again and once more to confirm

```powershell
Demo-win10:.ssh demo$ ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/demo/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /Users/demo/.ssh/id_rsa.
Your public key has been saved in /Users/demo/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:g5SyXmke+OAmYSl4nxc4wcRnsyeDO6RE9/Q9FKlcpKY demo@demo-win10-Desktop
The key’s randomart image is:
+—[RSA 2048]—-+
|   ..    .oo     |
|  .oo =. .+      |
| . .+*o=o=       |
|. ..oB=== o      |
|o.=o*.E+S  .     |
| +.=oO o .       |
|  . *.+          |
|   o .           |
|                 |
+—-[SHA256]—–+
```

ssh-agentを有効にする
(管理者権限でPowershellを起動する)

```powershell
> Get-Service ssh-agent
Status   Name               DisplayName
------   ----               -----------
Stopped  ssh-agent          OpenSSH Authentication Agent

> Get-Service ssh-agent | Select StartType
StartType
---------
Disabled

> Get-Service -Name ssh-agent | Set-Service -StartupType Manual

> Start-Service ssh-agent
```

Add the keys to the local Windows 10 keystore

```powershell
> ssh-add .\id_rsa
```

PuttyやTeraterm等で公開鍵(id_rsa.pub)の中身をubuntu(/home/you/.ssh/authorized_keys)にコピーする。


ログインする。

```powershell
> ssh demo@demo-desktop
```

以上。
オイラー積の証明

#動機
ぐぐるなり書籍をあたればオイラー積の証明は出てきますが、自分の言葉で書き下してみたくなりました。

##主定理

$$ \zeta(s)=\prod_{p:素数}(1-p^{-s})^{-1} = \sum_{n=1}^{\infty}n^{-s} $$

書き下した形

```math
\begin{align}
 \zeta(s)&= (\frac{1}{1-2^{-s}})(\frac{1}{1-3^{-s}})(\frac{1}{1-5^{-s}})(\frac{1}{1-7^{-s}})\cdots \\
&=1+\frac{1}{2^s}+\frac{1}{3^s}+\frac{1}{4^s} \cdots

\end{align}
```


###補助定理

```math

({1-p^{-s}})^{-1} = 1+p^{-s}+p^{-2s}+p^{-3s}\cdots\\

(ただし\: p \:は 1より大きな整数)

```


###補助定理の証明

初項$1$, 公比$r$の等比数列の和は

```math
S_n=1+r+r^2+r^3\cdots+r^n
```

両辺を$r$倍し、もとの式と差をとると

```math
\begin{align}
    S_n &= 1+ & r+r^2+r^3\cdots+r^{n-1}& \\
-) r S_n &=    & r+r^2+r^3\cdots+r^{n-1}&+r^n\\
\hline
(1-r)Sn &=1 &&-r^n\\
\end{align}

%\quad\quad\quad\quad\quad\quad\quad\:\;\,\;\, S_n = 1+ r+r^2+r^3\cdots+r^{n-1}\\
%\quad\quad\quad\quad\quad\quad\quad\quad\quad\;\;\underline{-) \quad rS_n =  \quad\quad\quad\:\; %r+r^2+r^3\cdots+r^{n-1}+r^n}\\
%(1-r)Sn =1 -r^n


```

よって $r\neq1$とすると

```math

S_n = \frac{1-r^n}{1-r}

```
$r=p^{-s}<1$とおくと

```math
\begin{align}

\lim_{n \to \infty}S_n &= \frac{1}{1-p^{-s}}\\
&=1+p^{-s}+(p^{-s})^2+(p^{-s})^3+(p^{-s})^4+(p^{-s})^5+\cdots\\
&=1+p^{-s}+p^{-2s}+p^{-3s}+p^{-4s}+p^{-5s}\cdots
\end{align}
```
補助定理証明終わり。

##主定理の証明

定義より

```math
\begin{align}

\zeta(s) &= \prod_{p:素数}(1-p^{-s})^{-1}\\

&=(1-2^{-s})^{-1}(1-3^{-s})^{-1}(1-5^{-s})^{-1}\cdots \\

\end{align}
```

ここで補助定理より

```math
\begin{align}
&=(1+2^{-s}+2^{-2s}+2^{-3s}+\cdots)\times \\
& \quad\; (1+3^{-s}+3^{-2s}+3^{-3s}+\cdots)\times \\
& \quad\; (1+5^{-s}+5^{-2s}+2^{-3s}+\cdots)\times \cdots \\
\\
&=(1+2^{-s}+(2^2)^{-s}+(2^3)^{-s}+\cdots)\times\\
& \quad\; (1+3^{-s}+(3^2)^{-s}+(3^3)^{-s}+\cdots)\times\\
& \quad\; (1+5^{-s}+(5^2)^{-s}+(5^3)^{-s}+\cdots)\times \cdots

\end{align}
```

ここで、[「算術の基本定理」](https://ja.wikipedia.org/wiki/%E7%AE%97%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC%E5%AE%9A%E7%90%86)つまり*「任意の正整数は、1 を除いて、一つまたはそれ以上の素数の積として（因子の順番の違いを除いて）ただ一通りに表すことができる」*という事実から

```math

\begin{align}
 &=(1\times1\times1\times1\times\cdots)+ &\color{blue}{(1の項)}\\ 
&\quad\;(2^{-s}\times1\times1\times1\times\cdots)+　 &\color{blue}{(2^{-s}の項)}\\
&\quad\;(1\times3^{-s}\times1\times1\times\cdots)+   &\color{blue}{(3^{-s}の項)}\\
&\quad\;((2^2)^{-s}\times1\times1\times1\times\cdots)+ &\color{blue}{(4^{-s}の項)}\\
&\quad\;(1\times1\times5^{-s}\times1\times\cdots)+ &\color{blue}{(5^{-s}の項)}\\
&\quad\;(2^{-s}\times3^{-s}\times1\times1\times\cdots)+ &\color{blue}{(6^{-s}の項)}\\
&\quad\;\cdots\\
&\quad\;\\

&= 1+2^{-s}+3^{-s}+4^{-s}+5^{-s}+6^{-s}+\cdots \\
&= \sum_{n=1}^{\infty}n^{-s}

\end{align}

```
主定理の証明終わり。
ウェブ地図の多様性と、ベクトルタイルで人を助けること

これは、[ベクトルタイル Advent Calendar 2021](https://qiita.com/advent-calendar/2021/vt)の22日目の記事です。

今回のアドベントカレンダーは、かなり高いレベルの成功に向かっているように思います。[ベクトルタイル Advent Calendar 2017](https://qiita.com/advent-calendar/2017/vt)と比べて格段に多様性が増大しており、多様性の増大は技術の持続性のために重要です。

昨日付の西川さんのエントリ[2021年、デジタル地図について考えたこと](https://shinichi.blog/answering-the-question/)にも、次の記載があります。

>地図のデザインの多様性がさらに上がることを期待している。特に、アニメ、浮世絵、かわいいなどの世界に影響を与えた価値観を生み出した日本での地図デザインが変わっていくといいな

地図の多様性が確保されることで、相互運用性と持続性、さらに信頼性が確保されます。その確保を行うための重要な手段が、自由で開かれていることです。自由のレベルにはさまざまなものがあり、それぞれの自由が共存することが重要だとも思っています。

ところで、**かわいい地図**を実現するための要素ってなんだろう、と思いました。ざっくりと分析してみたところ、こういうことじゃないかというブレストアイディアが出ています。

- 背景は黄色系
- 建物は青色系
- あちこちに猫がいる

今度、試してみたいなと思います。昨晩は、[UNVT Meetup](https://github.com/unvt/hackathonmeetup202112/blob/main/Meetup_draft_agenda.md)をやりました。若い方々が、UNVT の聳え立つ学習曲線にチャレンジしてくださったのですが、ベクトルタイルって、**地図そのものではなく、地図の印刷術**であるのだ、というところが難しいのだと思います。地図そのものと比較して、一段メタなのです。

印刷といえば、[ベンジャミン・フランクリン](https://ja.wikipedia.org/wiki/%E3%83%99%E3%83%B3%E3%82%B8%E3%83%A3%E3%83%9F%E3%83%B3%E3%83%BB%E3%83%95%E3%83%A9%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%B3)ですね。彼も我々の仲間なのだ、あるいは、我々は彼の仲間なのだ、と思います。

![ 2021-12-22 23.05.19.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102082/266f3417-ebca-71c3-105c-cd40771397fe.jpeg)

国連ベクトルタイルツールキットは、地図の印刷術であるベクトルタイルに貢献することによって、世界でも特に困っている人を助けることにつなげるという装置になっています。国連ベクトルタイルツールキット自身の持続のために必要なのは、多様な参加だと思っています。2021-01-19 に、国土地理院と国連 GGIM 防災部会、国連 GGIM アジア太平洋地域委員会が共催する「[Workshop on Geospatial DRR for Decade of Action (Day 2) - UN-GGIM WG-Disasters TG-B meeting](https://ggim-exercise.github.io/decade2/)」でも、似たようなコンセプトがあります。

紙数の残りを使って、上記のワークショップのコンセプトノートの最初の2段落を翻訳してみます。

> 気象や気候、気候変動、紛争、地震活動、また現在のパンデミックによって、世界のさまざまな地域の人々が脆弱になってきています。強靭な共同体を構築し、人々が最も助けを必要としているときに対応する必要があるのですが、準備や資源の不足に阻まれています。地理空間情報の科学と技術は、そういった資源を最大限に活用するための知的な前進をもたらすものです。なぜなら、災害管理サイクルの中で、リスクやハザードをモデル化したり、脆弱な人々やインフラを特定し支援したり、災害に備えた早期警報を出したり、リスクに晒された人々を支援する早期活動を実施したり、危機が発生で誰と何が影響を受けたのか理解したり、どういった支援が必要で、誰がその支援を提供しているのか、といった極めて重大な役割を地理空間情報の科学と技術は果たすからです。
>　政府、地方公共団体、国際機関、地域機関そして市民社会は、みな強靭性を構築して幅広いシナリオに対応する必要があるのですが、単一の地理空間ソリューションがあらゆる者に適合するわけではないのです。このワークショップでは、地理空間情報と技術ソリューションをいくつかの異なった見方から見ることで、共通性を見出し、災害管理システムを超えて知識を共有し、データ共有や発見といった、イノベーティブな思考を必要するところにおいて、いくつかのボトルネックや課題を特定します。地理空間コミュニティによる災害マネジメントへの対応は、UN-GGIM のより上位にある統合地理空間情報枠組（IGIF）での、社会を横断的に、マッピングと分析業務を強化するという目標に合致します。しかしながら、このワークショップでの対話は、災害マネジメントや人道支援システムのニーズへの理解を一般的なものから深いものに変えていき、そういった要求により合致するように我々地理空間情報の専門家が自分達の業務を調整するのに役立ちます。
HTTP基礎②

HTTP/1.1よりもさらにデータ通信を早くすることを目的にHTTP/2が誕生しました。
HTTP/２の特徴をまとめます

# ストリームによる通信経路の複数生成
HTTP/1.1
HTTPのリクエストが送られてきた順番通りにそれに対応したHTTPレスポンスを返さなければならない
→あるHTTP通信の処理に時間がかかってしまうとそれ以降のHTTP通信はその通信を待たなければならない

HTTP/2
一つのTCPコネクションに複数の通信経路である`コネクション`を複数生成します。それぞれのストリームは独立しているので、HTTP通信の待ち時間が生じることが無い


# HTTP通信にバイナリ形式のフォーマットを使用
HTTP/1.1
HTTPリクエスト・HTTPレスポンスでは全てのデータが一度に送信されるため時間がかかる

HTTP/2
HTTPリクエスト・HTTPレスポンスはフレームと呼ばれる単位に分けられ、バイナリ形式で送信される


# ヘッダー圧縮
HTTP/1.1
HTTP何度かやりとりされるHTTPリクエスト・HTTPレスポンスにはWebサーバーやWebブラウザなど重複する情報が多い

HTTP/2
ヘッダー情報から差分のみ送れるのでデータ転送量を削減できる


# サーバープッシュ
HTTP/2
HTTPリクエストの内容から判断し、HTTPリクエストを受ける前に必要なデータを事前にWebブラウザに転送する


# 参考
[イラスト図解式 この一冊で全部わかるWeb技術の基本](https://www.amazon.co.jp/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E5%9B%B3%E8%A7%A3%E5%BC%8F-%E3%81%93%E3%81%AE%E4%B8%80%E5%86%8A%E3%81%A7%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8BWeb%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC-%E5%B0%8F%E6%9E%97-%E6%81%AD%E5%B9%B3/dp/4797388811)
CarbonのSetTestNowの仕様変更


`Carbon::setTestNow()`で現在時刻を固定し、`Carbon::now()`で固定した値になっているかを確かめる以下のようなテストがあります。

```php
<?php

namespace Tests\Unit;

use Carbon\Carbon;
use PHPUnit\Framework\TestCase;

class Test extends TestCase
{
    public function test()
    {
        $now = new Carbon('2020-05-12T10:00:00+09:00');
        Carbon::setTestNow($now);

        self::assertSame(
            $now->format('Y-m-d H:i:s'),
            Carbon::now()->format('Y-m-d H:i:s')
        );
    }
}

```

つい最近まではこのコードで問題なかったのですが、最近の`Carbon`では失敗してしまいます。


```
Failed asserting that two strings are identical.
Expected :'2020-05-12 10:00:00'
Actual   :'2020-05-12 01:00:00'
```


原因となっているのはこちらの仕様変更です。
https://github.com/briannesbitt/Carbon/issues/2481

内容としては「`setTestNow()`では時間だけを固定し、タイムゾーンは固定しない」ようにするというものです。

上記テストコードでは`setTestNow()`で現在時刻を固定する時は`Asia/Tokyo`でタイムゾーンを設定していますが、`Carbon::now()`で現在時刻を取得する時はタイムゾーンを設定していないため`Carbon`のデフォルトである`UTC`が適用され、時刻のズレが発生しています。
また、`assertSame()`で比較するときはタイムゾーンの情報が失われているため、デバッグ時にも気付くのが大変です。
タイムゾーンの情報を含めた出力をすると以下のようになります。


```php
<?php

namespace Tests\Unit;

use Carbon\Carbon;
use PHPUnit\Framework\TestCase;

class Test extends TestCase
{
    public function test()
    {
        $now = new Carbon('2020-05-12T10:00:00+09:00');
        Carbon::setTestNow($now);
        dd(
            $now->format('Y-m-d\TH:i:sP'),
            Carbon::now()->format('Y-m-d\TH:i:sP')
        );
    }
}
```

```
PHPUnit 9.5.10 by Sebastian Bergmann and contributors.

 "2020-05-12T10:00:00+09:00"
 "2020-05-12T01:00:00+00:00"
```

解決策としては、`Carbon::setTestNow()`で設定したタイムゾーンと同じタイムゾーンで`Carbon::now()`を呼び出せばOKです。

```php
<?php

namespace Tests\Unit;

use Carbon\Carbon;
use PHPUnit\Framework\TestCase;

class Test extends TestCase
{
    public function test()
    {
        $now = new Carbon('2020-05-12T10:00:00+09:00');
        Carbon::setTestNow($now);

        self::assertSame(
            $now->format('Y-m-d H:i:s'),
            Carbon::now('Asia/Tokyo')->format('Y-m-d H:i:s') // タイムゾーンを揃える
        );
    }
}
```
どうやって半年で新しい学習サービスをローンチしたのか

### どんな学習体験を提供してるか
* インプットだけではなく、アウトプットもして、学習した内容を定着できる
* 学習した内容をアウトプット、実践できる
    * ケースを分析、設問を回答して、システムからフィードバックをもらうことで、 input->output->feedbackのサイクルができる
    * グループワックに参加し、受講者同士で学習した内容を議論、共有することで、新しい刺激、学びを得られる
* ライブ受講と動画学習の組み合わせて、インプットできる
* 学習した内容の振り返り、気づきを共有、議論ができる
* ペースメイクがあり、週ごとの学習計画があるので、学習を維持しやすくなる

### 新しいサービスをどうやって半年で作り上げたのか
* `得意な技術`を使う
    * 経験が長いRailsを使ったので、新しい技術を学ぶコストが少ない
* `新しい技術`を取り入れることで、`仕事のモチベーション`をあげる
    * 選定基準
        * 使ったことがない
        * 使ってみたい
        * 生産性が高い
*  `自主的に動く`チームを作る
    * 決定権を持って、意識決定を早くする
    * 各メンバーが現在のプロジェクト状況を踏まえて、自分が感じてる課題、リスクなどを気軽に、共有することで、スピード早く方向を調整、リスクを解消できる。
    * 管理コストを減らすことができる
* `職種の壁が薄い`
    * 異なる職種のメンバーが自分が得意じゃない分野でも自分の考えを気軽に話して、みんなの意見を取り入れながら、決めて進むようにする
* `フィードバックサイクルが早い`
    * 他のメンバーのアウトプット、課題に対して、素早くフィードバックをして、担当者が次のActionができるようにして、待ち時間が少なくする。例えば、 
        * 他の作業の前提条件になる作業は優先的にレビューして、次の作業が進めるようにする
        * QAが実装の前から参加して、QAの観点で、仕様の問題、プロジェクトの課題を見つけて、早期段階で解決できるものは後工程に持ち込まないようにする
* システム開発を着手する前に、`技術検証`用のシステムを開発して、新しく採用した技術を検証し、スキルを蓄積する
* `技術力を上げる`
    * 得意じゃない技術もできる限り、やってみることで、チーム全体のスキルアップして、長期的にチーム全体の生産性を上げる
* `Don't Reinvent the Wheel`
    * 例えば、今回、AIの部分は既存のシステムをAPI化し、使えるようにして、かなりの開発コストを削減しました
* `やってみる`
    * 如何すれば良いかが分からない時には、暫定案でとにかくやってみる、進めるにつれ、答えが見えてくることがある
* `MVP`に注力
* `変化を楽しむ`
    * 無理やりに計画したこと、仕様のままで進まないで、柔軟にやり方やゴールを変えていく

### 課題や、改善点すべきところ
ローンチまでは成功したけど、これから進化、もっといい価値を提供できるためには、課題もいろいろあると思います。

* テストコードが十分ではない、特にフロントのテストコードが整備してないので、これからの開発でデグレ発生する可能性が高くなったり、デグレ発生を減らすために、毎回のリリースでコスト高い手動テストを実行しないといけない、長期的に見ると、品質と生産性の低下になる
* 今回、flutter webを採用して、結果的に、ユーザーのアンケートで評価が高かったんですが、いくつか細かいところで従来のwebで期待したことができないことが気付きました。
    * デフォルトでページ全体の文字を選択できない
    * ページ内検索がうまくいかない
* releaseモードで発生したエラーの調査が難しい、今、[sentry-dart-plugin](https://github.com/getsentry/sentry-dart-plugin)を使って、解決中
* 手動運用が多いため
    * ミスを起こしやすい
    * コストが高くなる
    * 新しい価値の提供、改善に使う作業時間が減る
* 技術負債も少しずつ溜まってきたので、機能の開発と負債を返す必要がある

以上です。少しでもご参考になれば幸いです。ありがとうございます
パターンマッチでデフォルト値を設定したかった話

## はじめに

この記事は[「Ruby Advent Calendar 2021」](https://qiita.com/advent-calendar/2021/ruby)の22日目の記事です。
Ruby2.7から入ったパターンマッチ、皆さん使ってますか？
便利ですよね。
自分はここ数年仕事では JavaScript(TypeScript) を触るのがメインだったんですが、よく使われる構文として分割代入があります。
分割代入もパターンマッチも使い勝手が似ている部分が多いので分割代入に慣れているとパターンマッチが非常に手に馴染みます。(個人的所感)
ただ分割代入でできてパターンマッチでできないことがあります。
デフォルト値(既定値)の設定です。
この記事ではパターンマッチでデフォルト値を設定したい場合はどうするかを考えていきます。

## 分割代入の場合

まず JavaScript の分割代入の場合ですが、以下のようにしてデフォルト値の設定ができます。

```javascript
const obj = { a: 1 }
const { a, b = 2 } = obj // obj の b という key が undefined の場合にデフォルト値が設定される
foo(a, b)
```

`obj の特定の key に値が入っていない == obj の特定の key の値が undefined` なのでこれでデフォルト値が設定されます。
一方 Ruby のパターンマッチの場合、in節の中でデフォルト値を設定できないのでマッチ前かマッチ後のどちらかでデフォルト値を設定してやる必要があります。

## パターンマッチの場合

### 方法1: マッチ後にデフォルト値を設定する

1行in ならマッチしなかった変数は nil で初期化されるのでマッチ後に代入すればいけそうです。

```ruby
hash = { a: 1 }
hash in { a:, b: }
b ||= 2
foo(a, b)
```

ただし以下のように最初にマッチしなかった key 以降はパターンの検証が行われないため、残念ながらこの方法では思い通りにいきません。

```ruby
hash = { a: 1, c: 3 }
hash in { a:, b:, c: } # => b にマッチしないため c は nil
b ||= 2
foo(a, b, c) # 第３引数で 3 を渡しているつもり
```

### 方法2: マッチ前にデフォルト値を設定する

今度は先にデフォルト値を設定してみます。

```ruby
hash = { a: 1 }
default = { b: 2 }
default.merge(hash) => { a:, b: }
foo(a, b)
```

この方法の場合は key が必ず存在するので 1行in ではなく右代入でいけます。
また、方法1でうまくいかなかったケースも対応できます。

```ruby
hash = { a: 1, c: 3 }
default = { b: 2 }
default.merge(hash) => { a:, b:, c: }
foo(a, b, c)
```

ただし merge に渡す Hash でデフォルト値を設定したい key に nil が入っている場合 nil で上書きされてしまいます。

```ruby
hash = { a: 1, b: nil }
default = { b: 2 }
default.merge(hash) => { a:, b: }
foo(a, b) # => b は nil
```

このため、merge に渡す Hash から nil を排除する必要があります。

```ruby
hash = { a: 1, b: nil }
default = { b: 2 }
default.merge(hash.reject { |_, v| v.nil? }) => { a:, b: }
foo(a, b)
```

ここまでやってようやくやりたいことが実現できました :tada: :tada: :tada:

### 願望

はい、できたことはできたんですが分割代入のデフォルト値の設定と比較するとどうしても面倒に感じてしまうところがあります。
また、ネストした構造になってくると更に手間になってきます :innocent:

```ruby
hash = { a: { b: { c: nil }, d: 2 }, e: { f: nil } }
default = { a: { b: { c: 1 }, e: { f: 3 } } }
assigned = hash.reject do |_, v|
  # nil を除外するためのロジック
end
default.merge(assigned) => { a: { b: { c: }, d: }, e: { f: } }
foo(c, d, f)
```

なので、パターンマッチ(or 右代入)にデフォルト値を設定できる機能がほしいなぁと思う今日このごろです :joy_cat: 

## 最後に

何か他にもっとスマートなやり方があれば教えてください〜 :pray:
iOSアプリ名のローカライズ対応(Xcode13,1)

## 方法
#### 1. 追加したい言語を追加する
プロジェクト設定から、「Info」→「Localizations」→ 「+ボタン」を押下。
追加したい言語（Japanese）を選択する。
![スクリーンショット 2021-12-22 22.11.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/b1d8e99e-0900-a59a-b4c0-db87e8084bfb.png)
#### 2. ローカライズ用のファイルを作成する
「New File...」より「Strings File」を選択。
「InfoPlist.strings」という名前でファイルを新規作成。
![スクリーンショット 2021-12-22 22.12.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/79070f50-2ee0-c615-8f5c-28d70c89c194.png)
#### 3. 対応する言語を設定する
「InfoPlist.strings」を選択し、[File inspector]の[Localize...]ボタンを押下。
![スクリーンショット 2021-12-22 22.12.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/b4153f36-af18-a3c3-ea44-c6c1ea8da1ca.png)
ダイアログが表示されますが、そのまま「Localize」をクリック
![スクリーンショット 2021-12-22 22.12.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/f693e53a-e798-95a2-2b7e-af1db3bec191.png)
以下の２つ(対応したい言語)のチェックを入れる
- Localizable.string(Japanese)
- Localizable.string(English)
![スクリーンショット 2021-12-22 22.13.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/44f4630d-4319-b7c6-542d-a79c79e28731.png)
#### 4. 表示したい内容を記述する
 ``` title:Localizable.string(English)
 CFBundleDisplayName = "test";
 ```
 ``` title:Localizable.string(Japanese)
 CFBundleDisplayName = "テスト";
 ```
#### 5. 確認する
![Simulator Screen Shot - iPhone 13 - 2021-12-22 at 22.17.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/65761319-ca87-ea6b-7b96-609de9a09d50.png)
![Simulator Screen Shot - iPhone 13 - 2021-12-22 at 22.17.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667331/6a741634-0a5f-f0c7-6287-88387afc5b1f.png)
PHP 真偽値の判定 個人メモ

# 目的

- PHPにおける真偽値の判定方法をメモ的にまとめる

# 真偽値の判定アレコレ

- そのままif文の判定箇所に入れる。

    ```php
    <?php
    $bool = true;

    if ($bool) {
        echo 'trueです';
    }
    ```

- if文の判定箇所で`true`もしくは`false`を`===`で比較する。

    ```php
    <?php
    $bool = true;

    if ($bool === true) {
        echo 'trueです';
    }
    ```
サポートベクトルマシン

■サポートベクトルマシン
【特徴】
・線形２値分類手法
・外れ値の影響を受けにくい

どのように２値分類を行うのか？
・マージン：判別境界の周りにデータポイントが存在しない帯状の領域
・サポートベクトル：マージンの境界上のデータポイント
・マージンの大きさ：判別境界からサポートベクトルまでの距離（点と直線の距離）
上記の３点よりマージン=距離の大きさが最大となるように判別境界を設定します。

【点と直線の距離の公式】
点$(x_1, x_2)から直線w_1x_1 + w_2x_2 + b = 0$に下した垂線の長さを、点と直線間の距離といい下記の公式により求まります。


$距離 =\frac{|w_1x_1 + w_2x_2 + b|}{\sqrt{w_1^2 + w_2^2}}$

【イメージ】

![スクリーンショット 2021-12-20 0.16.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175940/84cae580-6805-11d8-e30a-e1f262c5c9e5.png)





# 実装



######1.モジュールインポート
```
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
```


######2.データ読み込み＆分割
```
import pandas as pd

df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/'
                      'machine-learning-databases/wine/wine.data',
                      header=None)

df_wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
                   'Alcalinity of ash', 'Magnesium', 'Total phenols',
                   'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
                   'Color intensity', 'Hue', 'OD280/OD315 of diluted wines',
                   'Proline'] #13個



# classlabel 1を削除　
df_wine = df_wine[df_wine['Class label'] != 1]


y = df_wine['Class label'].values
X = df_wine[['Alcohol', 'OD280/OD315 of diluted wines']].values
```

######3.ラベル変更
```
df_wine_data = df_wine[['Alcohol', 'OD280/OD315 of diluted wines']]

df_wine_data['Class'] = df_wine['Class label'].values

df_wine_target = df_wine[['Class label']]

#データラベルを１と-1に変更
df_wine_data['Class'] = df_wine_data['Class'].apply(lambda x: 1 if x == 2 else -1)

df_wine_data
```

![スクリーンショット 2021-12-22 22.26.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175940/4d8bae8b-2983-bcef-b77b-9938dbdb0ffe.png)


######4.データの可視化
```
X, y = df_wine_data[['Alcohol','OD280/OD315 of diluted wines']], df_wine_data['Class']

x1 = X['Alcohol']
x2 = X['OD280/OD315 of diluted wines']

plt.scatter(x1, x2, c=y, cmap='autumn')
plt.show()

```
![スクリーンショット 2021-12-22 22.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175940/610aeda5-ac8c-f69f-21a9-62e81e7178bc.png)


######5.モデル学習
```
from sklearn.svm import SVC
svc = SVC()
svc.fit(X, y)

#予測
y_pred = svc.predict(X_test)

#正解率確認
accuracy_score(y_test, y_pred)
#1.0

#決定領域プロット
xx, yy = np.meshgrid(np.linspace(start=11, stop=15, num=100),
                     np.linspace(start=1, stop=4, num=100))
x_test = np.c_[xx.ravel(), yy.ravel()]

y_pred = svc.predict(x_test)
y_pred
```


![スクリーンショット 2021-12-22 22.28.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175940/8782f49d-2679-2158-c5ca-855958abd485.png)


以上、モデルの作成・予測を行うことができました。今回は線形分離可能なモデルでしたが次回は非線形分類についても記事を書けたらと思います。
ConoHaを使ってPythonでWEB情報を取得するお話

#はじめに
この記事は「[ConoHa Advent Calendar 2021](https://qiita.com/advent-calendar/2021/conoha)」の第22日目の記事です．今回は，ConoHa上で，Pythonを使ってWEB情報を取得してみようというお話しになります．

#今回のお話
WEB情報を取得する方法はたくさんありますが，今回は最近流行している（ずいぶん前から流行っているかも知れませんが），Pythonという言語を使って，ConoHa上で1日1回実行して，WEBサイトに記載されている情報を取得しようというお話しです．ConoHaは24時間365日ずっと稼働できるVPSなのでこういう用途にはもってこいです．今回は，私が管理しているWEBサイトの情報を取得するということを行いました．

#技術的なお話
少し技術的なお話をしようかと思います．今回は，Pythonという言語を使用して，WEBスクレイピングを行うというお話になります．Pythonでは，いくつかWEBスクレイピングを行う方法がありますが，今回，スクレイピングに使用するPythonのライブラリは，RequestsとBeautiful Soupを使用しています．

#取得するWEBサイト
取得するWEBサイトは私が自作したゲームのデータを1日1回取得することが目的です．ゲームのデータは，次のような構造でWEBサイトに表示されています．サンプルのデータを紹介します．

|大当たりAの回数|大当たりBの回数|大当たりCの回数|今日のゲーム数|今日の総ゲーム数|大当たりAの確率|大当たりBの確率|AとBの合成確率|昨日の最終ゲーム数|状態|勝利ポイント|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|3|2|0|131|564|1/188|1/282|1/112.8|25|-|266|

という表の形式になっています．この数字の部分をテキストファイル（csv）で取得して保存することを試みることになります．

#プログラムのお話
Pythonやそれを実行する環境は実装されているものとして今回は環境構築に関する説明は割愛しようと思います．プログラムは以下のような簡単なものになります．

```
#ライブラリ等を使うためにおまじないを書きます
from os import write
import requests
import datetime
import csv
from bs4 import BeautifulSoup

#前日のデータを保存するために日付を計算しています
dt_now = datetime.date.today()
oneday = datetime.timedelta(days=1)
yesterday = dt_now - oneday

#取得したデータの保存先とファイル名を指定します
f = open('dataloger_' + str(yesterday) + '.csv', 'a+')
writer = csv.writer(f, lineterminator='\n')
csvlist = []

#取得するデータのURLを指定してtextとしてWEBページを読み込みます
html_doc = requests.get("http://...").text
soup = BeautifulSoup(html_doc, 'html.parser')

#表になっている要素を探しに行きます
el = soup.find_all('tr')

#表に書かれているテキストを保存するためのtmpファイルに保存する処理
#複数行ある可能性も考えてループ構造になっています
standing = []
for row in el:
    tmp = []
    for item in row.find_all('td'):
        if item:
            tmp.append(item.text)
    standing.append(tmp)

#取得したデータを実際にcsvに書き込んでいます
for item in standing:
    writer.writerow(item)
```

実際に取得されたデータはこちらです．
![2021-12-22_21_14_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311851/87380813-0c26-891b-179f-907a10ab9fc1.png)
このようなデータが毎日日付が変わったタイミングでcronで設定して取得しています．

#取得したデータは何に使うのか？
このようなデータは1日，2日ではなかなか利用する用途が難しくて，たくさん蓄積する必要があります．このプログラムは今年の夏に作成してそれ以降ずっと実行しているので，もう4ヶ月分データが貯まっています．ConoHaはストレージがたくさん使うことができるVPSなのでどれだけテキストデータを貯めても安心です．これらのデータを統計的な解析をして，例えば，曜日でゲーム数の傾向はあるのか，大当たりの確率はどうかなどを知るきっかけになります．
統計的な解析も少しConoHa上でPythonを使ってやっていますが，それはまた別の機会に書かせていただきます．

#最後に
少し早いですが，今年もConoHaのサービスでいろいろチャレンジすることができました．ダウンタイムもほとんどないので，大変助かっています．これからも積極的に使っていこうと思います．最後に，このはちゃん清楚可愛い(≧∇≦*)！！
VCI UI応用編-カラーサークルを作る-

この記事は[平面的なUIを作りたい](https://qiita.com/sakkinonana/items/fcd0f1709834431e4cab)と[VCIでリング的なUIをつくりたい](https://qiita.com/sakkinonana/items/aa5416ebb2dd7e520113)の続編のUIの記事です

# カラーサークルを作りたい


作るのは↓みたいな感じです。

https://twitter.com/sakkinonana/status/1473699175510724608
#モデル
今回は上記二つのモデルの流用でほぼできてしまいます。ただし、カラーの四角形を出すためにVCIでは直接テクスチャをいじれないため、三つのテクスチャを重ねて四角形を表現しています。（実は、アルファブレンドしかできないのでこれも正確ではないのですが、また込み入った話になるのでまたの機会に。）

unityのヒエラルキー（階層構造）は以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494837/2f4cb2db-0d2e-37a5-a962-e349a972ed05.png)

selection_coneが実際に持つアイテム、Sphereが操作に連動して動くインジケーター（最悪なくてもよい）、quadがカラーの四角形板で平面UIのcubeと同じくホワイトボードみたいな役割をします。

今までと同様バーチャルキャストではある経路に沿ってだけ動く、みたいな拘束はかけられないため、掴みたいスタイラスと、実際に値をとるものとを別にします。その上で板上のインジケーターの座標を計算してスクリプトで移動させるという形式を取ります。

#スクリプト
以下スクリプトを貼り付けておきます。前回の流用なので、例によって別オブジェクトの色を位置に応じて変えています。

```lua:main.lua
local stylus = vci.assets.GetTransform("selection_cone")
local indicator = vci.assets.GetTransform("SphereQ")
local plane = vci.assets.GetTransform("Quad1")
local ring = vci.assets.GetTransform("torus")
local ctr = vci.assets.GetTransform("Sphere")
local lscale=0.5*2
-- indicator.SetPosition(Vector3.zero)

local flg_color = 0

function onUse()
    flg_color = (flg_color + 1) %2
end

local hueangle = 0
function update()
    if flg_color == 0 then
        local nowctrpos = Vector3.ProjectOnPlane(stylus.GetPosition()-ring.GetPosition(),ring.GetRotation()*Vector3.up).normalized*.6*lscale
        ctr.SetPosition(ring.GetPosition() + nowctrpos)
        hueangle = Vector3.SignedAngle(nowctrpos,ring.GetRotation()*Vector3.left,ring.GetRotation()*Vector3.up)+180

        local starcolor = Color.HSVToRGB(hueangle/360,1,1)
        vci.assets.material._ALL_SetColorFromIndex(4,starcolor)
    elseif flg_color == 1 then
        -- local pos = Quaternion.Inverse(ring.GetLocalRotation())*Vector3.ProjectOnPlane(stylus.GetLocalPosition()-ring.GetLocalPosition(), ring.GetLocalRotation()* Vector3.up)*2   
        local pos =Quaternion.Euler(0,0,-90)*Quaternion.Euler(90,0,0)*Quaternion.Inverse(ring.GetRotation())*Vector3.ProjectOnPlane((stylus.GetPosition()-ring.GetPosition()), ring.GetRotation()*Vector3.up)/0.8*ring.GetLocalScale().x
        indicator.SetLocalPosition(pos)
        print(pos)
        --4 plane 0 stylus 1 ring 5はだめ 6 star 
        vci.assets.material._ALL_SetColorFromIndex(6,Color.HSVToRGB(hueangle/360,pos.y+0.5,pos.x+0.5))
    end

end
```

今回は、はじめはリングUIを操作し、一回useするとリング状のインジケーターは固定され、今度は四角形上のポインターが動き、もう一回useすると、最終的な色が決定されます。
ちょっと面倒なのでローカルだけで動くように作っているので、一部同期しないところがあるかもしれません。


#おわりに
実際UIを一から作るのは以外に大変ですから、VCI製作者としては他にも使いたいUIはたくさんあると思うので、ぜひ皆さんも作ったら共有していってください。いちいちUIに消耗してるのはもったいないからね。

今回はカラーサークルに使ったけど、他にも値の決定など使える場面はたくさんあると思います。これまでのスライドバー、リング、平面UIを組み合わせればいろいろなことができるようになるかもよ？


読んでいただきありがとうございました。
情報セキュリティマネジメント試験に合格した勉強方法

2021年7月に情報セキュリティマネジメント試験に
合格しました。

その時の勉強方法を書いていこうと思います。

#情報セキュリティマネジメント試験とは
IPA(独立行政法人情報処理推進機構)が実施している国家資格です。
平成28年4月から実施しているので新しい資格です。

最近ニュースで見ることも多いサイバー攻撃や内部不正を防止する
セキュリティマネジメント人材を増やすことが目的のようです。

#試験形式
試験は午前と午後に分かれています。
午前試験は90分で四択問題50問、
午後試験は90分で大問3題です。

午後の大問は1つの文章に関して10問前後の
選択問題が出る形式です。

また午前試験、午後試験となっていますが、
別日に申し込むこともできます。

#合格基準点と合格率
合格基準点は60点と公表されています。
合格率は50％前後ということで、
合格率20～30％の基本情報技術者試験などと比べると
易しい試験です。

#なぜ受験しようと思ったのか
IPAの資格で基本情報技術者試験は取得していたので、
次の資格ということで受験しようと思いました。

また仕事で画面の開発もするので
SQLインジェクションのような問題も
知っておいた方がいいと思い受験しました。

#勉強方法
使った問題集はインプレス社の
徹底攻略情報セキュリティマネジメント過去問題集です。

この問題集を1周して
間違えた問題をさらに解きなおしました。

午前試験はそうでもないのですが、
午後試験の問題が時間が足りなくなるので
時間を測って解くのがおすすめです。

#受験してよかったこと
ブルートフォース攻撃やディレクトリトラバーサル
のような攻撃手法を知ることができたことです。

対策しようとしても
攻撃手段が分からないと対策ができないと思うので、
まず攻撃方法が分かったことは良かったです。

また電子署名のような暗号化手法も
こういう機会がないと勉強しなかったと思うので
勉強できてよかったです。
他業種からプログラミング講座に挑戦してみて見えたこと（課題）

#はじめに
7月から県のIT人材育成講座（プログラミング）を受講して見えた自身の課題について記事にしてみようと思います。
仕事を継続したまま、パソコンスキル０で全くの他業種から挑戦して何が大変だったか、何が見えたか、何が見えなかったのか・・・ご助言もいただけると嬉しいです。
また初めて記事を書くので足らない部分もあると思いますがご了承ください。

#受講中に出会った壁
・パソコン操作がわからない（Macの使い方がわからない）
・環境構築・・・なんのことかわからず言われたままに操作
・時間の確保（仕事と学習のバランスが難しい）
・**分からないことが分からない**。これが一番辛かったです。

#受講中に出会った壁の乗り越え方
・習うより慣れろ。とにかく触りまくる。初歩の初歩ですがブラインドタッチの練習も行う。
・分からないことは割り切って先に進む勇気を持つ。
・時間はあるのではなく作るもの。・・・でも睡眠時間は削らないよう工夫。
・調べる調べる調べる。とりあえず調べることで乗り越えられたことも多々。

#乗り越えたと思って実はできていなかったこと（見えていなかった部分）
・調べることで、その場で解決して変な自信や満足感を得ているが、根本的に理解できていない。カンペやヒントを得ただけ。
・分からないとこは分からないまま放置していても解決することはなし。放置しても大丈夫な箇所なのかの判断もできないのに、とりあえず進めるは危険。効率よく進めるために省略することとは意味が違うことに後々気付く。

#上記のことから見えてきた私自身の課題
・そもそものパソコン、ITのことを知らなすぎて、プログラミング言語の学習だけでは知識が足りていない。
・点と点で覚えている状態でうまく繋ぎ合わせることができておらず総合的に理解できていない。

#課題解決に向けて行なっていること
・本を一冊読み込んでみる。必要箇所を見るのではなく一冊読み込むことで総合的に理解できることがある。
・TCP/IPやLinuxの学習をする。
・Qiitaのトレンドから分からない言葉を1日１０個調べる

#最後に
まだまだプログラミングの世界に入りきれていないような状況ですが、挫けず学習を続けていこうと思っています。
TOP 10 PROGRAMMING LANGUAGES THAT WILL KEEP YOU IN DEMAND IN 2022

 
      
TOP 10 PROGRAMMING LANGUAGES THAT WILL KEEP YOU IN DEMAND IN 2022
(2022年にあなたの需要を維持するトップ10のプログラミング言語)

Analytics Insightの記事で、2022年の需要のあるプログラミング言語が紹介されていました。
```
・JavaScript
・Python
・Go
・Kotlin
・C++
・Java
・R言語
・PHP
・Scala
・Dart
```

これから学ばれる方々の、検討になればいいと思います。
#考察
自分としては、JavaSctiptに関しては安定なる需要があると思う。
そして、トレンド視線でいうならばGoの需要が2022年は期待大だと思われる。

・参考文献
https://www.analyticsinsight.net/top-10-programming-languages-that-will-keep-you-in-demand-in-2022/
(原文は英語なのでDeeple翻訳を使われるといいと思います)
Mbed OSでCANの受信割り込みができない

#概要
MbedOSでCAN通信で受信割り込みができない不具合について調べました。
#環境
- NUCLEO-F767ZI
- Mbed OS 6.15

# 状況
受信割り込みを設定しても全く受信しない。もしくはMutexロックがかかっていてエラーを吐く。

#原因
受信割り込み時に`can.read()`を使うとエラーを吐く。
この関数は読み込み時にMutexロックをするため、割り込みコンテクスト（割り込み時に実行される）では使用できない。

# 解決法?
1. `mbed-os`フォルダ内の`can.h`を書き換える。
https://github.com/pilotak/NoMutexCAN
この記事のように、`can.h`を継承し、`CAN::read()`をオーバーライドすることでMutexを無効化する。

2. 別スレッドで受信割り込みを処理する。


```C++:main.cpp
#include "mbed.h"

void onReceive();
void CANreceive();

CAN can(PB_5, PB_6, 500000);
Thread t(osPriorityNormal, 2000);
EventQueue queue(32 * EVENTS_EVENT_SIZE);
int main(void)
{
  can.attach(onReceive, CAN::RxIrq);
  t.start(callback(&queue, &EventQueue::dispatch_forever));
  while (1)
  {
    printf("loop\n");
  }

  return 0;
}

void onReceive()
{

  queue.call(CANreceive);
}

void CANreceive()
{
  CANMessage msg;

  if (can.read(msg))
  {
    printf("data: %s,id:%d\n", msg.data, msg.id);
  }
}

```

ただし、これでもうまく行かないという報告もあります。

#まとめ
このエラーはMbed OS 5からずっと続いてるバグです。色々解決策が書かれていますが、どれもいまいち決め手に欠けます。
頑張って使えるようにするか、HALを使うのがいいのかもしれないです。

#参考文献
https://github.com/ARMmbed/mbed-os/issues/6714
https://forums.mbed.com/t/can-bus-interrupt-problem-mbed-5-15/10808/4
https://github.com/ARMmbed/mbed-os/issues/9495
https://github.com/pilotak/NoMutexCAN
https://qiita.com/noritan_org/items/172ca6c62fe4b36767d4
https://qiita.com/noritan_org/items/cc4a0ab2c6ff9c0aa5e
https://forums.mbed.com/t/can-attach-and-can-read-does-not-work-on-mbedos6/14720
（↑僕が質問しました）
Docker コンテナで特定のコマンドしか実行できないユーザーを作成したい

#### 目的
Docker コンテナで特定のコマンドしか実行できないユーザーを作成したい。
Docker のデフォルト設定では、コンテナ内のプロセスはroot権限で実行される。
これをまず、root 以外のユーザーで実行させるようにしたい。
更にそのユーザが使えるコマンドを制限したい。
~~はじめから使えるコマンドが少ない軽量な Docker Image を使えばよいのかもしれない。~~
取りあえず、centos:7 の Docker Image を元に、使えるコマンドを awk に制限してみます。

#### 1.ユーザー作成
awk コマンドは許可される awker という名前のユーザにします。
※awk 使えるといろいろと出来てしまいますが

```
// コンテナに入って
$ docker run -it centos:7 bash

// ユーザーを作成
# useradd awker

// パスワードも設定しておく
# passwd awker

// rbash(制限付きbash) を登録
# ln -s /bin/bash /bin/rbash
# echo "/bin/rbash" >> /etc/shells && cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/rbash
```

#### 2.ユーザディレクトリを作成
一回、作成したユーザで bash 起動し、ユーザディレクトリを作成する。
そのために、まずコンテナからイメージ作成する。

```
// コンテナからイメージ作成
$ docker commit [container_id] awk_base

// 作成したイメージを元に、制限したいユーザー(awker)で bash 起動する
$ docker run -u awker -it awk_base bash

// シェルを rbash に変更する
$ chsh
Changing shell for awker.
New shell [/bin/bash]: /bin/rbash
Password: {ユーザ作成時に設定したパスワード}
Shell changed.
```

#### 3. ~/.bash_profile の所有者・グループを root にする
awker 自身では変更できないようにするため。

```
// コンテナからイメージ作成
$ docker commit [container_id] awk_base2

// 作成したイメージを元に root で bash 起動する
$ docker run -u root -it awk_base2 bash

// .bash_profile の所有者・グループを root にする
# cd /home/awker/
# chown root .bash_profile
# chgrp root .bash_profile
# chmod 755 .bash_profile
# ls -al .bash_profile
-rwxr-xr-x 1 root root 193 Apr  1  2020 .bash_profile
```

#### 4. 使えるコマンドを設定する

```
// PATH を定義(/home/awker 以外でも構わない)
# echo "export PATH=/home/awker" >> .bash_profile

// PATHで定義した場所に、使いたいコマンド(awk)へのリンクを付ける
# ln -s /bin/awk /home/awker/awk

// コンテナからイメージ作成
$ docker commit [container_id] awk_img
```

これで awker ユーザーは、awk しか使えないイメージが作成できたはず。

#### 5. そのコンテナを使ってみる

```
$ docker run -u awker -it awk_img bash --login
// ls 実行できない
$ ls
bash: ls: command not found

// 恐ろしいコマンドも実行できない
$ rm -rf /
bash: rm: command not found
```

cat ではファイルの中身が見れないですが

```
$ cat .bash_profile
bash: cat: command not found
```

awk では確認ができる。

```
$ awk '{print}' .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin

export PATH
export PATH=/home/awker
```

あと、bash の組み込みコマンドである cd, help, echo などは実行できる。

#### 需要はあるのか？
コンテナ上でアドホックにコマンドを実行できるような仕組みを用意したけど、出来る限り余計なコマンドを実行させないようにしたい（など）
Postmanが便利だなと思い使い方をまとめてみました。

### Postmanを使ってみようと思った理由
実務で外部APIの疎通を確認するときにCurlコマンドを使って確認をおこなっていました。
Postmanという存在はそれまで知っていたが、確認作業が終わった後に、「あれ?Postmanの方が、レスポンス分かりやすかったんじゃないかな?」と思ったところから始まります。個人開発でバックエンドの開発に取り掛かった際に、わざわざブラウザ立ち上げるのも面倒だなと思ったのもあります

### Postmanの何がいいのか?
バックエンドの開発をするときにただバックエンドのレスポンスだけを見たいときに便利。
Postman以外でだと、Chromeの検証ツールかターミナルでcurlコマンドを打ち込むことで可能。
・Chromeの検証ツールの場合はフォームに値を入力しクリックイベントなどでリクエストを送る形になる
・Curlコマンドの場合POSTを送る際一つのコマンドに複数の情報をいれる。

```
curl -X POST -H "Content-Type: application/json" -d '{"Name":"sensuikan1973", "Age":"100"}' localhost:8080/api/v1/users
```
↓コマンドを参考にしたのはこちらです
https://qiita.com/sensuikan1973/items/b2085a9cdc6d1e97e8f8

#### `実際にリクエストを送ってみる`

Node.jsで簡単なAPIを作成しました。

```js
const createError = require('http-errors');
const express = require('express');
const path = require('path');

let datas = [
  {id: 1, title: 'ネーム', completed: true},
  {id: 2, title: '下書き', completed: false}
]
const app = express();
app.use(express.json())

app.get('/data', (req, res)=> {
  return res.json(datas);
});

let id = 2
app.post('/data', (req, res, next) => {
  const { title } = req.body
  if (typeof title !== 'string' || !title) {
    const err = new Error('title is required');
    err.statusCode = 400;
    return next(err);
  }
  const data = {
    id: id += 1,
    title,
    completed: false
  }
  datas.push(data);
  return res.status(201).json(data);
})

app.use((err, req, res, next) => {
  console.log(err);
  res.status(err.statusCode || 500).json({ error: err.message })
})

app.listen(3000);
```
上記コードはハンズオンNode.js(オライリー)のコードをもとに作成しています。

Postmanを開きます
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/3a557eb6-0884-7b80-7b6c-0f24ba2985ae.png' alt='postman1' width='800'>

メイン画面の左上のプラスをクリックするとエンドポイントを入力できる画面が表示されます。
![スクリーンショット 2021-12-22 22.08.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/a142412b-91f0-760f-30a7-1c4b0eea887f.png)
  
エンドポイントの左にHTTPメソッドの指定できるところがあります  
GETを選択しエンドポイントを入力してSendをクリックします
コードのエンドポイントの指定で

```ts
app.get('/data', (req, res)=> {
  return res.json(datas);
});
```
とあるので「localhost:3000/data」をGETメソッドで送ってみます。datasを返すので2つのデータが返ってくるはずです。
![スクリーンショット 2021-12-22 22.13.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/a1d5dade-3336-76d5-449a-d423079e0691.png)

しっかりと2つのデータが配列で帰ってきています。
次はPOSTでデータの追加を行います。
エンドポイントの左のHTTPメソッドをPOSTに変更し、今度は真ん中の領域に少し書き込みを行います。
Headersの部分のKEYに`Content-Type`,VALUEに`application/json`を指定してやります。
Bodyの部分に追加する内容を入力します。コードを見ると、idとcompletedの値は書かれるようになっているので、titleだけを書くようにします。rawの部分に書きます。

```json
{
  "title": "チョモランマ"
}
```
これでSendします。
追加しようとしたデータが表示されています。
![スクリーンショット 2021-12-22 22.16.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/02a01314-5459-d314-f3ed-137fd885541d.png)

ここで再度localhost:3000/dataのGETを確認し、id：3のデータが表示されていれば追加に成功しています。
![スクリーンショット 2021-12-22 22.17.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/1f188749-2500-d90b-238b-048b32ecc5df.png)
OKですね！

Postmanだとより、リクエストとレスポンスの入力出力が見やすいため、APIの開発を行なっているときには頼りになると思います。
GraphQLでのリクエスト、レスポンスも確認できるようです。確認方法がわかったら更新します。
has_one関連付けのbuild_associationメソッドは暗黙的にレコードを削除する

# 環境

- Rails 7.0.0
- Ruby 2.7.5
- MySQL 5.7


# 前提

- user.rb

```ruby
class User < ApplicationRecord
  has_one :item, dependent: :destroy
end
```

- item.rb

```ruby
class Item < ApplicationRecord
  belongs_to :user
end
```

# 解説

ActiveRecordでhas_one関連付けを利用すると、以下のメソッドが追加される。

- `build_association(attributes = {})`

このメソッドはオブジェクトを作成するだけでレコードを保存・更新・削除しないように見えるが、特定の状況ではレコードが削除される。

## 準備

userとそれに紐づくitemを作成する。

```ruby
$ irb(main):001:0> user = User.create!
  TRANSACTION (0.3ms)  BEGIN
  User Create (0.7ms)  INSERT INTO `users` (`name`, `created_at`, `updated_at`) VALUES (NULL, '2021-12-22 13:15:26.923535', '2021-12-22 13:15:26.923535')
  TRANSACTION (1.6ms)  COMMIT
=> #<User:0x00005555bc407cb8 id: 5, name: nil, created_at: Wed, 22 Dec 2021 13:15:26.923535000 UTC +00:00, updated_at: Wed, 22 Dec 2021 13:15:26.923535000 UTC +00:00>

$ irb(main):002:0> user.create_item
  TRANSACTION (0.7ms)  BEGIN
  Item Create (0.8ms)  INSERT INTO `items` (`user_id`, `name`, `created_at`, `updated_at`) VALUES (5, NULL, '2021-12-22 13:15:53.782148', '2021-12-22 13:15:53.782148')
  TRANSACTION (1.6ms)  COMMIT
  Item Load (1.2ms)  SELECT `items`.* FROM `items` WHERE `items`.`user_id` = 5 LIMIT 1
=> #<Item:0x00007f857080e768 id: 12, user_id: 5, name: nil, created_at: Wed, 22 Dec 2021 13:15:53.782148000 UTC +00:00, updated_at: Wed, 22 Dec 2021 13:15:53.782148000 UTC +00:00>
```

## 実際の動作

userがitemを持っている状態で `build_item` メソッドを実行すると、古いレコードが削除される。

```ruby
irb(main):003:0> user.build_item
  TRANSACTION (0.7ms)  BEGIN
  Item Destroy (1.1ms)  DELETE FROM `items` WHERE `items`.`id` = 12
  TRANSACTION (2.5ms)  COMMIT
=> #<Item:0x00007f857045c6d8 id: nil, user_id: 5, name: nil, created_at: nil, updated_at: nil>
```
Dynamics 365 Finance and Operations ~ Power Appsを活用する③ ~

[前回](https://qiita.com/TaichiKayama/items/bbaad4422a287b24059a)は一から画面を作ってみましたが、今日は一からテーブル（Dataverse）を作ってみたいと思います。

シナリオ：FO の発注書に発注追跡情報を補助データとして追加したい

① Dataverse > テーブル > +新しいテーブル
表示名：発注追跡
プライマリ名の列：PO Number ※ FO の PO Number と紐づけることを想定してプライマリ（必須）に。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/7ee506c7-12d6-8599-f65e-dea3ecc0aedd.png)
② +列の追加
メッセージ（テキスト）
緯度（浮動小数点）
経度（浮動小数点）
輸送ステータス（選択肢(複数)）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/16baa4d3-3fe5-afd7-9e8c-33ffcab7979c.png)
③ 何か一行データを作ってみる。大量にある場合は、Excel連携機能を使うと楽。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/d96baccd-f4bc-f68b-f505-af488c6f6201.png)
④ 画面を作る。[データから画面を作る](https://qiita.com/TaichiKayama/items/fff2b69ebef66f67fb62#%E7%B0%A1%E5%8D%98%E3%81%AB%E4%B8%80%E8%A6%A7%E6%96%B0%E8%A6%8F%E7%99%BB%E9%8C%B2%E7%B7%A8%E9%9B%86%E3%81%AE%E7%94%BB%E9%9D%A2%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)で、今作ったDataverseの「発注追跡」テーブルを指定。とりあえず画面作りは[これを](https://qiita.com/TaichiKayama/items/bbaad4422a287b24059a)パクる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/b7ce2e72-a520-982b-e9ce-f93060818776.png)
⑤ そして FO の 発注書画面に埋め込む。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/24499c6f-7c34-dab2-d55e-a6f8e582d610.png)
Amazon Quicksightで文字オブジェクトを作成する

# はじめに
AWSが提供しているBIツール、Amazon QuicksightはAWSに保管してあるデータとシームレスに連携できて便利なBIツールです。
ただ、タイトル文字の自由度が低く、メリハリをつけづらいので、ただグラフを並べるだけになってしまってUXが低下してしまいがちです。

なんですが、少しトリッキーな方法を使うことで、Quicksightでも自由な文字オブジェクトを作成・配置することができますので、紹介したいと思います。

# 手順
まず、左上の「＋追加」から「インサイトを追加」を選びます。

![Untitled(5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/917e8dfe-2b81-4fea-ffa2-24a58ef0eea0.png)

次に「計算タイプ」を選ぶ必要があるのですが、これは何を選んでも構いません。
インサイトがエラーにならないようにディメンションを選ぶ必要があるので、「一意の値」などを選択しておくと、ディメンション選択が楽だと思います。インサイトを作成したら「カテゴリ」に任意の項目を選んでください。
「時間」と「値」は空のママでOKです。

![スクリーンショット 2021-12-22 21.45.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/cec108ca-ebf7-1be7-caab-7a068839c936.png)

次にインサイトを選んで、三点リーダーから「説明をカスタマイズ」を選びます。

![Untitled(6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/f3fbedde-6b05-0854-b9ee-5b630ca68b30.png)

もともと入っている説明があるので、これらは一旦すべて削除します。

![スクリーンショット 2021-12-22 21.50.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/18827636-3aa1-a735-827d-d553492f1443.png)

その上で、タイトル文字を書きます。
「ラージヘッダー」を選んで文字サイズを大きくしたり、背景色をつけることもできます。文字の余白などは設定できないので、左右に余白を作りたい場合はスペースをいれて作ってください。文字の設定ができたら保存します。

![スクリーンショット 2021-12-22 21.55.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/3ef0ca4c-4e5b-d6ae-2157-a9e67408e8cb.png)

「インサイト」というタイトルが出てしまっているので、歯車アイコンから「タイトルを表示」のチェックを外します。
これで完成ですが、テーマがClassicのままだとインサイトのボックスの境界線が見えたままになるので、背景を白にしてボーダーを見えなくしたテーマにすることをオススメします。

Classicテーマでの表示
![スクリーンショット 2021-12-22 21.57.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/aa962659-1613-1bf6-143d-75a86b2a6fa5.png)


テーマ変更後の表示
![スクリーンショット 2021-12-22 21.58.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23578/1c8f2e15-e7fd-a1ba-42cb-38b7a0bdca7a.png)

# さいごに
いかがでしょうか。
BIツールの雄、Tableauほどリッチにはできないですが、こういった見出しを作ることで視認性は大きく上がります。
AWSも<a href='https://aws.amazon.com/jp/about-aws/whats-new/2021/11/amazon-redshift-serverless/' target='_blank'>Serverless Redshiftが提供</a>されたり、<a href='https://aws.amazon.com/jp/blogs/news/create-stunning-pixel-perfect-dashboards-with-the-new-free-form-layout-mode-in-amazon-quicksight/' target='_blank'>Quicksightでフリーレイアウトができる</a>ようになったりと日々進化しているので、文字オブジェクトの機能もいつか・・・・！と期待しております。

それでは！
透明かつ不透明が成立する : opaque, transparent, referencial transparency, referentially opaqueの意味と違い

純粋関数型プログラミング言語ではOpaque Data Typeも全て純粋関数なので常に参照透過性があるそうだ。([詳細はこちらの記事が詳しい](https://kazu-yamamoto.hatenablog.jp/entry/20090627/1246135829))
透明なのに不透明というのが面白くて言葉の意味を調べてみた。


#### 透明: transparent
> transparentは、物事が舞台裏で自動的に行われるという意味で（つまり、コードやプログラムのユーザーが対話する必要がないという意味で）、隠されるという意味

#### 不透明: opaque
> 不透明な型という言葉は、C/C++では特定の意味を持っており、**宣言されているがまだ定義されていない型**を意味する

出典: [stackoverflow:What do "transparent" and "opaque" mean when applied to programming concepts?](https://stackoverflow.com/questions/17384020/what-do-transparent-and-opaque-mean-when-applied-to-programming-concepts)


#### 参照透過性: [referencial transparency (wikipedia)](https://en.wikipedia.org/wiki/Referential_transparency)
> プログラムの動作を変えることなく、式を対応する値に置き換える（またはその逆）ことができるものを**参照透過性**と呼ぶ。このためには、**式が純粋であること、つまり同じ入力に対して式の値が同じであり、その評価に副作用がないことが必要**である。

#### 参照不透明性[^1]: [referentially opaque (wikipedia)](https://en.wikipedia.org/wiki/Referential_transparency)
> 参照透過性のない式は**参照不透明性[^1]**と呼ばれます



#### [Opaque data type (wikipedia)](https://en.wikipedia.org/wiki/Opaque_data_type)
> 具体的なデータ構造がインターフェースで定義されていないデータ型のこと。このデータ型の値を操作するには、不足している情報にアクセスできるサブルーチンを呼び出す必要があるため、情報の隠蔽が行われる。データ型の具体的な表現はユーザーから隠されており、目に見える実装は不完全です。不透明なデータ型は、抽象的なデータ型を実装するために頻繁に使用される。

[^1]: referentially opaqueに一般的な訳語はなさそうだがDeepLは”参照不透明性”と翻訳していた


### 常用の訳語

[opaque](https://ejje.weblio.jp/content/Opaque)
> 不透明な、光沢のない、くすんだ、はっきりしない、不明瞭な

[transparent](https://ejje.weblio.jp/content/transparent)
> 透明な、透き通る、目の透いた、ごく薄い、平明な、わかりやすい、明白な、見え透いた、率直な、気取らない

[referential](https://ejje.weblio.jp/content/referential)
> 参考の、参照の、参考用の、参照付きの


### ScalaのOpaque type
Scala3の新機能の一つには[Opaque type aliases](https://docs.scala-lang.org/scala3/book/types-opaque-types.html)があり、略してOpaque Typesと呼ばれています。
実態は拡張メソッドを実装するもので、Scala2のimplicit classと値クラス(AnyVal)による実行時のオーバーヘッドを無くす仕組みを合わせたもののシンタックスシュガーです。
値クラスによる実行時のオーバーヘッド解消では、コンパイル時のみ型チェックを行い実行時には型がない状態になるのでパターンマッチではつかえません。
そういう前提で考えると、opaque(不透明)=「宣言されているが定義されていない」という元の意味とつながり、普通のtype aliasがtransparentで対になっているように思えます。
【バーチャルキャスト】物体を相対的な距離と姿勢を維持したまま別の物体に追従させる 

# したいこと
子となる物体（動画中の青い立方体）を掴み自由に位置や姿勢を動かして離したら、親となる物体（赤い立方体）との相対的な位置と姿勢を維持したまま追従させたい。

https://twitter.com/S4heno/status/1470393933536849932

つまりこんな感じです。
**バーチャルキャストではSubItem同士が親子関係になれない** らしいので、一工夫必要らしい。

# 想定する読者
少しでもバーチャルキャストのVCIを作ったことがある方。
VCIとは、luaとはという説明はありません。
このコード自体の説明もありません！

# Unityでの設定

* 空のGameObjectを作成し、「VCI Object」を付ける
* その子にCubeを2つ作成する
* Cubeの一つを「Red」、もう一つを「Blue」という名前にする（ご自身のコードに合わせてください）
* 2つのCubeに「Box Collider（Is Trrigerオン）」「VCI Sub Item（Grabbableオン）」「Rigidbody（Use Gravityオフ、IS Kinematicオン）」を付ける
* わかりやすいようにCubeの色を変えたり掴みやすいように大きさを調整する

# コード

```main.lua
---変数の設定
---2つのCubeの情報を格納する
red = vci.assets.GetSubItem("Red")
blue = vci.assets.GetSubItem("Blue")

---相対位置、相対姿勢を初期化
dist = Vector3.zero
roat_r = Quaternion.identity
roat_b = Quaternion.identity

---追従させるかどうかのフラグ
trace = false

---全ユーザーで毎フレーム呼び出し
function updateAll()
    ---追従させるとき
    if trace == true then
        ---コピペなのでよくわからない
        ---Redの現在の位置（Vector3）を取得する
        ---Redの現在位置を取得
        local pos_red = red.GetPosition()

        ---Redの現在の姿勢（クォータニオン）を取得
        local roat = red.GetRotation()

        ---RedとBlueの相対位置（Blueを離した時点で決定）をRedの位置に加えるとBlueの位置になる
        local offset = roat * roat_r * dist
        local pos_blue = pos_red + offset
        blue.SetPosition(pos_blue)
        
        ---相対姿勢の追従
        blue.SetRotation(roat * Quaternion.Inverse(roat_b))
    end
end

---物体を離した時に呼び出し
function onUngrab(target)
    ---ターゲットがBlueの時のみ動作
    if target == "Blue" then
        ---Blueを離した時のBlueとRedの相対位置
        dist = blue.GetPosition() - red.GetPosition()

        ---これはよくわからない
        roat_r = Quaternion.Inverse(red.GetRotation())

        ---Blueを離した時のBlueとRedの相対姿勢、のはず
        roat_b = Quaternion.Inverse(blue.GetRotation()) * red.GetRotation()

        ---Blueを離したら追従を開始するのでtrue
        trace = true
    end
end

---物体を掴んだ時に呼び出し
function onGrab(target)
    ---ターゲットがBlueの時のみ動作
    if target == "Blue" then
        ---掴んでいる時は追従させないのでfalse
        trace = false
    end
end
```

# なぜこうなるのかはわからないけど予想


```
roat_b = Quaternion.Inverse(blue.GetRotation()) * red.GetRotation()
```
一回これでRedとBlueの相対的な姿勢を取得して

```
red.GetRotation() * Quaternion.Inverse(roat_b)
```
毎フレームこれでBlueのRedとの相対的な姿勢を計算しているということなのでしょうが

![無題243_20211222215612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394509/7f088597-c1e2-8474-b4e7-0f2f77461447.png)

ベクトルっぽく考えてRedの逆クオータニオンにBlueのクオータニオンを足したら二つの姿勢の差になると思ったのですが……。

https://learn-unity.12px.com/docs/basic/type/quaternion/

例えばこちらのサイトを参考にすると、RedのクオータニオンにBlueの逆クオータニオンを足すと差になるように思えます。
何が違うのやら……。

数学わからないのでほぼ総当たりだったのは内緒

# 参考サイト
バーチャルキャストやVCIのこと
https://virtualcast.jp/wiki/top

位置の追従のこと
https://qiita.com/toRisouP/items/1fe5f7397089cfb83153

クオータニオンのこと
https://learn-unity.12px.com/docs/basic/type/quaternion/

本当にありがとうございました。