OmniAICreator/Qiita-1.07M huggingface dataset:
sigaction()を用いてSA_RESETHANDの効果の検証

sigaction()にフラグを設定した際の動作についてどう挙動が変わるかについての検証を行なったのでその時のメモ。

#検証環境
Ubuntu 18.04.4
gcc 9.3.0

#SA_RESETHANDを設定した場合
SA_RESETHANDを設定した場合シグナルは、シグナルを捕捉するたびにデフォルトの設定に変更してから、シグナル処理を行う。本来であればSA_RESETHANDを設定しない場合、プロセス実行中はsigaction()で設定された処理が継続して実行される。

※検証のため「act.sa_flags = SA_RESETHAND | SA_RESTART;」をコメントアウトして実行する。

```c:sigaction_demo.c
/* コンパイル: gcc -o sigaction_demo sigaction_demo.c */

#include <signal.h>                                                                                 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define INPUTLEN 100

/* Ctrl+Cで呼び出される処理 */
static void t_handler()
{
  printf("シグナルハンドラが呼ばれました。3秒間スリープします\n");
  sleep(3);
  printf("シグナルハンドラを終了します\n");
}

int main(){
  int   nchars;
  char  input[INPUTLEN]; 
  struct sigaction act;
  act.sa_handler = t_handler;
  /* シグナル捕捉時デフォルト設定に変更 */
  /* 検証としてコメントアウトしている     */
  // act.sa_flags = SA_RESETHAND | SA_RESTART;
  act.sa_flags = SA_RESTART;

  if (sigaction(SIGINT, &act, NULL) == -1) 
    exit(EXIT_FAILURE);

  pause();
}
```

シグナルで割り込みをしてもSIGINTを関数呼び出しにしているため、強制終了させられない。

```bash:実行例
#(CTrl+Cを押す)
^Cシグナルハンドラが呼ばれました。3秒間スリープします
シグナルハンドラを終了します
#(Ctrl+Cを押す)
^Cシグナルハンドラが呼ばれました。3秒間スリープします
シグナルハンドラを終了します
#(Ctrl+\を押す)
^\終了 (コアダンプ)
```

検証用のコメントアウトを外した場合(上記ソースコードを下記のように変更する)
  act.sa_flags = SA_RESETHAND | SA_RESTART;
  //act.sa_flags = SA_RESTART;

```bash:実行例
#(CTrl+Cを押す)
^Cシグナルハンドラが呼ばれました。3秒間スリープします
シグナルハンドラを終了します
#(CTrl+Cを押す)
^C
```

1回目のシグナル捕捉後関数が呼ばれているが、2回目にシグナルを捕捉した時にはデフォルト設定の強制終了に戻っているのがわかる。

###参考資料
・『Linuxプログラミングインタフェース』
・『Unix/Linuxプログラミング理論と実践』
Docker 個人的メモ書き

## コマンドメモ

```bash
## imageの確認
docker images

## プロセスの確認
docker ps
docker ps -a
docker ps -aq

## Dockerfileからイメージをビルドする
docker build ./ -t example

## コンテナを実行する
docker run example

## DockerComposeによるコンテナの起動
## 「-d」はバックグラウンドで起動
## ベースイメージがなければベースイメージの取得からコンテナの起動まで、
## または既にイメージのビルドが済んでいればコンテナ起動だけを行っくれる
docker-compose up -d

## Docker Composeによるサービスの停止
docker-compose stop

## Docker Composeによるコンテナの停止
## ネットワークも削除してくれる
docker-compose down
```

## Windows 環境でのfirewallによるエラー

```bash
docker-sample_redis_1 is up-to-date
Creating docker-sample_web_1 ... error

ERROR: for docker-sample_web_1  Cannot create container for service web: b'Drive sharing seems blocked by a firewall'

ERROR: for web  Cannot create container for service web: b'Drive sharing seems blocked by a firewall'
ERROR: Encountered errors while bringing up the project.
```

## Hello World

[Play with Docker](https://labs.play-with-docker.com/)

[入門 Docker](https://y-ohgi.com/introduction-docker/)

## docker-compose と Docker の対応バージョン

[Compose file version 3 reference](https://docs.docker.com/compose/compose-file/#compose-and-docker-compatibility-matrix)

## Dockerfile 書き方ベストプラクティス

[Dockerfile を書くベスト・プラクティス - Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/engine/userguide/eng-image/dockerfile_best-practice.html)

[Dockerfileってどう書けばいいの？ 書き方ベストプラクティス #docker - クリエーションライン株式会社](https://www.creationline.com/lab/28678)

## CentOS のベースイメージ作成

[Docker向けのコンテナをゼロから作ってみよう | さくらのナレッジ](https://knowledge.sakura.ad.jp/2226/)

## Docs

[Docker入門（第六回）〜Docker Compose〜 | さくらのナレッジ](https://knowledge.sakura.ad.jp/16862/#)

[Dockerイメージの理解を目指すチュートリアル - Qiita](https://qiita.com/zembutsu/items/24558f9d0d254e33088f)

## HandsOn

[Docker for Windowsの基本的な使い方を解説！ | スマホアプリやiPhone/Androidスマホなどの各種デバイスの使い方・最新情報を紹介するメディアです。](https://appli-world.jp/posts/7173)

[[Docker] Windows 10 Pro 64bit に Docker と Docker Compose をインストールする - Qiita](https://qiita.com/ksh-fthr/items/6b1242c010fac7395a45)

[Docker Composeなどの便利なツールでKubernetesをわかりやすくしよう #docker #kubernetes #k8s - クリエーションライン株式会社](https://www.creationline.com/lab/25164)

[[Docker] Docker Compose の導入と環境構築 - Qiita](https://qiita.com/ksh-fthr/items/2b899e3e4c918707afb0)

[Go(Echo) + Vue.js + nginx の環境をDocker Composeで立てる。 - Qiita](https://qiita.com/69incat/items/9bbfbf8566535dc266c6)
Node.jsの基本的な使い方

# プログラミングの勉強日記
2020年6月17日　Progate Lv.122
　Node.jsⅠ
　Webアプリを作るために使われるNode.jsを学んだ。JavaScriptをサーバーサイドで動かす仕組みである。
　今回はNode.jsのフレームワークである<b>Express</b>を扱う。Node.jsには便利な機能を使えるようにまとめたパッケージがあり、Expressはそのパッケージのうちの1つである。

##npm
　パッケージを用意するために使うシステムである。Expressをnpmからインストールするには、`npm install`コマンドを使う。

```:ターミナル(入力したらEnterを押して実行)
$ npm install express
```
　インストールしたExpressを利用するためにはパッケージの読み込みと使用する準備が必要。以下の文は定型文として覚えてOK

```javascript:app.js
const express=require('express'); //expressの読み込み
const app=express(); //expressを使用するための準備
```

##サーバーの起動(listenメソッド)
　サーバーを起動するとサーバーがリクエストを受け取りレスポンスを返すことができる。
　listenメソッドを用意してapp.jsファイルを実行するとサーバーを起動できる。ファイルを実行するためには、`node ファイル名`とする。

```javascript:app.js
//localhost:3000でアクセス可能なサーバーを起動
app.listen(3000);
```

```:ターミナル(app.jsを実行)
$ node app.js
```

##ルーティング
　URLに対応する処理を実行すること。

```javascript:app.js
app.get('/top', ()=>{ //URL「/top」にアクセスしたとき
  //トップ画面を表示
});
```

###reqとres
　ルーティングの処理では`req`(リクエスト)、`res`(レスポンス)の2つの引数を受け取ることができる。
　ルーティングの処理で`res.render`と書くことで指定したビューファイルをブラウザに表示することができる。
　→ブラウザに表示する見た目部分にはEJSという形式のファイルを使い、viewsフォルダに配置する。見た目を作るファイルをビューファイルという。

<img width="398" alt="node1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/6e17f587-c64d-9f8f-9a71-d0495df57e0f.png">

```javascript:app.js
app.get('/top', (req,res)=>{ 
  res.render('top.ejs'); //指定したファイルを画面に表示させる
});
```

##EJS
　Embedded Java Scriptの略で、HTMLのコードの中にJavaScriptを埋め込む(embedded)することができる。EJSはターミナルで`npm install ejs`でインストールできる。

###JavaScriptを利用する
　`<% %>`または`<%= %>`で囲む。`<% %>`で囲むとブラウザには何も表示されない。そのため、変数などの定義などに用いる。反対に変数の値などを表示したい場合には`<%= %>`を使う。JavaScriptを使うことができるので、forEachメソッドなどメソッドも使うことができる。forEachメソッドを使うと、HTMLを直接記述するよりもすっきりと書くことができる。

```index.ejs
<% count item = {id:3, name:"キャベツ"} %>
<p> id : <%= item.id %> </p>
<p> name : <%= item.name %> </p>
```
　この実行結果は、idは表示されないがnameは表示される


##CSSの適用
　ExpressではCSSや画像などのファイルがどこに置かれているかを指定する必要がある。
<img width="696" alt="node2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/86e8d369-918a-2065-994c-6201ba30853d.png">

```javascript:app.js
//publicフォルダ内のファイルを読み込めるようにする
app.use(express.static('public'));
```
```html:top.ejs
<!--public内のパスを指定してCSSを読み込む-->
<link rel="stylesheet" href="/css/style.css">
<!--public内のパスを指定して画像を読み込む-->
<img src="/images/top.eng">
```

##ページ間リンク
　`/`のURLを<font color=orange>ルートURL</font>という。一番初めにアクセスするページはルートURLに設定するのが一般的である。

```javascript:app.js
app.get('/',(req,res)=>{
  res.render('top.ejs');
});
```
リンクボタンを付ける

```:top.ejs(一覧画面へ)
<a href="/index">一覧をみる</a>
```

```:index.ejs(トップ画面へ)
<a href="/">LIST APP</a>
```
Kinx アルゴリズム - エイト・クイーン

# Kinx アルゴリズム - エイト・クイーン

## はじめに

**「見た目は JavaScript、頭脳(中身)は Ruby、（安定感は AC/DC）」** でお届けしているスクリプト言語 [Kinx](https://github.com/Kray-G/kinx)。「プログラム＝アルゴリズム＋データ構造」。アルゴリズムの実装例をご紹介。

元ネタは「C言語による（30年経っても）最新アルゴリズム事典」。今回はエイト・クイーン（一般的には N Queens）です。

* 参考
    * 最初の動機 ... [スクリプト言語 KINX（ご紹介）](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76)
        * 個別記事へのリンクは全てここに集約してあります。
    * リポジトリ ... [https://github.com/Kray-G/kinx](https://github.com/Kray-G/kinx)
        * Pull Request 等お待ちしております。  

最新アルゴリズム事典にはこういうのも結構載ってる。パズル的な。

エイト・クイーンも Kinx の最初のころにサンプルを作り、ちゃんと 92 通りの解が出せるか確認に使った。

## エイト・クイーン

* https://ja.wikipedia.org/wiki/%E3%82%A8%E3%82%A4%E3%83%88%E3%83%BB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3

Wikipedia より
> エイト・クイーンとは、チェスの盤とコマを使用したパズルの名称である。
> チェスの盤上に、8個のクイーンを配置する。このとき、どの駒も他の駒に取られるような位置においてはいけない。

尚、この 8 個を **n 個に拡張** したのが N Queens です。

## ソースコード

```javascript
var a = [], b = [], c = [], x = [];
var solution = 0;

function found(n) {
    System.print("\nSolution %d\n" % ++solution);
    for (var i = 0; i < n; i++) {
        for (var j = 0; j < n; j++)
            if (x[i] == j) System.print(" Q");
            else           System.print(" .");
        System.print("\n");
    }
}

function test(i, n) {
    for (var j = 0; j < n; j++)
        if (a[j] && b[i + j] && c[i - j + n - 1]) {
            x[i] = j;
            if (i < n - 1) {
                a[j] = b[i + j] = c[i - j + n - 1] = 0;
                test(i + 1, n);
                a[j] = b[i + j] = c[i - j + n - 1] = 1;
            } else found(n);
        }
}

function nqueen(n) {
    for (var i = 0; i < n; i++)         a[i] = 1;
    for (var i = 0; i < 2 * n - 1; i++) b[i] = 1;
    for (var i = 0; i < 2 * n - 1; i++) c[i] = 1;
    test(0, n);
}

nqueen(8);
```

## 結果

```
Solution 1
 Q . . . . . . .
 . . . . Q . . .
 . . . . . . . Q
 . . . . . Q . .
 . . Q . . . . .
 . . . . . . Q .
 . Q . . . . . .
 . . . Q . . . .

Solution 2
 Q . . . . . . .
 . . . . . Q . .
 . . . . . . . Q
 . . Q . . . . .
 . . . . . . Q .
 . . . Q . . . .
 . Q . . . . . .
 . . . . Q . . .

Solution 3
 Q . . . . . . .
 . . . . . . Q .
 . . . Q . . . .
 . . . . . Q . .
 . . . . . . . Q
 . Q . . . . . .
 . . . . Q . . .
 . . Q . . . . .

...(省略)

Solution 92
 . . . . . . . Q
 . . . Q . . . .
 Q . . . . . . .
 . . Q . . . . .
 . . . . . Q . .
 . Q . . . . . .
 . . . . . . Q .
 . . . . Q . . .
```

## おわりに

これもほぼほぼ C 言語版ほぼそのままです。

こういうのがちゃんと動くと「うまくいってる感」があって前に進んでる感じがしてました、と当時を思い出す。やっぱり配列要素のアクセスとインクリメント・デクリメントあたりがきちんと動くようになった時が色々できるようになる最初の一歩でしたね。

ではまた、次回。
Express+MySQLでログインする

[前回の記事では](https://qiita.com/4201tosiyuki/items/80ee553ac42eeb323859)ユーザーtestパスワードtestのみのログインユーザーであった為、MySQLにユーザー情報を入れ、そこを参照してログインするを実装した備忘録です。

**各バージョン**

* Node v12.13.1
* express-session 1.17.1
* passport 0.4.1
* passport-local 1.0.0
* mysql 2.18.1
* bookshelf 1.2.0
* knex 0.21.1

では実装手順です。
必要なモジュールをインストールします。


```:terminal
npm install i mysql knex bookshelf
```

前回記事のユーザー名・パスワードをチェックするプログラムです。

```javascript:index.js
passport.use(new localStrategy({
  usernameField:'username',
  passwordField:'password',
  passReqToCallback: true,
  session:false,
},function(req,username,password,done){
  process.nextTick(function(){
    if(username === 'test' && password === 'test'){
      return done(null,username);
    }else{
      console.log('Login Error');
      return done(null,false,{message:'パスワードが正しくありません'});
    }
  })
}));
```

if(username===....のところをMySQLからデータを参照するプログラムに変更します。
実際に運用する場合は、パスワードはハッシュ化すべきでしょうが、今回はやっていません。

```javascript:index.js

var mysql = require('mysql');
var knex = require('knex')({
  client:'mysql',
  connection:{
    host:'localhost',
    user:'root',
    password:'',
    database:'データベース名',
    charset:'utf8',
  }
});
var Bookshelf = require('bookshelf')(knex);
var User = Bookshelf.Model.extend({
//1
  tableName:'users'
});

passport.use(new localStrategy({
  usernameField:'username',
  passwordField:'password',
  passReqToCallback: true,
  session:false,
},function(req,username,password,done){
  process.nextTick(function(){
//2
    var reqName = req.body.username;
    var reqPass = req.body.password;
    
    User.query({where: {username:reqName}, andWhere:{password:reqPass}})
    .fetch().then((model) => {
      if(model){
        return done(null,username);
      }else{
        console.log('Login Error');
        return done(null,false,{message:'パスワードが正しくありません'});
      }
    });
  });
}));

```

//1はユーザーデータがあるテーブル名を指定。
//2は/loginから送られてきたユーザー名とパスワードとデータベースを参照しています。

今回はここまでですが、本来はバリデーションを行ったり、ユーザー名はあってるけどパスワードが違う判定を行ったりするべきだと思いますが、その実装が出来たらまた、記事を書きます。

間違い、指摘がありましたらお願いします。
以上です。

参考文献

[Node.js超入門第２版](https://www.amazon.co.jp/dp/4798055220/ref=cm_sw_r_tw_dp_U_x_L4G6EbFDPWH3P)
【Unity2D】作ったテキストをカメラに合わせて表示する

HierarchyのCreateでUIからTextを選択。
そうするとデフォルトでカメラよりかなり大きいCanvasができてしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308839/f6afda5e-811a-63c3-88e8-30778512bf5c.png)

HierarchyのCanvasを選択し、Rnder Modeを「Screen Space - Camera」にし、Render CameraにMain Cameraをドラッグしてつける。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308839/9ccbfae3-a5f1-65db-8e1a-8c415eebd3f1.png)

そうすると、Canvasがカメラと同じ大きさになる。
confirm.php

<?php require_once('data.php') ?>

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Progate</title>
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
  <link href='https://fonts.googleapis.com/css?family=Pacifico|Lato' rel='stylesheet' type='text/css'>
</head>
<body>
  <div class="order-wrapper">
    <h2>注文内容確認</h2>
    <!-- 変数$totalPaymentを定義し、数値の0を代入してください -->
    <?php $totalPayment = 0; ?>
    
    <?php foreach ($menus as $menu): ?>
      <?php 
        $orderCount = $_POST[$menu->getName()];
        $menu->setOrderCount($orderCount);
        // $totalPaymentに、$menuのgetTotalPriceメソッドで得た値を足してください
        $totalPayment += $menu->getTotalPrice();
        
      ?>
      <p class="order-amount">
        <?php echo $menu->getName() ?>
        x
        <?php echo $orderCount ?>
        個
      </p>
      <p class="order-price"><?php echo $menu->getTotalPrice() ?>円</p>
    <?php endforeach ?>
    <!-- $totalPaymentを表示してください -->
    <h3>合計金額: <?php echo $totalPayment ?>円</h3>
  </div>
</body>
</html>
ラズベリー・パイ入門して調べた単語一覧

ラズベリー・パイに入門して調べた単語の一覧です。
[Raspberry Piのはじめ方] (https://info.nikkeibp.co.jp/media/RAS/atcl/books/013000007/) を読みつつ、足りない部分をwebで補ってメモっています。

# ハードウェア

### 電子パーツ
LDEライトやモーターなど

### 導線
電源と電子パーツをを接続する線。

### 電子回路
電源の＋側から電子パーツを介して、電源のーに戻ってくるよう導線で接続したもの。

### 電荷
電気の元　電荷が集まって電気になる。

### 電気
電荷をもつことによっておこる現象や電荷の移動現象の総称。

電気の活用例: 
**モーター**
鉄しんにコイルを巻いて電流を流すと磁石となる(電磁石)
N極とS極があり、お互いにしりぞけ合おうとする力が生まれる。
モーターはこの磁石の引き合う力を利用する。

**ライト**
フィラメントに電流が流れる時、電子が物質の中でおこす摩擦熱によって2000度以上の高温になると白く光る。

### 電圧
電源から電荷を押し出す力。V（ボルト）で表す。これが強いと流れる電荷の量が大きくなる。水道管に例えると水を押し出す力。

### 電流
ある面を単位時間に通過する電荷の量。A（アンペア）で表す。
一度に流れる電荷の量。水道管に例えるとパイプの太さ。

### クーロン
電荷の単位。
１アンペアで秒間1クローンが流れる。
1クローン = 624億の1億倍の電荷。

### ワット
実際に消費される電気エネルギ。
電圧 V（ボルト） x 電流 A（アンペア） = ワット w

### 抵抗
電気の流れにくさ。単位はオーム（Ω）

### 抵抗器
回路に電荷が流れすぎてショートするのを防ぐ為に使用される。
抵抗器内部で電流が絞られて、回路全体に流れる電流が小さくなる。

### オームの法則
電流、電圧を計算するときに使う公式。
電圧V（ボルト） =  電流 A（アンペア） × 抵抗オーム（Ω）


### ブレッドボード
電子パーツを差し込むだけで接続できる。はんだ付け不要。延長コードのようなものでラズベリーパイのピンを拡張できる基盤。別名プロトタイプ基板

### ジャンパー線
離れた電気回路間をつなぐ役目
ラズベリーパイとブレードボードを繋げる。
ジャンパー線で電子パーツと繋げる。

## ラズベリー・パイ
ラズベリー・パイには役割の違う複数種類の端子が付いている。
https://pinout.xyz/pinout/ground

### GPIO (General Purpose Input/Output)
プログラムからON/OFFを制御できる。
GPIO端子を使用して電子パーツを操作する。

16mAまでの電流しか流せないので抵抗器で調整する必要がある。
http://www.howisit.jp/2016/06/30/rasp-basic/

### Ground (GND)
電池の-側と同じ役割。

### 3.3v Power
3.3vの電源。ラズベリー・パイに電源を入れればプログラムしなくても使用できる。

### 5v Power
5vの電源。ラズベリー・パイに電源を入れればプログラムしなくても使用できる。


# プログラム
pythonのGPIOを操作するライブラリーでメジャーどころ３つ

### gpiozero
https://gpiozero.readthedocs.io/en/stable/
複雑な操作がラップされていて個人的に一番使いやすい。

```python

from gpiozero import LED
from time import sleep

led = LED(18)

while True:
    led.on()
    sleep(1)
    led.off()
    sleep(1)
```

### pigpio
http://abyz.me.uk/rpi/pigpio/python.html

```python

import pigpio
from time import sleep

pi = pigpio.pi() 
pi.set_mode(18, pigpio.OUTPUT) ¥

while True:
     pi.write(18, 1) 
     time.sleep(1)
     pi.write(18, 0) 
     time.sleep(1)
```


### RPi.GPIO

```python

import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
 
while True:
    GPIO.output(18, GPIO.HIGH)
    sleep(1)
    GPIO.output(18, GPIO.LOW)
    sleep(1)
```
StudioLibraryをPythonから操作してみる。【Anim Save編】

StudioLibraryでのアニメーション登録をPythonから操作する方法を紹介します。

製作者様のGitHubにサンプルが公開されているので、まずはこちらを確認して頂くのがオススメです。
https://github.com/krathjen/studiolibrary/blob/master/src/studiolibrarymaya/README.md

# 環境
- python2.7
- maya2019.2
- studiolibrary2.7.1

#Animationの登録
選択しているリグのアニメーションをDドライブにTanuki.animとして保存する場合。

## スクリプト
```python
# studiolibrary2.7.1
import os
import maya.cmds as cmds
from studiolibrarymaya import animitem

path    = os.path.join("D:/studiolibrary/root/dev", "Tanuki.anim")
objects = cmds.ls(selection=True) or []

# Saving an animation item
if objects :
    animitem.save(
        path, 
        objects         = objects, 
        frameRange      = (0, 40),
        fileType        = "mayaAscii",
        thumbnail       = "D:/studiolibrary/image/tibitanu.jpg",
        comment         = "This is Tanuki",
        bakeConnected   = False,
        )
```
## saveで使用するフラグの解説
- path 
 - `str`
 - アニメーションの保存先の指定します。
 - `D:/studiolibrary/xxx/xxx/hoge.anim`
 
- objects
 - `[str, str, str, str]`
 - アニメーションを登録するオブジェクトを指定します。
 - サンプルの実装では`cmds.ls(sl=True)`で選択しているオブジェクトのアニメーションを保存しています。
- frameRange
 - `(int, int)`
 - 登録するアニメーションの範囲を指定します。
 - 数値を指定しない場合は、アニメーションの始まりと終わりが自動的に検出されその値で登録されます。
- fileType
 - `str` 
 - 作成されるMayaファイルの保存形式を指定します。
 - `MayaAScii`もしくは `mayaBinary`
- thumbnail
 - `str` 
 - サムネイルに使用する画像のファイルパスを指定します。
 - `D:/studiolibrary/image/tibitanu.jpg` 
 - 登録時に.animフォルダに画像がコピーされ`thumbnail.jpg`という画像が自動生成されます。
- comment
 - `str` 
 - コメントです。
- bakeConnected
 - どういう機能なのか分からなかったのでOffにしています。分かり次第追記。 


## 実行結果
実際に動かすとこんな感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79407/d96c5b95-f223-f2d8-8604-d36984c45295.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79407/09f90d18-4808-091c-d281-9a2be3d4074a.png)
ちびたぬはいいぞ

## studiolibrary2.5.7より前のバージョンの場合
studiolibrary2.5.7より前のバージョンを使っている場合は書き方が少し異なります。
一度itemをインスタンス化する必要があるので注意しましょう。

```python
# studiolibrary2.5.7
import os
import maya.cmds as cmds
from studiolibrarymaya import animitem

path    = os.path.join("D:/studiolibrary/root/dev", "Tanuki.anim")
objects = cmds.ls(selection=True) or []

item = animitem.AnimItem(path)

# Saving an animation item
if objects :
    item.save(
        objects         = objects, 
        frameRange      = (0, 40),
        fileType        = "mayaAscii",
        bakeConnected   = False,
        )
```

----

次回はPythonを使ったStudioLibraryでのアニメーション読み込み方法を書きます。
クラウド・インフラ技術を学んでいくためにAWSを始めてみた（その４：インフラ運用・S3,CloudFront活用）

#はじめに

　今回で４回目のクラウド・インフラ技術編です。
　
　前回、`TCP/IP`等ネットワーク通信の基礎についておさらいしました。今回は`S3`及び`CloudFront`を用いて画像配信サービスを作ることをまとめました。

　今回も参考にしたサイトはこちらです。

+ [AWS：ゼロから実践するAmazon Web Services](https://www.udemy.com/course/aws-and-infra/)

##インフラ設計において重要な観点

　`S3`及び`CloudFront`を活用した画像配信サービスを考え前に、インフラ設計の考え方を整理します。

　下記に図で簡単にまとめています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567823/69e5cc19-3e4e-1e34-d055-0c4a3de380a3.png)


　インフラ構築は、運用保守しやすく安定稼働させることが重要なポイントです。そのための項目は５つあります。

+ 可用性
+ 運用保守性
+ セキュリティ
+ 性能・拡張性
+ 移行性


となります。

　今回はこの中から性能拡張性を高める目的で、`S3`及び`CloudFront`による画像配信についてまとめます。


##S3及びCloudFrontによる画像配信

###S3とは

 `S3`とは`AWS`のサービスの一つです。Simple Storage Serviceの略称となります。

　クラウド型のオブジェクトストレージサービスです。オブジェクトストレージとは、オブジェクト（ファイルなど）単位で出し入れが可能なストレージです。

　`S3`へ画像の保存を行うことのメリットとしては下記が挙げられます。

+ Webサーバーのストレージ容量不足を防ぐ
+ `HTML`へのアクセスと画像アクセスを分けることで負荷分散
+ サーバーの台数を増やしやすくする
+ コンテンツ配信サービスから配信することで、画像配信を高速化

次に、重要概念を三つまとめます。

+ バケット：オブジェクトの保存場所
+ オブジェクト：データ本体、`URL`が付与
+ キー：オブジェクトの格納`URL`パス

実際に`S3`を使うべきシーンについて例が下記です。

+ 静的コンテンツ（画像）の配信
+ バッチ連携用のファイル置き場：バッチは定期的に実行するプログラム
+ ログなどの出力先：定期的に`S3`にログを送る
+ 静的ウェブホスティング


###CloudFrontについて

　次に、`CluodFront`についてです。

　`CloudFront`はAWSにおける`CDN`(Contents Delivery Network)サービスです。コンテンツファイルをサーバー（今回では`S3`）から直接配信せず、`CDN`を介してユーザーに配信します。
　
　メリットとしては、

+ サーバーの負荷軽減
+ ネットワークレイテンシ（遅延時間）の削減

等が挙げられます。

　今回は、`S3`と`CloudFront`を使って以下のような構成で構築したいと思います。
　元々は、`WordPress`上に画像を保存していたものを、`S3`へ格納＋`CloudFront`で配信する形にしたいと思います。ネットワークの構成としては下記となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567823/f5a8da6d-1746-78d2-871c-cc754dbcfe53.png)

###Certificate Manager について

　`Certificate Manager`とは、`AWS`におけるサービスで`SSL/TLS`証明書を簡単に作成、管理できるようにするものです。

　`SSL`サーバー証明書は、Webサーバーの持ち主が実在していることを証明書です。

 `HTTPS`通信をする際に必要となってきます。



#終わりに

　画像の配信と高速化についてまとめました。システムのリスク分散という観点でも重要な技術であると感じました。
【Go】fmt.Errorf("%w %s", err, `実行してる箇所`)でスタックトレースをログに出すという案


# はじめに

Go言語にて

__Before (Issue)__

```go
if err != nil {
    return err
}
```
だけしてる場合は出力結果が例えば

```
cause of error in repo
```

このようにエラーメッセージだけ出力され、エラー箇所が分かりづらい問題があるあるだと思います。

__After (One of solutions)__

後述のWrap関数を使い、スタックトレースを取りたい各エラー箇所を`return Wrap(err)`にするだけで、下記のようなスタックトレースを付けて出力することができます。

```
cause of error in repo /tmp/sandbox244131559/prog.go:27 main.repo
 /tmp/sandbox244131559/prog.go:39 main.service
 /tmp/sandbox244131559/prog.go:49 main.handler
```

# 環境

* go version go1.14.2 darwin/amd64

# 実装

以下のコードで説明します。

下記のコードは __[こちらの Go Playground 上](https://play.golang.org/p/JMh8kvRwqoP)__ で試せます。

```go
package main

import (
	"errors"
	"fmt"
	"runtime"
)

func Wrap(err error) error {
	if err == nil {
		return err
	}

	// スタックトレースの取得
	pc := make([]uintptr, 1)
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
	s := fmt.Sprintf("%s:%d %s\n", frame.File, frame.Line, frame.Function)

	// スタックトレースを含めてWrapして返す
	return fmt.Errorf("%w %s", err, s)
}

func repo() error {
	err := errors.New("cause of error in repo")
	return Wrap(err)
}

type serviceError struct {
	error
	code int
}

func service() error {
	err := repo()
	if err != nil {
		return &serviceError{
			error: Wrap(err),
			code:  10,
		}
	}
	return nil
}

func handler() error {
	err := service()
	if err != nil {
		return Wrap(err)
	}
	return nil
}

func main() {
	err := handler()
	if err != nil {
		fmt.Println(err)
		/*
			cause of error in repo /tmp/sandbox818611801/prog.go:27 main.repo
			/tmp/sandbox818611801/prog.go:39 main.service
			/tmp/sandbox818611801/prog.go:49 main.handler
		*/
	}

	var e *serviceError
	if errors.As(err, &e) { // Unwrap
		fmt.Println(e)
		/*
			cause of error in repo /tmp/sandbox334532468/prog.go:27 main.repo
			/tmp/sandbox334532468/prog.go:39 main.service
		*/
	}
}
```

## 解説

`Wrap(err error) error`関数は

* オリジナルのエラーを受け取り、
* `実行してる箇所`をruntimeパッケージを使って取得し、
* fmt.Errorfの`%w`オプションでスタックトレースを付けてオリジナルのエラーをラップして返します。

runtimeパッケージを使ったスタックトレース取得の内容の詳細は下記になります。

0. `pc := make([]uintptr, 1)` は スタックトレース1つ分を確保
0. `n := runtime.Callers(2, pc)` は2スキップ分開始対象にしてpcへバインドします。 0はCallers関数自体、1はWrap関数なので、2にすると0スタックトレースを取りたい`Wrap(err)`を呼んでいる箇所が対象になります。
0. `frames := runtime.CallersFrames(pc[:n])` により`runtime.Frame`型にして取得します。Go1.7以降このFrameを利用するのが推奨とのことです。

より詳細は公式パッケージを参照ください。 https://golang.org/pkg/runtime/#Callers

また、上記の例での`serviceError`型などのカスタムエラー型をWrapしても、もちろん`errors.As`, `errors.Is`メソッドでUnwrapすることができます。

# おわりに

Wrap関数をパッケージ化しました。https://github.com/momotaro98/stew このアイディアが良いか悪いかフィードバックをいただければと思います。
Intel Realsense D455 発表 ～D435とD455をスペック比較する～

インテルは2020年6月16日　Realsense D455を発表及びプレオーダーを開始しました。
Intel RealSense Depth Camera D455
https://www.intelrealsense.com/depth-camera-d455/

#Realsenseとは？
Realsenseはインテルが製造しているデプス（深度）カメラです。
深度カメラにより奥行方向（深度）に対して、障害物をヒートマップの形で見る事が可能です。
（Realsenseの場合、RealSenseViewerなど）
近年は、ROSなどのロボットや自動走行カーなどにおいて地図の生成から、障害物の検出にLidarと共に使用されています。

###D435参考画像
![Realsense-usb-cable-USBケーブル高い奴2-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/483a0a53-86a5-d907-0046-992b334b37d3.jpeg)

#Realsenseのラインナップ
以下は、Realsenseシリーズの比較表です
https://www.intelrealsense.com/compare-depth-cameras/

#Realsense D455の特徴
D455は、今までの製品とどう違うのでしょうか？
##2倍の性能
最大深度距離が10mから20mへと2倍にのびています。
画質を落とすことなく、最大深度が2倍になった事で性能が2倍と称されています。
##最小デプス距離
D435：0.105m
D455：0.4m
デプスセンサにおける最小距離は10.5㎝から40㎝と遠くなっており、スペックダウンです。
近距離においては別センサーがあると良いでしょう。	
##最適距離
0.4mから6m
**20mは最大距離
##D455のデプスセンサのフレームレート
1280 × 720 @ 30fps
848 × 480 @ 90fps
**D435はUp to 1280 x 720、Up to 90 fps
最大フレームレートが90fpsであり、90fps出るわけではありません
##RGBの画角の向上
D435：69°±1 × 42°±1
D455：86° × 57° (±3)
D435は、RGBカメラの映像とデプスカメラの映像の画角が異なっていましたが、D455は同画角となりました。
これにより、デプスカメラの深度情報と、RGBカメラの画像の比較が簡単になりました。
**なお、デプスセンサの画角はどちらも86° × 57° (±3°)です。
##RGBの画質の低下
D435：1920 × 1080 at 30 fps
D455：1280 × 800 at 30 fps
RGBの画質はスペックダウンです。

##グローバルシャッター方式
D435も同じです。

##IMU（慣性測定ユニット）を搭載
IMUは、慣性測定に使用されており、加速度、角速度、地磁気データなどを取得します。
これらのセンサーデータによりロボットなどの姿勢を算出しています。

D435はD435iのみIMUを搭載していましたがD455は標準搭載となりました。
D455も6DOF慣性測定センサ　BMI055を搭載しています。
BMI055は6軸慣性センサで12ビットの3軸の加速度センサと16ビットの3軸ジャイロスコープを搭載しています。
**Intel RealSense Depth Camera D455 includes InertialMeasurement Unit (IMU) for 6 degrees of freedom (6DoF)
Inertial measurement unit:Bosch BMI055
##大きくなった理由・・・デプスカメラの距離
横幅やD435の90㎜から124㎜へとかなり大きくなっています。
背面の穴ピッチも45㎜から95㎜と倍以上になっています。
これは、2つのデプスカメラの距離を95㎜へと拡大したことによるものです。
これにより深い深度においても高精度なデータ取得が可能になったそうです。
(ステレオカメラなので、距離が離れている方が確度はあがります）
##エラー率
上記カメラ間の距離を広げたことにより
深度センサのエラー率は4mにおいて2％未満となっています。

D35とD455のサイズ比較
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/345fed18-b1a1-c080-537a-17708b00431b.png)
(C)https://www.intelrealsense.com/wp-content/uploads/2020/06/Intel-RealSense-D400-Series-Datasheet-June-2020.pdf

#価格
D435：$179
D435i：$199
D455：$239
#総合計金額
プレオーダー中で7月末(7月20日の週）から発送だそうです。
日本への送料は13ドル～16ドル程度
合計で255ドル程度です。

##実機比較
Intel Realsense D455とD435を実機比較するよ
https://qiita.com/usashirou/items/9c10506cd98a8f9a08b8
[Kotlin + SpringBoot] サロゲートペア文字を含む文字列のSize Validation

#はじめに
サロゲートペア(4バイトの文字)を含む文字列のValidationをしようとしたときに、サロゲートペアだけ2文字カウントされてうまくいかなかったので、これも1文字カウントするカスタムアノテーションを作ってみました。
#コード
```kotlin
Constraint(validatedBy = [CustomSizeValidator::class])
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@ReportAsSingleViolation
annotation class CustomSize(
        val message: String = "Size is invalid",
        val groups: Array<KClass<out Any>> = [],
        val payload: Array<KClass<out Payload>> = [],
        val max: Int = Int.MAX_VALUE,
        val min: Int = 0
)

class CustomSizeValidator : ConstraintValidator<CustomSize, String> {
    private var maxSize: Int by Delegates.notNull()
    private var minSize: Int by Delegates.notNull()

    override fun initialize(customSize: CustomSize) {
        maxSize = customSize.max
        minSize = customSize.min
    }

    override fun isValid(value: String?, context: ConstraintValidatorContext?): Boolean {
        return (value?.codePointCount(0, value.length) in minSize..maxSize)
    }
}
```
`annotation class`のところはお作法？にしたがいます。
`max`, `min`のデフォルト値は`initialize`で初期化するため、初期化遅延する必要があります。
しかしプリミティブ型の変数は`lateinit`が使えないので、

```kotlin 
private var maxSize: Int by Delegates.notNull()
private var minSize: Int by Delegates.notNull()
```
としています。
`codePointCount`を用いることで、サロゲートペアも1文字としてカウントできます。
`@CustomSize(min = 1, max = 10)`などと指定するとサロゲートペアでも1文字扱いでValidationをかけることができます。
#使用例
```kotlin
data class Hoge(
    @field:NotNull
    val id: Int?

    @field:NotEmpty
    @field:CustomSize(max = 20)
    val name: String?,
)
...
fun hogeController(@RequestBody @Valid book : Book){
    ...
}
```
細かなところは省きますが、これでhogeControllerに`𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋𠀋`こんなサロゲートペアの文字20個を含むHogeを渡しても大丈夫です！
fpm (Fortran Package Manager) を使ってみた

# 能書き
[@implicit_none さんの紹介記事](https://qiita.com/implicit_none/items/167d36fdc3a30e4135d0)の出た [fpm (Fortran Package Manager)](https://github.com/fortran-lang/fpm) を使ってみました。

makefile を書くのもだるいし automake も流行らないようだしで、楽ちんそうなfpm に浮上してもらいたいです。最近 rust の cargo のようにネットから必要なライブラリのソースを引っ張ってこれるようにもなったようなので期待上げです。

# mp1 encoder

題材としては、[以前記事にした mp1 encpoder](https://qiita.com/cure_honey/items/25da03704c5c2588a6b4) を使ってみました。

とりあえず fpm 設定が出来ているならば（これが結構めんどかった）github から落としてきて fpm build を何回か繰り返せばおｋです。

https://github.com/cure-honey/uzura1_fpm

```
$git clone https://github.com/cure-honey/uzura1_fpm.git
$cd uzura1_fpm
$fpm build --release
$fpm build --release
... （何回か繰り返す必要あり）
$fpm test
（test/sweep.wav を test/sweep.mp1 に変換）
$build/app/gfortran_release/uzura1_fpm  ＷＡＶファイル名
（コマンドライン引数に変換するファイル名[拡張子抜き]を書くので、fpm run は無理？）
```

fpm.toml ファイルの書き方がよく分からないので、メインプログラムは app/main.f90 に、残りの module 群は 1 モジュール 1 ファイルにしてファイル名とモジュール名を同じにしました。というか、そうしないとうまくいきませんでした。fpm.toml で main.f90 などは変えられるようです。

## その他

少しだけ命名法を変えて、インデントを４スペースにしてみました。モノラルファイル場合にバグがあったので直しておきました。また maxloc/minloc 関数の挙動を最近のものに合わせるように直しました。


お粗末ですが、これでおしまい。
Raspberry Pi 3にUbuntu20.04・GPIO・ROSをインストールしてみた(WiFi設定も)

##はじめに
簡単なロボットの制御をRaspberryPiで実現したかったので、一通りインストールしてみました。  
RaspberryPiを使うときに、どのOSにするか最初に悩みます。
今回はUbuntu20.04にしました。
決め手は最新のROSを入れれるのと、18.04と比較して簡単にGPIOの設定ができるからです。今回はROS1を入れましたが、UbuntuなのでROS2も容易に入れられるようです。こちらも試したらいつか記事にしたいと思います。

##使用デバイス
* Raspberry Pi 3 Model B+

##Ubuntu20.04の書き込み
これは既に情報が豊富ですね。
自分は[Ubuntuの公式サイト](https://ubuntu.com/download/raspberry-pi/thank-you?version=20.04&architecture=arm64+raspi)の通りでできました。

##初期設定
最初は有線LANをつないで設定するのがオススメのようです。
(どうしても有線LANが準備できない場合は、以下のWiFi設定を先にしても大丈夫かもしれないですが、自分は試していないです。)

起動後は

|ユーザ名|パスワード|
|---|---|
|ubuntu|ubuntu|

でログインできます。

ログインしたら、お決まりのコマンドでアップデートしておきます。  

```console
$sudo apt update
$sudo apt upgrade
```
あと、自分はifconfigに頼っているのでnet-toolsもインストールします。

```Console
$sudo apt install net-tools
```

##WiFiの設定
[こちらの記事](https://asukiaaa.blogspot.com/2019/10/raspberry-pi-3b64bitubuntuwifi.html)はUbuntu18.04ですが、同じ方法でWiFiが使えました。

##WiringPi(GPIO)のインストール(6/29修正)
[こちらの記事](https://qiita.com/myasu/items/5b122c782c5a616d8b60)を参考にしましたが、
/dev/gpiomemをchownでグループ変更する方法では再起動すると元に戻ってしまうようです。

[こちら](https://github.com/raspberrypi/linux/issues/1225)に書いてあるとおり、udevの設定ファイルを追加することで、永続的に/dev/gpiomemのグループを変更できます。

全体の手順は以下のとおりです。

```console
$ sudo apt install wiringpi
$ sudo adduser ubuntu gpio
```

/etc/udev/rules.d/99-com.rulesを新規作成し、以下の内容を記述します。

```
SUBSYSTEM=="bcm2835-gpiomem", GROUP="gpio", MODE="0660"
```

これでGPIOコマンドは使えるようになりますが、CでwiringPiのライブラリを呼び出そうとすると、

```console
$ gcc test_pwm.c -o test_pwm -lwiringPi
test_pwm.c:1:10: fatal error: wiringPi.h: No such file or directory
    1 | #include <wiringPi.h>
      |          ^~~~~~~~~~~~
compilation terminated.
```
と怒られてしまいますので、libwiringpi-devをインストールします。

```console
$ sudo apt install libwiringpi-dev
```

##ROS(Noetic)のインストール
[ROS公式サイト](http://wiki.ros.org/noetic/Installation/Ubuntu)の手順通りで、問題なくインストールできました。
今回はRaspberryPi本体でGUIを使うつもりがないのでbaseを選択しました。
JavaScriptで文字列と数字が混在したソート

# やる事
文字列と数字が混在した配列でも、それっぽいソートをしたい。

```
Test1
Test10
Test11
Test2
Test3
...
```

という「なんだかな～」っていう並びを

```
Test1
Test2
Test3
...
Test9
Test10
Test11
```

にするやつです。
他にいいやつあるかな～と思ったけど、~~この位だと作った方が早いし、~~多言語に移植する予定もあったので、考察の為

とりあえず、適当に列挙したこれが

```yaml:yaml
- '25'
- 12.234.111.233
- 12.234.111.28
- 12.234.27.255
- 184
- a9-b
- a100
- a9-a
- tenuno01
- test
- test00030-1
- test00123-156-3
- test123-4
- wawa1
```

これになります。

```yaml:yaml
- 12.234.27.255
- 12.234.111.28
- 12.234.111.233
- '25'
- 184
- a9-a
- a9-b
- a100
- tenuno01
- test
- test00030-1
- test123-4
- test00123-156-3
- wawa1
```

気に入らなければ話はここで終わりDA（改善点聞かせてください＞＜）

# 考察

- 例えば `Test1-10` といった値は 「110」という捉え方ではなく、「1」 グループの中の 「10」 という捉え方とする
- 文字列の長さ優先ソートではなく、中途半端にゼロ埋めされたデータにも対応したい（ `1` と `01` とか）
- 従って既存のゼロ埋めは無視（ `ABC-00123` と `ABC-05` だと05が前に来る等）
- 数の接続詞（- / : . (n) 等）の重みは考慮しない（考慮するときりがない・・）
- つまり・・数字は「数字の塊」、文字は「文字の塊」と見なしてソートする
- マイナス無視（ハイフンとみなす為）

# コード

プロトタイプで失礼。バグや、他に良いものがあれば教えて下さい。

**追記:** 更に良いものを教えていただきましたので、この例はあくまで経緯としてご覧ください。


```js:JavaScript
// テスト
var array_test = ["25", "12.234.111.233", "12.234.111.28", "12.234.27.255", 184, "a9-b", "a100", "a9-a", "tenuno01", "test", "test00030-1", "test00123-156-3", "test123-4", "wawa1"];

console.log(array_test.sort(sort_num_block));
// ["12.234.27.255", "12.234.111.28", "12.234.111.233", "25", 184, "a9-a", "a9-b", "a100", "tenuno01", "test", "test00030-1", "test123-4", "test00123-156-3", "wawa1"]

/**
 * 数値文字列グループ化ソート
 *
 * - ゼロ埋め無視（ゼロ埋めの桁数が合ってなくても無視）
 * - マイナス無視（ハイフンとみなす）
 */
function sort_num_block(a, b) {
    // 数字のかたまりと、文字のかたまりをグループ化
    ma = String(a).match(/([0-9]+|[^0-9]+)/g);
    mb = String(b).match(/([0-9]+|[^0-9]+)/g);
    if (!ma && !mb) return 0;
    if (!ma && mb) return -1;
    if (!mb && ma) return 1;
    for (var i = 0; i < ma.length; i++) {
        if (!mb[i]) return 1;
        if (!isNaN(ma[i]) && !isNaN(mb[i])) {
            // 両方数値化できれば数値で比較
            if (parseInt(ma[i]) != parseInt(mb[i])) {
                return parseInt(ma[i]) - parseInt(mb[i]);
            }
        } else {
            // それ以外は文字列で比較
            if (ma[i] > mb[i]) {
                return 1;
            } else if (ma[i] < mb[i]) {
                return -1;
            }
        }
    }
    if (ma.length < b.length) return -1;
    return 0;
}

```

## 追記：更に良いコード
@vf8974 さんありがとうございます！

私の書いた先程の記載だと以下の問題が生じます。

- どうしても数値比較なので、桁数があふれるとオーバーフローを起こす。

`sort_num_block` の関数を以下の様に書き換えることにより改善できます。

```js:JavaScript
function sort_num_block(a, b) {
    const sa = String(a).replace(/(\d+)/g, m => m.padStart(30, '0'));
    const sb = String(b).replace(/(\d+)/g, m => m.padStart(30, '0'));
    return sa < sb ? -1 : sa > sb ? 1 : 0;
}
```

数字の個所を想定範囲以上にゼロ埋めして**文字列**としてソートする
分かりやすい例として（コード上は30桁を想定していますが、例として10桁埋めとします。）

`Test12-3-456`
`Test1-234-56`
を
`Test0000000012-0000000003-0000000456`
`Test0000000001-0000000234-0000000056`

とすると、文字列でソートしても問題なくソートできるという仕組みです。
【Rails】refileとrefile-s3を用いて、画像をAWS S3へアップロードする方法

# 目標

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/a8fb4365-df4c-9164-63e7-75b12f12dfd3.gif)

# 開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

# 前提

下記記事の`AWSの設定`と`実装`の「キーを環境変数化」までを行う。

[Carrierwaveとfog-awsを用いて、画像をAWS S3へアップロードする方法](https://qiita.com/matsubishi5/items/96721426cff2b1d67cdd)

# 実装

###`refile.rb`を作成・編集

```terminal:ターミナル
$ touch config/initializers/refile.rb
```

```ruby:refile.rb
require 'refile/s3'

if Rails.env.production? # 本番環境の場合はS3へアップロード
  aws = {
    access_key_id: ENV['S3_ACCESS_KEY_ID'], # アクセスキーID
    secret_access_key: ENV['S3_SECRET_ACCESS_KEY'], # シークレットアクセスキー
    region: 'ap-northeast-1', # リージョン
    bucket: 'matsubishi-sample', # バケット名
  }
  Refile.cache = Refile::S3.new(prefix: 'cache', **aws)
  Refile.store = Refile::S3.new(prefix: 'store', **aws)
end
```
PRML　演習問題 4.16（基礎）　解答 

## 問題
> $t$ = 0または$t$ = 1に対応する2クラスの1つに属することが知られている各観測値$\mathbf{x} _ {n}$における2値分類問題を考える。このとき、学習データがときどき間違ったラベルを付けられるため、学習データの収集手順は完全なものではないと仮定する。すべてのデータ$\mathbf{x} _ {n}$に対し、クラスラベルの値$t_n$を与える代わりに、$t_n = 1$となる確率を表現する値$\pi_n$を与える。確率モデル$p(t = 1|\phi)$が与えられた場合、そのようなデータ集合に適切な対数尤度関数を記述せよ。

## 参考
*少々怪しい解答になることをご了承ください。
クラスラベルの値$t_n$が{0, 1}の時はベルヌーイ分布となるため、

```math
\begin {align*}
p_n = p\left(t_{n}=1 | \phi\left(\mathbf{x}_{n}\right)\right)
\end {align*}
```  
とおくと、観測値$\mathbf{x} _ {n}$における尤度関数、および対数尤度関数は

```math
\begin {align*}
p\left(t_{n} | \phi\left(\mathbf{x}_{n}\right)\right)=p_n^{t_{n}} (1 - p_n)^{1-t_{n}}
\tag{ex4.16.1}
\end {align*}
```  
```math
\begin {align*}
\ln p\left(t_{n} | \phi\left(\mathbf{x}_{n}\right)\right)=t_{n} \ln p_{n}+(1-t_{n} ) \ln \left(1-p_{n}\right)
\tag{ex4.16.2}
\end {align*}
```  
と簡単に表すことができる。(ex4.16.2)は観測値$\mathbf{x} _ {n}$は$t_n=1$の時対数尤度関数を$\ln p_n$だけ増加させ、$t_n=0$の時対数尤度関数を$\ln (1 - p_n)$だけ増加させていると解釈することができる。

## 解答
今回の問題は
「クラスラベルの値$t_n$を与える代わりに、$t_n = 1$となる確率を表現する値$\pi_n$を与える。」という点が特殊である。この条件は「参考」における解釈を用いると、確率$\pi_n$で対数尤度関数を$\ln p_n$だけ増加させ確率$1-\pi_n$で対数尤度関数を$\ln (1 - p_n)$だけ増加させると考えることができる。
そのため、今回の対数尤度関数は(ex4.16.2)を少し変形してやると、

```math
\begin {align*}
\ln p\left(t_{n} | \phi\left(\mathbf{x}_{n}\right)\right)=\pi_{n} \ln p_{n}+(1-\pi_{n} ) \ln \left(1-p_{n}\right)
\end {align*}
```  
と表すことができる。さらにnが1からNまでの値を表すと考えると、

```math
\begin {align*}
\ln p\left(\mathbf{t} | \phi\right)=\sum_{n=1}^N \{\pi_{n} \ln p_{n}+(1-\pi_{n} ) \ln \left(1-p_{n}\right)\}
\end {align*}
```  

これで対数尤度関数を記述することができた。
PostgreSQLの起動と停止の方法

学習内容の備忘録

PC環境

- macOS Mojave
- PostgreSQL version 12.3

#バージョンの確認
```terminal
$ psql -V
psql (PostgreSQL) 12.3
```

#PostgreSQLの起動・停止

**起動**

```terminal
$ brew services start postgresql
==> Successfully started `postgresql` (label: homebrew.mxcl.postgresql)
```


**停止**

```
$ brew services stop postgresql
==> Successfully stopped `postgresql` (label: homebrew.mxcl.postgresql)
```
respond_to(respond_with)とインスタンス変数の記述順に関する注意

#問題
業務中に開発チームメイトが、コントローラで定義したviewにインスタンス変数を渡せないという問題にはまったため、その解決法を備忘録的に残しておく。

#やりたいこと
同じviewファイルを使っている2つactionにおいて、あるactionによって呼ばれた時だけ表示させたい項目があり、urlの値によって条件分岐させたい(editの際は表示させて、newの時は表示させたくない)。

```html:sample.html.slim
   ...中略...

  - if @url.include?("edit")
      f.input :hoge
```

```ruby:sample_controller.rb
   ...中略...

  def new
     @sample = Sample.find(params[:id])
     respond_with(@sample)
     @url = request.url
  end

  def edit
     @sample = Sample.find(params[:id])
     respond_with(@sample)
     @url = request.url
  end
```

すると、「nilクラスにinclude?メソッド使えないよ～」的なエラー分が出ていた（はず）。
コントローラで＠url定義しているのに（byebugでコントローラ上では@urlに値は入っていることも確認済み）おかしい…。

#解決法
```ruby:sample_controller.rb
   ...中略...

  def new
     @url = request.url
     @sample = Sample.find(params[:id])
     respond_with(@sample)
  end

  def edit
     @url = request.url
     @sample = Sample.find(params[:id])
     respond_with(@sample)
  end
```
これで直った。
respond_withの後にインスタンス変数を定義しても、すでにレスポンスを返した後だから＠urlはviewファイルに渡せてなかったのが原因っぽい。
respond_with(ないしrespond_to)の内部処理についてもっと深く知る必要がありそう。今回はただの感で「コード入れ替えてみたらどうでしょう？」と言って解決できたが…。
mapメソッドについて

# mapメソッドについて
mapメソッドとは、各要素に対してブロックを評価した結果を新しい配列にして返します。
エイリアスメソッドは、collectメソッドです。

（例）配列の各要素を3倍にした新しい配列を作るコード

```ruby
numbers = [1,2,3]
new_numbers = []
numbers.each { |n| new_numbers << n * 3 }
new_numbers #=> [3, 6, 9]
```

mapメソッドを使用すると、ブロックの戻り値が配列の要素となる新しい配列が作成されるため、mapメソッドの戻り値をそのまま新しい変数に入れることができます。

```ruby
numbers = [1,2,3]
# ブロックの戻り値が新しい配列の各要素になる
new_numbers = numbers.map { |n| n * 3 }
new_numbers #=> [3, 6, 9]
```

このように、mapメソッドを使用することで、空の配列を用意して他の配列をループ処理した結果を空の配列に詰め込んでいくような処理の大半を置き換えることができます。


## 参考にした文献

[プロを目指す人のためのRuby入門](https://www.amazon.co.jp/dp/4774193976/ref=cm_sw_em_r_mt_dp_U_shaUEbXSFD416)
.NETCore3.1でDevelopmentモードに変更する

めちゃくちゃ単純な話ですが、探すと意外と見つからない。
こいつが設定できないとずっとただの「500 Error」となり、場合によってはデバッグ不能となる。

答えはコレ

# Program.cs

``` C#
public static void Main(string[] args)
{
     Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");  //追記
     CreateHostBuilder(args).Build().Run();
}

```


# Startup.cs
あとは`Startup.cs`のほうでこうなってればOK
※mvcでProjectを立てたら最初からこうなってました。

``` C#
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment()) //ここがtrueになるので
    {
        app.UseDeveloperExceptionPage(); //これが効く
        app.UseDatabaseErrorPage();  //これも効く
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapRazorPages();
    });
}
```

# おわり

`Startup.cs`の話はあちこちに書いてあるんですけどね。
`Program.cs`のほうがなかなかレアでした。
MLflowに入門してみる

# MLflowとは

[公式ドキュメントのトップページ](https://www.mlflow.org/docs/latest/index.html)によると以下。

* オープンソースで、機械学習の一連のサイクルを管理するためのソフトウェア。
* MLflowはPython, R, JavaのAPIを持つ他、REST APIやCLIもあるので様々なライブラリや言語と合わせて利用することができる。
* 以下４つの機能を持つ。
  * MLflow tracking
      * 学習に利用するコードやパラメータ、学習の結果を記録することで、過去の学習記録を簡単にトラッキングできるようにする。
  * MLflow Projects
      * コードを再利用可能にする仕組み。
  * MLflow Models
      * 機械学習モデルをパッケージングし、様々なプラットフォームで利用な可能な形式で提供することを可能にする
  * MLflow Model Registry
      * 機械学習モデルを保存するレジストリ。バージョンや学習の情報などを提供する。

# Tutorial
https://www.mlflow.org/docs/latest/tutorials-and-examples/tutorial.html

## このチュートリアルの内容

1. 線形回帰モデルを学習
1. コードをパッケージングし再利用可能な状態にする
1. モデルをHTTPで利用可能な形でデプロイする

## 実践
```
# 環境構築
pipenv install "mlflow[extras]" 
```

### 学習を実行（MLflow Tracking）
以下を写経
https://github.com/mlflow/mlflow/blob/master/examples/sklearn_elasticnet_wine/train.py

```
# 実行
## ハイパーパラメータを適当に変えていくつか作ってみる
$ pipenv run python sklearn_elasticnet_wine_train.py
$ pipenv run python sklearn_elasticnet_wine_train.py 0.6 0.6
$ pipenv run python sklearn_elasticnet_wine_train.py 0.4 0.4

# mlrunsというディレクトリができる
```

### 学習を結果を確認
```
# UIを起動
pipenv run mlflow ui
```

* モデルの作成時刻やハイパーパラメータ、学習結果などを閲覧可能。
* モデルごとの比較が可能

### モデルをパッケージングする（MLflow Projects)
#### 基本的なディレクトリを作る
```
mkdir sklearn_elasticnet_wine
mv sklearn_elasticnet_wine.py sklearn_elasticnet_wine/train.py
```

#### Projectsファイルを作成
こちらに記載のある二つのファイルを作成する。

https://www.mlflow.org/docs/latest/tutorials-and-examples/tutorial.html#packaging-training-code-in-a-conda-environment

※ `conda.yaml`は、UIのモデル詳細にあったのでコピペした

#### 実行
condaは使いたくないので `--no-conda`を利用

```
pipenv run mlflow run sklearn_elasticnet_wine -P alpha=0.42 --no-conda 
```

MLProjectsの実行環境は、`conda`, `Docker`, `System Environment` (今回)の３つを選択可能。

これで、モデル生成に利用したコードと実行環境を別環境でも再現できるようになった。

### モデルをサーブする(MLflow Model)
#### 生成されたモデルアーティファクト
モデル作成のステップで作成された `mlruns/0/ハッシュ値/artifacts/model/`ディレクトリに必要なものが格納されている。

* MLmodel: モデルに関するメタ情報
* model.pkl: 学習済みモデルをシリアライズしたもの

ちなみに、MLProjectsで利用した`conda.yaml`もここに入っている。

#### web APIとしてデプロイ
こちらも、condaを入れたくないので `--no-conda`で動かす
```
pipenv run mlflow models serve -m mlruns/0/2ca121e400654d5898de9f4f9e1fe928/artifacts/model -p 1234 --no-conda 
```

リクエストできた。
```
curl -X POST -H "Content-Type:application/json; format=pandas-split" --data '{"columns":["alcohol", "chlorides", "citric acid", "density", "fixed acidity", "free sulfur dioxide", "pH", "residual sugar", "sulphates", "total sulfur dioxide", "volatile acidity"],"data":[[12.8, 0.029, 0.48, 0.98, 6.2, 29, 3.33, 1.2, 0.39, 75, 0.66]]}' http://127.0.0.1:1234/invocations

[4.479576972663602]
```
Dronecode Devマニュアル抜粋&翻訳 - FlightModes

#この記事は
前回の [Dronecode Platform Overview](https://qiita.com/sakaeda11/items/9b6c5b0b6c78de05821b) に引き続き、
Dronecode本家サイトの[FlightModes](https://dev.px4.io/master/en/concept/flight_modes.html)ページの抜粋・翻訳です。

主に自分の理解用に書いています。
※ Multirotorsの説明のみ扱います。固定翼などの説明は割愛します。

# 前置き
- フライトモードとは、ユーザの操作や機体の動きに応じてどういう反応をさせるかを定義したものです。
- 多数のフライトモードがありますが、大まかに、マニュアルモード、アシストモード、自動モードといった分類ができます。
- フライトモードは、GCSやリモコンを用いて変更できます。
- 機体の種類(クアッドコプターなのか固定翼機なのかなど)や、機体の状態(離陸前なのか飛行中なのか)などによって、取れるフライトモードは異なってきます。

# Manual flight modes
- マニュアル操作モードですが、その中でもいくつかのモードがあります。
    - 例えば熟達者がアクチュエータをダイレクトに操作したい用のモードや初心者がある程度保護された範囲で操作したい用のモードなどがあります。

## Fixed wing aircraft/ rovers / boats
(割愛します。)

## Multirotors
### MANUAL/STABILIZED
- ドローンの姿勢(yaw,pitch,roll)を直接操作するモード
- 操作をやめると(コントローラのスティックを中央に戻すと)、yaw,pitch,rollはゼロ(水平)になる
    - この場合も位置固定されるわけではなく、例えば風が吹くと流されていく

### ACRO
※Dronecodeにかかれている説明だけだとよくわからなかったのですが、
https://videosalon.jp/serialization/microdrone-biginner02/
などのサイトがわかりやすかったのでこちらの言葉を借ります。

スティックの操作量に応じた角速度で機体を傾け、スティックを中央に戻すと、その時点の機体の姿勢を維持しようとするモード。

ということのようです。
アクロバティックな飛行操作をするためのモードのようです。

### RATTITUDE
しきい値以上の入力は、オートパイロットに渡され、オートパイロットが制御するが、
しきい値以内なら直接yaw,pitch,rollを操作するモードです。


# Assisted flight modes
アシストモードもユーザが操作するモードですが、例えば風などがあっても、位置や方向を自動的に維持してくれるモードです。

## ALTCTL (Altitude Control)
- (コントローラの)スロットル操作によって上昇・下降を操作できるモード。
- オートパイロットは高度のみをコントロールする。風が吹くと水平方向には動く

## POSCTL (Position Control)
- Rollの操作で左右、Pitchの操作で前後に移動し、Yawの操作で向き変え、スロットル操作で上昇下降を操作
- スロットルを中央に戻すと風があっても位置固定するようになる


# Auto flight modes
ユーザ操作がほとんど必要ないモード

## AUTO_LOITER (Loiter)
現在の位置・高度でホバリングし続けるモード

## AUTO_RTL (Return to Land)
指定位置に直線的に戻ってきて着陸するモード
- 現在の高度がRTL_RETURN_ALT(帰投時の高度)より高いときは現在高度を維持したまま戻ってくる
- そうでない場合はRTL_RETURN_ALTまで上昇した後戻ってくる

## AUTO_MISSION (Mission)
### All system types
- GCSから指示された動作を行う
- GCSからの指示がなければその場にとどまる

# Flight Mode Evaluation Diagram
- シリアルケーブルやMAVLinkで接続されたコンパニオンコンピュータからの指示に従って移動する
- なお、指示はMAVSDK や MAVROSといったAPIで行われる

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124098/8d89a3cf-ef82-71c3-64ae-4e1c97a0774a.png width=70%>

どのモードになるかの判断順序
大まかには
自動系モード　> アシスト系モード > マニュアルモード
という優先順位の模様
ブックマークレットでQiitaにタイマー投稿してみる実験

## 概要
Qiitaには通常の予約投稿が無さそうなので、ブックマークレットでそれっぽい事やってみようって試みです。

<p class="codepen" data-height="188" data-theme-id="dark" data-default-tab="result" data-user="HongKong3" data-slug-hash="YzwpWOP" style="height: 188px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Qiitaimer">
  <span>See the Pen <a href="https://codepen.io/HongKong3/pen/YzwpWOP">
  Qiitaimer</a> by HongKong (<a href="https://codepen.io/HongKong3">@HongKong3</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
8. 投稿直前の状態でブックマークレットを実行  
   **利用規約のチェック等は予め済ませて下さい**
8. 予定時刻をセット
8. そのまま投稿画面を放置
8. 予定時刻になったら「投稿」ボタンを自動クリック

てな仕組みです。

## 仕様
- 投稿ボタンの状態は見てません、予め確認して下さい[^1]。
- 予定時刻の設定は**数値の個数**しか見てません、時・分・秒の順で割り当てます[^2]。  
  現在より過去の時間なら日付を進めます[^3]。
  - 数値が4個以上なら、日・月・年の指定として扱います。
  - 予定時刻との時差で`setTimeOut()`してるだけなので、精度は良くなさそうです。

[^1]: 下書き保存 / 限定共有投稿 / Qiitaに投稿　の選択状態など
[^2]: 「22:11:33」 「22/11/33」 「22日11時33分」 どれも22時11分33秒として扱います
[^3]: 20:00に「01:00」と指定すると、翌日の01:00になる感じです

## 実験動機
Qiita API 駆使した手法もあるようですが、それだけの為に環境構築も面倒なので「投稿画面放置とかでも良いんじゃね？」て思いました。

予約投稿に拘る理由も無いんですけど。:cheese:
GNU timeを知った

[High Performance Python 2nd Edition](https://www.oreilly.com/library/view/high-performance-python/9781492055013/)を読む中で、
timeはGNU版と簡易版の二つがあることを知った。

### time（シェル組み込み）
bashやzshのプロンプトでパスが通っている `time`はシェル組み込みのtimeで、簡易版らしい。

```
# zsh
$ time sleep 1
sleep 1  0.00s user 0.00s system 0% cpu 1.004 total
```

### GNU time
`/usr/bin/time`にインストールされたコマンドはGNU版で、上記よりもリッチな情報を出すことができる。

macの場合は`brew install gnu-time`で`gtime`としてインストール可能。

```
$ gtime --verbose sleep 1
        Command being timed: "sleep 1"
        User time (seconds): 0.00
        System time (seconds): 0.00
        Percent of CPU this job got: 0%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.00
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 612
        Average resident set size (kbytes): 0
        Major (requiring I/O) page faults: 0
        Minor (reclaiming a frame) page faults: 297
        Voluntary context switches: 0
        Involuntary context switches: 17
        Swaps: 0
        File system inputs: 0
        File system outputs: 0
        Socket messages sent: 0
        Socket messages received: 0
        Signals delivered: 0
        Page size (bytes): 4096
        Exit status: 0
```

`Major (requiring I/O) page faults`は、スワップの発生を意味しており注意すべきメトリクスである。
アルゴリズムの計算量についての備忘録

##目次
エラトステネスの篩　2020/6/17


##エラトステネスの篩
計算量は

```math
\mathcal{O(n\log \log n)}
```

1~nまでの各整数に対して、その整数の平方根までチェックをするという愚直な方法では

```math
\mathcal{O(n \sqrt{n})}
```
かかる。

[エラトステネスのふるいとその計算量](https://mathtrain.jp/eratosthenes)
[素数の逆数和が発散することの証明](https://mathtrain.jp/primeinverse)
[メルテンスの定理](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%AB%E3%83%86%E3%83%B3%E3%82%B9%E3%81%AE%E5%AE%9A%E7%90%86)
AWS S3 で削除したファイルを復旧させる方法 (削除マーカーを削除する方法)


AWS S3 バケットでファイルを削除しても、バージョン機能をオンにしていれば、削除キーが追加された状態で、S3 バケットに残り続けます。

今回、削除した S3 バケット内のファイルを一斉に復旧させる必要があったので、クラメソさんブログのサンプルシェルをちょっと改造して実行しました。

クラスメソッドさんのブログはいつもお世話になっております。

- [S3で誤って削除してしまったオブジェクトを過去VersionからAWS CLIで復旧](https://dev.classmethod.jp/articles/s3-restore-from-previous-version-with-aws-cli/)

しかし、このブログ記事はバケット全体で、特定のフォルダだけを復旧させたい場合には対応していなかったので、シェルスクリプト化してパラメーターを入れて特定フォルダ (prefix) 対応な復旧をできるようにしました。

また、ググったら別の良いシェルスクリプトのサンプルを見つけたので、2番目に追記します。

ファイルの復旧には1オブジェクト1秒ぐらいの時間がかかるので、オブジェクト数が多い Bucket の復旧をする際は、時間がかかるということを覚悟しておいてください。


# CLI で一発で行う方法 (クラメソさんの方法)

## 手順

### 1. AWS CLI で、IAM User 設定、もしくは EC2 インスタンスに IAM Role を割り当てる

### 2. 下記のシェルスクリプトをサーバー or ローカルに作成する。

```s3-restore.sh
# /bin/bash
BUCKET=$1
PREFIX=$2
aws s3api list-object-versions --bucket $BUCKET\
  --bucket ${BUCKET}\
  --prefix ${PREFIX}\
  --query "DeleteMarkers[?IsLatest==\`true\`].[Key,VersionId]" \
  --output text | while read line
  do
    array=($line)
    KEY=${array[0]}
    VERID=${array[1]}
    aws s3api delete-object\
      --bucket ${BUCKET}\
      --version-id ${VERID}\
      --key ${KEY}
  done
```

### 3. シェルを実行する。

実行フォーマットはこんな感じです。

```
$ sh s3-restore.sh [バケット名] [復旧対象パス]
```

例「katzcurry」 S3 バケットの中の「/curry/images/」フォルダの中の削除マーカーがついたファイルを全部復旧させる場合


```
$ sh s3-restore.sh katzcurry curry/images/
```

最初のスラッシュは不要です。

## 注意

t3.medium なインスタンスで実行したんですが、1秒/ファイルぐらい時間がかかりました。
たくさんファイルがあると時間がかかるようです。


# aws-s3-mass-undelete: 順番に作業ファイルを作って行う方法 (ググって見つけた)

ググって見つけたこのシェルスクリプトサンプル、使えます。
指定した日付以降に削除マーカーが付いたファイルのみを復旧させます。

Gist
https://gist.github.com/crazycodr/ef1b6b65cf03350fafbde9d1b56bd637

## 設定方法

- gist のファイルを `aws-s3-mass-undelete.sh` というファイル名で任意の場所に保存します
- `aws configure` で対象の S3 バケットに権限があるIAMを紐付けます。
- `aws-s3-mass-undelete.sh` のパラメータを変更
    - BUCKET_NAME に対象のバケットの名をいれます。
    - DATE_LIMIT に日時の指定を入れます。おそらく UTC だと思います。（未検証。どなたか確認をお願いします）
- `sh aws-s3-mass-undelete.sh` で実行されます。


- `objects.json` に対象のバケットすべてのファイル (key) 一覧が出力されます。
- `objects.json` をベースに、 `markers-to-delete.json` に削除キーが最新になっている、削除された状態になっていて、かつ、指定した日時以降のオブジェクトリストだけが抽出されます。
- `markers-to-delete.json` から、 `undelete.sh` とという、実際にファイルを復元するためのシェルスクリプトが生成されます。
- `undelete.sh` のシェルが実行されます。



以上