OmniAICreator/Qiita-1.07M huggingface dataset:
ルート検索エンジン（OSRM）をコンテナで簡単に動かしてみた

###背景
改めて、Docker（コンテナ）を利用することでの非常に有益な気づきがあったので、その事例を備忘録として整理することにしました。

###そもそも何がしたかったのか

**OpenStreetMap（OSM）**を利用した、ルート検索エンジンの**OSRM（Open Source Routing Machine）**を簡単に使ってみたかったのですが、その環境構築が面倒なようで、何とかならないかと調べていました。

###何と、すでに構築された環境がDockerイメージとして提供されていた

[Project-OSRM/osrm-backend](https://github.com/Project-OSRM/osrm-backend)　において、以下のような記述がありました。

> The easiest and quickest way to setup your own routing engine is to use Docker images we provide.

###しかも、つぎのコマンド実行のみで、dockerhub からコンテナイメージを取得（ダウンロード）して、そのイメージからコンテナ（ルート検索エンジンとしての）を作成・起動してくれます

```
docker run -t -i -p 5000:5000 -v "${PWD}:/data" osrm/osrm-backend osrm-routed --algorithm mld /data/kanto-latest.osrm &
```

この例では、**osrm/osrm-backend** がコンテナイメージで、**osrm-routed** がコンテナ内で実行するコマンドになります。

ただし、この実行においては、事前に以下の作業が必要です。その中で、以下の整形とか最適化処理は、osrm/osrm-backendから新たにコンテナを起動（その処理用のコマンドをコンテナとして起動します）して実行しています。

- OSRMで使用する地図（OSM）のダウンロード
- OSRMで使用できるように整形
- 徒歩・車・自転車などの速度の最適化
- その他

本来であれば、以下の手順で、**2. 6. 7. を除いた処理が必要**とのことなので、Dockerを使うことでより早く確実に試せることがわかります。

1.更新とセキュリティ
2.**マップエクスポートのダウンロード**
3.依存関係のインストール
4.OSRMのコンパイル
5.STXXLの構成
6.**マップの抽出**
7.**移動時間の計算**
8.Webサービスの実行とテスト
9.Nginxのセットアップ
10.スーパーバイザーのインストールと構成

####ということで、コンテナイメージを使うことで、非常に簡単に実行環境の構築ができることを、改めて確認することができました。

参考までに、上記で立ち上げたルート検索エンジンに、以下のコマンドを実行して、ルート情報（JSON形式）を取得してみました。

この例では、北鎌倉から鎌倉大仏までの徒歩ルートを取得するために、それぞれの位置情報をパラメータとして検索エンジンに投げています。

```
curl --noproxy 127.0.0.1 'http://127.0.0.1:5000/route/v1/walking/139.545056,35.337103;139.535689,35.316696?alternatives=3&geometries=geojson' | jq 'def hexdec(i): "0123456789abcdef"[i:i+1]; {"type": "FeatureCollection", "features": [[.routes[].geometry] | [., keys] | transpose[] | {"geometry": .[0], "type": "Feature", "properties": {"stroke-width": 2, "stroke": ("#" + hexdec(15-.[1]*2) + hexdec(.[1]*2) + hexdec(.[1]*2))}}]}' > routes_kamakura.json
```
そして、取得したJson形式ファイルを、[**geojson.io** ](http://geojson.io/)上に読み込ませると、以下のような、北鎌倉から鎌倉大仏までの散歩コースの複数ルートが取得できました。（これはこれで、別途、別な記事として整理したいと思います）

![kamakura.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583736/33cd1322-cf25-04c7-3600-9f7c6c832566.png)
【Unity】マウスがオブジェクトに重なったらアウトラインを出す（自分用）

![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688851/8023d3ac-6542-31de-e35a-c29a18d56e3d.gif)


アセットストアで「Quick Outline」というアセットをダウンロード。
![“shot” 2020-11-09 23.56.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688851/cc5b95de-be62-273f-c1d8-afcff266f55c.png)

適当にキューブとからのゲームオブジェクトを作成。

ダウンロードしたアセットの中に「Outline」というスクリプトがあるのでそれをアウトラインをつけたいオブジェクトにつける。
（今回はキューブ）
インスペクタービューでアウトラインの色や太さを変えれるのでお好みで変更する。

「cube」というタグを作り今作ったキューブのタグを「cube」にする。

↓のスクリプトをからのオブジェクトにつける

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class raymanejer : MonoBehaviour
{

    void Start()
    {
        
    }

    void Update()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit = new RaycastHit();

        if (Physics.Raycast(ray,out hit))
        {
            //レイが当たったタグがcubeならアウトラインスクリプトをON
            if (hit.collider.tag == "cube")
            {
                hit.collider.GetComponent<Outline>().enabled = true;
            }
            ///レイが当たったオブジェクトのタグがcubeではなかったらcubeタグを持つオブジェクトのアウトラインを全てOFF
            else if (hit.collider.tag != "cube")
            {
                GameObject[] objects = GameObject.FindGameObjectsWithTag("cube");
                for (int i = 0; i < objects.Length; i++)
                {
                    objects[i].GetComponent<Outline>().enabled = false;
                };
            }
        }

        ///レイが当たっていなかったらcubeタグのアウトラインを全てOFF
        if (!Physics.Raycast(ray, out hit))
        {
            GameObject[] objects = GameObject.FindGameObjectsWithTag("cube");
            for (int i = 0; i < objects.Length; i++)
            {
                objects[i].GetComponent<Outline>().enabled = false;
            }
        }
    }
}

```


「補足」

もしrayの発車地点をマウスカーソルからVR用のコントローラーからなどからにするには


```
 public Transform rayTransform = null;


Ray laserPointer = new Ray(rayTransform.position, rayTransform.forward);

```

トランスフォームのところにRightHandAnchorを入れる。
Leghtでも良い。

　以上。
ラビットチャレンジ - 深層学習 Day2 Section5 最新のCNN

# 0．概要
本記事は日本ディープラーニング協会認定の講座プログラムである「ラビット・チャレンジ」が提供している科目の1つである深層学習のレポートである。
記事タイトルに記載のとおり、Day2 Section5 最新のCNNについて以下にまとめる。

# 1．AlexNet
2012年にImageNetコンペティションで優勝したモデル。

5層の畳み込み層およびプーリング層、それに続いて2層の全結合層という構造。

ドロップアウトを使用して過学習を抑えている。

https://qiita.com/ttomomasa/items/8243f6a29a024a02512f

# 2．他のモデル
講義動画ではAlexNetだけだったため個人的にいくつか簡単に調べてみた。

参考
https://qiita.com/yu4u/items/7e93c454c9410c4b5427

## 2.2．ZFNet
2013年にImageNetコンペティションで優勝したモデル。
AlexNetを改良したモデル。

## 2.3．GoogLeNet
2014年にImageNetコンペティションで優勝したモデル。
Inceptionモジュールを通常の層のように複数重ねていることが特徴。

### 2.3.1．Inceptionモジュール
複数の畳み込み層やpooling層から構成されるモジュール。
ネットワークを分岐させてその中で異なるサイズで畳み込みを行い、出力をつなぎ合わせている。

### 2.3.2．全体平均プーリング(Global Average Pooling)
これまでのCNNでは最後に全結合層をつないでいたが、過学習の原因にもなっていた(そのためAlexNetでもやっているようにドロップアウトをさせる)。
全体平均プーリングは入力と同じサイズの平均値プーリングを行うプーリング層。

各チャンネルごとに画素平均を計算し、まとめる。

全結合層を使わずに最終的な出力層と同じ次元数の結果を得られる。
全結合層より計算量も少なく過学習も防げる。

今では全結合層よりこちらを使う方が一般的。
色々調べながらCNNを試していた時、既になんとなく使っていました。

## 2.4．VGGNet
2014年にImageNetコンペティションで2位となったモデル。
CNNの深さに主眼を置いたモデル。
畳み込みのサイズは基本的に3×3のみ。
畳み込み層を幾つか重ねた上で最大値プーリング層を重ねて出力のサイズを半分にする。

## 2.5．ResNet
2015年にImageNetコンペティションで優勝したモデル。
これまでの前の層から次の層へ順々に伝播させていたCNNと違い、入力をショートカット(層を飛ばす)するResidualモジュールを含んだモデル。
VGGNetであまりに深いモデルは学習効率が悪いことが分かっていたが、ショートカットさせることで改善。

## 2.6．SENet
2017年にImageNetコンペティションで優勝したモデル。
Attentionを導入したモデルということだがAttentionはRNNで使われる仕組み？レベルの認識なので正直全然分かっていない。

# 3．今後CNNはなくなる？
新しく登場したVision Transformer(ViT)はこれまでより性能も良い上、計算コストも低いらしい。
Transformerというものをベースにしているようなので詳しく学ぶのはTransformerをある程度知ってからが良さそう。

https://qiita.com/omiita/items/0049ade809c4817670d7

# X．ラビットチャレンジとは
ラビットチャレンジとは、日本ディープラーニング協会認定の講座プログラムの1つ。
E資格を受験するためにはこのラビットチャレンジ等、いずれかの講座プログラムを修了しなければならない。

ラビットチャレンジの特徴は「現場で潰しが効くディープラーニング講座」の通学講座録画ビデオを編集した教材を使用した自習スタイルであるという点。
サポートは他の講座より少なく、受け身ではなく自主的に学んでいく姿勢でなければ進められないが、その分、他の講座に比べると安価であり、手が出しやすい。
ある程度知識がある人、自力で頑張るぞというガッツのある人向けではないかと感じる。

![bnr_jdla.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389699/bce66671-a2f5-a7f9-de6f-3f87e15c253b.png)
Accessibilityフレームワークを使う

# 要約
`import Accessibility`により、accessibilityLabelの他にもアクセシビリティのコンテンツが含められるようになりました。

# 従来のアクセシビリティ
例えば、小説の表紙の画像があるとします。

![IMG_4131.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62305/a946e4cc-1a51-24ba-8f4b-5371acf309ed.png)

視認することができる状態であれば、画像を見てその小説がなんのタイトルであるかわかると思いますが、視認できない状態の場合もあります。そういった時、`accessibilityLabel`にタイトルを割り当てて、読み上げに使ったりすることを可能にします。

しかし、小説にはタイトル以外にも、著者を重要視したり、あるいは出版社だったりを知りたい場合もあるかと思います。そういった時、accessibilityLabelに全ての要素を含むと、本来タイトルだけ知れればいい人にとってはいささか読み上げが長いと感じる可能性もあります。

# カスタムコンテンツの追加
iOS 14から加わった`Accessibility` をimportすることにより、カスタムコンテンツの追加が可能になりました。
カスタムコンテンツを含めたいクラスを、`AXCustomContentProvider`に適合させ、`accessibilityCustomContent` に `AXCustomContent` を含めます。
AXCustomContentには`label`と`value`のセットを含めることができます。


## コード
```swift
import UIKit
import Accessibility

class NovelImageView: UIImageView,AXCustomContentProvider {
    private var _accessibilityCustomContent: [AXCustomContent] = [
        AXCustomContent(label: "著者", value: "日向強"),
        AXCustomContent(label: "出版", value: "コーヒーパブリッシング"),
    ]
    var accessibilityCustomContent: [AXCustomContent]! {
        get {
            _accessibilityCustomContent
        }
        set {
            _accessibilityCustomContent = newValue
        }
    }
}

```

# カスタムコンテンツの読み上げ
iPhoneのローターより、`その他のコンテンツ`を選択し、上下にスワイプすることによって、accessibilityCustomContentに設定したAXCustomContentを読み上げることができます。
![IMG_4132.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62305/8cda10d7-1745-c6b5-7c2d-9b1d1b1703d4.png)

# まとめ
つかおう！アクセシビリティ！
VSCode + Next.js + Docker (+ Chrome)でデバッグ （サーバーサイド・クライアントサイド両方に対応）

先人たちの事例を自分の環境なりに再現させて、事例をもう一つ増やしました （こんなんなんぼあってもいいですからね）
Chromeがカッコ付けなのはクライアントサイドのデバッグのみ利用するためです

## 前提
1. デバッグ用ブラウザはChrome  
他のブラウザの場合はよしなに設定等を読み替えてください
2. Next.jsのバージョンは9  
多分10でも動きますが未検証です

## 実施内容
#### 1. [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome)のインストール  
#### 2. `.vscode/launch.json`を作成して、以下の内容を記述

```
{
    "version": "0.2.0",
    "configurations": [
        // For server side rendering debug
        {
            "type": "node", // 固定
            "request": "attach", // 固定
            "name": "Next: Node", // 好きな名前で
            "port": 9229, // 3. のポートと合わせる
            "address": "localhost", // 基本的に固定
            "localRoot": "${workspaceFolder}", // 固定
            "remoteRoot": "/src", // Docker内のモジュールのRootディレクトリ
            "protocol": "inspector" // 固定
        },
        // For client side rendering debug
        {
            "type": "chrome", // 固定 (ブラウザを変えたい場合は1.のインストールとともに変更してください
            "request": "launch", // 固定
            "name": "Next: Chrome", // 好きな名前で
            "url": "http://localhost:3000", // DockerComponseのポートと、サービスのディレクトリなど、お好みでカスタマイズしてください
            "webRoot": "${workspaceFolder}", // 固定
            "sourceMapPathOverrides": { // 固定
                "webpack:///./*": "${webRoot}/src/*"
            }
        }
    ]
}
```

#### 3. `package.json`のscriptに以下の内容を追加し、Next.jsのDockerを起動
```
"dev": "node --inspect=0.0.0.0:9229 node_modules/next/dist/bin/next"
```
Docker(Compose)が起動する内容を上記にしてください。devである必要はありません。ポートなどはよしなに

#### 4. `実行`の中の`Next: Node`と`Next: Chrome`をそれぞれ実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8770/37be507a-d877-2744-42c5-9ab6901a5490.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8770/64e709cf-1b7d-5e55-7ec4-3be49409a193.png)

##### 4.1 `Next: Chrome`を起動すると、1で導入したデバッグ用のChromeが起動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8770/1e594797-16ee-4649-6f50-1b68336ae47d.png)


#### 5. 下のバーが赤くなったら成功

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8770/9fab40c0-59e8-59e0-2306-bda4b53c722b.png)


以上でクライアントサイド、サーバーサイドそれぞれで、ブレークポイントを貼った場所に止まります
クライアントサイドは、4.1で起動したChrome内で画面を描画しないと止まらないので注意

## 参考

[【VSCoe】VisualStudioCodeでDockerのNode.jsにリモートデバッグしてみよう【Nust.js/Vue.js】](https://blogenist.jp/2019/06/18/8607/)
[【console.logとはおさらば】Next.jsをVSCodeでデバッグさせる方法](https://ichiki.netlify.app/blog/20200113_nextjs_debug/)
[Visual Studio CodeでJavaScriptのデバッグ方法](https://codeaid.jp/vscode-js-debug/)
SQL文について

##SQLとは
データベースに指示を出すための`命令文`で、SQLという言語によって記述される。
`異なる形式のデータベースでも同じようにSQL文で命令可能`。

##SQL文の種類
・データ`取得`→`SELECT`(セレクト)
・データ`追加`→`INSERT`(インサート)
・データ`更新`→`UPDATE`(アップデート)
・データ`削除`→`DELETE`(デリート)

各SQL文について下記のテーブルを元に紹介します。
####テーブル名：users

|id|name|age|
|:---:|:---:|:---:|
|　1　|　　佐藤　　|　　　20　　　|
|　　2　　|　　山崎　　|　　　26　　　|


##データ取得 SELECT文
`SELECT 取得したいカラム(列)名 FROM テーブル名;`
`WHERE 条件式`を使うことで、抽出するデータの`条件を絞れます`。

`SELECT id,name,age FROM users WHERE 100 <= age；`
　　↓ `*`(アスタリスクで全てのカラム指定が可能)
`SELECT ＊ FROM users WHERE 20 <= age；` 
これで20歳以上のみデータを取得できます。


##データ追加 INSERT文
`INSERT INTO データを追加したいテーブル名 (カラム名) VALUES (カラムに入れるデータ);`
`INSERT INTO users (id, name) VALUE (3,加藤);`
この場合、ageが追加されてないので、データベースでageの値は`NULL(値が無い)`となります。
`すべての列にデータを追加`する場合は、`列名の記述は省略可能`。

##データ更新 UPDATE文
`UPDATE テーブル名 SET 更新処理内容;`
`WHERE 条件式`を使うことで、`条件を付けて特定のデータのみ更新`できます。
`UPDATE users SET age = 30 WHERE name = 佐藤;`
これで佐藤さんの年齢を30歳にできます。

##データ削除 DELETE文
`DELETE FROM テーブル名;`

usersテーブルの全てを削除。
`DELETE FROM users;`

一般的には、条件を付けて部分的にデータを削除します。
`DELETE FROM テーブル名 WHERE 条件式 ;`

usersテーブルから佐藤さんのデータを削除する場合
`DELETE FROM users WHERE name = 佐藤;`


参考元はこちら
(https://it-trend.jp/development_tools/article/32-0012#:~:text=%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E3%80%8CSELECT,%E3%81%AB%E8%A6%8B%E3%81%A6%E3%81%84%E3%81%8D%E3%81%BE%E3%81%97%E3%82%87%E3%81%86%E3%80%82)
あなたは何柱？お館様による柱任命bot (Discord)

# はじめに
もし、自分が鬼滅の刃に登場でき、柱になれるとしたら何柱になれるのか疑問に思いました。
なので、お館様を作ってしまい、柱に認定していただくことにしました。


## 実装

### 前準備
まず下記の環境構築をしていきます。
[Discord Bot（基礎編）](https://note.com/exteoi/n/nf1c37cb26c41)

### メインとなる処理部分を変更
glitch内に仕込んだserver.jsを変更していきます。

```server.js
const http = require('http');
const querystring = require('querystring');
const discord = require('discord.js');
const client = new discord.Client();

http.createServer(function(req, res){
  if (req.method == 'POST'){
    let data = "";
    req.on('data', function(chunk){
      data += chunk;
    });
    req.on('end', function(){
      if(!data){
        res.end("No post data");
        return;
      }
      const dataObject = querystring.parse(data);
      console.log("post:" + dataObject.type);
      if(dataObject.type == "wake"){
        console.log("Woke up in post");
        res.end();
        return;
      }
      res.end();
    });
  }
  else if (req.method == 'GET'){
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Discord Bot is active now\n');
  }
}).listen(3000);

client.on('ready', message =>{
 client.user.setActivity('永遠というのは人の想いだ');
});

client.on('message', message =>{
 if (message.author.id == client.user.id){
   return;
 }
 if(message.isMemberMentioned(client.user)){
   var text = "<@" + message.author.id + ">";
   
   const PillarName = ['炎柱:', '水柱:', '恋柱:', '蟲柱:', '音柱:', '岩柱:', '霞柱:', '蛇柱:', '風柱:']
   const random = Math.round(Math.random() * 9);
   const name = PillarName[random];
   
   message.guild.member(message.author.id).setNickname(name + message.member.displayName);

   text = "これからは<@!" + message.author.id + ">として鬼殺隊を支えてくれるかい？";
   message.channel.send(text);
   return;
 }
});

if(process.env.DISCORD_BOT_TOKEN == undefined){
 console.log('DISCORD_BOT_TOKENが設定されていません。');
 process.exit(0);
}

client.login( process.env.DISCORD_BOT_TOKEN );

function sendReply(message, text){
  message.reply(text)
    .then(console.log("リプライ送信: " + text))
    .catch(console.error);
}

function sendMsg(channelId, text, option={}){
  client.channels.get(channelId).send(text, option)
    .then(console.log("メッセージ送信: " + text + JSON.stringify(option)))
    .catch(console.error);
}

```

### 実行

まずは、下記のような感じにお館様と僕がいることを確認します。

![スクリーンショット 2020-11-10 0.08.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/462f2fdd-8cb0-9558-7ccc-b586981825ed.png)

それでは、お館様を呼んでみましょう。
![スクリーンショット 2020-11-10 0.00.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/11fcabd8-8985-6332-1939-e29af368c0e1.png)
**やった、蛇柱ですねw**
ちなみに柱は、arrayリストにしてあり、ランダムで何が出るかは分かりません。

```
['炎柱:', '水柱:', '恋柱:', '蟲柱:', '音柱:', '岩柱:', '霞柱:', '蛇柱:', '風柱:']
```

そして任命とともに、Discord上のニックネームが下記のように自動で変更されます。
これで今日から蛇柱と名乗れます。

![スクリーンショット 2020-11-10 0.13.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/66ba8c19-6289-8f20-e15c-e916208d6d04.png)


# おわり
ちなみに上記のコードは、botを追加したサーバの管理者での実行はできないです。(ロールの問題により)

# 参考
[Discord Bot（基礎編）](https://note.com/exteoi/n/nf1c37cb26c41)
[湯婆婆bot](https://qiita.com/nekozuki_dev/items/485d47a459a63f59400f)
データ容量の確認

#コマンド
| 内容 | コマンド | 実行例・補足 |
|:-:|:-:|:-:|
| DBの最大容量と利用量を確認  | select DatabaseName, sum(MaxPerm), sum(CurrentPerm) from dbc.DiskSpace where DatabaseName in ('SYSDBA') group by DatabaseName;  |   |
|   |   |   |
|   |   |   |

#実行例
```
select DatabaseName, sum(MaxPerm), sum(CurrentPerm) from dbc.DiskSpace where DatabaseName in ('SYSDBA') group by DatabaseName;

DatabaseName                                  Sum(MaxPerm)            Sum(CurrentPerm)
------------------------------  --------------------------  --------------------------
SYSDBA                                       9,996,000,000                 963,018,752
```

#参考
[DiskSpaceV[X] • Teradata Vantage™ データ ディクショナリ • リーダー • Teradataドキュメント](https://docs.teradata.com/reader/fMqp0D_uNdzh8~BHZ2S~9w/spI7Kn7~vrQEvi2K6z50lA)
[]()
[]()
AWS〜EC2にSSHログインし、Railsの環境構築をする〜

# この記事を読んでできるようになること
**EC2にSSHログインし、環境構築を行う**ことができる。
# 記事を読むにあたってのお願い
私は**AWSの初学者**で、アウトプットをすることで知識を定着させるためにこの記事を書いています。内容に誤りがある場合は、コメントをいただけますと幸いです。
`学習に使用した教材`
AWS：ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
https://www.udemy.com/course/aws-and-infra/
# SSHとは
Secure Shellの略で、リモートコンピュータと通信するためのプロトコル。認証など全てのネットワーク通信が暗号化されており、安全に通信を行うことができる。
# EC2へのログイン手順
**※[EC2インスタンスの作成](https://qiita.com/kawano30/items/06f6ee056b90968ed376)まで完了している前提です。**
**※MACでの操作手順となります。ご了承ください。**
① 「ターミナル」を起動する。

```
② .sshというディレクトリを作成
  % mkdir ~/.ssh
③ ダウンロードしたpemファイルを.ssh内に移動
  % mv Downloads/〇〇.pem .ssh/
④ ワーキングディレクトリを.sshへ変更
  % cd .ssh
⑤ pemファイルの権限を、所有者のみ読み書き可能な状態に変更
  % chmod 600 〇〇.pem
⑥ 秘密鍵（pemファイル）を使用して、EC2インスタンスにSSHログイン
  % ssh -i 〇〇.pem ec2-user@Elastic IP
```
![スクリーンショット 2020-11-09 23.17.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/807318/5030c090-1456-4c86-888b-093d3df2872b.png)

```
⑦ Are you sure you want to continue connecting (yes/no)?と聞かれるので、yesと入力
  % yes
```
# 環境構築手順

```
① yumをアップデートする。-yオプションは、問いに対してyesと答えるオプション
  % sudo yum -y update
② 環境構築に必要なパッケージをインストール
  % sudo yum  -y install git make gcc-c++ patch libyaml-devel libffi-devel libicu-devel zlib-devel readline-devel libxml2-devel libxslt-devel ImageMagick ImageMagick-devel openssl-devel libcurl libcurl-devel curl
③ 総ダウンロード容量: 120 M \ Is this ok [y/d/N]:と聞かれるので、yを入力
  % y
④ Node.jsをインストール
  % sudo curl -sL https://rpm.nodesource.com/setup_10.x | sudo bash -
  % sudo yum -y install nodejs
⑤ Yarnをインストール
  % sudo yum -y install wget
  % sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
  % sudo yum -y install yarn
⑥ rbenvとruby-buildをインストール
# rbenvのインストール
  % git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
# パスを通す
  % echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
# rbenvを呼び出すための記述
  % echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
# .bash_profileの読み込み
  % source .bash_profile
# ruby-buildのインストール
  % git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
# rehashを行う
  % rbenv rehash
⑦ Rubyをインストール
# Ruby 〇.〇.〇のバージョンをインストール（バージョンはローカルと同じもの）
  % rbenv install 〇.〇.〇
# Rubyのバージョンを決める
  % rbenv global 〇.〇.〇
# rehashを行う
  % rbenv rehash
# バージョンを確認
  % ruby -v
```
# 補足
### yumとは
Linuxシステムにおけるソフトウェアパッケージの管理システムのこと
### yarnとは
JavaScriptのパッケージマネージャーのこと
### rbenvとは
Rubyのバージョン管理ツールのこと

---

これで、**Rails**を動かすための準備ができました。

次回は**データベースの準備**を行って行こうと思います。
Linuxコンテナ・Docker入門(前編)

# 前置き

この記事は、これからLinuxコンテナやDockerを使い始める人向けに書いた記事です。
触ったことがないととっつきにくいコンテナを理解するためにざっくり概要をまとめました。

長いので[Linuxコンテナ・Docker入門(後編)](https://qiita.com/satken2/items/8515900a5a7b9bb0d0c9)と2つに分けて書きました。

# **Linuxコンテナ(LXC)**

## コンテナの考え方

コンテナとは、端的に言えばアプリケーションをホストOSから隔離する技術のことである。
LinuxOSの中に隔離された空間を作り、他のコンテナ内のプロセスやホストOS上のプロセスに一切干渉せずに動作できる環境を作る。
同時に、既存のホストOSから分離した環境を作ることで、クリーンな環境を提供することができる。

## Linuxカーネルとディストリビューションについて

コンテナの詳細に移る前に、まずはLinuxについて説明する。
Linuxという言葉には2つの意味があり、狭義には「Linuxカーネル」、広義では「Linuxディストリビューション」をそれぞれ指す。

### 狭義のLinux: Linuxカーネル

カーネルは、OSのコア部分にあたり、基本的なプロセス管理やメモリ管理等を行う。
カーネルは全Linux系OSにおいて共通である。

### 広義のLinux: Linuxディストリビューション(Linux系OS)

LinuxカーネルだけではそのままPCやサーバーにインストールすることはできない。
HWとやり取りするために必要な各種のドライバーやライブラリ、アプリケーションをまとめてパッケージ化したものを「Linuxディストリビューション」と呼ぶ。

例：
- RedHat Enterprise Linux
- Debian GNU Linux
- Android
- SUSE Linux
- CentOS
- Ubuntu
- etc...(無数にある)

**⇒見た目は違うものの、Linux系OSはすべて同じLinuxカーネルを使っている。**(当然、バージョンは異なるが)

## コンテナの概要と、LXCの役割

LXCとは、Linuxカーネルの機能を利用してコンテナ環境を作るためのツールである。
主に以下のようなカーネルの機能を利用する。

- Namespace … プロセスやNWリソース(仮想NICなど)を分割し、互いに干渉できないようにする。
- CGroup … プロセルをグループ化し、それぞれが使用できるCPU,メモリ等のリソースを制限する。



### 従来の場合

- OS上にあるライブラリ(この場合はJDK)を複数のソフトで共有していることが多い。
- デフォルトで入っているライブラリやパッケージの中には、使っていないものもある
- ある環境で動くソフトが、別の環境では動かなかったりする（環境差分）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215103/93bef9c4-ad82-1685-3aa8-cae16747cec6.png)



### コンテナを使うと

- 依存するパッケージはすべてコンテナ内に入れ、逆に必要のないものは入れない。
- 同じカーネルを使っているLinux系OSであればどのディストリビューションでも同じように動く。
- コンテナ内のプロセスはNamespaceによって隔離されており、コンテナ外には干渉できない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215103/af0856a2-d810-7710-c0b5-432bae91e1ce.png)

**コンテナは「コンパクトなVM」と考えるよりも「隔離されたプロセス」と考える方が理解はしやすい(と思っている)**

## VMとコンテナの違い

### 分け方の違い

VM ... ハードウェアをエミュレートして、その上でOSを立ち上げる
コンテナ ... 同じOS上にあるプロセスやディレクトリを、見かけ上隔離する

**VMとコンテナは似て非なるもの。アプローチは真逆。**

### オーバーヘッド

VM ... ハードウェアをエミュレートしたり、OSを稼働させるためのオーバーヘッドが発生する
コンテナ ... 実体はホストOS上で稼働するただのプロセスに過ぎないので、オーバーヘッドはほぼない。(※)

※マイクロサービス的に多数のコンテナを動かす場合は当然ネットワークのオーバヘッドが発生する

### 入れるソフト

※これは、LinuxコンテナというよりかはDockerの特徴かもしれない。

VM ... 物理サーバーと同じように、多数のソフトをインストールして使う
コンテナ ... 基本的に1コンテナ1ソフト。不要なライブラリやコマンドは入れない(※)

※最大限まで軽量化されたコンテナでは`ls`や`yum`といった基本的なコマンドすら入ってなかったりする。これは少し使いづらいこともある。

コンテナ内で`ps`コマンドを使うとこのことがよくわかる。

![psax2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215103/c1dbf0a0-e756-c12c-5762-5d0ffa115823.png)

通常LinuxはPID1のinitプロセスから子プロセスが大量に派生するが、コンテナ内ではPID1がいきなりApacheになっているのがわかる。

通常はこう。PID1は`init`になっている。
![psax.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215103/340ca120-6af0-9c14-fc8d-985a1539fbea.png)


## コンテナを利用することによるメリット

大きく、以下のメリットがある。(LXCの公式サイトから引用)

1. セキュリティの向上
アプリケーションが他のアプリケーションに干渉できなくなることで、システムに侵入された時の被害を軽減することができる。

2. 疎結合性の向上
一つのホストOSの中に互いに干渉しない形でアプリケーションを動かすことができるため、1つのソフトに対する変更が他のソフトに影響を及ぼすことがない。

3. システムの抽象化
コンテナはホストOSやハードウェアを隠蔽し、どのような環境でも安定して動作する環境を作ることができる。

# まとめ

## コンテナ

- コンテナでは、アプリとその実行に必要なライブラリなど一式をひとまとめにして、簡単に作成、破棄できる。

- コンテナの実体は、Namespaceで区切られたホストOS上のディレクトリやプロセスである。

- 基本的にコンテナ内には動作に必要な最低限のファイルのみを入れるが、
ディストリビューション全体をコンテナ化するような使い方もできなくはない。

# 後編

[Linuxコンテナ・Docker入門(後編)](https://qiita.com/satken2/items/8515900a5a7b9bb0d0c9)に続きます。
ROSで湯婆婆を実装してみた。


最近Qiitaが湯婆婆で溢れているので、~~便乗すればもしかしたらLGTMもらえるかも~~ せっかくなのでまだ見ていない物を使って実装しようと思ったので、[ROS](https://www.ros.org/)を使用していきます。

### srvファイル
```Yubaba.srv
string name
---
string new_name
```
名前を入力したら、新しい名前を返してくれるサービスです。

### Service Proxy
```python
import rospy
from std_msgs.msg import String, Empty
from yubaba.srv import Yubaba

def listen_to_yubaba(msg):
    print(msg.data)


yubaba_proxy = rospy.ServiceProxy("/yubaba/name_service", Yubaba)
yubaba_words = rospy.Subscriber("/yubaba/words", String, listen_to_yubaba)
greet_yubaba = rospy.Publisher("greet_yubaba", Empty, queue_size=1)

if __name__ == "__main__":
    rospy.init_node("client")
    greet_yubaba.publish()
    name = input()
    new_name = yubaba_proxy(name)
```

### Yubaba Node
```python
import rospy
import random
from yubaba.srv import Yubaba
from std_msgs.msg import String, Empty

class YubabaNode:

    def __init__(self):
        rospy.init_node("yubaba")
        self.yubaba_service = rospy.Service("~name_service", Yubaba, self.name_service)
        self.word_publisher = rospy.Publisher("~words", String, queue_size=1)
        self.greet_subscriber = rospy.Subscriber("greet_yubaba", Empty, self.start)

    def start(self, msg):
        self.word_publisher.publish("契約書だよ。そこに名前を書きな。")


    def name_service(self, req):
        name = req.name
        self.word_publisher.publish(f"フン。{name}というのかい。贅沢な名だねぇ。")
        rospy.sleep(0.5)
        new_name = random.choice(name)
        self.word_publisher.publish(f"今からお前の名前は{new_name}だ。いいかい、{new_name}だよ。分かったら返事をするんだ、{new_name}!!")
        return new_name

if __name__ == "__main__":
    yubaba = YubabaNode()
    rospy.spin()
```

### おまけのlistener
```python
import sys
import rospy
from std_msgs.msg import String

def listen_to_yubaba(msg):
    print(msg.data)

yubaba_words = rospy.Subscriber("/yubaba/words", String, listen_to_yubaba)

if __name__ == "__main__":
    args = sys.argv
    rospy.init_node(f"listener{args[1]}")
    rospy.spin()

```

## 実行例
![Peek 2020-11-09 23-26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262637/9e2c607b-94d8-2d40-9e73-d8e55b1fc5c8.gif)

## 構成
- Yubaba Node
    - /yubaba/words: 湯婆婆様のありがたいお言葉。
    - /yubaba/name_service: 名前を新しく変えてくれるやつです。

- /greet_yubaba: まずは湯婆婆に挨拶。

## まとめ

もしかして `ROS + 湯婆婆　= 老婆婆？？`
deviseでサインインのエラーハンドリング の方法

#はじめに
　deviseを用いて、ユーザー管理をして、新規登録では、エラーハンドリング を
`renderメソッド`で簡単にできたが、サインインのエラーハンドリング がどうもうまくできなかったので、調べてまとめておく。

##deviseでサインインのエラーメッセージを表示させる方法

```ruby:sessions/new.erb
<%= alert %>
```

を表示させたいところに記述する。

この記述で、エラーとなったときに、「パスワードがちがいます」みたいなメッセージが出る。新規登録のときにように細かく、いくつエラーがあって、どの部分がエラーか、までは表示できない模様。

##deviseのエラーメッセージを日本語にする方法
日本語でエラーメッセージを表示したい場合は、
`config/locales`に、`devise.ja.yml`ファイルを作成し、
[これ](https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml)を貼り付ける。

##最後に
　なぜ、サインインだけこの方法を使わないといけないのか、なぜこれでエラーメッセージが表示できるのかは、全くのなぞである。
湯Vala（ゆばーら）　―Valaで湯婆婆を実装してみる―

ひさびさにQiitaを開いてみたら、@Nemesisさんの「[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)」という記事を読んだ。自称・ジブリファンとして、ここは私もオマージュを投稿してみたい。多分誰もやらなさそうな、 **超どマイナー言語・[Vala](https://ja.wikipedia.org/wiki/Vala)** で……

# コード
```vala:yubaba.vala
public class Yubaba {
    public static int main (string[] args) {
        stdout.printf ("契約書だよ。そこに名前を書きな。\n");

        string name = stdin.read_line ();
        stdout.printf ("フン。%sというのかい。贅沢な名だねぇ。\n", name);

        int new_name_index = GLib.Random.int_range (0, name.char_count ());
        string new_name = name.get_char (name.index_of_nth_char (new_name_index)).to_string ();
        stdout.printf ("今からお前の名前は%sだ。いいかい、%sだよ。分かったら返事をするんだ、%s!!\n", new_name, new_name, new_name);

        return 0;
    }
}
```

Ubuntu系であれば

```
$ sudo apt install -y valac libglib2.0-dev
```

でコンパイラとライブラリをインストールしてあげて

```
$ valac ./yubaba.vala
$ ./yubaba
```

で動く。

# 解説
## 標準入力という契約書
```vala
stdout.printf ("契約書だよ。そこに名前を書きな。\n");

string name = stdin.read_line ();
stdout.printf ("フン。%sというのかい。贅沢な名だねぇ。\n", name);
```

`stdin.read_line ()`で名前を取得し、変数`name`に代入。

## 名前を奪う
```vala
int new_name_index = GLib.Random.int_range (0, name.char_count ());
string new_name = name.get_char (name.index_of_nth_char (new_name_index)).to_string ();
```

Valaの標準ライブラリであるGLibには`Random`という名前空間があり、`int_range`というメソッドが用意されているので、それを使う。
引数には、起点（1文字目）と、終点（`name`の文字数）を渡してあげます。注意したいのは、`name.length`だと`name`のバイト数が取得されてしまい、`name`が全角文字の場合に正しく文字を抽出できないので、`char_count`メソッドを使うという点[^1]。
`new_name_index`を用いて取り出した1文字はunichar型（32 bitのUnicode文字型）なので、string型に変換する。

## 名前を与える
```vala
stdout.printf ("今からお前の名前は%sだ。いいかい、%sだよ。分かったら返事をするんだ、%s!!\n", new_name, new_name, new_name);
```

標準出力で新しい名前を表示。`new_name, new_name, new_name`が冗長なのなんとかならないだろうか……

# 実行結果
![Screenshot from 2020-11-09 22-58-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292557/6c3dba36-acd5-52ea-d72e-eaffc4fd11ef.png)

# おまけ
![Screenshot from 2020-11-09 22-58-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292557/e6cac6a0-8839-0b43-88ef-70cbc9ffcaf5.png)

なんも入力しないと、`int_range`メソッドの引数が両方とも0になってしまい、起点＜終点というアサーションに失敗したというエラーが表示される。ただし、その後の処理はエラーにならないので、湯婆婆は発音できない名前を与えてくれます。

[^1]: 挙動の違いは[こちらのコード](https://valadoc.org/glib-2.0/string.length.html)を参照。
ms-settingsを用いたショートカットボタン(パワーシェル)

#作成の目的
Win10のタイルボタンによく使う設定項目を配置する要望を受け、
それを実現する方法を検討しました。

ms-settingsの内容をスクリプトに書いて、
それをintuneに配信という方法をとりました。

このスクリプトでは、以下3点を追加しています。
WindowsUpdate,WindowsDefender,職場へのアクセス


#パワーシェルの中身

```
####変数定義
$env_dir= $env:APPDATA
$WsShell = New-Object -ComObject WScript.Shell

#WindowsUpdateのショートカット
$Shortcut_winup = $WsShell.CreateShortcut($env_dir+"\Microsoft\Windows\Start Menu\Programs\WinUpdate.lnk")
$Shortcut_winup.TargetPath = "ms-settings:windowsupdate-action"
$Shortcut_winup.IconLocation = "%SystemRoot%\system32\SHELL32.dll, 153"
$Shortcut_winup.Save()

#WindowsDefenderのショートカット
$Shortcut_windefender = $WsShell.CreateShortcut($env_dir+"\Microsoft\Windows\Start Menu\Programs\WinDefender.lnk")
$Shortcut_windefender.TargetPath = "ms-settings:windowsdefender"
$Shortcut_windefender.IconLocation = "%SystemRoot%\system32\SHELL32.dll, 16"
$Shortcut_windefender.save()

#同期ボタンのショートカット
$Shortcut_wordplace = $WsShell.CreateShortcut($env_dir+"\Microsoft\Windows\Start Menu\Programs\Workplace.lnk")
$Shortcut_wordplace.TargetPath = "ms-settings:workplace"
$Shortcut_wordplace.IconLocation = "%SystemRoot%\system32\SHELL32.dll, 18"
$Shortcut_wordplace.save()
```

#パワーシェルの中身説明(1)
```
####変数定義
$env_dir= $env:APPDATA
$WsShell = New-Object -ComObject WScript.Shell
```

ユーザーのプロファイル領域にショートカットを置くため、
必要な環境変数を変数に入れます。
COMオブジェクトのWScript.Shellを使用すると、オブジェクトを定義します。

#パワーシェルの中身説明(2)
説明用に番号を振っています。

```
#WindowsUpdateのショートカット
１）$Shortcut_winup = $WsShell.CreateShortcut($env_dir+"\Microsoft\Windows\Start Menu\Programs\WinUpdate.lnk")
２）$Shortcut_winup.TargetPath = "ms-settings:windowsupdate-action"
３）$Shortcut_winup.IconLocation = "%SystemRoot%\system32\SHELL32.dll, 153"
４）$Shortcut_winup.Save()
```
１）WScript.ShellのCreateShortcutメソッドを使用します。
ここには実際にファイルを置く場所を指定する。
これをユーザーのプロファイル領域のスタートメニューに置く。
拡張子は、.lnkにする。

２）ここにはどこへのショートカットかを定義する
ここではms-settingsの内容を入れたいので、その値を入力する。

３）ここを指定しないと、アイコンがデフォルトのものになってしまうので、
自分の意図で設定します。

SHELL32.dllというのがWindowsのアイコンを定義しています。
ここにパラメータとして番号を与えるることで、アイコンを定義できます。
ここに指定する番号は下記のサイトを参考にさせて頂きました。

４）ここはお作法ですが作成したショートカットを保存します。


#まとめ
この要領で必要な分のショートカットを定義して完成です。
ms-settingsで定義できることは多岐にわたるので、お好みでカスタマイズください。


#参考にさせて頂いたサイト様
■パワーシェルコマンド
https://hosopro.blogspot.com/2017/09/powershell-shortcut-icon.html
■アイコン
https://www.billionwallet.com/windows10/icon-numbers.html
辞書、この単語の意味を教えて！

# 目的
あなたは外国語で読書をやったことがありますか、分からない単語があったらどうですか？わたしなら、本を置いて、辞書アプリで単語を探して、本を拾って、続けます。もし、わからない単語が多い場合はひどくなります。

それで、今回、指で指差すと、言葉を辞書に入れて意味を出すツールを作りたいです。例えば：

![IMG_3157.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521590/cd7a3dbd-8fb5-29fc-be81-76da2ad57159.jpeg)
上の写真　→　「procrastination」の意味：怠慢、延期


# 必要なもの：

- 画像のどこに指先があるか教えてくれるモデル　->　handposeモデル

> handpose パッケージは、入力されたイメージまたは動画ストリームから手を検知し、それぞれの手の特徴の位置を示す 21 個の 3 次元ランドマークを返します。このランドマークには、それぞれの指の関節や手のひらの位置も含まれます。
参考：https://developers-jp.googleblog.com/2020/04/mediapipe-tensorflowjs.html


- 画像にあるテキストを認識するモデル -> OCRモデル

> OCR（Optical Character Recognition/Reader、オーシーアール、光学的文字認識）とは、手書きや印刷された文字を、イメージスキャナやデジタルカメラによって読みとり、コンピュータが利用できるデジタルの文字コードに変換する技術です。
参考：https://mediadrive.jp/technology/ocr.html

## システムの仕組みは下のイメージ

![指でOCR.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521590/942aec8d-1483-062d-8103-64cc17000a26.jpeg)

1. カメラから画像をhandposeモデルに入れる
2. handposeモデルの結果から指す手振り（:point_up:）かどうかを判断して、もし指す手振りだったら、画像をOCRモデルに渡す


3. OCRモデルでテキストを認証して、単語の内容と位置をアウトプットする
4. 人差し指位置から近い単語を辞書に渡す

# 実装
ml5jsを利用して、ウェブを作ってみます。

## Handposeモデル
[試しリンク](https://viz.mediapipe.dev/demo/hand_tracking)（実施するために、右上の人アイコンをクリックしてください）

Handposeモデルのアウトプットの例
![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521590/a9ef1fbe-613a-07cd-6aa1-d73d363622bb.png)
見えるように、モデルのアウトプットは手の21点です。で、必要な点は以下の写真になります。

![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521590/d0b9b1b7-c26c-f8fe-a09b-caa716c93c86.png)


```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ml5.js - Handposeモデル</title>
  </head>
  <body>
    <h1>ml5.js - Handposeモデル</h1>

    <!-- このapp内のみVue.jsの管理範囲です -->
    <div id="app">
      <p>{{ detectedName }}</p>
      <video id="myvideo" width="640" height="480" muted autoplay playsinline></video>
    </div>

    <!-- ml5.jsとVue.jsをCDNから読み込みます -->
    <script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>

      const app = new Vue({
        el: '#app',
        data: {
          detectedName: 'モデルのロード中です...',
        },

        // DOMの構築が完了してから実行する（それ以前だとvideoタグを見つけられない）
        async mounted() {
          const stream = await navigator.mediaDevices.getUserMedia({
            audio: true,
            video: true,
          });

          const video = document.getElementById('myvideo');

          video.srcObject = stream;
          const handpose  = await ml5.handpose(video);
          app.detectedName = 'モデルロード完了';

          handpose .on('predict', (results) => {
            console.log(results);
          });

          function onDetect(err, results) {
            console.log(results);
          }
        },
      });

    </script>
  </body>
</html>
```


# OCR
emptyとissetの違い

###php言語をおけるemptyとissetの違いについて

emptyは空かどうかを判定し、空ならtrueを返す。

逆にissetは入っているかを判定し、入っていればtrueを返す。

だから、下記のような認識をしていた。

```sample.php
empty === !isset
```
しかし、これは間違っています。

それは、0の判定の場合です。

emptyは「0」は「空」と判定します。

一方issetは「０」は「入っている」と判定します。

また、issetは空の配列も「入っている」と判定します。

ここの部分がemptyとissetの違いです。

ですから、その時の状況によってemptyとissetを使い分けるようにしましょう。
Ubuntu on WSL2 : Cannot connect to the Docker daemon at unix ～ を解決した

###背景
WSL2上のUbuntuのターミナルから、Dockerコマンドを発行した際に、
*Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?*
が表示され、その解決に手間取ったので、今後のために、備忘録として残すこととした。

###解決方法

Dokcer Desktopを起動して、Resources から **WSL INTEGRATION** を選び、
以下、２つを有効にすることで、すんなりと解決した。

**Enable integration with my default WSL distro**
**Ubuntu-xxxx （例：18.04）**
Pythonの学習！Javaとの比較（基本の関数）

#はじめに
Pythonの学習を始めたため、習得したJavaと比較していきたいと思います。

#print関数

```python
print('こんにちは')
print("こんにちは")
```
実行結果
![スクリーンショット 2020-11-09 150744.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/98fb9683-3957-fb23-f12b-418e002aac59.png)
Javaの場合

```java
System.out.println("こんにちは");
```
#コメントアウト
```python
#コメントアウト
print('コメントは表示されません')
```

Javaの場合

```java
//コメントアウト
System.out.println("コメントは表示されません");
```
#変数
```python
name = '佐藤'
age = '20'
print(name)
print(age)
```
実行結果
![スクリーンショット 2020-11-09 151912.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/43c76b7f-8f08-c189-f395-4f350aff5ef7.png)
Javaの場合

```java
String name = "佐藤";
int age = 20;
System.out.println(name);
System.out.println(age);
```
#input関数
```python
name = input('名前を入力してください >>')
age = input('年齢を入力してください >>')
print(name)
print(age)
```
実行結果
![スクリーンショット 2020-11-09 154543.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/64ca6155-1618-514a-d2ca-ce5b28a795af.png)
Javaの場合

```java
System.out.println("名前を入力してください");
String name = new java.util.Scanner(System.in).nextLine();
System.out.println("名前を入力してください");
int age = new java.util.Scanner(System.in).nextInt();
System.out.println(name);
System.out.println(age);
```
<font color="Red">※input関数で入力された数字はstr（文字列）として扱われるため下記のデータ型の変換が必要</font>
#データ型の変換
###str型からint型へ変換

```python
#xに文字列「1」を代入
x = '1'
#文字列「1」を整数「1」に変換
y = int(x)
#整数同士の計算をする
print(y + 1)
```
実行結果
![スクリーンショット 2020-11-09 160518.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/21010691-143c-e85a-8560-f59459146638.png)
Javaの場合

```java
//xに文字列「1」を代入
String x = "1";
//文字列「1」を整数「1」に変換
int y = Integer.parseInt(x);
//整数同士の計算
System.out.println(y + 1);
```
###int型からstr型へ変換

```python
#xに整数「1」を代入
x = 1
#整数「1」を文字列「1」に変換
y = str(x)
#文字列同士の連結
print(y + '1')
```
実行結果
![スクリーンショット 2020-11-09 161900.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/e80bb9df-e1a0-09ba-1739-3daef718c321.png)
Javaの場合

```java
//xに文字列「1」を代入
int x = 1;
//整数「1」を文字列「1」に変換
String y = String.valueOf(x);
//文字列同士の連結
System.out.println(y + "1");
```
###typ関数
変数内の値のデータ型を調べる

```python
a = 'こんにちは'
b = 1
print(type(a))
print(type(b))
```
実行結果
![スクリーンショット 2020-11-09 223333.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/dba5e888-a8ab-2f9e-55d2-e99f86a0ed03.png)
#format関数
文字列の中に数値を埋め込む

```python
name = '佐藤'
age = 20
print('私の名前は{}です。年齢は{}歳です。'.format(name, age))
```
または

```python
name = '佐藤'
age = 20
print(f'私の名前は{name}です。年齢は{age}歳です。')
```
実行結果
![スクリーンショット 2020-11-09 230636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603568/617ac244-7284-a0a6-916c-caeb52d198c2.png)
Javaの場合

```java
String name = "佐藤";
int age = 20;
String str = String.format("私の名前は%sです。年齢は%d歳です。", name, age);
System.out.println(str);
```
#参考文献
https://book.impress.co.jp/books/1118101169

次回はコレクションについて学んでいきたいと思います。
Oculus Setupのインストールが失敗したときの解決法

#問題
windows10でoculus quest2 の quest linkを使うためにoculusの公式アプリをインストールしようと，oculus setupを実行すると．最後に，コンピュータを再起動．インストール中にエラーが発生しました．というエラーが出てインストールができない．
![20191120172318.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205808/6db2c838-af32-ea9b-bc86-c1b8e2259f43.png)

#解決法
windows10で管理者権限のない別アカウントを作り，そこでoculus setupを実行したところインストールに成功した．
インストールに成功した後は，管理者権限のある本アカウントでもOculusアプリが使えるようになっていた．

#余談
いつの間にかwindows10で別アカウントを作るのに，新しいマイクロソフトアカウントが必要になっていて驚いた．
quest linkではoculusアカウントも使えるので，facebookアカウントが凍結されても，とりあえずはquestである程度のことができるのでお勧め．
アコーディオン

https://techacademy.jp/magazine/19737

https://saruwakakun.com/html-css/reference/accordion

https://www.webcreatorbox.com/tech/details-summary

http://blog.e-riverstyle.com/2009/07/jqueryjs-8.html

https://hacknote.jp/archives/12829/

https://into-the-program.com/tr-display-block-none/
CSVファイルとは

##結論
`CSVファイル` = `カンマで値を区切ったもの`が入っているファイル。
　　　　　　　`Comma(カンマ)`　`Separated(区切った)`　`Value(値)`の略。
　　　　　　　`拡張子`は `.csv`で、そのままクリックしてメモ帳で開くことができる。
`拡張子` = `ファイルの種類を識別するためにファイルの名前の末尾につけられる`文字列。

##CSVを用いる場面
・Excel・`データベースソフト`間でファイルをやり取りする。
→`データを整理して蓄積し、さまざまな組み合わせで取り出すことのできるソフトウェア`
・`Googleアナリティクス`のアクセスレポートを出力する。
→`Googleが無料で提供するWebページのアクセス解析サービス`
・Excelを持っているか不明な相手にデータを送る。
・ファイルのデータ容量を軽くする。
・表計算データをオープンソースで配布する。etc...

##CSVファイルのメリット
・装飾や機能が省かれる分データ容量が軽くなる。
・受け取った人がExcelにインポートし、列や行を削除・編集・計算できる。
・他のアプリケーションでも活用できる。

##CSVファイルの使い方
`Excelファイルと互換性のない`データベースソフトでは、Excelで作った表は`CSVファイルに変換して読み込む必要`があります。
反対にデータベースソフトのデータも拡張子`.xlsxとして出力できない`ため、`CSVファイルとして出力してExcelに読み込ませる`ことになります。

企業によって使用しているアプリケーションは様々です。
相手に`どの形式でデータを渡せばいいのか？`と問い合わせなくても、`CSVファイルならまず間違いありません`。
`テキストファイル`なので`容量も軽く、転送がスムーズ`に行えます。




参考元はこちら
(https://www.pc-master.jp/sousa/csv.html)
(https://data.wingarc.com/csv-excel-2-19747)
改行したいのにword-brockが効かない時にwhite-spaceを見てみた

## やりたかったこと
とあるページを修正しスマホで見たら自動改行されていないことが原因で横スクロールが入ってしまっていたので、適切なところで改行させて横スクロールを無くしたい。

## 試したこと
「css 改行」的な感じで検索するとどうやら`word-break`というプロパティで改行をコントロールできるらしいということがわかったので早速デベロッパーツール上で追記。

```style.css
a {
    word-break: break-all;
}
```

ヘッヘッヘ、これで完璧だぜ。。。と思っていたのですが、これが**全く効かない。**
プロパティの値を`keep-all`とか他のにしても**全く効かない。**
`overflow-wrap`なんかも試してみたけど**全く効かない。**

## 解決方法

```style.css
a {
    white-space: normal;
}
```

実は該当のpタグに設定していたclassに対して`white-space: nowrap;`が設定されており、それが原因で`word-break`が効かなかったようです。
これで改行まで行ってくれるので一件落着。


## 参考

https://developer.mozilla.org/ja/docs/Web/CSS/word-break
https://developer.mozilla.org/ja/docs/Web/CSS/white-space
Microsoft Edge（Chromium 版）で「デベロッパーモードの拡張機能を無効にする」を表示しないようにする

Chromium 版 Edge に開発者モードで読み込んだ拡張機能があると、`デベロッパーモードの拡張機能を無効にする` という警告が表示され、拡張機能が無効化されます。セキュリティ対策を意図した機能と考えますが、ストアに提出していない自作拡張機能のサイドロードが制限されてしまうため不便です。どうにかしたい。

## ローカルグループポリシーで特定の拡張機能のインストールを許可する

Chromium 版 Edge は [Google Chrome の場合](https://cloud.google.com/docs/chrome-enterprise/policies)と同様、`edge://settings/` にはない設定をポリシーから指定できるようになっています。なお、ローカルグループポリシーを設定するには Windows 10 が Pro Edition 以上である必要があります。

まず、Microsoft の[ビジネス向け Edge](https://www.microsoft.com/ja-jp/edge/business/download) のページからポリシーテンプレートを取得します。チャンネル/バージョンとビルドを指定すると、ダウンロードのリンクが有効化されます。

ダウンロードしたポリシーテンプレートを所定のディレクトリに配置します。[^2]

[^2]: `msedgeupdate` は Edge の更新方法と更新タイミングを制御するため、`msedgewebview2` はWebView2 の実行方法を構成するためのポリシーテンプレートですので、今回は必要ありません。

* `msedge.admx`
  * From: `windows\admx\`
  * To  : `C:\Windows\PolicyDefinitions\`
* `msedge.adml`
  * From: `windows\admx\ja-JP`
  * To  : `C:\Windows\PolicyDefinitions\ja-JP\`

次に、拡張機能をインストールします。`edge://extensions/` を表示し、開発者モードに切り替えてから `.crx` 形式のファイルをドラッグ&ドロップしてください。

![EdgeExtensionInstallSources2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463374/2c689360-0943-dadd-9158-f03b85ab98dd.jpeg)

しかし、`この拡張機能は既知のソースからのものではなく、ユーザーの知らないうちに追加された可能性があります。` と表示され、無効化されてしまいました。個別に許可する必要がありますので、拡張機能 ID を控え、削除しましょう。

グループポリシーエディタを開き、`管理用テンプレート\Microsoft Edge\拡張機能\特定の拡張機能のインストールを許可する` を開きます。

![EdgeExtentionAllowList.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463374/6b9d0a01-28bc-2675-3469-7e104fe28d20.jpeg)

`禁止リストから除外する拡張子 ID`[^1] にインストールを許可したい拡張機能の IDを指定します。

[^1]: 拡張機能 ID (`extention_id`)の誤訳と思われます。

Edge の再起動後、ローカルホストからのインストールを再試行してください。今度は成功するはずです！

なお、この方法で導入した拡張機能を更新する場合 `.pem` ファイルを削除して新しい `.crx` ファイルを作成しないと正しく動作しない可能性があります。このとき、`.pem` ファイルを引き継がないと拡張機能 ID が変化することから、グループポリシーの再変更が必要となります。

## ちなみに

Google Chrome における該当の事象について調べている最中、ポリシー名の表記ゆれがあることに気が付きました。どうやら、BLM 運動に関連して名称の変更が行われたようです。

* `ExtensionInstallBlacklist` => `ExtensionInstallBlocklist`
* `ExtensionInstallWhitelist` => `ExtensionInstallAllowlist`

[そろそろ本格的にプログラミング用語を置き換える時期なのかも](https://qiita.com/Daara_y/items/c7caf39dba0e6a61e7da)しれません。

## 参考リンク

* [「デベロッパーモードの拡張機能を無効にする」の警告の対処法！](https://aprico-media.com/posts/4131)
* [ビジネスに適した新しい Microsoft Edge をダウンロードして展開する](https://www.microsoft.com/ja-jp/edge/business/download)
* [ExtensionInstallAllowlist（Edge）](https://docs.microsoft.com/en-us/DeployEdge/microsoft-edge-policies#extensioninstallallowlist)
* [ExtensionInstallAllowlist（Chrome）](https://cloud.google.com/docs/chrome-enterprise/policies?policy=ExtensionInstallAllowlist)
[Python+Selenium]スクレイピングで使える小技メモ

##この記事について
実務でスクレイピングを行うことがあったので、その際にインプットした小技のメモです。


##ツール
Python3(3.6.2)
Selenium
Chrome driver(85.0.4183.87)


##1.jsを操作する（非表示要素を表示させる）
execute_scriptメソッドを使うことでSeleniumからJavascriptを操作することができます。

例えば、下記のようにjsのsetAttributeメソッドを操作してテキストの色を変えることができます。

```python:
from selenium import webdriver
driver = webdriver.Chrome()

driver.get("https://www.hogefuga")

element = driver.find_element_by_xpath("//div[@class='fuga']/span")
driver.execute_script("arguments[0].setAttribute('style','color: red;')", element)

```

このメソッドを活用すれば、display: none;になっている要素を表示させることもできます。例えばdisplay:none;が適用されているclass名を非表示となっている要素から削除することで非表示要素を表示させることができます。

```python:
# closeクラスにdisplay:none;が適用されている場合
element = driver.find_element_by_xpath("//div[@class='hoge close']/span")
driver.execute_script("arguments[0].setAttribute('class','hoge')", element)

```



##2.iframe内の要素を取得する

ifame内の要素を取得するには、**switch_to_frame()**が必要です。

```python:
driver.switch_to_frame(driver.find_element_by_xpath("//div[@class='hoge']/iframe"))
```

これでifame内の要素を取得可能な状態にすることができます。一方でiframe外の要素は取得できなくなります。そのため、元の要素を取得したい場合は**switch_to_default_content()**によって再び元の要素を取得できるように切り替える必要があります。

```python:
driver.switch_to_default_content()
```


##3.Seleniumの操作対象を別ウィンドウに切り替える
seleniumを操作してスクレイピングする際に、リンクをクリック後に別ウインドウが開く場合があります。別ウインドウに対して何らかの操作を行いたい場合は、**switch_to_window()**によって操作対象を別ウインドウに切り替えます。

```python:
#別ウインドウを開く
driver.find_element_by_xpath("//div[@class='hoge']/a").click()

#当初から開いているウインドウ
window_before = driver.window_handles[0]
#新しく開いているウインドウ
window_after = driver.window_handles[1]

#seleniumの操作対象を新しく表示されたウインドウに切り替える
driver.switch_to_window(window_after)

#seleniumの操作対象を当初から開いているウインドウに切り替える
driver.switch_to_window(window_before)

```


##4.ラジオボタンをクリック


```python:
# ラジオボタン要素を取得
element = driver.find_element_by_id(“fugafuga”)

driver.execute_script("arguments[0].click();", element)
```

##5.HeadlessChromeでWEBページからファイルをダウンロードする
HeadlessChromeはセキュリティ上の観点からデフォルトではファイルのダウンロード機能は実装されていないようです。そのためpost通信によってファイルダウンロードを許可する設定を行う必要があるようです。


```python:
from selenium import webdriver

DOWNLOAD_URL = "https:www.hogefuga/file/download"
download_dir = "/home/download"  #ダウンロードしたファイルの置き場所

def enable_download(driver, download_dir):
    driver.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')
    params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
    driver.execute("send_command", params)

def setting_chrome_options():
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument('--no-sandbox')
    return chrome_options;

driver = webdriver.Chrome(executable_path="/usr/local/bin/chromedriver",options=setting_chrome_options())
enable_download(driver, download_dir)
driver.get(DOWNLOAD_URL)

```
※executable_pathは各々の環境に合わせて変更してください。
Lambdaで"An error occurred (AccessDenied) when calling the GetObject operation: Access Denied"と言われてハマった

#概要
LambdaにてS3の特定オブジェクトをダウンロードする操作をPython(boto3)で実行したが、Access Deniedと言われて実行できない。
実行ロールにAmazonS3FullAccessを付与するも同様の結果。

#実行内容
```Python
import json
import boto3

def lambda_handler(event, context):
    
    s3 = boto3.resource('s3')
    bucket = s3.Bucket('my-hoge-hoge-bucket')
    bucket.download_file('test.txt', 'fuga.txt')

```

#Lambdaで表示されるエラー
```
{
  "errorMessage": "An error occurred (AccessDenied) when calling the GetObject operation: Access Denied",
  "errorType": "ClientError",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 11, in lambda_handler\n    bucket.download_file('test.txt', 'fuga.txt')\n",
    "  File \"/var/runtime/boto3/s3/inject.py\", line 244, in bucket_download_file\n    return self.meta.client.download_file(\n",
    "  File \"/var/runtime/boto3/s3/inject.py\", line 170, in download_file\n    return transfer.download_file(\n",
    "  File \"/var/runtime/boto3/s3/transfer.py\", line 307, in download_file\n    future.result()\n",
    "  File \"/var/runtime/s3transfer/futures.py\", line 106, in result\n    return self._coordinator.result()\n",
    "  File \"/var/runtime/s3transfer/futures.py\", line 265, in result\n    raise self._exception\n",
    "  File \"/var/runtime/s3transfer/tasks.py\", line 126, in __call__\n    return self._execute_main(kwargs)\n",
    "  File \"/var/runtime/s3transfer/tasks.py\", line 150, in _execute_main\n    return_value = self._main(**kwargs)\n",
    "  File \"/var/runtime/s3transfer/download.py\", line 511, in _main\n    response = client.get_object(\n",
    "  File \"/var/runtime/botocore/client.py\", line 357, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n",
    "  File \"/var/runtime/botocore/client.py\", line 676, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n"
  ]
}
```

#原因
KMSによる[デフォルト暗号化](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/bucket-encryption.html)が有効なバケットのオブジェクトを操作していた。

<img width="600" alt="s3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671034/81dba9d7-b20b-78e1-46f2-d7a7c999f62e.png">

#解決策
KMSにて、暗号化に使用しているキーのキーユーザーに対象となるLambdaの実行ロールを追加する。

![スクリーンショット 2020-11-09 22.34.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671034/e9874cc0-3a11-d26b-7fc7-301ccd5ee892.png)

意図的にKMSでの暗号化を設定していると気付きますが、awsによって自動的に暗号化される(RDSのスナップショットなど)場合はなかなか気づけないですね。
[Swift][初心者]#selectorについていろいろ調べてみた

#はじめに
最近
[作って楽しむプログラミング　iPhoneアプリ超入門 Xcode 11 ＆ Swift 5で学ぶはじめてのスマホアプリ作成](https://www.nikkeibp.co.jp/atclpubmkt/book/20/P53910/)
という教材でswiftについて勉強しています。
その中で` #selector` というものが出てきました。

# #selectorとは
selector(セレクタ)とはあるメソッドを別のメソッドの引数とすることを指すらしいです。
使い方については下記に書いてありました。
[使い方](https://qiita.com/Kyome/items/4dc89a2f991dac72c668)

#引数について
引数についていろいろ調べたところ
[こちら](https://qiita.com/st43/items/43c5c0f5e1f727ba0ff0)にもあるとおり
>セレクタで指定したメソッドの引数に何を渡せるかを決めるのは、そのセレクタを引数にとる関数が決めます。

らしいです。例えばテキストボックスに入力された文字を渡したりとかはできないようです。(頑張ればできないこともないようですが・・・)

##結論
selectorって難しいけど使う場面多そうなので慣れなきゃいけないですね
(swift勉強してて思うのは、
私は業務でobjective-c使ってたから今のところある程度理解できますが、
完全初学者だと理解するのすごく難しそう・・・)
deviseでログインしていない場合はログイン画面に遷移するメモ

##ログインしていない場合はログイン画面に遷移する

###authenticate_user!メソッド


authenticate_user!メソッドは、deviseのヘルパーメソッドである。authenticate_user!メソッドを使用すると、処理が呼ばれた段階で、ユーザーがログインしていなければ、そのユーザーをログイン画面に遷移させる。つまり、ログイン状態によって表示するページを切り替えることができる。


before_actionで呼び出すことで、アクションを実行する前にログインしていなければログイン画面に遷移させることができる。

<br>
(記述例)

`コントローラーの先頭に、before_action :authenticate_user!と記述`

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end
```
<br>

 記述後、ログインしていない場合はログイン画面に遷移するようになる。

<br>
なでしこ3で湯婆婆を実装してみる

令和の「令和のHello World!」である「湯婆婆を実装してみる」シリーズを日本語プログラミング言語「なでしこ」で作ってみました。[なでしこ3](https://nadesi.com/doc3/go.php?10)ならブラウザで試せるので試してみてください！！

> 原作: [Javaで湯婆婆を実装してみる - Qiita](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)


```湯婆婆.nako3
「契約書だよ。そこに名前を書きな。」と尋ねて名前に代入。
もし、名前が空ならば、名前は「名無し」
名前の文字数の乱数をNに代入。
名前で(N+1)から1文字抜出して新しい名前に代入。

「フン。{名前}というのかい。贅沢な名だねぇ。
今からお前の名前は{新しい名前}だ。
いいかい、{新しい名前}だよ。
分かったら返事をするんだ、{新しい名前}!!」と表示。
```

簡易エディタに上記プログラムを記入したら「実行」ボタンを押します。

![スクリーンショット 2020-11-09 22.19.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/2030ef8b-d538-9eab-7cb8-92944d73db7c.png)

試しに「クジラ飛行机」と入力します。すると・・・

```
フン。クジラ飛行机というのかい。贅沢な名だねぇ。
今からお前の名前は飛だ。
いいかい、飛だよ。
分かったら返事をするんだ、飛!!
```

と、このように表示されます。

なお、無入力だった場合、空白になるので「名無し」とかにしてみました。

上記のプログラムを実行して、入力を空にすると、名無しが名前になり、以下のような感じになるのでOKです。

```
フン。名無しというのかい。贅沢な名だねぇ。
今からお前の名前はしだ。
いいかい、しだよ。分かったら返事をするんだ、し!!
```

## 参考

- Python3 - https://qiita.com/everylittle/items/aae58c241194c0e5f515
- C# - https://qiita.com/everylittle/items/d4df566a9c5f4bb58d5f
- Perl - https://qiita.com/fujitanozomu/items/d403f50ef285e606343b