OmniAICreator/Qiita-1.07M huggingface dataset:
Oracle Cloud オブジェクトストレージを cli で作成してファイルのアップロード+ダウンロード

# はじめに

Oracle Cloud の勉強の一環で、公式のチュートリアルを基に進めていきます。公式のチュートリアルでは日本語、かつ、GUI操作の内容となっています。わかりやすく書かれているので、基本は[こちら](https://community.oracle.com/docs/DOC-1019313)を参照していただけるとよいと思います。

このQiitaの記事は、上記のチュートリアルを CLI であえて実施した備忘録として書きます。
CLI の理由は、GUIと比べて再現性や再実行性が高いのと、**なんとなくかっこいいから**



# 今回のテーマ

Object Storage を使ってみる
https://community.oracle.com/docs/DOC-1019520



# 前提作業

## oci cliの導入

oci cli と jq コマンドを使用可能なこと。次のQiita記事で導入した手順を書いています
https://qiita.com/sugimount/items/63a8cfe1163030ae8804



# Privateのバケットの場合

## バケットの作成 (Private)

Object Storage上で、Privateのバケットを作成します

```
oci os bucket create --name tutorial-bucket1 --public-access-type NoPublicAccess --storage-tier Standard
```



## FileのUpload

test用のファイルを作成

```
echo 'test' > ~/test2/test.txt
```



testファイルをアップロード

```
oci os object put --bucket-name tutorial-bucket1 --file '/home/sugi/test2/test.txt' --name tutorial-testput.txt 
```



## 事前認証リクエストの作成

OCI にログインしていない環境から、Object Storage 上のファイルをダウンロード/アップロードを許可ために、事前認証リクエスト(Pre-Authenticated Request )を作成します

access-typeには以下の4種類があります

- ObjectRead : 指定したオブジェクトに対してダウンロードのみ可能なURLを生成
- ObjectWrite : 指定したオブジェクトに対してアップロードのみ可能なURLを生成
- ObjectReadWrite : 指定したオブジェクトに対してダウンロード・アップロードが可能なURLを生成
- AnyObjectWrite : 指定したバケットに対して、アップロード可能なURLを生成

```
oci os preauth-request create --bucket-name tutorial-bucket1 --name tutorial-preauth1 --access-type ObjectRead --object-name tutorial-testput.txt --time-expires 2019-03-15T20:30:00Z
```



実行例

```
> oci os preauth-request create --bucket-name tutorial-bucket1 --name tutorial-preauth1 --access-type ObjectRead --object-name tutorial-testput.txt --time-expires 2019-03-15T20:30:00Z
{
  "data": {
    "access-type": "ObjectRead",
    "access-uri": "/p/gjk75dZS9F76VHFi0J_yYrJOsDW3K1UvD7Liuhs312E/n/sugimount2/b/tutorial-bucket1/o/tutorial-testput.txt",
    "id": "AMvrTdsZ49xSV3SIWChmpE/wd71qwVukTKd/w4Tzpm8=:tutorial-testput.txt",
    "name": "tutorial-preauth1",
    "object-name": "tutorial-testput.txt",
    "time-created": "2019-02-05T00:55:36.916000+00:00",
    "time-expires": "2019-03-15T20:30:00+00:00"
  }
}
```



上記に記載されている access-uri を使用して、アクセスしたいエンドポイントにアクセスすると、ファイルをダウンロードすることが出来ます

```
wget -XGET https://objectstorage.us-ashburn-1.oraclecloud.com/p/gjk75dZS9F76VHFi0J_yYrJOsDW3K1UvD7Liuhs312E/n/sugimount2/b/tutorial-bucket1/o/tutorial-testput.txt
```







# 参考URL

チュートリアル一覧

https://community.oracle.com/docs/DOC-1019313
Jenkinsfile で リリース後、リリースタグを作成したい時

### Jenkinsfile で Tag を Push する

```
stage 'push tag'

def date = new Date()
def dateFormat = new SimpleDateFormat("yyyyMMddHHmm")
def yyyyMMddHHmm = dateFormat.format(date)

// Jenkinsで「認証情報の追加(GIT_CRDT_ID)」をしておいてください。
withCredentials([[$class: 'UsernamePasswordMultiBinding'
         ,credentialsId: 'GIT_CRDT_ID'
         ,usernameVariable: 'GIT_USER'
         ,passwordVariable: 'GIT_PASS']]) {
  sh "git tag -a ${yyyyMMddHHmm} -m jenkins"
  sh "git push https://${GIT_USER}:${GIT_PASS}@${GIT_URL}.git --tags"
}
```
プロキシの基本的なトラップの仕方

# はじめに

[BurpSuite](https://portswigger.net/burp), [ZAP](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project), [Fiddler](https://www.telerik.com/fiddler) は、SSL の通信を解読しながら転送するプロキシツールで、デバグ/セキュリティ診断で使われている

トラップ(通信を一旦停止して、デスクトップ上に編集可能な状態で表示する)の設定について

# BurpSuiteの場合

![burp1.png](https://qiita-image-store.s3.amazonaws.com/0/182822/95bc513b-e0ad-65c9-2e28-4e4c3fbdea76.png)

このあたりで、どのようなリクエスト(拡張子が画像とかは無視とか、特定のWebサイトだけトラップするようにする(Scopeの設定)とか)

![burp2.png](https://qiita-image-store.s3.amazonaws.com/0/182822/5decac1b-ecb3-d396-0f27-abd6ec69325c.png)

BurpSuiteの場合は「Intercept」という。これが「On」でトラップ。「Off」でスルー。

![burp3.png](https://qiita-image-store.s3.amazonaws.com/0/182822/5519274b-d8da-c461-b1d8-f364dbcde409.png)

トラップした通信は「Forward」で転送される

# ZAPの場合

![zap1.png](https://qiita-image-store.s3.amazonaws.com/0/182822/b907f60b-4ee0-7bd2-2bab-1b38279f74de.png)

ZAPの場合は「ブレークポイント」という。
これでトラップできる状態にしたりスルーする状態にしたりする。

![zap2.png](https://qiita-image-store.s3.amazonaws.com/0/182822/771a9ee2-9932-1d2d-3ba5-866336dc607b.png)

こちらの再生ボタンで、転送される。

# Parosの場合

![paros.png](https://qiita-image-store.s3.amazonaws.com/0/182822/34524acd-95c3-6eab-6ea3-db200e3efedf.png)

Parosの場合「トラップ」という。
トラップするかどうかの設定をして、トラップしたデータを転送(「Continue」)するボタン。
そんな感じ

# Fiddlerの場合

![fiddler1.png](https://qiita-image-store.s3.amazonaws.com/0/182822/e7ca8b25-4aba-7d7c-b052-d17f20c50529.png)

Fiddlerの場合は「ブレークポイント」という。
「Before Requests」つまり、リクエストを転送する前にブレークポイントを設定すれば、トラップできるようになる。
「After Response」は「レスポンスを受信した後」なので、レスポンスの転送前にトラップできるようになる。

![fiddler2.png](https://qiita-image-store.s3.amazonaws.com/0/182822/df188fe4-3a38-6261-4ef1-1df790b281e1.png)

通信のリストをクリックすると、右ペインの上部がリクエスト。下部がレスポンス。
リクエストの「Raw」が馴染みのある感じかな。
「Break on Response」は、このリクエストのレスポンスを急遽トラップ。
「Run to Completion」は、このまま通信を完成させる。

# Index

[Indexへ戻る](https://qiita.com/tomoki0sanaki/items/258d6e77e4b16bc7d1c9)

# 以上
Jenkinsfile で コミットコメントを共有したい時

### コミットログを commitLogs に格納する例

```:Jenkinsfile
// 例えば、今日コミットした一覧(commitLogs)を取得する

def commitLogs = ""

def date = new Date()
def dateFormatHyphen = new SimpleDateFormat("yyyy-MM-dd")
def todayHyphen = dateFormatHyphen.format(date)

// 今日アップしたコミットコメントを取得
def logs = sh(script: "git log --pretty=format:\"%h - %an, %ar : %s\" --after=\"${todayHyphen} 00:00:00\"", returnStdout: true).split("\r?\n")
for (log in logs) {
  // 一覧に入ってほしくないコミットコメントを除く例:Merge, Pull Requestなど
  if (!log.contains("Merge pull request") && !log.contains("Merge remote-tracking branch") && !log.contains("Merge branch")) {
    commitLogs += log + "\n"
  }
}
```

例えば、上記のサクセスメールのbodyにcommitLogsを追加したりして共有できます。

```
stage 'success mail'
mail from: "${MAIL_FROM}",
       to: "${MAIL_TO}",
  subject: "【成功】 ${MAIL_SUBJECT}",
     body: "${MAIL_BODY}\n\n【Today's Commit Logs】\n${commitLogs}",
       cc: '',
      bcc: '',
  replyTo: ''
```

[Jenkinsfile で 成功／エラーメールを送る方法](https://qiita.com/kouji-kojima/items/93dd9505c97f6898e47e)
Jenkinsfile で 成功／エラーメールを送る方法

### Jenkinsfile で SUCCESS/ERROR メールを送る方法

```
def MAIL_FROM    = '送り元メアド'
def MAIL_TO      = '送り先メアド'
def MAIL_SUBJECT = 'タイトル'
def MAIL_BODY    = '本文'

node {

  try {

    ・・・処理・・・

  } catch (e) {

    stage 'error mail'
    mail from: "${MAIL_FROM}",
           to: "${MAIL_TO}",
      subject: "【失敗】 ${MAIL_SUBJECT}",
         body: "${MAIL_BODY}",
           cc: '',
          bcc: '',
      replyTo: ''

    throw e;

  }

  stage 'success mail'
  mail from: "${MAIL_FROM}",
         to: "${MAIL_TO}",
    subject: "【成功】 ${MAIL_SUBJECT}",
       body: "${MAIL_BODY}",
         cc: '',
        bcc: '',
    replyTo: ''

}
```
Elasticsearch で Beats の インデックス を消したのに ディスク が空かない時

# サイズの大きいインデックスを特定

Beatsのインデックスを消したのですが、ディスクが空かなかったので調べてみました。

```:DevTools(検索コマンド)
GET /_cat/indices?v&s=store.size:desc
```

サイズの大きい順にインデックスを検索できますので。あとは古いものなどを削除していってください。

```:DevTools(削除コマンド)
DELETE インデックス名
```
【JavaScript】lodashの使い方

# lodashとは？

便利な関数をまとめて提供しているライブラリです。
値の操作に長けた便利関数が数多く存在します。
あまりに多いためこの記事では私よく見るものや便利だと思ったものを紹介していきます。

気になった方は公式ドキュメントを眺めてみてください。

[Github | lodash](https://github.com/lodash/lodash)
[公式ドキュメント](https://lodash.com/docs/4.17.11)

## 使い方

npmを使ってインストール

```
npm install --save lodash
```

yarnを使ってインストール

```
yarn add lodash
```

インストール後インポートして使用する

```javascript

import _ from 'lodash';
```

## 関数

### is系

真偽値を返す関数群です。数十種類存在するため大抵のものはカバーされています。
引数にとった値が期待通りならtrueを返し、そうでなければfalseを返します。
主にif文での判定に使うでしょう。

```javascript

_.isString("abc"); // true
_.isString(1); // false

_.isNumber(1); // true
_.isNumber('abc'); // false

_.isArray([1,2,3]); // true
_.isArray(20); // false

// nullもしくはundefinedならtrueを返す
_.isNil(null) // true
_.isNil(undefined) // true
_.isNil("abc") // false

```

### each / forEach

配列やオブジェクトを第一引数に受け取り、繰り返し処理を行う関数です。
ES5で追加されたforEachメソッドとは違い、オブジェクトに対しても使うことができます。
eachはforEachのaliasなのでどちらを使っても処理結果自体は同じです。


```javascript

const user = { name: "taro", age: 25, score: 90 };

// オブジェクトに対して繰り返し処理を行う
_.forEach(user, (value, key) => console.log(value));
// taro
// 25
// 90
```

### sortBy

配列やオブジェクトを第一引数に受け取り、昇順ソートを行います。
標準サポートされているsortメソッドと違い、非破壊的なため元の配列やオブジェクト自体は変わりません。
そのためソートした値を使う場合は、変数に代入するか更新する必要があります。

```javascript

const users = [
  { name: "taro", age: 25 },
  { name: "hanako", age: 55 },
  { name: "taro", age: 10 },
  { name: "hanako", age: 28 }
];

// 名前順にソート
_.sortBy(users, "name");
// [ 
//    {name: "hanako", age: 55},
//    {name: "hanako", age: 28},
//    {name: "taro", age: 25},
//    {name: "taro", age: 10}
// ]

// 名前=>年齢の順番でソート
_.sortBy(users, ["name", "age"]);
// [ 
//    {name: "hanako", age: 28},
//    {name: "hanako", age: 55},
//    {name: "taro", age: 10},
//    {name: "taro", age: 25}
// ]

```

### orderBy

配列やオブジェクトを第一引数に受け取り、ソートを行います。
sortByと近い関数ですがこちらは昇順、降順を指定することができます。

```javascript

const users = [
  { name: "taro", age: 25 },
  { name: "hanako", age: 55 },
  { name: "taro", age: 10 },
  { name: "hanako", age: 28 }
];

// 名前順に降順でソート
_.orderBy(users, "name", "desc");
// [ 
//    {name: "taro", age: 25},
//    {name: "taro", age: 10},
//    {name: "hanako", age: 55},
//    {name: "hanako", age: 28}
// ]

// 名前は降順=>年齢は昇順でソート
_.orderBy(users, ["name", "age"], ["desc", "asc"]);
// [ 
//    {name: "taro", age: 10},
//    {name: "taro", age: 25},
//    {name: "hanako", age: 28},
//    {name: "hanako", age: 55}
// ]
```

# 最後に
ここで紹介した関数は非常にほんの一部です。
どういった事ができるかを簡単に覚えておくと便利だと思います。
ERC721を活用した、全てのロジックとデータをSolidityで管理する方法（後編）

本記事は[ERC721を活用した、全てのロジックとデータをSolidityで管理する方法（前編）](https://qiita.com/biga816/items/09a088d4f4d0055cc860)の後編です。
全てのロジックとデータをSolidityで実装しようとすると記述量がものすごい増え、一瞬でカオスになってしまうので、前編ではマスタデータをSolidityで管理する際にコード量を減らしてシンプルする方法をまとめました。
後編ではロジックをシンプルにする手法をまとめてみたいと思います。

## 手法1. OpenZeppelinのRoleコントラクトを使い、分離したロジック側コントラクトからマスタデータ管理用コントラクトにアクセスする

前編にある「マスタデータ関連ロジックとその他ロジックの分離」を単純にそのまま実行してしまうと、分離したロジック側のコントラクトから、マスタデータ管理用コントラクト内のデータを更新する系のfunctionを呼ぶことができなくなります。
そこで、OpenZeppelinのRoleコントラクトを継承したManagerRoleを作成し、マスタデータ用コントラクトにManagerRoleコントラクトを継承させます。
これにより、Managerとして設定されたコントラクトからもデータを更新ができるようになります。

```CatMaster.sol
import "./modules/MasterDataModule.sol";
import "./utils/ManagerRole.sol";

contract CatMaster is MasterDataModule, ManagerRole {

    struct Cat { string name; uint256 age;}
    Cat[] public cats;
    
    function createCat(string name, uint256 age) external onlyManager {
        Cat memory cat;
        cat.name = name;
        cat.age = age;
        uint256 catId = cats.push(cat) - 1;
        _mint(msg.sender, catId);
    }

    :

}
```

ただしこの手法を用いると、コントラクトオーナーであれば好きなアドレスをManagerに設定でき、コントラクトオーナーが好き勝手できてしまうイメージを持たれてしまう可能性があるので、純粋に資産として扱うERC20やERC721のようなコントラクトでは用いないほうが良いでしょう。

## 手法2. Factoryパターンの導入
前述のCatMasterコントラクトのCatのような簡単な構造体を管理するコントラクトであれば、1つのコントラクト内で複数のデータを管理しても問題ないと思いますが、例えばERC20のような複雑なデータを複数管理する場合は、１つのコントラクト内で実装しようとすると一瞬でカオスになります。
そこで Factoryパターンの出番です。
例えばERC20を複数管理するとした場合に、ERC20のコントラクト自体はそのまま通常通りデプロイします。
そのデプロイした際のコントラクトアドレスをFactoryコントラクト内で管理することで、Factoryコントラクトを通じて任意のコントラクトを参照できるようにします。

```TokenFactory.sol
contract TokenFactory {
    address[] public contracts;

    function addToken(address _contractAddress public returns (bool) {
        contracts.push(_contractAddress);
        return true;
    }

    function contractOf(uint256 _tokenId) public constant returns(address) {
        return contracts[_tokenId];
    }
}
```

上記コントラクトでは、管理対象のコントラクト(ERC20)のデプロイはコントラクト外で実施し、アドレス登録の処理だけをFactoryコントラクト内で実行することを想定しています。
デプロイ自体もFactoryコントラクト内で実行することも可能ですが、gas limitに引っかかってデプロイできないことが多いので、デプロイ自体はコントラクト外で実施したほうが無難と思われます。


## 手法3. ロジックの共通化、切り出し
コードの量を減らすために些細な処理でも共通化できる部分は共通モジュール化し、必要に応じて継承して使うようにします。
これは他の言語でも当たり前のことですが、Solidityにおいては別の意味でも重要となります。
Solidityでfunction内のロジックが複雑化して使用する変数が増えると、すぐに下記のエラーが発生します。
`Stack too deep, try removing local variables.`
このエラーは処理を共通化して外出ししていると起きにくくなるので、Solidityにおいて処理の共有化や切り出しはとても重要になります。

## まとめ
前編、後編とで様々なSolidityの実装における工夫や懸念点をまとめました。
これによりSolidityで全てのロジックとデータを管理するコントラクトを開発する際に、比較的簡単に実装できるようになると思います。
是非試してみてください。

---
ブログでも書いています
[ERC721を活用した、全てのロジックとデータをSolidityで管理する方法（後編）](http://blog.tanakas.org/how-to-use-solidity-to-manage-all-logic-and-data-vol2/)
Boccoのメッセージを再生するトリガをサーバに置く


気がつけば MyThings のサービスが1/31で終了とのこと。
Boccoをちょっとしたお知らせに使用していたのですが、でくの坊と化しました・・
が、お知らせを発行する機能は便利だったので、別の方法を探します。

IFTTTというアプリが便利そうです。が、Boccoに対応していません。でも他に手がなさそうなので、IFTTT使います。面倒だけどAPI使って実行するしかない（のかなあ）。

どうにか動いたので、手順含め公開しておきます。なお、外からアクセスできるHTTPサーバを持っていないとこの方法は実現できません。

# API KEY の入手
Boccoを売っているユカイ工学さんに申し込みます。数日後にメールでAPI KEYが伝えられます。翌日ぐらいに来た記憶。ありがとうございます。

# Room ID の入手
単に喋らせるだけの場合、Roomは固定で良いわけです。API KEY の使用方法サンプルに、Room IDの取得方法が掲載されているのでその通りにコンソールから実行。
access tokenは毎回変わるので都度取得が必要ですが、Room IDは不変なので、あらかじめ調べておいてプログラムに埋め込みます。

# サーバにプログラムを配備

以下のphpプログラムを配備します。使用する際は
・APIKEY(Sbalsdkflaksevd8fajsefxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
・アカウント(your_account@mailaddr.com)
・パスワード(your_password)
・Room ID(11111111-2222-333f-your-roomkeyxxxxx)
を置換してください。もちろんメッセージの'ヤッホー'も。

それから、アカウントとパスワードは捨てアカ作りました。平文パスワードとか置きたくないですからね。

```php:call.php
<html>
  <head>
    <meta charset="UTF-8">
    <title>bocco</title>
  </head>
<body>
<?php
exec_bocco();
?>
</body>
</html>
<?php
function exec_bocco() 
{
	send_message('ヤッホー');
}	

function send_message($message)
{
	$url = "https://api.bocco.me/alpha/sessions";
	$post_data = array("apikey" => "Sbalsdkflaksevd8fajsefxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
					   "email" => "your_account@mailaddr.com",
					   "password" => "your_password");
	$dat = getApiDataCurl($url, $post_data, NULL);
	if ($dat == []) {
		echo "<h1>no dat!</h1>\n";
		return;
	}
	$token = $dat{'access_token'};

	$url = "https://api.bocco.me/alpha/rooms/11111111-2222-333f-your-roomkeyxxxxx/messages";
		
	$post_data = array("access_token" => $token,
					   "unique_id" => uuid(),
					   "media" => "text",
					   "text" => $message);
	$header_data = array("Accept-Language: ja");

	$dat = getApiDataCurl($url, $post_data, $header_data);

	echo "<p>".date("Y/m/d H:i:s")."</p>\n";
	echo "<p>".$message."</p>\n";
}

function getApiDataCurl($url, $post_data, $header_data)
{
    $option = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 5,
    ];

    $ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url); 
    curl_setopt_array($ch, $option);
	curl_setopt($ch, CURLOPT_POST, true);
	curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
    if ($header_data != NULL) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header_data);
    }

    $json    = curl_exec($ch);
    $info    = curl_getinfo($ch);
    $errorNo = curl_errno($ch);

	curl_close($ch);

    if ($errorNo !== CURLE_OK) {
		echo "<h1>errorNo:".$errorNo."</h1>\n";
        return [];
    }

    if ($info['http_code'] !== 200 && $info['http_code'] !== 201) {
		echo $url."\n";
		echo "<h1>http_code:".$info['http_code']."</h1>\n";
		echo "result:".$json."\n";
        return [];
    }

    $jsonArray = json_decode($json, true);
    return $jsonArray;
}

function uuid()
{
	$data = openssl_random_pseudo_bytes(16);
	#$data = random_bytes(16);
	$data[6] = chr(ord($data[6]) & 0x0f | 0x40); 
	$data[8] = chr(ord($data[8]) & 0x3f | 0x80); 
	return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

?>
```
なんだかんだで苦労しました。uuidの生成って、PHPにAPIないんですねえ。

#IFTTTアプリのWebHookで呼び出す
サーバに置いた上記のプログラムを呼び出すように設定して、完成です。
テストする限り、動いている模様。めでたしめでたし。
Gravioのセンサー接続可能数の検証

こちらの記事は、Gravioの「センサーの接続可能数」について記載していきます。
[Gravio](https://www.gravio.com/jp/gpromo/1901-casual-iot)は簡単にエッジでセンサーからのデータ収集を始めることができる、IoTソフトウェアです。

#使用したPCのスペック

Microsoft Surface Studio
- CPU：Intel Core i7 6820HQ CPU @2.70GHz,2.71GHz
- メモリ：16GB

#センサーの接続可能数検証
##1回目検証
###接続センサー　計12個

|センサー|個数|
|:-----------------|:------------------:|
|ソフトウェアセンサー|1|
|Aqara　温度センサー|9|
|Aqara　人感センサー|1|
|Aqara　ボタンセンサー|1|

検証期間：12/7～1/7

ソフトウェアセンサーで利用しているのはPCに内蔵のカメラとNumberOfPeople-Liteという推論モデルです。今回は10秒に1回の動作設定としています。

###検証結果
平常時CPU使用率：22%前後
なお、ソフトウェアセンサー動作時は一時的に6%程度、使用率が増加します。


##2回目検証
###接続センサー　計17個

|センサー|個数|
|:-----------------:|:------------------:|
|ソフトウェアセンサー|1|
|Aqara　温度センサー|9|
|Aqara　人感センサー|6（前回+5）|
|Aqara　ボタンセンサー|1|

検証期間：1/8～1/15

ソフトウェアセンサーの設定は先程の検証と同一としています。

###検証結果
CPU使用率：23%前後
ソフトウェアセンサー動作時に6%程度一時的に使用率が増えます。


#まとめ、考察
Aqaraのセンサーを増やしましたが、CPUの使用率は大きく変化しませんでした。
センサーを増設した際のパフォーマンス変化を見る限り、この程度の追加であれば、余裕をもって処理できることがわかりました。
なお、ソフトウェアセンサー機能やデータのファイル出力など、処理の内容によってはメモリを大量に消費するため、結果としてパフォーマンスに影響を与える場合があります。

#あとがき
今後、MacやRaspberry Piでの検証を進めていきたいと考えています。
量と質　ソフトウェアの評価。仮説（159）

ソフトウェアの評価を、量と質の観点から行う。

ここでは、ソースコードのないソフトウェアを含めて検討し、ソースコードのある場合は

量と質　ソースコードの評価
と別記事にする。
# ROM, Monitor, BIOS
ハードウェアに組み込んで、ROMなどから自動お的に起動するソフトウェア。
SDKなどの開発きっこがあれば、ソースコードがついていることもある。
デバッガで、機械語・アセンブラにして、解読できる場合もある。

ここでは、利用する側の視点でまず考える。

プログラマにも読んでほしい「QC検定にも役立つ！QCべからず集」
https://qiita.com/kaizen_nagoya/items/d8ada7b7fceafe2e5f0e

# 参考資料
質と量。仮説（156）
https://qiita.com/kaizen_nagoya/items/d5361daeeb13c71caa91

ネット記事の指針。仮説（157）質と量　
https://qiita.com/kaizen_nagoya/items/44a83508ac6ec2fa4cf0

ソースコードの評価。仮説（158）量と質　
https://qiita.com/kaizen_nagoya/items/f35aa0e4bf64ac49b1bc

ソフトウェアの評価。仮説（159）量と質　
https://qiita.com/kaizen_nagoya/items/415a1bc4013c7a879548

### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

#### Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
レイヤードアーキテクチャについて

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257568/3b7f52f1-83d6-2719-a171-3a6576e82ac1.png)

現在扱うシステムで採用されているアーキテクチャなので、こちらを読んで焦点を絞ったまとめ

## レイヤードアーキテクチャとは
ソフトウェアシステムの関心事を切り離し、**ドメイン層を他から分離する**テクニック。

### ドメインとは
システムが担う業務知識、業務影響、または業務活動の領域
ユーザーがプログラムを適用する対象領域
レイヤードアーキテクチャにおける核の部分

### ドメイン層とは
ドメインロジックの責務を負う、設計および実装の一部分。単位
ドメインモデルのソフトウェアにおける表現をそのまま反映させた場所

### ドメインロジックとは
ドメインを成立させているプログラム処理

### ドメインモデルとは
特定の図ではなく図が伝えようとしている**考え方**
図で**知識が厳密に構成され、選び抜かれて抽象化されたもの**を表すことができる
なんか分かりづらかったがドメインモデル図イメージできれば良いと思っている

### モデルとは
選び抜かれてシンプルにされ、意図的に組み立てられた知識の表現形式
情報のもつ意味を明らかにし、その情報を問題に集中させたもの

ここまで前提的知識

## ドメイン層とそれ以外の層の構成
- ユーザーインターフェース層
  - 外部からの操作によるコマンドを解釈する領域
  - 例)バッチにおけるCLI、MVCにおけるViewなど
- アプリケーション層
  - ソフトウェアが行うことになっている仕事を定義する領域
  - 例)プログラムの進捗状態反映(ログ)、MVCにおけるControllerなど
- **ドメイン層**
  - ビジネスの概念、情報、ルールを表す領域
  - 例)ドメインロジック、MVCにおけるModelなど
- インフラストラクチャ層
  - 上位のレイヤ全体を支える一般的な技術的機能
  - 外部との接続機構、MVCにおけるO/R Mapperなど


### 重要な考え方
- ドメイン層は特別ということ
- レイヤ内のどの要素も、**同じレイヤの他の要素か、その「下にある」レイヤの要素にしか依存しない** ということ。
- 凝集度の高い側面を隔離するレイヤを選び出すこと
- ビジネスの本質的な情報のみなので、変更・保守・追加がし易いこと
- 特定のアーキテクチャに依存しないこと(なのでこれが確立したアーキテクチャな訳ではない)
- DI化されたレイヤードアーキテクチャ、ヘキサゴナルアーキテクチャなどがある(実装レベルの別記事にて)

## 書籍情報
https://amzn.to/2Df8ZqX
Eric Evans, エリック・エヴァンスのドメイン駆動設計

## 雑感
ドメインを理解するには、「それ以外」を理解できないといけない感じがした。
レイヤードアーキテクチャが、「ドメインとそれ以外」と表現するのはドメインが本質な事を強調しているのであって、実際は「それ以外」のレイヤ達も適切に切り分けることが重要。なので、「それ以外」を理解しないといけなそう
MAMP環境でのブラウジングがやけに遅い時の対処法

今まで問題なかったのですが、Larabelを使う現場に移ってからローカル環境のブラウジングがやけに遅いので、MAMPが怪しいと思い調査しました。
一番の原因はxdebugっぽくて、コメントアウトしたら改善されました。

#やったこと
php.iniの設定を変更します。
ちなみに、変更するファイルは、/Applications/MAMP/bin/php/php7.x.x/conf/php.iniです。
/Applications/MAMP/conf/php7.x.x/php.iniではないのでお気をつけて！

##xdebugのコメントアウト
デフォルトはOFFなので、OFFだったら別問題

```/Applications/MAMP/bin/php/php7.2.8/conf/php.ini
// zend_extensio~のとこにセミコロンつければOK

[xdebug]
;zend_extension="/Applications/MAMP/bin/php/php7.2.8/lib/php/extensions/no-debug-non-zts-20170718/xdebug.so"
xdebug.remote_enable=on
xdebug.remote_autostart=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.idekey=Listen for XDebug
xdebug.profiler_enable=1
xdebug.profiler_output_dir="/Applications/MAMP/tmp"
```

##メモリ制限の解除
念のため、メモリ上限を増やしておきます。というか無制限(-1)にしました。

```/Applications/MAMP/bin/php/php7.2.8/conf/php.ini
// -1は無制限、2048MBとかでもOK

; Maximum amount of memory a script may consume (128MB)
; http://php.net/memory-limit
memory_limit = -1
```


##OPcacheのコメントアウト
OPcacheとは
http://php.net/manual/ja/book.opcache.php
これは設定いじらなくてもいいかも。お任せします。

```/Applications/MAMP/bin/php/php7.2.8/conf/php.ini
// zend_extens~　にセミコロンつければOK
//　opcache.revalidate_freqの値を2(phpのデフォルト値)にするとか、でもOKらしい
// opcache.enable_cliを0、opcache.enable=0を追加でもOKらしい
// MAMPのPreference　>　php　>　Cacheの設定をOFFにしてたらデフォルトはOFFなのかも

[OPcache]
;zend_extension="/Applications/MAMP/bin/php/php7.2.8/lib/php/extensions/no-debug-non-zts-20170718/opcache.so"
  opcache.memory_consumption=128
  opcache.interned_strings_buffer=8
  opcache.max_accelerated_files=4000
  opcache.revalidate_freq=60
  opcache.enable_cli=1
```
Djangoにおける静的ファイル(static file)の取り扱い

DjangoのチュートリアルやUdemyの授業を進める中で、理解できなかったsettings.pyの下の方に追記する、**STATICFILES_DIRS**や**STATIC_ROOT**、**STATIC_URL**についてわかりやすい記事があったので、備忘のために。(翻訳許可済み)
[Django Static Files](http://rahmonov.me/posts/django-static-files/)

同じことに悩まれている方の参考になれば嬉しいです。

# STATICFILES_DIRS

個別のアプリケーションではなく、トップページに表示する画像などを保管する任意の場所を、Djangoに探すように指定するのが**STATICFILES_DIRS**。(ここでは仮にプロジェクト直下に"assets"というフォルダを作成。)

```python:settings.py
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "assets")
]
```

# Application/static/
**"Application/"**という名前のアプリケーションを作成したとする。このアプリケーションに関するstatic_file（cssやjs, 画像など）は、**"Application/static/"**に保管する。これはアプリケーションごとに作成するので、アプリケーションの数だけ増える。

これで、下のように静的ファイルの置き場所ができた。(Application1,2,3を作成したとする。)
ローカルでの開発環境では、このように静的ファイルが別々のフォルダに格納されていても問題はない。

<img width="218" alt="Screen Shot 2019-02-05 at 0.03.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/330669/3fe41e9d-39b2-2dab-1851-795b4347e010.png">


# collectstatic コマンド
web server(NGINX等)やHerokuにデプロイする際には、静的ファイルの置き場所を複数ではなく、一つの場所に集めてあげる必要がある。それが**collectstatic**コマンド。しかし、collectstaticする前に、集める場所をsettings.pyに設定する必要がある。(プロジェクト直下、"static"というフォルダを指定。)

```python:settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
```
この後、

```console:
$ python manage.py collectstatic
```
これで下のように静的ファイルが、プロジェクト直下の"static"に集約される。
<img width="386" alt="Screen Shot 2019-02-05 at 0.30.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/330669/0c4d961d-518b-b3d5-0a03-732b53dbdc2d.png">

# STATIC_URL
web serverに静的ファイルを見に行く場所を指定する。
・NGNIXの例

``` console:
location /static/ {
    root    /my/project/static/;
}
```
そして最後に、デプロイ環境で、{% static 'main.css' %}などのDjangoテンプレートが読みに行く場所をsettings.pyに**STATIC_URL**で指定してあげる。

```python:settings.py
STATIC_URL = '/static/'
```

# まとめ
最終的には下のイメージになる。
開発環境では、プロジェクト直下や各アプリケーションごとに静的ファイルの置き場を作成してそれぞれを呼び出す。
デプロイする際は、個別の静的ファイルを**STATIC_ROOT**で指定した場所に**collectstatic**で全て集める。
その後、web serverに**STATIC_ROOT(static/)**を見に行くように**STATIC_URL**で指定する。
<img width="446" alt="Screen Shot 2019-02-05 at 0.54.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/330669/5dfea6d6-e9c8-a02e-4c6c-720d4767473e.png">


間違っている箇所等あれば、コメントいただけると助かります。
以上です。
【Unity】Spriteインポート時にピボットを設定する

## はじめに

画像をプロジェクトにインポートした際に、OnPreprocessTexture()やOnPostprocessTexture()内で色々と設定を行う場合があります。今回はピボットを変更する必要があったのですが、```spritePivot```を設定するだけでは不十分でした。

```これだけだとダメ.cs
public class ImportProcess : AssetPostprocessor
{
    void OnPreprocessTexture()
    {
        var ti = (TextureImporter)assetImporter;
        ti.spritePivot = new Vector2(0.0f, 0.0f);
    }
}
```

## どうすればうまく行くか

spritePivotを設定する前に```TextureImporterSettings```の```spriteAlignment```をCustomに設定してやる必要がありました。

```TextureImporterSettingsを使う.cs
public class ImportProcess : AssetPostprocessor
{
    void OnPreprocessTexture()
    {
        var ti = (TextureImporter)assetImporter;

        var texSettings = new TextureImporterSettings();
        ti.ReadTextureSettings(texSettings);
        texSettings.spriteAlignment = (int)SpriteAlignment.Custom;
        ti.SetTextureSettings(texSettings);

        ti.spritePivot = new Vector2(0.5f, 0.0f);
    }
}
```

「Editor上でPivotをCustomに設定する作業」、に該当するコードを書く必要があったみたいです。

#### 参考

https://answers.unity.com/questions/1318809/onpostprocesstexture-textureimporterspritepivot-do.html
Пролетарии всех стран, соединяйтесь!

```
🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎
🍎🍎🍎🍎🍎🍎🍎🍎🍊🍎🍎🍎🍎🍎🍎
🍎🍎🍎🍎🍎🍊🍊🍎🍊🍊🍎🍎🍎🍎🍎
🍎🍎🍎🍎🍊🍊🍊🍎🍎🍊🍊🍎🍎🍎🍎
🍎🍎🍎🍊🍊🍊🍊🍎🍎🍎🍊🍊🍎🍎🍎
🍎🍎🍊🍊🍊🍊🍎🍎🍎🍎🍊🍊🍊🍎🍎
🍎🍊🍊🍊🍊🍊🍊🍎🍎🍎🍎🍊🍊🍎🍎
🍎🍎🍊🍊🍎🍊🍊🍊🍎🍎🍎🍊🍊🍊🍎
🍎🍎🍎🍎🍎🍎🍊🍊🍊🍎🍎🍎🍊🍊🍎
🍎🍎🍎🍎🍎🍎🍎🍊🍊🍊🍎🍊🍊🍊🍎
🍎🍎🍎🍎🍊🍎🍎🍎🍊🍊🍊🍊🍊🍎🍎
🍎🍎🍎🍊🍊🍊🍎🍎🍎🍊🍊🍊🍎🍎🍎
🍎🍊🍊🍊🍎🍊🍊🍊🍊🍊🍊🍊🍊🍎🍎
🍎🍊🍊🍎🍎🍎🍊🍊🍊🍎🍎🍊🍊🍎🍎
🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎
```

```ruby:unite.rb
puts "1FFFFFDFFC9FF19FC39F0F1C0F3C8E3F8E7F88FB83E38F100E719FFFF".hex.to_s(2).gsub("1", "🍎").gsub("0", "🍊").scan(/.{15}/)
```
Unityの教科書レベル８　メモ

#四捨五入に関して
Math.RoundToIntメソッドを使う
例)
 float x = Mathf.RountToInt("四捨五入したい変数");

#光線とコライダの衝突について
Physics.Raycastメソッドを使う
例)
If(Physics.Raycast(ray, out hit,Mathf.Infinity)){
    }

ray : Ray変数(本来ここはrayの出る座標、方向などが入る)
hit :out変数でここに値を詰めて返す
Math.Infinity :光線の長さ（どれだけの長さを当たり判定の適用範囲にするか)

#Physicsによる当たり判定の条件
・両方のオブジェクトにColliderコンポーネントがアタッチされている
・少なくとも一方のオブジェクトにRigidbodyコンポーネントがアタッチされている

#Tagを使う
スクリプトからタグを利用してオブジェクトが判別できるようになる
例）
if(other.gameObject.tag=="Apple"){
   }

#複数の効果音の鳴らし方
1.音を鳴らしたいオブジェクトにAudioSourceコンポーネントをアタッチする
（注：衝突して消えるオブジェクトにアタッチしたい場合はAudioSource.PlayClipAtPoint(AudioClip.clip,Vector3.pos)メソッドを使う。このメソッドは音源と音を鳴らしたい座標を指定すると指定した場所に新しくゲームオブジェクトを生成してそこで効果音を発生させる)
2.いつどの効果音を鳴らすかをスクリプトから指定する
3.スクリプト内の変数に効果音ファイルを代入する
numpyの速度を最大限に活かすために

# 前置き
numpyの処理（argmax）がボトルネックになるような計算（[otheroの強化学習](https://qiita.com/ryuoujisinta/items/2439b4d3eb0de50be1c2)）をしていたときに気づいたので共有する。意外と速度が違う。

# 結論
numpy.ndarrayのメンバ関数が使える処理はそれを使おう。また、1つの数字に対する操作はmathジュールの方が速い。

# ベンチマーク
jupyter notebook上で次のベンチマークを行った。コメント行は結果を示す。明らかにnumpy.ndarrayの関数が速い。また、sqrtはmathモジュールの方が速い。

```test.py
import numpy as np
import math

a = np.random.rand(100)

%timeit np.argmax(a)
# 1.48 µs ± 19.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit a.argmax()
# 668 ns ± 6.52 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit np.max(a) 
# 3.32 µs ± 24.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit a.max() 
# 2.82 µs ± 30.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.sum(a) 
# 3.17 µs ± 34.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit a.sum() 
# 2.44 µs ± 61.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit math.sqrt(a.sum())
# 2.71 µs ± 39.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.sqrt(a.sum())
# 4.21 µs ± 36.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
```
配列サイズを大きくしたものも行った。差異は小さくなっているが、依然としてnumpy.ndarrayの関数が速い。maxは殆ど一緒になっている。

```test.py
a = np.random.rand(10000)

%timeit np.argmax(a)
# 9.94 µs ± 536 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit a.argmax()
# 8.96 µs ± 355 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.max(a) 
# 7.98 µs ± 151 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit a.max() 
# 8 µs ± 372 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.sum(a) 
# 9.12 µs ± 193 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit a.sum() 
# 7.89 µs ± 274 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each

%timeit math.sqrt(a.sum())
# 7.99 µs ± 158 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.sqrt(a.sum())
# 9.92 µs ± 64.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
```
Azure Stream Analytics Jobsで時刻情報（UTC）を日本時間（JST）に変換する方法

How to convert UTC time into JST time region via Stream Analytics Jobs.

先日AzureのStream JobsでAzure IoT Hubから取得したデータのQueue時刻情報をUTC時間で取得して，それをPower BIで視覚化していたのですが，この時刻情報の変換する方法について判明したのでそのメモを残します．

なお，執筆時以前（2019/02/04）にはこの情報を見つけることができませんでした(StackOver Flowで見つけました)。

ちなみにこの方法はSQLクエリを書く際には一般的な方法だと思います．SQLクエリで時刻を変換したい人があまりいないため情報が見つかりにくかったのかも？

## Azure Stream Analytics Jobsについて

Azure Stream Analyticsとは

> Azure Stream Analytics は、デバイスからの大量のデータ ストリームを分析することができるイベント処理エンジンです。 受信データは、デバイス、センサー、Web サイト、ソーシャル メディア フィード、アプリケーションなどから得ることができます。 また、データ ストリームから情報を抽出し、パターンや関係を把握することもできます。 これらのパターンを使用して、アラートの作成、レポート ツールへの情報のフィード、後で使用するための情報の保存など、別のアクションをダウンストリームでトリガーすることができます。

*https://docs.microsoft.com/ja-jp/azure/stream-analytics/stream-analytics-introduction*

AWSのKinesis StreamのAzure版のStreamデータを扱うサービスだと私は捉えています．

今回，Azure IoT HubとAStream Analyticsを繋ぎ，その際に取得できるJSON形式のデータ中の時刻情報の変換について触れます．

## フロー

![Flow.png](https://qiita-image-store.s3.amazonaws.com/0/211407/1cfc0c23-87b2-cec4-6628-740cf4a4d1b1.png)

このようにIoTデバイスから流れてきたJSONにAzure IoT Hubがさらにいくつかの情報を追加で付与したものがStream Analytics Jobsで流れてくるので，これを変換しましょう．

## UTCをJSTに変換

Stream Analyticsには「クエリ」を書くことができます．ここで，「流れてくるデータ」から必要なデータを抽出，必要に応じて変換して他のサービスに流すことができるというすぐれものです．

![StreamJobs.png](https://qiita-image-store.s3.amazonaws.com/0/211407/430e50bb-8075-7ac8-6435-78d5afb49fb9.png)

「クエリ」はStream Analyticsの左のメニューのジョブトポロジ（Job Topology）の中にあります．

- Azure IoT Hubから流れてくるデータ
    - https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-define-inputs

> When your data comes from an Event Hub stream input, you have access to the following metadata fields in your Stream Analytics query:

上記マイクロソフトのリファレンスから，以下のデータが付与されて届くので(これ以外にもあります），これらを変換する例を示します．

| Property | Description |
|:--|:--|
| EventProcessedUtcTime | The date and time that the event was processed by Stream Analytics. |
| EventEnqueuedUtcTime | The date and time that the event was received by Event Hubs. |
| PartitionId | The zero-based partition ID for the input adapter. || EventProcessedUtcTime | The date and time that the event was processed by Stream Analytics. |
| EventEnqueuedUtcTime | The date and time that the event was received by Event Hubs. |

#### そのままの場合

以下のクエリで時刻情報はUTC timeのまま流せます

```sql
SELECT
    EventProcessedUtcTime,
    EventEnqueuedUtcTime,
    PartitionId
INTO
    [YourOutputAlias]
FROM
    [YourInputAlias]
```

これをPower BIで受けとると，日本の現地時間の９時間前の時間が表示されます．PartitionIDはString型です．

なお，EventProcessedUtcTimeが取れない場合はIoTHub.EnqueuedTimeでも試してみると良いかもしれません．私の場合はなぜかこちらしか取れませんでした．

#### 日本時間（JST）へ変換

本題です．といっても普通にSQLでUTC時間を変換する常套手段です．

UTC(Coordinated Universal Time)とは協定世界時であり，世界で基準となる時刻です．日本とイギリスの時差は+9hなので，+0900すれば良いです．クエリを以下に書き換えることで日本時間になります．

```sql
SELECT
    DATEADD(hour, 9, EventProcessedUtcTime),
    DATEADD(hour, 9, EventEnqueuedUtcTime),
    PartitionId
INTO
    [YourOutputAlias]
FROM
    [YourInputAlias]
```

これからわかるように，他の地域の時刻へも変換できます．これで他のサービスへ流すと変換された時刻情報が送られます．

今回，Power BIで時刻情報をそのまま表示するとこのように見えました．

![image.png](https://qiita-image-store.s3.amazonaws.com/0/211407/ebfbe5d8-9543-c66d-3bdb-476a9c3be7bd.png)

これで変換できたことが確認できました．
go言語の複数戻り値とscopeのハマりどころ

# はじめに
go言語で複数の戻り値を使った変数への代入と、scopeの扱いでバグを出してしまったので恥ずかしながらその供養に。

# 例題
いきなりですが、よくプログラミングの課題であるやつ

```
A
AA
AAA
AAAA
AAAAA
AAAAAA
AAAAAAA
AAAAAAAA
AAAAAAAAA
AAAAAAAAAA
```

をあえて無限ループを使って作ってみた以下のコードは正しく動くでしょうか。

```golang
package main

import (
	"fmt"
)

func main() {
	str := "A"
	current := 1

	for {
		output, current := appendAndIncrement(str, current)
		fmt.Println(output)

		if current > 10 {
			break
		}
	}
}

// 元文字列と繰り返しの数 n を受け取り、n だけ繰り返された文字列とインクリメントされた n を返す。
func appendAndIncrement(src string, n int) (str string, incr int) {
	for i := 0; i < n; i++ {
		str += src
	}
	incr = n + 1

	return
}
```

試しにやってみると`current`がインクリメントされずにループを抜け出せないことがわかります。
https://play.golang.org/p/hCjSEGzw3Qc

分かってしまえば理由は単純で、`output`を新規変数として宣言しようとして誤って`current`まで新規に宣言してしまっています。goでは内側のscope（この場合は`for`の中）内で変数の再宣言が可能なためです。

http://golang.jp/go_spec#Declarations_and_scope

```
ブロック内で宣言された識別子は、内側のブロック内で再宣言できます。内側のブロック内で宣言した識別子がスコープ内にある間、その識別子は内側で宣言した実体を表しつづけます。
```

普段は特に意識しなくても自然に使っている仕様ですが、複数戻り値が絡んだ際に意図せず変数の再宣言をしてしまったのが上のコードでした。正しく動作させるには`for`の中身を以下のように修正しないといけません。

```go
for {
	var output string // 個別に宣言する
	output, current = appendAndIncrement(str, current) // 既存変数への再代入
	fmt.Println(output)

	if current > 10 {
		break
	}
}
```

# どんな時にハマったか
redisのSCAN機能を使ってkeyのリストを取り出したい時に、うっかり以下のようなコードを書くと無限ループにハマって死にます。

```go
var cursor uint64

var keys []string
var err error
for {
	tmpKeys, cursor, err := redisdb.Scan(cursor, "key*", 20).Result()
	if err != nil {
		panic(err)
	}
	keys = append(keys, tmpKeys...)
	if cursor == 0 {
		break
	}
}
fmt.Println("key length:", len(keys))
```

タチが悪いのは、テスト環境などでredisのkeyが20以下だと最初から`cursor`に`0`が入るので、一見正しく動いてるように見えてしまうところですね。
英語の勉強時に使っている海外サービス一覧(随時更新)

海外の大学院行きたい人とか向け。プログラミングに関係するというよりも一般向けです。他にいいものがあれば教えてください :bow: 

## 1. Quizlet

単語帳アプリ。画像も登録できるから便利。

https://quizlet.com

## 2. vocabulary.com

言葉のニュアンスを掴むときに便利。こんな感じでニュアンスが伝わる文章を書いてくれてる

https://vocabulary.com


![image.png](https://qiita-image-store.s3.amazonaws.com/0/63876/58da9843-b644-6bad-cff2-812d733d12b7.png)


## 3. pinterest(google画像検索)

言葉のニュアンスを掴むときに画像を調べる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/63876/7c63987c-51ad-dc63-5ad1-cc23398b7315.png)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/63876/53b0526c-868a-6c59-2b04-7a16a09af434.png)

## 4. Kahn Academy
小学校から大学までのいろいろな科目の授業をオンラインで無料公開している。

https://www.khanacademy.org/

## 5. English language & Usage StackOverflow

英語のニュアンスとかについて質問できる。
スタックオーバーフローの英語学習版

https://english.stackexchange.com/

## 6. iTalki

ランゲージエクスチェンジの相手を探せる。
フリーランスの先生とも契約可能。

https://www.italki.com/
Windows10でRustの開発環境を構築

なんか新しい言語をさわってみたくなったので、Rustを選んでみました。
構築のやり方はQiitaにも既に上がっていますが、自分のためのメモのつもりで残しておきます。

# Windows Native環境へのインストール
## Visual C++ Build Tools のインストール
RustをWindowsで使用する時、C++のコンパイラーが別途必要になるので、あらかじめVisualStudio Build Toolsをインストールしておきます。

[VisualStudioダウンロードページ](https://visualstudio.microsoft.com/ja/thank-you-downloading-visual-studio/?sku=BuildTools)をクリックしてBuildToolsをダウンロードします。
`vs_buildtools__1122083509.1549292620` 2019/2/5時点では左記のファイル名
ダウンロードしたファイルを実行して、Visual C++ Build Tools にチェックを入れてインストールします。

![buildtiool.png](https://qiita-image-store.s3.amazonaws.com/0/24418/b7172417-59c6-9c0a-2b82-4f5c515568f9.png)

もちろんVisualStudio IDEをインストールしてもOK


## Rustupのインストール
Rustupは、Rustのためのツールチェーンマネージャーで、簡単にコンパイラーのバージョンやターゲットを変更できるようなので、これを使ってインストールすることが推奨されているようです。
[Rustup](https://rustup.rs/)のサイトへ行って `rustup‑init.exe` のリンクをクリックするとダウンロードが始まる。
ダウンロードした`rustup-init.exe`をクリックすると以下の画面が表示されるので、最後のプロンプト>で1を入力してエンターキーを押すとインストールが始まります。

```
Welcome to Rust!

This will download and install the official compiler for the Rust programming
language, and its package manager, Cargo.

It will add the cargo, rustc, rustup and other commands to Cargo's bin
directory, located at:

  C:\Users\[ユーザー名]\.cargo\bin

This path will then be added to your PATH environment variable by modifying the
HKEY_CURRENT_USER/Environment/PATH registry key.

You can uninstall at any time with rustup self uninstall and these changes will
be reverted.

Current installation options:

   default host triple: x86_64-pc-windows-msvc
     default toolchain: stable
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1
```
割と時間がかかるのでそのままじっと待って

```
Rust is installed now. Great!

To get started you need Cargo's bin directory (%USERPROFILE%\.cargo\bin) in
your PATH environment variable. Future applications will automatically have the
correct environment, but you may need to restart your current shell.

Press the Enter key to continue.
```
こんな感じに表示されたらインストール完了、環境変数のPATHにはCargoのbinディレクトリが登録されているのでコンソールを新しく開けば使えるようになっています。

```
C:\rust> rustc --version
rustc 1.32.0 (9fda7c223 2019-01-16)

C:\>cargo --version
cargo 1.32.0 (8610973aa 2019-01-02)
```

# WSL環境へのインストール

[Rustup](https://rustup.rs/)のサイトに書いてある

```
$ curl https://sh.rustup.rs -sSf | sh
```
を実行します。Windows Nativeの時と同じように進めていって

```
Rust is installed now. Great!
```
が表示できればOK
GameObjectを円運動させてみた

###１．狙い
GameObjectを円運動させるだけなら、調べれば簡単にできますが、円運動する座標が決まっており、いくつ配置しても同じ場所でしか円運動を行わないものがあったので、プレハブ化した後に好きな場所にオブジェクトをおいてそこから円運動を行えるようにしました。


##２．手順

1.3DObjectを作成する（Cube・Sphereなど重くならないものをお勧めします）。
2.3DObjectにC#scriptをアタッチする。
これらのやり方がわからない場合は、前回の投稿を参考にしてください。

※SphereをCubeに当てたら100が表示。
https://qiita.com/uroshinse/items/9962480517359a9175fb

##３．ソース

C#スクリプトを編集します。

~~~C#
public class CubeRotate : MonoBehaviour {
    private int speed;                //オブジェクトのスピード
    private int radius;               //円を描く半径
    private Vector3 defPosition;      //defPositionをVector3で定義する。
    float x;                         
    float z;

	// Use this for initialization
	void Start () {
        speed = 1;
        radius = 2;
        
        defPosition = transform.position;    //defPositionを自分のいる位置に設定する。
	}
	
	// Update is called once per frame
	void Update () {
        x = radius * Mathf.Sin(Time.time * speed);      //X軸の設定
        z = radius * Mathf.Cos(Time.time * speed);      //Z軸の設定

        transform.position = new Vector3(x+defPosition.x,defPosition.y, z+defPosition.z);  //自分のいる位置から座標を動かす。

        

	}
}

~~~

入力したら再生ボタンを押してみましょう。

![movie.gif](https://qiita-image-store.s3.amazonaws.com/0/307841/d451a346-3c90-54bf-9b59-c4908777c552.gif)


##4. 参考サイト
Unity3DCG
https://uni.gas.mixh.jp/unity/circle.html

##5.作ってみて
自分は電気を専攻してそれなりになじみがあったので、すんなり理解できた。
Sin・Cosを使って別の動きも試してみたが、応用で上下運動の繰り返しもできるので幅広く使うことができる。
次回は運動の繰り返しについての記事を投稿します。
BluetoothLEAdvertisementWatcher.Received のコールバックが返って来ない

# 最初に結論
`Package.appxmanifest` を編集してBluetoothの機能を使う設定にしてください。

# BluetoothLEAdvertisementWatcher
https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementwatcher
このクラスの`Received`のイベントにコールバックを登録すると、周辺でアドバタイズ中のBLEデバイスの情報を随時取得できます。

## 実装例
```c#
var BleWatcher = new BluetoothLEAdvertisementWatcher 
{ 
    ScanningMode = BluetoothLEScanningMode.Active
};

BleWatcher.Received += async (w, btAdv) => {
    var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
    Debug.WriteLine($"BLEWATCHER Found: {device.name}");

    // SERVICES!!
    var gatt = await device.GetGattServicesAsync();
    Debug.WriteLine($"{device.Name} Services: {gatt.Services.Count}, {gatt.Status}, {gatt.ProtocolError}");

    // CHARACTERISTICS!!
    var characs = await gatt.Services.Single(s => s.Uuid == SAMPLESERVICEUUID).GetCharacteristicsAsync();
    var charac = characs.Single(c => c.Uuid == SAMPLECHARACUUID);
    await charac.WriteValueAsync(SOMEDATA);
};

BleWatcher.Start();
```

## だがしかし
ログに何も出てきません。色々調べながら回りまわって公式ドキュメントに目を通していると、
https://docs.microsoft.com/ja-jp/windows/uwp/devices-sensors/ble-beacon
![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/274974/583e0fde-3daa-0b62-431e-d774f0f55329.png)
🤮

## 再チャレンジ
Visual Studio上のソリューションエクスプローラから
![無題2.png](https://qiita-image-store.s3.amazonaws.com/0/274974/d927c9c2-1663-6de3-2b7a-e34c31f703ca.png)
`Package.appxmanifest`をダブルクリックして編集します。

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/274974/ce24c6f5-714c-5620-0721-6a0d36b34919.png)
[機能]から**Bluetooth**にチェックを入れます。

さすればログに目的のBLEデバイスのスキャン結果が表示されるようになりました。

Androidの`Android.manifest`やiOSの`info.plist`にもBLEのパーミッションを記載する設定ファイルがありますが、こちらは開発(デバッグ)中は未設定でも動作したはずですが、WindowsのUWPアプリの仕様は違うようです。

何も出ないのでBLEデバイス側に問題があるのかとか色々ハマりました。
何かしらエラーを吐いてくれれば気づけたでしょうが、公式のドキュメントはちゃんと見た方がよいという話です。(個々人のブログだと当たり前すぎることは書いてないので)

# 参考
[Why is BluetoothLEDevice.GattServices Empty](https://stackoverflow.com/questions/35937580/why-is-bluetoothledevice-gattservices-empty)
[Windows 10 における Bluetooth サポートについて](https://blogs.msdn.microsoft.com/shozoa/2016/02/28/windows-10-bluetooth/)
sqlite

```ruby:ターミナル１
 $python manage.py runserver $IP:$PORT
```

```ruby:ターミナル2
 $ python
Python 3.6.5 (default, Apr 26 2018, 00:14:31) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import test                                                                                                                                                 
>>> test.write("ss","aa2");
```

```ruby:ターミナル3
 $sqlite3 sample_db.sqlite 
SQLite version 3.7.17 2013-05-20 00:56:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from aiueo;
1|abc|abc|abc
sqlite> select * from aiueo;
1|abc|abc|abc
1|abc|abc|abc
1|abjjj|abjjj|abjjj
sqlite> CREATE TABLE test(
   ...>   id INTEGER PRIMARY KEY AUTOINCREMENT,
   ...>   name VARCHAR(255) NOT NULL,
   ...>   comment TEXT,
   ...>   created_at TIMESTAMP DEFAULT (DATETIME('now','localtime'))
   ...> );
sqlite> select * from test;
```
macOS Mojaveで pyenv のインストールに失敗するときの対処方法

pyenv で 3.7.x をインストールしようとしたらエラーが発生したので解決方法のメモ

環境は MacOS Mojave（v10.14.3）。

## TL;DR

たどり着いた解決方法は次の通り。

```bash
$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
$ brew install openssl@1.1
$ CONFIGURE_OPTS="--with-openssl=$(brew --prefix openssl@1.1)" pyenv install 3.7.1
```

以下、上記に至る経緯。

## zlibのエラーが発生した

次のようなエラーが発生した。

```bash
$ pyenv install 3.7.１
〜 略 〜
  File "/private/var/folders/4x/swb9y49s0pjgb9glg4h566qh0000gn/T/python-build.20190204231156.47930/Python-3.7.1/Lib/ensurepip/__init__.py", line 27, in _run_pip
    import pip._internal
zipimport.ZipImportError: can't decompress data; zlib not available
make: *** [install] Error 1
```

[Common build problems · pyenv/pyenv Wiki](https://github.com/pyenv/pyenv/wiki/Common-build-problems) を参考に次のコマンドを実行した。

```bash
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
```

これで、zlibのエラーは出なくなったのだが...

## OpenSSLのエラーが発生した

今度は次のようなメッセージが出て、インストールできなかった。

```
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?
```

[Common build problems · pyenv/pyenv Wiki](https://github.com/pyenv/pyenv/wiki/Common-build-problems) を参考に次の様にしてみたが、ダメだった。

```
CFLAGS="-I$(brew --prefix openssl)/include" LDFLAGS="-L$(brew --prefix openssl)/lib" pyenv install -v 3.7.1
```

ログを見ていると、このような記述があった。

```
Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
LibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381
```

でインストールしているOpenSSLを確認してみた。

```bash
$ openssl version
LibreSSL 2.6.4
```

うーん、これではダメだとログは言っている。
なので次を試した。

```bash
$ brew install openssl@1.1
$ CFLAGS="-I$(brew --prefix openssl@1.1)/include" LDFLAGS="-L$(brew --prefix openssl@1.1)/lib" pyenv install -v 3.7.1
```

これでもダメ。

[Python 3\.7\.0 :: The Python ssl extension was not compiled\. Missing the OpenSSL lib? · Issue \#1184 · pyenv/pyenv](https://github.com/pyenv/pyenv/issues/1184)を参考に次の様にするとインストールできた。

```bash
$ CONFIGURE_OPTS="--with-openssl=$(brew --prefix openssl@1.1)" pyenv install 3.7.1
```

ちなみに、3.7.2 も同様にしてインストールできた。
【今日から携わる】Angularを試してみた（Angular入門・チュートリアル）

Angularを試してみたので共有します。
jsフレームワーク未経験の方でもできる、Angular公式チュートリアルをやってみました。
＜作業時間＞
１回目：10分
２回目：3分

> Angularチュートリアル
https://angular.jp/guide/quickstart

# このチュートリアルでできること
・Angularをインストール
・新規プロジェクト作成
・ブラウザで確認する
・編集する（タイトルの文言&スタイル変更）
<img width="833" alt="スクリーンショット 2019-02-05 0.45.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/254652/b0c8a3af-7f07-3845-2f11-ceb07af45b09.png">

# (1)Angular CLIのインストール

## Nodeのバージョンを確認

```
node -v
//バージョン8.xまたは10.xが必要
```

## Angularをグローバルインストール

```
npm install -g @angular/cli
```

# (2)新規プロジェクト作成

```
ローカルに新規フォルダを作成する。
↓↓↓
ng new my-app
//新しいワークスペースと初期アプリケーションプロジェクトを作成する
↓↓↓
Enterキーを押してデフォルト値を受ける
```

# (3)アプリケーションをサーブ

```
cd my-app
//ワークスペースフォルダ（my-app）に移動
↓↓↓
ng serve --open
//--openオプションを付けてCLIコマンド ng serve を使用してサーバーを起動
↓↓↓
http://localhost:4200/
//ブラウザで開く
```

<img width="702" alt="スクリーンショット 2019-02-05 0.27.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/254652/3523ab83-3aa7-73d7-e843-2a0d1d40f9d6.png">

# (4)Angularコンポーネントを編集

## my-appフォルダをエディタで開く

```ts:app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'my-app';
}

//1. src/app/app.component.tsを開く
//2. title プロパティを 'my-app'から 'My First Angular App'に変更
```

↓変更する

```src/app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'My First Angular App!';
}
```

ブラウザで確認する
http://localhost:4200/

<img width="750" alt="スクリーンショット 2019-02-05 0.40.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/254652/ae61e5a9-f3fd-ea2a-d322-982c74c7153d.png">

h1のスタイルをCSSで変更する

```css:src/app/app.component.css
h1 {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 250%;
  }
```

<img width="833" alt="スクリーンショット 2019-02-05 0.45.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/254652/b0c8a3af-7f07-3845-2f11-ceb07af45b09.png">

”入門”おわり


[【今日から携わる】Angularを試してみた（Angular基礎・ツアー・オブ・ヒーローズ チュートリアル）](https://qiita.com/abeno/items/97402cf31c8a28e83039)
Dockerでcredentials.yml.encが編集できない時はEditorがインストールされているか確かめる

# 事象
[Docker公式のruby:2.6イメージ](https://github.com/docker-library/ruby/blob/6301325faf42a96b1fd1be5650e451cae31e0728/2.6/stretch/Dockerfile)から作成したコンテナ上で、
Rails5.2のcredential管理に使われる`config/credentials.yml.enc`を編集しようとしたら、困りました。

```
$ EDITOR=vim bin/rails credentials:edit

# 何も起きないでこれだけが返ってくる
New credentials encrypted and saved. 
```
編集できない！

# 原因
何もエラーが表示されなかったのでしばらく止まりましたが、原因はこれでした。

```
$ vim
bash: vim: command not found
```
vimがインストールされていませんでした…:innocent:

# 対処

```
$ apt-get install vim
```
vimをインストール。
完了後、無事にこのコマンドで`config/credentials.yml.enc`の編集が行えました。

```
$ EDITOR=vim bin/rails credentials:edit
```

# 参考
**credentials.yml.enc**についてはこちらを参考にしました。
[Rails5.2から追加された credentials.yml.enc のキホン](https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39)
MobaXtermでSocks経由でVMにアクセスする方法

# 早速本題

社内環境などプロキシで囲まれた場所からAWS, Azureなどで立てたVMにアクセスするための方法として、Socksを使う方法があります。

MobaXtermでこれをやろうと思って「MobaXterm socks」などでググるとSSH tunnelやポートフォワーディングの設定方法が出てきますが、単純にSocks 5などでアクセスする場合はこの設定は必要ありません。

Socks 5を使用する場合は、通常のRemote hostやらユーザーやらを設定するとともに、以下の手順で接続します。

1. Session settings -> SSH -> Network settingsを開く
2. Proxy settingsの"Proxy type"を"Socks5"に変更する
3. Host, Login ID, Portをセットする
4. パスワードが求められるので、入力する

<img width="614" alt="mobaXtermでのsocks5設定.png" src="https://qiita-image-store.s3.amazonaws.com/0/309199/5ff11a32-e830-04b6-3bcc-569e3a37d9fb.png">
Vue.js入門

# 目的
とりあえずインストールまでやろう。
備忘録として残そう。

# Vue.jsって何？
- Javascriptのフレームワーク
- MVVMパターンを採用している
- 双方向データバインディングを行うのが主な役割

# 手順
以前、Node.jsを触った事があったのでnpmは入ってた・・・

***npmとは***
Node.jsのパッケージを管理するツール
インストール方法は割愛します。

***VueCLIのインストール***

```console
$ npm install -g @vue/cli
```

***プロジェクトの作成***
上手くいったからプロジェクト作るぞー
あれ、以下のメッセージ出てうまくいかない・・・

```console
$ vue create test

  vue create is a Vue CLI 3 only command and you are using Vue CLI 2.9.6.
  You may want to run the following to upgrade to Vue CLI 3:

  npm uninstall -g vue-cli
  npm install -g @vue/cli
```

どうやらVueCLIのバージョンが3未満の為、"create"コマンドは使えない模様

***一旦、VueCLIをアンインストール***

```sh
npm uninstall -g vue-cli
```
***npmのバージョンを上げよう***

```sh
npm update npm
```

***もう一度、Vueをインストールしてプロジェクト作成しよう***

```console
$ npm install -g @vue/cli
$ vue create test
```
***途中で選択を求められる***
babelってなんやねん・・・
eslintってなんやねん・・・
とりあえずdefaultで作成しよう。

```
❯ default (babel, eslint) 
  Manually select features 
```
* babelとは？

最新のJavascriptで書かれたコードを、サポートされていないブラウザの為に以前のバージョンに変換してくれるツール

* eslintとは？

Javascriptの静的検証ツール
コードを実行する前に明らかなバグを見つけてくれる

***動作確認***

```console
$ cd test
$ npm run serve
```
***http://localhost:8080/ にアクセス***
![スクリーンショット 2019-02-04 23.37.32.png](https://qiita-image-store.s3.amazonaws.com/0/344952/9e971d04-109c-df8f-60b5-33997b9ad8ec.png)

# まとめ
npmのバージョンが古かったり、VueCLIのバージョンが古かったりと回り道が多かったが、なんとかインストールは終了。
分からない言葉が多かったので意味は適宜残していきます。
Salesforce CLIでメタデータ取得(retrieve)

#[概要]
本記事は、Salesforce CLIを使用してメタデータを取得する方法をまとめたものです。

#[事前準備]
Salesforce CLIのインストールは下記を参照
https://developer.salesforce.com/docs/atlas.en-us.218.0.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm

#[手順]
######①対象組織のpackge.xmlを準備する
全てのメタデータを取得するのであれば
https://qiita.com/takahito0508/items/f5dac3ac214bc75142cf
で紹介されているツールが便利です。

######②リリース対象の組織へログイン
sfdx force:auth:web:login -r <ログインURL> -a <別名を指定>

Sandboxの場合、ログインURLは"https://test.salesforce.com"

コマンドのオプションは以下を参照
https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_auth.htm

######③接続できたかを確認
sfdx force:org:list

######④メタデータを取得
sfdx force:mdapi:retrieve -s -r <出力ディレクトリ名> -k ./package.xml -u <別名もしくはUSERNAME>

~~
=== Result
Status:  Succeeded
~~
と表示されれば完了

コマンドのオプションは以下を参照
https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_mdapi.htm

######⑤zipを解凍
unzip unpackaged.zip

######⑥ログアウト
sfdx force:auth:logout -u <別名もしくはUSERNAME>

#[参考]
https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference.htm
Ubuntu on VMware Fusionでログイン画面から仮想コンソールを表示する

# ログインループ発生！
`~/.profile`を変に弄ってしまい、再起動したらログインループが発生してしまった！
そうだ！仮想コンソールを起動して直そう！

# 前提環境
Ubuntu 17.10 on VMware Fusion 11.0.2
on MacBookPro 2018 TouchBar搭載モデル

# 少し調べてみた
巷では`Ctrl+Alt+F1`で仮想コンソールが起動するとか言われていますが、当方はMacBookなので一般的なキー配列の場合と同じようにはいきません。困った困った。
ついでに言うと、`Ctrl+Alt+F1`で仮想コンソール起動、`Alt+F7`でGUIに戻るというのはどうも昔の情報っぽくて(本当か？)、比較的新しい記事 ( https://muroiwataru.net/entry/linux-console-root ) によると
>Ubuntuには仮想コンソールが６つ用意されているのでそれを呼び出します。
Ctrl + Alt + F1～F6で切り替えることができます。
GUIが表示されているデフォルトのコンソールが１番目なので、２～６番目に切り替えてください。
Ctrl + Alt + F1を押せばGUIに戻ります。

とのことです。

# Macのキーボードの場合は結局どうやんの？
`Ctrl + Option + fn + f2`

# Touch Bar搭載モデルの人は注意！
Touch Bar上でFnボタンを押してファンクションキー一覧を表示 → `Ctrl + Option + f2`だと仮想コンソールは起動してくれません！
私はここで詰まって時間を溶かしました......