OmniAICreator/Qiita-1.07M huggingface dataset:
【GORM】セッションを維持して別処理を呼び出す

共通処理を呼び出してテーブル更新するAPIをGo言語で実装していたときに、共通処理含めてロールバックする方法を作りました。
GORMガイドでは、トランザクションの説明はあるものの、処理をまたいだロールバックについては記載されていないようなので、記事としてまとめてみました。

## 環境

Golang 1.14.4

##  例題

図書館のシステムに、
「利用者が本を借りたとき、利用者の所持数を加算し、書架テーブルの貸出中フラグを1に更新する」処理があったとする。
この処理をコードで表すと以下の通り。


```go
func bookRent() error {
    // リクエスト情報を受け取る。今回は割愛して固定値で指定する。
    userID := 1
    bookID := 23

    // DB接続用の情報を設定する。    
    DBMS := “mysql”
    CONNECT := “root:mysql@tcp(localhost:3306)/testDB”
    db, err := gorm.Open(DBMS,CONNECT)
    if err != nil {
        return err.ERROR()
    }

    // セッションを開始する。
    tx := db.Begin()

    // 予期せぬエラー時のロールバックを行う。
    defer func() {
        if r := recover(); r != nil {
            tx.Rollback()
        }
    }

    // 利用者の貸し出し冊数に加算する。
    var user model.User
    if err := tx.Model(&user).Where(“user_id = ?  AND delete_flg = 0”, userID).Update(“rental_count”, gorm.Expr(“rental_count + 1”)).Error; err != nil {
        tx.Rollback()
        return err.ERROR
    }

    // 蔵書に対して、貸し出し中フラグを「1:貸し出し中」に更新する。
    var liblary model.Library
    if err := tx.Model(&liblary).Where(“book_id = ? AND delete_flg = 0”, bookID).Update(“rental_flg”, 1).Error; err != nil {
        tx.Rollback()
        return err.ERROR
    }

    // すべての更新処理が終わったら、コミットを行う。
    tx.Commit()

    return nil
}
```

この処理に対し「貸出中フラグを更新する処理を共通化し、共通化処理を呼び出す形で実装したい」という課題が出た。
この時、正常にロールバックが機能する実装方法を考える。

##  解決方法

共通処理の引数に、セッション情報を持たせる。

```go

// rentalBoook は、対象となった本を一括で貸し出し中に更新する共通処理です。
func rentalBook(tx *gorm.DB, bookIDs ...int) error {
    // 蔵書に対して、貸し出し中フラグを「1:貸し出し中」に更新する。
    var liblary model.Library
    if err := tx.Model(&liblary).Where(“book_id IN (?) AND delete_flg = 0”, bookIDs).Update(“rental_flg”, 1).Error; err != nil {
        tx.Rollback()
        return err.ERROR
    }

    return nil
}
```

もともとの処理であるbookRentは、以下のように修正する。（変更箇所近辺のみ抜粋）

```go

    // セッションを開始する。
    tx := db.Begin()

    // 予期せぬエラー時のロールバックを行う。
    defer func() {
        if r := recover(); r != nil {
            tx.Rollback()
            return err.ERROR()
        }
    }

    // 利用者の貸し出し冊数に加算する。
    var user model.User
    if err := tx.Model(&user).Where(“user_id = ?  AND delete_flg = 0”, userID).Update(“rental_count”, gorm.Expr(“rental_count + 1”)).Error; err != nil {
        tx.Rollback()
        return err.ERROR()
    }

    // 共通処理を呼び出して、貸し出しフラグを「1:貸し出し中」に更新する。
    bookErr := rentalBook(tx,[]int{bookID}...)
    if bookErr != nil {
        // 共通処理側でロールバックしているので、こちらではロールバックしない。
        return bookErr.ERROR()
    }

    // すべての更新処理が終わったら、コミットを行う。
    tx.Commit()
```

共通処理を呼び出した際のロールバックについては、呼び出し元の処理で行うか、共通処理側でやるかという問題があると思います。
共通処理で問題が発生し次第ロールバックしたほうが安全だと思うので、上記の例ではそう記載しています。
CentOSでRabbitMQ+PHPを試す

PHPで非同期処理を導入するために、RabbitMQを試した際のメモ。
※この記事ではCentOS7、PHP7.3を使用しています。

# MQの準備
## RabbitMQインストール
```
yum --enablerepo=epel -y install rabbitmq-server
systemctl start rabbitmq-server
systemctl enable rabbitmq-server
```
## ユーザ追加
```
rabbitmqctl add_user mquser password
rabbitmqctl list_users
```
## バーチャルホスト追加
```
rabbitmqctl add_vhost myhost
rabbitmqctl list_vhosts
```
## パーミッション設定
```
rabbitmqctl set_permissions -p myhost mquser ".*" ".*" ".*"
rabbitmqctl list_permissions -p myhost
```
# PHPプログラムの準備(送信側&受信側)
## phpライブラリインストール
```
yum -y install --enablerepo=epel,remi-php73 php php-bcmath composer
```
## composerインストール
※一般ユーザにて実施

```
cd
mkdir mq
cd mq
composer require php-amqplib/php-amqplib
composer install
```
# 送信側
## 送信アプリ作成
```
vi send_msg.php
```
```
<?php
require_once __DIR__ . '/vendor/autoload.php';

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('127.0.0.1', 5672, 'mquser', 'password', 'myhost');

$channel = $connection->channel();
$channel->queue_declare('Hello_World', false, false, false, false);

$msg = new AMQPMessage('Hello RabbitMQ World!');
$channel->basic_publish($msg, '', 'Hello_World');
echo " [x] Sent 'Hello_World'\n";

$channel->close();
$connection->close();
?>
```
## 送信
```
php send_msg.php
```
# 受信側
## 受信アプリ作成
```
vi receive_msg.php
```
```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('127.0.0.1', 5672, 'mquser', 'password', 'myhost');
$channel = $connection->channel();

$channel->queue_declare('Hello_World', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {
    echo " [x] Received ", $msg->body, "\n";
};

$channel->basic_consume('Hello_World', '', false, true, false, false, $callback);

while(count($channel->callbacks)) {
    $channel->wait();
}
?>
```
## 受信
```
php receive_msg.php
(CTRL+Cで停止)
```
Azure Functions v3の.Net Core デプロイをAzure DevOpsのPipelinesで行う方法

# はじめに

Azure Functionsではデプロイセンターから自動でPipelineの作成を行う機能がありますが、.Net Core 3.1用のPipelinesは自動生成できなかっため(2020年8月時)Azure DevOps上で作成する必要があります。
ここではAzure Functions v3向けのPipelinesの作成手順を記載します。

## 開発環境

- Windows 10
- Visual Studio 2019
- .Net Core 3.1

## Azure Functionsの作成
Azure PortalでAzure Functionsを作成します。
Azure Functions v3にするにはランタイムスタックを「.Net Core」、バージョンを「3.1」とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/4a7a5a23-cc03-4f56-3987-e0a2d4c2da7b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/dbc8fe0d-2471-39f2-ad52-c02597c8d9f9.png)

## Azure DevOpsのプロジェクト作成
Azure DevOpsで任意のプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/3acb0287-4427-573d-5b72-deb8c54a9a07.png)


## コードの作成
Visual StudioでAzure Functionsのプロジェクトを作成します。
今回はHttpトリガーの関数で作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/1461c1ec-ace3-63ac-1118-2543030e375d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/f2e9b684-1f61-85a2-bbc0-1c6a1edfcbe6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/88de947d-02b2-9963-c79c-cc92bc0c986c.png)

GitでAzure DevOpsのプロジェクトにリポジトリをpushしてソースコードが共有されていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/b104379a-68b4-a579-2e77-67fdd6d6f352.png)


## Pipelinesの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/767dd8f5-e566-5d27-16d9-1d25d9de797d.png)
Azure Repos Gitを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/cb6addb0-85e0-e888-8c99-beefdcf2eb17.png)
Functionsのソースコードがあるリポジトリを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/508dc80d-6edf-2678-2d77-c3f843c91db5.png)
.Net Core Function App to Windows on Azureを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/9139e03e-ea20-353b-dc96-8007c0c9c1d0.png)
対象のAzure Functions Appを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/25862f5c-cbe4-a7bd-d161-d0a458a81192.png)
YAMLが自動生成されるので、Save and runを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/7633e69a-9509-ecd6-8e71-59f38703002a.png)
commitの情報を書く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/2d3cb369-43c1-aec3-2622-8a5475e72f2c.png)

実行するとFunctionsの関数に関数が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/99d25768-93a0-5109-f77c-b77677224e6d.png)

## まとめ
Pipelineでは.Net CoreのAzure Functions向けテンプレートが存在するためそれを使いましょう。
もともとは別のやり方でを紹介するつもりだったのですが、もっと楽な方法があることが知れたので良かったです…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648805/e7ace198-c799-032a-82bb-72938a834406.png)
django rest framework で pngファイルをgetで受け取る方法

django　templateで開発した後にcomponentsを使ってspa開発をすると
色々うまくいかなくてかなり大変ですね。。。

今回はdjango✖️spaを使ってgetで受け取る時に詰まった箇所の備忘録を書きます。

```view.js
class AuthInfoGetView(generics.RetrieveAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = User.objects.all()
    serializer_class = AccountSerializer

    def get(self, request, format=None):
            return Response(data={
            'username': request.user.username,
            'icon': request.user.image,
            },
            status=status.HTTP_200_OK)
```

このようなget関数を使って特定のアカウントのイメージファイルを指すと

'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte

とエラーが出ます

これは、imageファイル自体を指す事であってimageファイルまでのpathを指すことができていないので、エラーが出てしまっています。


なので

```
'icon': request.user.image,
```
を

```
'icon': request.user.image.url
```

に変えると動きました。
warning: http.sslcapath has multiple values エラー

# 背景
gitの設定値の sslCAPathの設定中に `warning: http.sslcapath has multiple values` が発生して設定がうまくできない場合

# 原因

エラーメッセージ通り複数のsslcapathが設定されている場合にエラーとなる。

複数あるか確認

```
git config -l | grep ssl
http.sslcapath=/Library/xxx/somecacert1.pem
http.sslcapath=/Library/xxx/somecacert2.pem
```

# 解決策
unset-allする。

```
# いい例
sudo git config --unset-all --system http.sslCAPath
```

普通にunsetしようとしてもうまくできないので注意

```
# ダメな例
sudo git config --unset --system http.sslCAPath
```

# 参考
[Window Git $ git config --global http.proxy warning: http.proxy has multiple values
](https://stackoverflow.com/questions/6529433/window-git-git-config-global-http-proxy-warning-http-proxy-has-multiple-val)
Google Earth Engineで地物の増減

#概要

Google Earth Engineで、地物の増減、計算してみた。

#写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/31f4e1f7-5bcc-b5d6-92d4-9cc37477b6b4.jpeg)


#サンプルコード


```
var pt = ee.Geometry.Point(139.7978, 35.6028);
var collection = ee.ImageCollection('COPERNICUS/S1_GRD').filterBounds(pt).filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')).select('VV');
var before = collection.filterDate('2016-05-01', '2016-07-17').mosaic();
var after = collection.filterDate('2020-06-30', '2020-09-01').mosaic();
Map.centerObject(pt, 12);
Map.addLayer(before, {
	min: -30,
	max: 0
}, 'Before', 0);
Map.addLayer(after, {
	min: -30,
	max: 0
}, 'After', 0);
Map.addLayer(after.subtract(before), {
	min: -30,
	max: 30,
	opacity: 0.5,
	palette: ['red', 'black', 'aqua']
}, 'diff', 1);


```


以上。
MotionBuilder　OpenRealitySDK HISender

#OpenRealitySDK HISender

MotionBuilderのコールバック関数は以下のようにHISenderとHKEventをとる

```C++
void EventXXXX(HISender pSender, HKEvent pEvent)
```

HISenderから発火元のコンポーネントの情報を調べる
https://forums.autodesk.com/t5/motionbuilder-forum/how-to-use-interface-callback-s-hisender-psender/td-p/4158488

pSenderからイベントを送ったコンポーネントを取得するには以下のコードで良い。

```C++
FBComponent* lComp = FBGetFBComponent( (HIObject) pSender ); 
if (lComp && lComp->Is(FBButton::TypeInfo)) {
 // Do stuff
}
```

コンポーネントの名前を取得する例

```C++
FBComponent* lComp = FBGetFBComponent( (HIObject) pSender );
if (lComp) {
  auto name = FBComponentGetName(lComp);
}
```
Shutdown時のタイムアウト時間を設定する

# Shutdown時のタイムアウト時間を設定する

Camelではシャットダウンする前に処理中のExchangeがある場合、300秒のタイムアウトまでは処理を継続するようになっています。
300秒が長い場合はタイムアウト時間を変更します。

以下はSPring XML DSLの場合の設定例です。
タイムアウト時間をデフォルト（300秒）から5秒に変更しています。

```xml
	<bean id="shutdownStrategy" class="org.apache.camel.impl.DefaultShutdownStrategy">
		<property name="timeout" value="5"/>
	</bean>
```

Java DSLの場合は公式サイト（[Graceful Shutdown](https://camel.apache.org/manual/latest/graceful-shutdown.html)）に以下のようにコーディング例が記載されていたのですが、XML DSLの場合の例は見当たらなかったので投稿してみました。

```java
        // give it 30 seconds to shutdown
        context.getShutdownStrategy().setTimeout(30);
```


# 参考

- [Graceful Shutdown(公式サイト)](https://camel.apache.org/manual/latest/graceful-shutdown.html)
2021年のオリンピックによる祝日移動は、まだ本決まりではない

現在は案が出された状態で、2020年のような祝日移動は2021年では決まっていない。

* https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html

秋以降、国会での審議待ち。

![スクリーンショット_2020-09-29_18-33-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/f8c1874a-f9b0-e114-84d9-5e537b7a87a4.png)



## 参考資料

* https://www.kantei.go.jp/jp/singi/tokyo2020_suishin_honbu/kaigi/dai15/gijisidai.html
* https://www.kantei.go.jp/jp/singi/tokyo2020_suishin_honbu/kaigi/dai15/sankou.pdf
* https://www.cas.go.jp/jp/houan/200429/siryou1.pdf

* https://www.nippon.com/ja/japan-data/h00738/
anacondaでmysql-connector-pythonがインストール出来ない対処

#状況
pythonを学習するにあたりanacondaを使用しているが、データベースを使用するためにインストールしようとしたが、エラーが出た

```
% conda install mysql-connector-python
Collecting package metadata (current_repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
Solving environment: failed with repodata from current_repodata.json, will retry with next repodata source.
Collecting package metadata (repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
Solving environment: \
Found conflicts! Looking for incompatible packages.
This can take several minutes.  Press CTRL-C to abort.
failed

UnsatisfiableError: The following specifications were found
to be incompatible with the existing python installation in your environment:

Specifications:

  - mysql-connector-python -> python[version='>=2.7,<2.8.0a0|>=3.7,<3.8.0a0|>=3.6,<3.7.0a0|>=3.5,<3.6.0a0']

Your python: python=3.8

If python is on the left-most side of the chain, that's the version you've asked for.
When python appears to the right, that indicates that the thing on the left is somehow
not available for the python version you are constrained to. Note that conda will not
change your python version to a different minor version unless you explicitly specify
that.
```

詳しくはわからないが、互換性がない？バージョンの指定が必要？などが言われているような気がする。
エラーの内容が詳しくわかる方がいるのなら教えてください。

##対処法
```conda install -c conda-forge mysql-connector-python```
Anacondaはパッケージが少ないため、conda-forgeというチャンネルからinstallした。
pipでもインストール出来そうだが、anacondaとpipを混ぜるのは危険という記事を複数見つけたため、今回は使用しなかった。
(conda > conda-forge > pipの順で探してみるといい気がする。)

###一言
```conda search mysql-connector-python```を実行したときにpkgs/main channelにあるよ！的なことがわかったから、これを入力してもインストールできるのかもしれない

コマンド実行時に複数のパッケージのインストールがされると表示されたが、これがmysql-connector-pythonの使用に必須の物なのか疑問
terminalのショートカットを改良した話

# きっかけ
最近、Terminalをterminatorに切り替えた。デフォルトのCtrl + Alt + Tだと、一々新しいウィンドウが開いて邪魔くさい。オプション使って新しいタブで開くことは出来るが、画面分割で使うのでそれも微妙。
開いてないときだけ新たに開いて、既に開いている場合は最前面に持ってくるだけにしたかった。

# 実装
psからterminatorのプロセスIDを拾ってそれをwmctrlでウィンドウIDに変換してxdootoolで最前面に持ってくるだけ
アプリケーション閉じてもpsにはしばらく残るのでウィンドウidで判定させた。

```{bash}
pid=`ps -A | awk '$4=="terminator" {print $1}'`
wid=`wmctrl -lp | awk -v pid=$pid '$3==pid {print $1}'`

if [ "${wid}" = "" ]; then
    terminator
else
    xdotool windowactivate $wid
fi
```

これをカスタムショートカットでCtrl + Alt + Tに設定し直す。

# おわり
CentOS8にベータ版php8.0をインストールする方法

#経緯
php8.0が2020年11月26日にリリースされる予定らしい。
[remi氏](https://rpms.remirepo.net/)のリポジトリでもベータ版が出ているのでインストールして動作確認する。

#インストール方法
[百番煎じくらいの、CentOS8でPHP8環境作るコピペ](https://qiita.com/world_of_bear/items/1e72166604b65d24ff51)
[Centos8 php8.0をインストールする方法](https://mebee.info/2020/07/17/post-12973/)
[php80-php-8.0.0~beta4-32.el8.remi.x86_64.rpm](https://centos.pkgs.org/8/remi-x86_64/php80-php-8.0.0~beta4-32.el8.remi.x86_64.rpm.html)

phpの本体を入れる。

```
dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf install yum-utils
dnf --enablerepo=remi install php80-php
```

データベースの接続も試したいのでmariadbを入れる

```
dnf install mariadb-server
systemctl start mariadb.service
mysql_secure_installation
```
phpのモジュールを入れる。

```
dnf install --enablerepo=remi php80-php-mysqlnd php80-php-mysqli php80-php-gd php80-php-cli php80-php-opcache
dnf install --enablerepo=remi php80-php-pecl-zip php80-php-devel php80-php-pear
```

php、pear、peclなどのコマンドはインストールするだけではパスが通らないので、findで探してフルパスで呼び出す。

```
find / -name pear
find / -name pecl
/opt/remi/php80/root/usr/bin/pecl install APCu
/opt/remi/php80/root/usr/bin/pear install Mail_MimeDecode
/opt/remi/php80/root/usr/bin/pear install HTTP_Client
/opt/remi/php80/root/usr/bin/pear install Net_IPv6
```

alternativesを利用してバージョンを切り替えると上品だけど、今回はテストなのでしない。
[複数のバージョンの PHP を切り替えて使う](https://qiita.com/centipede/items/0a5e2f55ec3f66dc6bd9)

httpdとphpを起動。最近はphp-fpmが入るのが普通らしい。

```
systemctl start httpd.service
systemctl start php80-php-fpm.service
```
phpinfo();を実行し「Loaded Configuration File」を調べてphp.iniのパスを確認する。
![php_ini.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563735/2c9ae9fe-e357-6abb-6c94-a5a65474de9f.png)
php.iniに追記。

```php.ini
extension=apcu.so
```
phpを再起動。

```
systemctl restart php80-php-fpm.service
```

#結果
gdやmysqliは異常なし。
OPcacheもapcuも普通に動いてる。
Net_IPv6がFatal errorを吐くので修正。

```/opt/remi/php80/root/usr/share/pear/Net/IPv6.php
# 806行目付近
#            $ip{$pos} = '_'; #修正前
            $ip[$pos] = '_'; #修正後
```
GAE(Python3) Cloud NDBを使用して登録・更新・取得を行う。

# 今回の目的
GAE(Python3)でCloud NDBを使用してデータの登録更新・取得を可能にします。
基本的に[githubのサンプル](https://github.com/GoogleCloudPlatform/python-docs-samples)を使用します。
今回はpython-docs-samples\appengine\standard_python3\building-an-app\building-an-app-2のモジュールを
ベースに作成しています。

# requirements.txtの修正・インストール
プロジェクト直下のrequirements.txtに以下を追記します。

```txt:requirements.txt
google-cloud-ndb
```
追加後、プロジェクト直下のディレクトリで以下コマンドで実行し、google-cloud-ndbをインストールします。

```sh
pip install -r requirements.txt
```
これでCloud NDBのインストールが完了です。

# データの登録・更新・取得処理の作成
今回は単純なデータ登録更新取得処理のモジュールを作成します。
以下の内容です。

```py:main.py
import datetime
from flask import Flask, render_template
from datastore import user

app = Flask(__name__)

@app.route('/')
def root():
  # テストユーザの登録または更新
  user.putData('test')
  # テストユーザの取得
  selectUsr = user.get('test')
  return render_template('index.html', user=selectUsr)


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080, debug=True)
```

```py:datastore/user.py
import datetime
from google.cloud import ndb

#ユーザ情報
class User(ndb.Model):
  # 最終ログイン日時
  lastLoginDt = ndb.DateTimeProperty()

client = ndb.Client()

#ユーザ登録・更新
def putData(idStr):
  with client.context():
    user = User(
      id=idStr,
      lastLoginDt = datetime.datetime.now())
    user.put()

#ユーザ取得
def get(idStr):
  with client.context():
    return ndb.Key(User, idStr).get()
```
classで項目を設定します。
ユーザ登録・更新、ユーザ取得はwith client.context():配下で実施します。
今回は単純ですが、データがなければ登録あればログイン日付を更新する処理を記載しています。

```html:templates/index.html
<!doctype html>
<html>
<head>
  <title>Sample</title>
  <script src="{{ url_for('static', filename='script.js') }}"></script>
  <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>

  <h1>Sample</h1>
  <h2>{{ user.lastLoginDt }}</h2>
</body>
</html>
```
登録更新したログインユーザのログイン日時が表示されることを確認します。

以下を実行します。

```sh
python main.py
```
http://127.0.0.1:8080/ を確認します。

![2020-09-23_02h38_58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/2c48a982-55c3-db59-1551-6273720c18e3.jpeg)
ログイン日時が確認できました。
データストアを見てみます。
![2020-09-23_02h40_00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/4be55932-bb92-2c38-cfd1-0c4c1d02c9ee.jpeg)
データが登録されていました。
![2020-09-23_02h41_49.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/27d7e70e-73a9-1d26-dbe9-bfe1cd1e96de.jpeg)
再度アクセスすると日時が更新されていることを確認できました。

なんだかあまりうまくできなくて時間が結構かかったので、記載しておきます。

今回はここまでです。

ありがとうございました。
【JavaScript】Mapの値を配列に変換する

#はじめに
Mapで格納した値のvaluesのみを抽出して配列に変換したい時に使えるTipsです。

#一般的な方法
```index.js
const sampleMap = new Map();
sampleMap.set(1, 'a');
sampleMap.set(2, 'b');
const values = Array.from(sampleMap.values());
// ["a", "b"]
```

#スプレッド演算子を用いた方法
```index.js
const sampleMap = new Map();
sampleMap.set(1, 'a');
sampleMap.set(2, 'b');
const values =[...sampleMap.values()];
// ["a", "b"]
```
HTMLにおける相対パスの開発環境と本番環境での違いをなんとかする

#相対パスとは
相対パスは、HTMLにおいてはそのファイルからみた相対的な位置を表現したパスであり、要は同じフォルダにあるファイルなどを参照するのに使われます。
しかし、常にこれが同じになるとは限らず、かつ開発時と本番時を揃えるのが面倒くさい時にはなんとかしないといけません。
HTMLでは相対パスは`base`タグで決められます。JavaScriptでは`document.baseURI`で取得できます。
しかし`document.baseURI`は読み取り専用です。
#相対パスを変更する。
`base`タグを利用すれば相対パスを変更できます。なんでか知らないですが`document.baseURI`では変更できないので、`base`タグにid属性をつけて`href`属性を変更することで相対パスを変更できます。
この際にスクリプトなどは再読み込みされるようなので、パスが変更されることによって別のスクリプトが動作することになったりする可能性があります。

```javascript
document.querySelector("#base").href=location.href;
```
AirPods Proの加速度センサーの値を取得する【iOS14】

# はじめに
皆さんは，AirPods ProのSpatial Audioと呼ばれる空間オーディオ再現技術試しましたか？
臨場感がすごいですよね．

SpatialAudioは，AirPods Proに搭載されている加速度センサーやジャイロスコープを用いて音場をリマップして，，，
みたいなことをしているらしい．

iOS14からCoreMotionの中にCMHeadphoneMotionManagerが追加され
簡単に取ってこれることがわかったのでちょっと調べてみました．

**2020/10/1 更新： 一部内容に誤りがあったため修正しました．**

# いるもの
Xcode : 12.0+
iOS   : 14.0+
AirPods Pro


# Info.plistに使用目的を記述
CoreMotionを使うのでInfo.plistにさくっと追加
![スクリーンショット 2020-09-23 0.58.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/7ac4ff49-eba1-8f65-c0f7-95eadf1ddcc3.png)

# 実装
```swift
import UIKit
import CoreMotion

class ViewController: UIViewController, CMHeadphoneMotionManagerDelegate {

    //AirPods Pro => APP :)
    let APP = CMHeadphoneMotionManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        APP.delegate = self

        guard APP.isDeviceMotionAvailable else { return }
        APP.startDeviceMotionUpdates(to: OperationQueue.current!, withHandler: {[weak self] motion, error  in
            guard let motion = motion, error == nil else { return }
            self?.printData(motion)
        })
    }
    
    func printData(_ data: CMDeviceMotion) {
      print(data.attitude)            // 姿勢 pitch, roll, yaw
      print(data.gravity)             // 重力加速度
      print(data.rotationRate)        // 角速度
      print(data.userAcceleration)    // 加速度
      print(data.magneticField)       // 磁気フィールド　磁気ベクトルを返す
      print(data.heading)             // 方位角
    }

}
```
上記のコードでは，AirPodsを繋いでいたり，何も接続していない時など諸々の処理をする必要がありますが，
実行すると標準出力に取得してきたデータが出てくることがわかります．

![A.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/0639cda2-7aaa-a89e-7063-1e8fc32ad174.gif)
# おわりに
今回は，AirPodsProの加速度センサの値を取得する方法を書きましたが，
今回取得できたデータを綺麗に整形してゴニョゴニョして使えば，頭の向きだけを使用したゲームが作れたりするんだろうなと感じました．
また,ARグラスを作っているなど噂もありますので今後どうなっていくのか期待ですね．

今回のプロジェクト+αを[GitHub](https://github.com/tukuyo/AirPodsProMotionSample)に上げておきました
さくっと試したい方はクローンして使ってみてください．

夜中に調べて作ったのでいろいろ間違いがあると思いますので，
間違いや改善点があればコメントで教えてください．



# 参考文献
 - CMHeadphoneMotionManager | Apple Developer Documentation  
https://developer.apple.com/documentation/coremotion/cmheadphonemotionmanager
WEB画面、代表的なテストパターンについて


新卒1、2年目又はIT業界1、2年目向けに投稿。

# 目次 #

・テストパターンを作る意味・重要性
・前提条件
・テストパターン例
・テストパターンの失敗例
・おわりに

##テストパターンを作る意味・重要性　##
自分が作成したプログラムのテスト、又はテスターとしてテストを行う際
テスト不足での確認漏れを防ぐために、マトリクス図等を作り必要なテストパターンを網羅する
必要がある。

テスト不足が原因で、システム運用時にエラーが多発すると自分の評価が下がることにも
繋がってしまう。

WEB画面のテストの内、代表的なテストパターンを記載していく。


## 前提条件
**仕様を理解する**
仕様書を確認して、仕様の内容を理解すること。
場合によっては仕様書の作成者に、仕様について確認する必要あり。

**使用するテストデータの前提条件確認**
「この項目は数値以外想定しない」「この項目は小数のみ許容している」等の
前提条件はテストパターン作成前に確認する事。不要なテストを行わずにすむ。

##テストパターン例
　
**①必須チェック**
入力状態・未入力状態の2パターンでテストを行う。
例：会員登録画面の「名前」という項目に対して、入力・未入力でテストを行い
　　未入力の場合、エラーが発生するか確認。

**②最大文字数チェック**
 最大文字数・最大文字数+1の2パターンでテストを行う
例：最大文字数が10文字の項目の場合、10文字・11文字で
　　入力して、11文字の場合エラーが発生するか確認。

**③文字種チェック**
仕様書の記載に基づいて、半角文字、全角文字、数字、整数、小数等のテストを行う
例：仕様書に「半角文字のみ入力可能」と記載されている項目の場合、半角文字以外にも
　　全角文字、数字を入力して、エラーが発生するか確認。

**④フォーマットチェック**
特定のフォーマットでのみ入力OKな項目の場合、そのフォーマット・フォーマット以外の
2パターンでテストを行う
例：メールアドレスのテストを行う場合、「メールアドレスのフォーマット」
　「メールアドレスのフォーマットではない」2パターンを入力して
　「メールアドレスのフォーマットではない」パターンの場合、エラーが発生するか確認

**⑤境界値チェック**
「〇〇以上」・「〇〇未満」のテストを行う際、境界の値を入力する
例：0～19の入力、20～39の入力で表示されるメッセージボックスが変わるかどうかの
　　テストを行う場合、19と20を入力して、メッセージが変更されるか確認。

**⑥組み合わせチェック**
入力値等、与える条件の2つ以上のテストを行う
例：商品一覧画面で「ID」「名前」「値段」でソートする事ができる場合下記の組み合わせで
　　検索を行う。
　　・IDと名前　・IDと値段　・名前と値段

**⑦DBの存在チェック**
一覧画面等、DBからデータを取得して画面に表示させる仕様の場合
DBのデータを削除した後の動作を確認する。
例：商品一覧画面からカートに入れるボタンを押下してカートに入れる仕様の場合
　　一覧画面を表示している状態で商品Aのデータを削除。その後に
　　商品Aをカートに入れようとして、エラーが発生するか確認。

##テストパターン失敗例

テストパターンを作成する際のよくある失敗パターンを、自分の体験を元に3点
上げていく。

**①異常系のテスト実施不足**
代表的なパターンは、数値のみを許容している入力項目に対して文字を入力した場合や
一覧画面等に表示されている商品のデータがデータベース上から削除された時の
動作等、異常を引き起こすパターンが不足している

システムの運用が始まり、お客様がシステムを触り始めると、システムを開発した人が予想していない
動作が行われることは少なくない。

ユーザー目線でシステム開発、及びテストを実施する事が必要。

**②不要なテストパターン作成**
テストパターンに漏れがないよう気を使いすぎると、不要なテストパターンを作ってしまうこと
がある。

テスト完了日は決められているので、そこから逆算して
テストパターンを取捨選択する必要がある。
テストパターン不十分はNGだが、あえて外す事も必要。

**③必要なテストパターン不足**
②とは逆に、テストパターン不十分で失敗するケースがある。これは
3ケースの内、一番やってはいけない失敗。

経験が浅いうちは、自分が作成したテストパターンを上司に確認してもらうのがベター。
そこから必要なテストパターンは何なのかを学んでいく。


##終わりに

・本稿の内容はIT業界が長い人にとっては当たり前のことだと思います。
　IT業界1、2年目向けだと思っていただければ。
・初めて投稿するので、文章が稚拙だと思います。指摘などがあれば
　遠慮なくコメントにお書きください。
NUXTJS公式のS3とCloudFrontを使用してAWSへデプロイするには？をdocker-composeで実行する

# はじめに
公式ドキュメント内の`S3 と CloudFront を使用して AWS へデプロイするには？`をdocker-composeで簡単にデプロイする方法をまとめたいと思います。

[(公式ドキュメント)S3 と CloudFront を使用して AWS へデプロイするには？](https://ja.nuxtjs.org/faq/deployment-aws-s3-cloudfront/)

AWS(S3,CloudFront)の設定については[こちら](https://qiita.com/h-matsufuji/items/969bcacf8bb72ecc7108)を参考に作成してください。

# 1.ファイル構成
```
nuxtapp/docker-compose.yml
nuxtapp/Dockerfile
nuxtapp/deploy.sh
nuxtapp/gulpfile.js
```

※`deploy.sh`と`gulpfile.js`は公式の手順通り作成してください。

# 2.Docker化に必要なファイル準備


```Dockerfile:Dockerfile
FROM node:12.18.3-alpine3.9
RUN apk add --no-cache openssh bash python make
RUN npm install -g gulp
RUN npm install --save-dev gulp gulp-awspublish gulp-cloudfront-invalidate-aws-publish concurrent-transform
```



```yml:docker-compose.yml
version: '3'

services:
  node: &app_base
    build: .
    # tty: true
    working_dir: /var/www
    volumes:
      - .:/var/www
    environment:
      PORT: 3000
      HOST: 0.0.0.0
  install:
    <<: *app_base
    command: npm ci
  dev:
    <<: *app_base
    ports:
      - "3000:3000"
    command: npm run dev
  generate:
    <<: *app_base
    command: npm run generate
  dev_static:
    image: httpd
    volumes:
      - ./dist:/usr/local/apache2/htdocs/
    ports:
      - "80:80"
  s3deploy:
    <<: *app_base
    command: ./deploy.sh
```

`docker-compose.yml`は[こちら](https://qiita.com/h-matsufuji/items/2a26050c4c1026d2b7e0)の記事をyarnからnpmに変更し、コンテナに手動でインストールしていた手順をDockerfileで準備したものです。


# 3.使用方法

各コンテナは必要に応じで`docker-compose.yml`に定義してください。

## アプリの開発環境起動
```
$ docker-compose up dev
```
コンテナ内部で`npm run dev`を実行します。

## 静的ファイル生成

```
$ docker-compose up generate
```
コンテナ内部で`npm run generate`を実行します。
出力結果はデフォルトだとnuxtapp/distに出力されます。

## 出力された静的ファイルのローカルでの動作確認
```
$ docker-compose up dev_static
```
ローカルでTomcatコンテナでdistを公開します。
http://localhostにアクセスするとアプリを確認できます。

## デプロイ
```
$ docker-compose up s3deploy
```
コンテナ内で`deploy.sh`を実行します。


公式の手順の成功イメージ通りになれば完了です。
【Android】ContentResolverのinsertがnullになる場合

# ContentResolverのinsertがnullになる
そのファイルが存在しているのにinsertをかけようとすると返り値がnullになります。

```
val values = ContentValues().apply{
    put(MediaStore.Images.Media.DISPLAY_NAME, "hoge.jpg")
    put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/fuga")
    put(MediaStore.Images.Media.MIME_TYPE, "image/jpg")
}
val uri = contentResolver.insert(
    MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
    values
)
Log.d("log",uri.toString())
---
2020-09-19 22:23:48.688 29801-29801/com.example.sample D/log: content://media/external_primary/images/media/7173
2020-09-19 22:23:50.858 29801-29801/com.example.sample D/log: null
```

# idを取得してupdateする
insertしてnullだった場合、そのファイルを検索してidを取得し、そこからUriを作成してupdateなりdeleteなりよしなにすればOKです。
1. query
2. Uri.withAppendedPath
3. update

```
contentResolver.query(
  MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
  null,
  "${MediaStore.Images.Media.DISPLAY_NAME}=?",
  arrayOf("hoge.jpg"),
  null)?.use{
    if(it.moveToNext()){
      val id = it.getColumnIndexOrThrow(BaseColumns._ID)
      val uri = Uri.withAppendedPath(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        id.toString()
      )
    }
}
```

# 実ファイルが存在しないのにinsertがnullになる場合
なんらかの契機でたまに発生します。MediaStoreのdeleteではなく、ファイルマネージャ等から削除するとか・・・？
MediaStoreのDBにおそらくレコードが残ってしまっていて、実際の状態と不整合を起こしています。

AndroidはMediaScannerがなんらかのタイミングで走り、保存されたファイルをMediaStoreのDBに登録しています。（＝フォトから見れるようになる）
なので、こうなってしまった場合は端末を再起動するか、しばらく時間を置くと自然と治っている事が多いです。
Basemapでハマった記録


これでエラーが出た

```py
from mpl_toolkits.basemap import Basemap
ModuleNotFoundError: No module named 'mpl_toolkits.basemap'
```

これを入れてみた

```
!pip install mpl_toolkits
!conda install -y basemap
```

またエラーが出た

```
KeyError: 'PROJ_LIB'
```

環境変数が必要みたいなので、以下のコードを丸ごとコピーしてjupyterに貼った

```py
import os
import conda

conda_file_dir = conda.__file__
conda_dir = conda_file_dir.split('lib')[0]
proj_lib = os.path.join(os.path.join(conda_dir, 'share'), 'proj')
os.environ["PROJ_LIB"] = proj_lib

from mpl_toolkits.basemap import Basemap
```

無事に直りました！

こちらを参考にしました
http://hirotaka-hachiya.hatenablog.com/entry/2019/01/27/220047
AndroidStudioでアプリHelloWorld+ライブラリ作成


# 概要
AndroidStudioでアプリHelloWorld、ライブラリ作成してHelloworldAppからライブラリ内関数を呼ぶ。

# 環境
前の記事と同様

# メモ
https://developer.android.com/studio/projects/android-library.html
https://github.com/TechBooster/AndroidSamples

# 本文
普通にHelloWorld作成する。Add New Moduleでライブラリを作成する。
その後、build.gradle(Module:app)のdependenciesタグに次を追加する。

 <font color="HotPink">
    implementation project(":AARPlugin")  </font>　

```

dependencies {
    implementation project(":AARPlugin") //！！！！

    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}


```
kaggleのビットコインの1分足データからN分足データを生成

#お気持ち
Kaggleにビットコインの約定データが挙げられてました
https://www.kaggle.com/mczielinski/bitcoin-historical-data

ビットコインの大規模な過去約定データは今としては結構貴重なような気がします
(bitflyerは1ヶ月前までしか取得できなくなったんだっけ)

機械学習なら1分足で十分かもですが、個人的に1分足以外のデータを見たいのでN分足に直せるプログラムを作りました

#コード
甘えと妥協の産物

```python:rosoku.py
import pandas as pd
import numpy as np
import datetime

#N分足のデータに加工
N=15

#任意の日付以降を加工する
date_from=int(datetime.datetime(2016, 1, 2, 0, 0, 0).timestamp())

df=pd.read_csv("bitstampUSD_1-min_data_2012-01-01_to_2020-09-14.csv")
df=df[2000000:] 
#↑これより前はデータが欠損してると思う　Timestampの数字とlen(df)のつじつまが合わない
#まあ昔すぎてあっても意味ないと思う
df=df.iloc[(date_from-df.iloc[0,0])//60:]

#nan埋め nanの原因はおそらくその1分間に取引がなかったため
def remove_nan(df):
    #dfにappendするんじゃなくて、listを作ってからdfにする方が速かった
    temp=[[] for i in range(len(df.columns))]
    
    for i in range(len(df)):
        if np.isnan(df.iloc[i,1]):
            temp[0].append(df.iloc[i,0])
            temp[1].append(temp_price)
            temp[2].append(temp_price)
            temp[3].append(temp_price)
            temp[4].append(temp_price)
            temp[5].append(0)
            temp[6].append(0)
            temp[7].append(temp_wprice)
        else:
            temp_price=df.iloc[i,4]#欠損値を埋める用のデータ取得
            temp_wprice=df.iloc[i,7]#こっちも
            for c in range(len(df.columns)):
                temp[c].append(df.iloc[i,c])
    data={}
    for col_name,col_value in zip(df.columns,temp):
        data[col_name]=col_value
    
    tempdf=pd.DataFrame(data,columns=df.columns)

    return tempdf

#N分足にする
def rosoku_N(df):
    newdf=pd.DataFrame(columns=df.columns)

    temp=[[] for i in range(len(df.columns))]
    
    for i in range(len(df)//N):
        temp[0].append(df.iloc[i*N,0])
        temp[1].append(df.iloc[i*N,1])
        temp[2].append(max(df.iloc[i*N:i*N+N,2]))
        temp[3].append(min(df.iloc[i*N:i*N+N,3]))
        temp[4].append(df.iloc[i*N+N,4])
        temp[5].append(sum(df.iloc[i*N:i*N+N,5]))
        temp[6].append(sum(df.iloc[i*N:i*N+N,6]))
        temp[7].append(sum(df.iloc[i*N:i*N+N,7])/N)
    
    data={}
    for col_name,col_value in zip(df.columns,temp):
        data[col_name]=col_value
    
    newdf=pd.DataFrame(data,columns=df.columns)
    newdf["Timestamp"]=newdf["Timestamp"].astype(int)
    
    return newdf

df=rosoku_N(remove_nan(df))

df.to_csv("BTC_N="+str(N)+"_rosoku.csv")
```

↑のコードの処理は数分くらいで終わると思う
pandasよくわからない　まだ高速化できるかな
でも最初は3日かかる勢いだったから短くできてよかった


素人考えだけど1分足より15分足とかで機械学習した方が結果出るんじゃないかと思ってる
お世話になったMacZip4Winがついに使えなくなったので代替を探した。その名も keka

# TL;DR;
- 色々ツール使ってみたけど、kekaに落ち着いた
- とにかく、シンプル。パスワード保護にも対応してる。(ある無料のツールでは、数字4桁縛りがあってやめた)
- なんと言っても無料かつ、標準で日本語対応なので、うちのメンバーへの説明コストが低い
- いままでありがとうMacZip4Win

# Keka
- https://www.keka.io/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8571/55e8430c-5dd3-e2dd-94a8-845e294598c2.png)

- ダンゴムシかわいい

# まず設定いじる
- windowsで文字化けしないように設定しておく
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8571/07998dad-29b5-bbbf-9b6c-2e5943cdef59.png" width="350">

- 次に、dockに追加しておく
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8571/21fbd2fb-8ae6-80de-da63-bff4384af3a7.png" width="350">

# 使う
- dockのダンゴムシにファイルをD&Dすればよい


# and more.
- 公式のExtractionを利用すれば、システム標準に設定もできる
- 右クリックメニューに追加もできるけど、それはAutomatorつかったひと手間が必要なので、興味のある人はググって
勉強日誌17日目（夜の部）

夜の部開始


正答率　71% (71)

timedatectl set-time "年-月-日 時:分:秒"
システムクロックとハードウェアクロックを設定

pool
複数のNTPサーバを集約した名前を指定

ntpdate pool.ntp.org
タイムサーバ pool.ntp.org から現在時刻を取得するコマンド

tracking
chronycコマンドのサブコマンド、時刻同期の詳細情報

activity
chronycコマンドのサブコマンド、オンライン/オフライン状態のNTPサーバ数

sources
chronycコマンドのサブコマンドで、時刻のソースを表示

server
時刻を取得するNTPサーバを指定。自身はクライアントとしてNTPサーバの時刻に同期する関係

rtcsync
定期的にシステムクロックをハードウェアクロックに反映させるものは

date 月日年月日.秒
システムクロックを設定

正答率　61% (55)

-u
--unit
特定のユニットのログに限定して表示する

_SYSTEMD_UNIT=ログ
journalctlでログを指定

_UNIT=100
journalctlでrootユーザが生成したログ

-r
--reverse
最新のログから出力

journalctl
systemd でユニットが出力するログ

/var/log/journal
systemd-journald のログを永続的に保存させる

journalctl -o json
ログをjson形式で出力

--since
--until
特定の期間のログに限定して表示させる

-b
--boot
特定の起動時のログに限定して表示

sytemd-cat
systemd-journaldのジャーナルファイルに書き込む

systemd.journald
バイナリ形式のジャーナルファイル名

/var/log/wtmp
systemd-journald　デーモンの設定ファイル名

正答率　60%　（72）
/etc/cups
印刷サービスCUPSの設定ファイル

/var/spool/mail
sendmailの受信メール

/var/spool/mqueue
sendmailの送信メール

lpr
レガシーな印刷コマンド　印刷ジョブ登録、指定したファイルを印刷
Blender2.8 備忘録 〜オブジェクトをくり抜く〜

※2019年10月にざっくりメモしていたものを自分用のためにも投稿しています。


モディファイアを追加→ブーリアンを使う

演算は差分を選択すればくり抜ける。
ただし適用しないとくり抜けられないので注意。
TCP/IPの動作確認に用いる各種の便利なコマンドたち

TCP/IPに関する設定がコンピューターにうまく反映されているかどうかは、`コンピューターに内臓するコマンド(Windowはコマンドプロンプト、Linuxは何らかのシェル)`で確認することができる。


#コマンドの例

- 「ping」コマンド：指定したコンピューターまでIPで通信できるかどうか確認するコマンドである。


- 「nslookup」コマンドと「dig」コマンド：DNSに名前解決をさせて、DNSが正しく動作するかどうかを確認するコマンドである。


その他、まとめると以下の表になる。

| 確認する項目 | Windowsのコマンド | Linuxのコマンド(いずれか)  　　　      　　　　　|
|:-----------|:------------|:------------|
| 指定コンピューターとIPで通信できるか| ping　コンピューター名| ping　コンピューター名|
| 名前解決が正しく動作するか | nslookup コンピューター名 |dig コンピューター名(*1)<br>dig -x IPアドレス<br>nslookup コンピューター名                    |
| 指定コンピューターまでに経由するルーター | tracert　コンピューター名 |traceroute コンピューター名|
| IPアドレスやMACアドレスの値     | ipconfig / all   |ip a<br>ifconfig -a                 |
| ルーティングテーブルの設定状況  | route print       |ip r<br>route       |


(*1)以外のコンピューター名にはIPアドレスを指定してもよい
アウトプットと単語集

勉強用に作成

## Storage
まずStorageとは、補助記憶装置の総称でHDD,SDD等のことです。
また、IBMのV7000などの同筐体に入れることで同一ディスクとして扱うことができます。


### HSM

### VIOS

### TCP

### powerHA

### BigFix

### HMC

### HULFT

### LPAR

### CBRR

### revoke

### VIOC

### VE

### LPM

### IVM

### NIM

### WIｎSCP

### バイナリーモード

### アスキーモード

### GoldenGate

### フラッシュコピー

### VG

### PP

### jfs2

### smitty

### LUN

### HBA

### RAID

### PV

### TE

### ID払い出し

### N/A

### 公開鍵認証システム

### PVs

### 余裕率

### rootUserを消さない理由

### cron

### NFS

### AIX,TL,SP

### sudo

### PP SIZE

### LPs

### PPs*LPs

### PPs*LPs*PVs

### boot device

### ダンプ

### コアダンプ

### hd8

### NIC

### ACL

### NIM backup

### TFTP

### IPL

### Ansible

### play book

### NIM master

### NIM client

### rootvg

### mksysb

### backup

###
未経験からエンジニア就職するために一生懸命作ったクソアプリを晒していく。

# はじめに
未経験からエンジニアになる方法として、プログラミングスクールに通う人は多いと思います。
ただスクールで作った物を面接で見せても、採用サイドからすると「またそれね。」って感じらしいです。

某有名スクールのなんとかエキスパートだと、メルカリのクローン作りますよね。
僕は実際の面接で、「それの説明はいいよ」って言われました。

就職するためには`プラスアルファでどれだけ勉強したか`が重要となってきます。
ただ、どんなものを作ればよいか悩む人は多いのではないかなと思います。


当時、僕が就職するために作ったクソアプリたちが出てきたので、参考にして頂ければ幸いです。
「あ、こんなのでいいんだ」と就職活動の緊張から開放されることを願っております。


## 経歴

2018年9月〜12月　プログラミングスクール
2019年1月　クソアプリ作り始める
2019年2月　内定が出る
2019年4月　東京で就職


# 作ったクソアプリたち
<font color="Red">※ スマホで動くか微妙です。</font>
## 神になって惑星を消すアプリ

![スクリーンショット 2020-09-22 23.01.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303344/cfe56817-e729-d02d-6e8f-81716ef8086f.png)
惑星の画像が並んでいて、クリックすると惑星が消える。
JavaScriptでクリックした要素をRemoveしてるだけだと思います。
[このアプリのURL](https://taiga-ishikawa.herokuapp.com/day3)

## 目指せホームラン王！！江越大賀の挑戦
![スクリーンショット 2020-09-22 23.01.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303344/ed1a7047-5fdf-8f7c-a4a2-70f1611e6e8f.png)

江越大賀という当たれば飛ぶと言われている選手が阪神タイガースにいて、
その選手がホームラン王になれるのは何年後かを計算するアプリ。

おそらくif文でぐちゃーっと計算してる。

[このアプリのURL](https://taiga-ishikawa.herokuapp.com/day5)

## あいあい傘メーカー
![スクリーンショット 2020-09-22 23.02.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303344/6d2cfd7c-047a-d40f-fb4a-8883c1ec5249.png)
![スクリーンショット 2020-09-22 23.02.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303344/72844923-e8a2-a072-e9a7-a99abeb412c5.png)

二人分の名前を入力したら相合い傘に名前が書かれる。
たしか、全部Railsで作っていて、POSTとか使いたいなと思って作った。

全部上書きで一番上のレコード取得してくるだけの仕様。
文字を縦にするのが難しかった記憶もある。
[このアプリのURL](https://taiga-ishikawa.herokuapp.com/posttests)

## ジョブスの発表会
![スクリーンショット 2020-09-22 23.03.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303344/cbd68a60-59f0-8df9-9429-c506d462acb8.png)

ジョブスが発表したっぽい画像を作るアプリ。
入力した文字の画像を生成できる。
Canvasに文字を入れるだけなんだけど、今見たら日本語に対応してなかった。
テキストエリアの文字消してもCanvasから消せなかったから、「TextReset」っていうボタンを付けたみたい。
「CreateImage」押したら下に、画像が貼付けされる。

[このアプリのURL](https://taiga-ishikawa.herokuapp.com/day10)

## おのののかを探せ
![スクリーンショット 2020-09-22 23.04.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303344/059db1c3-397e-4d71-bf95-572299790e83.png)

「おのののか」っていう文字列を探すアプリ。
本当のランダムに生成していなくて、一列分の「おのののか」っぽい文字列を配列で登録しておいて、
それを並び替えているっぽい。

[このアプリのURL](https://taiga-ishikawa.herokuapp.com/day11)

## その他
[他にも色々ありました](https://taiga-ishikawa.herokuapp.com/app)のでよかったら見てみてください。
# 結論
誰がどう見てもクソアプリでした。
でも、コレ見せて就職できたのだから作ることって大事なんだと思います。

質はともかくとりあえず作ってみるのが良いです。

# 自己紹介
今更ツイッタはじめました。
よかったらフォローしたり、質問してください。

[ツイッター](https://twitter.com/taigahavefun)←こちら
文字列配列を長さ&五十音順にソートする(Elixir)

# はじめに
- @tsukada_cs さんの[文字列配列を長さ&五十音順にソートする](https://qiita.com/tsukada_cs/items/85c36e0f1ca2518cc4e4)を拝見しまして、私は[Elixir](https://elixir-lang.org/)でやってみました
    - タプルの比較について理解を深めることとなりました
- `IEx`でやってみます
- [Elixir](https://elixir-lang.org/)は`1.10.4`を使っています
- 一瞬どうやってやればいいのかわからなかったのですが、[Python](https://www.python.org/)で書かれた元の記事を参考に書いてみることで同じ結果が得られました

```elixir
iex> words = ["にほん", "あめりか", "ろしあ", "ふらんす", "いたりあ", "ちゅうごく", "しんがぽーる", "おーすとらりあ", "たい", "ちり", "どいつ", "いぎりす"]

iex> Enum.sort_by(words, fn word -> {String.length(word), word} end)  
["たい", "ちり", "どいつ", "にほん", "ろしあ", "あめりか",
 "いぎりす", "いたりあ", "ふらんす", "ちゅうごく",
 "しんがぽーる", "おーすとらりあ"]

iex> Enum.sort_by(words, &({String.length(&1), &1}))                
["たい", "ちり", "どいつ", "にほん", "ろしあ", "あめりか",
 "いぎりす", "いたりあ", "ふらんす", "ちゅうごく",
 "しんがぽーる", "おーすとらりあ"]
```

- タプルの比較とは何だろうと思って調べたところ、こちらにさらっと記載がありました
    - [Comparison operators](https://hexdocs.pm/elixir/operators.html#comparison-operators) 
  
> The collection types are compared using the following rules:
> - Tuples are compared by size, then element by element.

サイズが大きいものが大きい、サイズが同じなら各要素の比較になるよ(先頭から決着がついたらそれが比較結果さ)と言っています。

## 例
```elixir
iex> {0, 0, 0} > {10000000}
true

iex> {1000000000} > {-1, -1}
false

iex> {0, -100} > {-1, -1}         
true
```

# Wrapping Up
- タプルの比較を学びました :tada::lgtm::tada::lgtm::tada::lgtm: 
- Enjoy [Elixir](https://elixir-lang.org/)!!! :rocket::rocket::rocket:
Xcode11→12にしてSimulatorでRunしたらMach error -308 - (ipc/mig) server diedと出た話

起こった環境

1. macOS Catalina 10.15.6
2. 元のXcode 11.7
3. 新しいXcode 12.0



# エラー発生から解決までの経緯

## ことの始まり

 Xcode12がReleaseされたので使ってみたいけどちょっと不安だから今までのXcodeも残そうと思い、

ダウンロードしてきたXcode_12.xipを解凍して、Xcode12.appにリネームしてアプリケーションフォルダに突っ込む。

それからXcode12を起動してテキトーなプロジェクトでTargetをiPhone11のSimulatorにしてRun!

Simulatorが起動するもXcodeのウィンドウ内上方にダイアログが出て、

**"The operation couldn’t be completed. (Mach error -308 - (ipc/mig) server died)"**

と表示され。ナンノコッチャと。

ちなみに手持ちのiPhone11実機ではふつうにRunできました。



## 試したこと

###  "Command CompileSwift failed with a nonzero exit code" error."とも出ていたのでそっち中心で最初調べていました。

1. Clean Build Folder(shift⌘K、shift⌘⌥K) … **変化なし**
2. /Library/Developer/Xcode/DerivedDataの削除…**変化なし**
3. Xcodeの再起動…**変化なし**
4. Macの再起動…**変化なし**



### Mach error -308 - (ipc/mig) server died 方面で調べてみる

1. ファイアウォールをオフにしてみる…**変化なし**

2. Xcode Command Line Toolsを入れ直す

   ``` bash
   $ sudo rm -r /Library/Developer/CommandLineTools
   ```

   してから

   ```bash
   $ xcode-select --install
   ```

   変化なしどころかインストール失敗。[Apple Developer](https://developer.apple.com/download/more/)からCommand Line Tools for Xcode 12をダウンロードしてきてインストール。

   それからMac再起動…**変化なし**

   

# 諦めかけたその時！

**/Library/Developer/PrivateFrameworks/CoreSimulator.framework を削除**して
**Xcodeをもう一度起動してダイアログが出て、指示に従ってコンポーネントを追加**してみた…





# うごいた !

無事にXcode12でもSimulatorが使えるようになりましたとさ、めでたしめでたし。

同じようなエラーで悩んでいる方の一助となりますように

## 参考にさせていただいたところ

[Mach error -308 - (ipc/mig) server died](https://developer.apple.com/forums/thread/82197)

[Cannot run application on simulator after installing Xcode 11 - CFBundleVersion error](https://stackoverflow.com/questions/56450295/cannot-run-application-on-simulator-after-installing-xcode-11-cfbundleversion)
Turbolinks : link_toで遷移した時にリロードしないとJSが上手く表示されない問題を解決したい

## 目次
1. [はじめに](#はじめに)
2. [JSの表示を邪魔するのは・・・](#jsの表示を邪魔するのは)
3. [Turbolinksって何者？](#turbolinksって何者)
4. [解決策](#解決策)
5. [最後に](#最後に)

## はじめに

現在、ポートフォリオを作成中であり、
その中でJavaScriptを用いたカレンダー機能を実装していたのですが、

**link_toからカレンダーページに遷移した際に、
１度リロードしないとJavaScriptが適用されない問題が生じた**ので、

この辺の原因を明確にして、記録を残そうということでこの記事を執筆しています。
本記事は、プログラミング初心者によるものであることをご了承ください。


## JSの表示を邪魔するのは・・・
ずばり、**Turbolinks**です。
コイツのせいで、頑張って書いたJSが遷移先で表示されないのです。

このように考えると何だか憎たらしいヤツに思えてきちゃいますが、
色々調べていると、実は良いヤツらしい。

良いヤツなんだけど、たまに余計なお節介をして、
うっかり我々の大事な大事なJSを隠してしまうようです。

Turbolinks、意外と憎めないやつかもしれない。
ってことでもっと知りたくなってきましたね(無理矢理)。

てなわけでもう少し詳しく見ていきます。


## Turbolinksって何者？

Turbolinksとは、リンククリックに対して、ページ遷移を自動的にAjax化してくれるライブラリです。

①aタグをクリックすると、遷移先のページをAjaxで取得する

②その取得したページが要求するCSSやJSが、現在のページのものと同じである場合、titleやbodyのみ(画面の一部だけ)を置き換える

というのがTurbolinksの主な仕組みです。


####Turbolinks導入のメリット
Turbolinks導入の最大のメリットは、**画面表示を高速化**してくれることです。

通常であれば、リンクをクリックすると、指定されたページに遷移するため、その分時間がかかりますが、Turbolinksを導入している場合、**ページの遷移は行われず、Ajaxにより画面の一部だけを更新する仕組み**になっているので、結果的に読み込みに時間がかからず、ページの表示が高速化するというわけです。

サイトを見ている側からすると、少しでも待たされる時間をなくしたいわけですから、
TurbolinksはUXを向上させる救世主って感じですね。

何だ、やっぱり良いヤツじゃん:laughing:
最初から導入されているってことは、それなりに便利で使えるからなんですよね。


とは言いながらも、どんなに良いヤツでも、時と場合によっては煩わしく感じてしまうものです。

####Turbolinks導入のデメリット
Turbolinks導入のデメリットは、**JSやCSSの適切な表示を妨げてしまう場合がある**ことです。

メリットのところで、Turbolinksは画面の一部だけを更新させると説明しましたが、
この仕組みこそが、JavaScriptが上手く反映しない問題を生じさせていると言えます。
上記で、Turbolinksを用いると、**ページの遷移は行われず、Ajaxにより画面の一部だけを更新する**事になると述べました。

**ブラウザのページ遷移が行われていないので、JavaScriptのイベントが発火せず**、結果的にJavaScriptが上手く反映しないというわけです。

これが噂のTurbolinksの余計なお節介ってやつか。なるほど。

##解決策
Turbolinksを導入しつつ、必要なところではそれを無効化し、
何とかJavaScriptの動作を上手く反映させたい。

そういう人向けに、どうやら2つの解決策があるみたいです。

####① Turbolinksが提供するイベントを追加
JSファイルに、Turbolinks専用のイベント``turbolinks:load``を追加することでJSを正常に動作させます。

```test.js
document.addEventListner('turbolinks:load', function() {
  console.log('Loaded');
});
```


####② 特定のリンクでTurbolinksを無効化
aタグ(link_to)に``data: {"turbolinks" => false}``を加えることによって、
Turbolinksを無効化し、遷移先に飛ぶようにすることでJSを正常に動作させます。

```test.html.slim
=link_to "テスト", tests_path, data: {"turbolinks" => false}
```



## 最後に
ポートフォリオ作成をきっかけにたまたまTurbolinksを調べることになったわけですが、
調べれば調べる程、まだまだ奥が深そうな感じがしました。
今回は、基本の部分で留めておこうと思いますが、また機会があれば調べてみたいところです。

尚、本記事の内容で間違っている点や不足している点などがありましたら、ご教示いただけると幸いです。

参考：[Railsガイド Turbolinks動作原理](https://railsguides.jp/working_with_javascript_in_rails.html#turbolinks)
　　　[Ruby on Rails 速習ガイド p.340-p.344](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2RTWZ5N8BXF8J&dchild=1&keywords=rails+%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89&qid=1600782175&sprefix=rails+%E5%AE%9F%E8%B7%B5%2Caps%2C249&sr=8-1)
Pythonで2次元チューリングパターンを描く

Pythonで2次元チューリングパターンを陽解法で計算して描画してみました

![2D_Turing_Pattern(1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253018/501d475c-29c2-8dad-cfc4-6d8cb97546a2.gif)


考える系や前提条件などの説明は下記の記事を参照ください。

https://qiita.com/STInverSpinel/items/b9d844c98e63dfe72adc

### 拡散方程式


```math
p(x,y,t+dt)=p(x,y,t)+\Biggl(f(p(x,y,t),q(x,y,t))+\frac{d_p}{dx^2}\Bigl(p(x+dx,y,t)+p(x-dx,y,t)+p(x,y+dy,t)+p(x,y-dy,t)-4p(x,y,t)\Bigr)\Biggr)dt\\
q(x,y,t+dt)=q(x,y,t)+\Biggl(g(p(x,y,t),q(x,y,t))+\frac{d_q}{dx^2}\Bigl(q(x+dx,y,t)+q(x-dx,y,t)+q(x,y+dy,t)+q(x,y-dy,t)-4q(x,y,t)\Bigl)\Biggr)dt
```

ここで、$d_p,d_q$はそれぞれ活性因子、抑制因子の拡散係数。境界条件は周期境界条件を用います。


#### 定数と関数の宣言

```python
import numpy as np
import matplotlib.pyplot as plt

dx=0.04
dt=0.02
N=int(1/dx)

Dp=2*10**-4
Dq=0.01

def f(a,b):
    return 0.6*a-1.0*b-a*a*a

def g(a,b):
    return 1.5*a-2.0*b

def laplacian(v):
    res=np.roll(v,1,axis=0)\
       +np.roll(v,-1,axis=0)\
       +np.roll(v,1,axis=1)\
       +np.roll(v,-1,axis=1)\
       -4*v
    
    return res

```

#### 計算セル
初期濃度にはrand()を使ってある程度の揺らぎを与えておきます。

```python
%%time
p=np.random.rand(N,N,1)*0.01
q=np.random.rand(N,N,1)*0.01

tmax=2000
for i in range(tmax):
    next_p=p[:,:,-1]+dt*(f(p[:,:,-1],q[:,:,-1])+Dp*laplacian(p[:,:,-1])/(dx*dx))
    next_q=q[:,:,-1]+dt*(g(p[:,:,-1],q[:,:,-1])+Dq*laplacian(q[:,:,-1])/(dx*dx))
    p=np.dstack([p,next_p])
    q=np.dstack([q,next_q])
```
CPU times: user 2.47 s, sys: 2.89 s, total: 5.36 s
Wall time: 5.39 s


#### Gif作成用
`%matplotlib nbagg`はJupyter notebook上で動画を表示するために必要です。
容量削減のために10枚ごとに描画しています。

```python
%matplotlib nbagg
from matplotlib.animation import PillowWriter,FuncAnimation

def animate(i):
    clock=dt*i*10
    step=i*10
    plt.cla()
    plt.imshow(p[:,:,i*10],interpolation='nearest',vmin=-1,vmax=1,cmap='jet')
    
    plt.title("t={0:.1f} ,step={1:3d}".format(clock,step))

fig=plt.figure()
plt.colorbar(plt.imshow(p[:,:,-1],interpolation='nearest',vmin=-1,vmax=1,cmap='jet'))

anim=FuncAnimation(fig,animate,repeat=False,frames=200,interval=10)
#anim.save("2D_Turing_Pattern.gif", writer='pillow',fps=10) #Gifを保存する場合はコメントアウトを外す
#plt.show() #Gifを表示する場合はコメントアウトを外す
[UE4C++]BlueprintFunctionLibraryを継承したクラスでUUserWidgetクラスを参照するとビルドエラーになった時の対処

#状況
BlueprintFunctionLibraryを継承したC++クラス
関数の引数に**UUserWidget**のクラスを指定したい
![スクリーンショット (100).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695645/801eb9fb-65e6-5a92-2d2e-fce5235b9a24.png)

ビルドするとリンクエラーが出る
コード：2019
説明：未解決の外部シンボル ○○○ が関数 △△△ で参照されました
![101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695645/d55dfacb-2d96-381d-c57e-a92d51515404.png)

#完成形
![スクリーンショット (101).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695645/8589c70a-84da-270e-2c48-a7b86a0e348b.png)

#解決方法
**Module**を**Build.csのPublicDependencyModuleNames.AddRange**に追加
※Moduleはクラスの公式ドキュメントに記載
※UUserWidgetのModuleは"UMG"
![スクリーンショット (102).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695645/20d9bbf1-0eca-f69b-74ad-eddcff0a0388.png)

#まとめ
私が詰まった問題なので忘れないように記事に残す。
今回の状況以外にもリンクエラーになる場合はあると思う。

#余談
BlueprintFunctionLibrary以外の汎用的なクラス（Actorとか）の継承であればリンクエラーはでなかった。まぁ単純にプログラムの知識の話だと思う。
オンラインでiOSDC参加しました！ 完成度に感動した！

# 0. 概要

オンラインのカンファレンス [iOSDC JAPAN 2020](https://iosdc.jp/2020/) に参加しました。

あまりの完成度に驚き、とても感動しました。
オンラインでここまでの臨場感が出せるものなのかと。むしろ、オンラインならではの臨場感がありましたね。そしてオンラインを活かす数々の施策。
もはや、**すべてのカンファレンスがこの形ならいいのに** と思っちゃいましたね。

何が良かったのかを紹介したいと思います。

# 1. リモートの良さ

## 1-1. 現地に行く必要がない

家に居ながらにして細切れに参加できました。これ、すごいよかった。
何しろ子供ができてからというもの、休日なのに１日家を空けるなど言語道断で家族会議の遡上にもあげづらいものでしたが、時間空いたら参加するというスタンスが取れたので（そして実際は意外と時間取れる）、 **とりあえずチケット購入しておく** という選択が取れましたね。これリアルカンファレンスだったら、参加あきらめてましたね。

## 1-2. トラックのリアル移動が不要

座ったままポチポチでトラック移れる。**席争奪のストレスもない**。すごい快適でした。

## 1-3. 自分のPCで見れる

字が遠くて見えないこともない。PC電源に困ることもない。素晴らしかった。

# 2. 冊子の事前郵送

なんと **ムック本のような100ページ越えの冊子** が届いたのです。
スケジュール表が判りやすい詳細とともに書かれており、これが見やすかった。**紙なので〇付けたりも自由**。

そして何より、けっこう面白い **技術記事** がふんだんに入っているというものでした。
装丁のデザインもかっこいい。
今までリアルなカンファレンスで事前にWebページに技術記事載せたとしてもあまり見なかったし、スポンサーの紹介もほぼ見なかったけど、これは読みましたね（流し読みではありますが）。読みやすかったです。

技術記事うまいですね。いつもはカンファレンス終わったらこの手のものは捨てますが、これは保存しておきたくなるレベルでしたね。
このレベルに仕上げるのは編集相当大変だったと思います。

# 3. 臨場感

オンラインとなれば、ふつうは多少損なわれるものですが、様々な施策が講じられており、リアルカンファレンス以上に臨場感を感じることができました。
主にニコニコ生放送（ドワンゴさん）のノウハウなのかなと思いますが、いくつか紹介します。

## 3-1. オープニングのライブトーク

タイトルをバックに突然、主催者の長谷川さんが横から出てきてしゃべりだすという驚きの演出でした。（しゃべりも面白かった。）
てっきり静止画のスライドが映っていると思っていたので（スライドを背景に特殊効果で重ねているのでしょうけど）、驚いたし、ニコニコ生放送のコメント弾幕もあって、その場にいる錯覚になりましたね。リアルのときって距離を感じるときもありましたけど、これはすごい身近に感じました。

## 3-2. ニコニコ生放送のコメント弾幕

これやっぱりすごいです。普段あまり使ってなかったのですが、ニコニコ、見直しました。ここまで臨場感というか一体感というかが演出できるなんて。
リアルカンファレンスよりずっと臨場感を感じることができましたね。

## 3-3. 登壇者の顔が映っている

トークは基本、録画を流していたのですが、登壇者の顔が電話会議にみたいに小さく映っているんですね（顔ごと録画されている）。これ意外といい感じでした。表情的なものが見えたりして。
コメント流れてても録画だから気づかないのですが、ついリアクションおくっちゃいますね。
なんどもリアルで拍手しちゃいましたよ。

## 3-4. トーク後に登壇者と話せる

トーク後に時間がとって合って、別室(Discordというシステムを使う)で質疑応答できるんですね。
これよかった。聞き入りすぎて、おもわず次のトークに遅刻することも何度かあったりして（＾＾；

# 4. オープニング/エンディングムービー/BGM

もはやできの良さは衝撃レベルでしたね。

画面の動きもかっこいいんだけど、声優にエヴァの　**シンジ君（緒方恵美さん）** と **ミサトさん（三石琴乃さん）** の声の人を起用していて、世代的に胸熱でしたね。（T-T）

**BGMもすごいよかった**。なんか聞いたことないけど、聞いたことあるような。ずっと流れてても聞き飽きず、主張もしてこない。ホントのプロの仕事でしたね。作曲者は誰なんだろう。


# 5. まとめ

世の中のカンファレンス、この形ならいいのにと思いましたね。
これ裏で回している方々ほんとうにすごいと思います。
ほんとに感動しました。