OmniAICreator/Qiita-1.07M huggingface dataset:
UnityでOculus IntegrationのSampleFrameworkを使ってOculus Questのハンドトラッキングを試す (2)

# はじめに

前回は、トリガーアクションでキューブの色を変えました。
[UnityでOculus IntegrationのSampleFrameworkを使ってOculus Questのハンドトラッキングを試す](https://qiita.com/qvtec/items/9e45b6bdad17a940a236)

今回は、SampleFrameworkのHandsを使って、ピンチ幅の取得してみます。
ついでにAll Valid Tools Tagsを変更し、それぞれどのような動きになるかも試します。

# Handsで使えそうなもの

### Hands.cs

**表示タイプを切り替える**
`Hands.Instance.SwitchVisualization();`

**左右取得**
`Hands.Instance.LeftHand`
`Hands.Instance.RightHand`

### Hand.cs

Handsから左右のhandを取得し、それぞれに実行できる

**ピンチ幅取得**
`hand.PinchStrength(OVRPlugin.HandFinger.Middle)`

**スケルトン表示**
`hand.PinchStrength(OVRPlugin.HandFinger.Middle)`


# ピンチ操作

MyHand.csスクリプトを作り、Handsに追加しておく

```MyHand.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OculusSampleFramework;

public class MyHand : MonoBehaviour
{
    private Renderer renderer;

    void Start()
    {
        renderer = GameObject.Find("CubeButtonRay").GetComponent<Renderer>();
    }

    void Update()
    {
        if (Hands.Instance.LeftHand.PinchStrength(OVRPlugin.HandFinger.Middle) > 0.9f)
        {
            renderer.material.color = Color.black;
        }
        else if (renderer.material.color == Color.black)
        {
            renderer.material.color = Color.white;
        }
    }
}
```

using OculusSampleFramework で Handsが使える
中指をピンチしたらキューブの色を黒にする
離したら白にする

![ダウンロード (7).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/6d5ed929-664c-3c29-989d-35458b577f66.gif)

# 表示タイプを切り替えてみる

ButtonController の Interactable State Change で Hands の SwitchVisualization を呼び出す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/9e3d86bf-18ae-c47c-9d47-7004f1b297c4.png)

キューブを選択したら手の表示が切り替わる

![ダウンロード (6).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/8006b25b-a30d-b309-edec-957dae8ecb25.gif)

# All Valid Tools Tags

前回はすべてAllにしていたので、キューブを複製し、Ray,Poke,Pinchをそれぞれ配置してみました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/f707a253-f9d7-5336-57fd-572090a3926a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/18cafa0a-bcd8-f7ef-ec76-6c3fd5d1271e.png)

## All

RayでもPokeでも動く

## Ray

ちょっと離れないと選択できない
線が当たると吸い付くので意外と選択しやすかった

![ダウンロード (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/0b3994e4-8c05-897b-a7e0-1985be6975c2.gif)

## Poke

直接触ると発火する
線が当たっても吸い付かない

![ダウンロード (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/d1225a66-c18f-d2cc-e62c-8895eabae686.gif)

## Pinch

どうやって動くの？


# さいごに

あとは自由に作ってみよう！
ハンドトラッキングのメニュー表示をかっこよくしたい。
アバターの移動はどうやって操作しよう。
手を見失ったときの挙動を考えたい。
Amplifyでリソース作成に失敗したときの対処法

amplify pushしようとしたらエラーが出た

[該当issue](https://github.com/aws-amplify/amplify-cli/issues/3149)

```bash:エラー内容


Following resources failed

Resource Name: UserPoolClientLambda (AWS::Lambda::Function)
Event Type: create
Reason: The runtime parameter of nodejs8.10 is no longer supported for creating or updating AWS Lambda functions. We recommend you use the new runtime (nodejs12.x) while creating or updating functions.
```

バージョンをあげましょう

```
$ npm install -g @aws-amplify/cli
```
PHP 定数

# 目的

- 定数の定義方法をまとめる

# 書き方の例

- 定数は書き換えられない。
- 定数の出力時は定数名の前に`$`はつけない。
- 下記に定数の定義方法をまとめる。

```php
//定数の定義
define("定数名(大文字)", "定数に格納する不変の値");

//定数の出力
echo 定数名;
```

# 特殊な定数

- 下記にコードを書く際に定義せずともすでに最初から定義されている定数を紹介する。

```php
//現在の行数を出力する定数
var_dump(__LINE__);

//実行されているファイル名を出力する定数
var_dump(__FILE__);

//実行されているファイルが存在するディレクトリを出力する定数
var_dump(__DIR__);

```
[漏洞通告]CVE-2020-2551/Weblogic IIOP协议远程代码执行

### 漏洞描述
最近Oracle发布了新一轮补丁,其中重点了修复多个高危安全漏洞.其中较为严重之一的则是`CVE-2020-2551`.攻击者可以在未授权的情况下通过`IIOP`协议对存在漏洞的WebLogic进行远程代码执行的攻击.成功利用该漏洞的攻击者可以直接控制服务器,危害性极高。

### CVE编号
CVE-2020-2551

### 漏洞威胁等级
高危

### 影响范围
10.3.6.0.0
12.1.3.0.0
12.2.1.3.0
12.2.1.4.0

### 简单分析
该`IIOP`协议第一次听说源自2019年`blackhat`在欧洲地区的议题`An Far Sides Of Java Remote  Protocols`.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/3045f871-74f4-d943-40f4-40634e1f72e6.png)

后来在国内由知道创宇404实验室的`Longofo`在`paper`上进行披露

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/7c1091a4-e3a4-323f-f6d6-0a5c5ecee4fe.png)

根据提示,这个漏洞是由JNDI的方式进行注入完成攻击.在完成攻击前需要找到`weblogic`相应的工厂类才能完成攻击.由于该漏洞较为敏感，过多细节不再透露.下图为攻击演示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/8e9e0a85-6206-6762-6058-43a2bbfaa5f9.png)
### 修复建议
- 1.关闭`IIOP协议`
登录控制台，以此点击`环境`——`服务器`——`你的Server(例如AdminServer (管理)）`——`协议`——`IIOP协议框反选`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/f08a3f08-ae0a-7cf6-5cf5-f37507fdf9b5.png)

- 2.由于是JNDI注入,建议升级JDK各个大版本的最新版本号
- 3.打上相关补丁
补丁文件目前只发布了`12.2.1.4.0`版本的，本月末Oracle将发布后续补丁
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/db5d7dcd-6d28-ef0f-a6d7-6e100f8f7463.png)

### 时间轴
[0] 2020/01/15 Oracle/NVD发布该漏洞
[1] 2020/01/16 亚信安全网络攻防实验室分析&复现该漏洞并发布漏洞通告
### 鸣谢
感谢大晚上一起研究的以下小伙伴(排名不分先后)
`Qianxin Ntears、`
`Qianxin LuFei`
`AlibabaCloud pyn3rd`
### Reference
https://paper.seebug.org/1105/#weblogicrmi-iiop
https://nvd.nist.gov/vuln/detail/CVE-2020-2551
https://www.oracle.com/security-alerts/cpujan2020.html
Elasticsearchを7.Xにアップグレードしたら、hitsが10,000 になってた

# 概要
ここ最近、Elasticsearchを7.Xにアップグレードしたら、1万件超えてるデータのhitsが10,000 になっていた
また、「Java High Level REST Client」を使用したアプリでの取得は0になっていた・・・・・

# Elasticsearch7.0.0から10,000hitsまで正確に確認できる

*  [Elasticsearch version 7.0.0 Release note](https://www.elastic.co/guide/en/elasticsearch/reference/current//release-notes-7.0.0.html)
→Track total hits up to 10,000 by default #37466 (issue: #33028)
*  [Track total hits up to 10,000 by default #37466](https://github.com/elastic/elasticsearch/pull/37466)

# 10,000hits以上どうやって検索する？
ドキュメントのサンプルから持ってきたのだが、track_total_hitsをtrueに設定すると
10,000hits以上を検索できる

```
curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "track_total_hits": true,
     "query": {
        "match" : {
            "message" : "Elasticsearch"
        }
     }
}
```

[Track total hits](https://www.elastic.co/guide/en/elasticsearch/reference/7.x/search-request-body.html)

# Java High Level REST Clientでは？
まず、7.0.0以上の「Java High Level REST Client」を使用する

「SearchSourceBuilder」の「trackTotalHits」メソッドに「true」を設定すればできる

```
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder. trackTotalHits(true);
```

[(java doc) SearchSourceBuilder.trackTotalHits](https://www.javadoc.io/doc/org.elasticsearch/elasticsearch/latest/org/elasticsearch/search/builder/SearchSourceBuilder.html#trackTotalHits(boolean))

hitsの件数の取得方法が6.Xのものと比べて変更があった

```
long hits = hits.getTotalHits().value;
```

6.Xの時は「getTotalHits」メソッドの戻り値がlongだった

```
long totalHits = hits.getTotalHits();
```
SwiftUIでキーボードで文字が隠れないように処理をいれる

## UIKit同様にキーボードが閉じる処理は元々入っていない
- iOSの開発をすると必ず直面するキーボードを閉じる処理。
- Returnキーを押したときや、他の箇所をタップした時に閉じたり、キーボードで入力される文字が隠れないように自分で処理を作成しなければならない。
- 今回は`キーボードで入力される文字が隠れないようにする`処理を作成する
- UIKitの時と同様にNotificationCenterを使ってキーボードの監視を行う。

## 実装
### キーボードを監視するクラス

```swift

import SwiftUI
import Combine

class KeyboardObserver: ObservableObject {

  @Published var keyboardHeight: CGFloat = 0.0

  /// Observerの追加
  func addObserver() {
    NotificationCenter
      .default
      .addObserver(self,
                   selector: #selector(self.keyboardWillChangeFrame(_:)),
                   name: UIResponder.keyboardWillChangeFrameNotification,
                   object: nil)
  }

  /// Observerの削除
  func removeObserver() {
    NotificationCenter
      .default
      .removeObserver(self,
                      name: UIResponder.keyboardWillChangeFrameNotification,
                      object: nil)
  }

  /// キーボードのフレーム検知処理
  /// - Parameter notification: Notification
  @objc func keyboardWillChangeFrame(_ notification: Notification) {
    if let endFrame = notification
      .userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
    let beginFrame = notification
      .userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue {
      let endFrameMinY: CGFloat = endFrame.cgRectValue.minY
      let beginFrameMinY: CGFloat = beginFrame.cgRectValue.minY

      self.keyboardHeight = beginFrameMinY - endFrameMinY
      if self.keyboardHeight < 0 {
        self.keyboardHeight = 0
      }
    }
  }

}

```

### Viewのクラス

```swift
struct ContentView: View {

  @ObservedObject var keyboard = KeyboardObserver()
  @State var text: String = ""

  var body: some View {
    VStack {
      Spacer()
      Rectangle()
        .frame(width: 300, height: 300)
      TextField("入力", text: self.$text)
        .padding()
    }.onAppear(perform: {
      self.keyboard.addObserver()
    }).onDisappear(perform: {
      self.keyboard.removeObserver()
    }).padding(.bottom,
               self.keyboard.keyboardHeight)
      .animation(.easeOut)
  }

}
```

## 実行結果

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/673a7f8c-5932-4ba4-9c4a-b96d0c669e65.gif)


## まとめ
- SwiftUIでも文字が隠れないように処理を入れることができた。
- つぎは他の箇所をタップした際にも閉じられる処理を掲載する。
Swagger-codegenを使おうと思ったが、エラーで使えなかった件

## 発生した問題
swagger-codegenでnodejs-serverを選択し、モックサーバーを立てようとしたら以下のエラーが出た。

```
Error: Cannot find module './middleware/swagger.router'
```
パッケージの中を確認すると、確かにswagger.routerがない。
issueが立ってた。パッケージに間違いがあるらしい。
https://github.com/bug-hunters/oas3-tools/issues/17

## 解決策
Swagger-codegenのバージョンを下げて、
swagger-codegen@2で対応した。

```bash
$ brew install swagger-codegen@2
```

## 学んだこと
パッケージも間違っていることがある。
npmのサイトにissuesが上がっていることがある。
Weekly downloadsとかが多いものは信頼性が**ちょっと**高い。
Kotlin/Native MPPのMVPアーキテクチャのサンプルコード

- [kotlinconf-app : b83d00e](https://github.com/JetBrains/kotlinconf-app/tree/b83d00eec10ba514904ef6870472bec1899d27e5)
    - 開発者が変わったため、masterブランチの最新はMVPではなくなってしまったのですが、リンク先の時点まではMVPで実装されていました。
    - JetBrains謹製なので、最も参考になるコードです。
あえてseleniumを使わずにフォームに入力してみる

# はじめに
「あえて」というほどでもないのですが、Pythonでフォームの編集を調べているとseleniumが良く出てくるのでRequests+BeautifulSoupで実装してみました。

[以前投稿した記事](https://qiita.com/sssssssiiiiinnn/items/14f7035abe9ce4111323)の発展編としてちょうどいいのでQiitaのプロフィール文を編集してみました。

# 編集用関数
編集可能な多くの項目はtypeが['text', 'url', 'checkbox']のいずれかであることがソースから判明したため、ほとんど手打ちする必要なく取得できました。
取得もれである'user[desctiption]]'を追加するついでに編集すればpost用データの完成です。なぜかemail公開のチェックボックスがデフォルトでチェック済みになっていたため0に修正しています。データの作成ができたらログイン時のセッションを使ってPostすれば完成です。

```Python
def edit_profile(session):
    profile_page_data = get_page_data(session, profile_url)
    bs_profile_page = BeautifulSoup(profile_page_data.text, 'html.parser')
    authenticity_token = str(bs_profile_page.find(attrs={'name':'authenticity_token'}).get('value'))
    post_data = {
        'utf-8':'✓',
        '_method': 'put',
        'authenticity_token':authenticity_token
    }
    response = bs_profile_page.find_all(attrs={'type':['text', 'url', 'checkbox']})
    for i in response:
        value = i.get('value')
        post_data[i.get('name')] = value
    post_data['user[public_email]'] = 0 # なぜかデフォルトで1
    post_data['user[description]'] = '編集したよ！！！！'
    print(post_data)
    response = session.post(profile_url, post_data)
    print(response)
```

# いざ実行
前回作成したプログラムに上で記載したedit_profile()を追加すればプログラムの完成です。

```Python
import requests
import os
from bs4 import BeautifulSoup
import json


user_name = 'user_name'
user_password = 'user_password'
login_url = 'https://qiita.com/login'
profile_url = 'https://qiita.com/settings/profile'
    

def get_authenticity_token(session, login_url):
    page_data = get_page_data(session, login_url)
    bs_page_data = BeautifulSoup(page_data.text, 'html.parser')
    authenticity_token = str(bs_login_page.find(attrs={'name':'authenticity_token'}).get('value'))
    return bs_page_data, authenticity_token


def get_page_data(session, url):
    response = session.get(url)
    response.encoding = response.apparent_encoding
    return response


def login(session):
    login_form = {
        'utf-8':'✓',
        'authenticity_token':'token',
        'identity':user_name,
        'password':user_password
    }
    bs_login_page, authenticity_token = get_authenticity_token(session, login_url)
    login_form['authenticity_token'] = authenticity_token
    session.post(login_url, login_form)
    

def edit_profile(session):
    bs_profile_page, authenticity_token = get_authenticity_token(session, profile_url)
    post_data = {
        'utf-8':'✓',
        '_method': 'put',
        'authenticity_token':authenticity_token
    }
    response = bs_profile_page.find_all(attrs={'type':['text', 'url', 'checkbox', 'textarea']})
    for i in response:
        value = i.get('value')
        post_data[i.get('name')] = value
    post_data['user[public_email]'] = 0 # なぜかデフォルトで1
    post_data['user[description]'] = '編集したよ！！！！'
    print(post_data)
    response = session.post(profile_url, post_data)
    print(response)
    
if __name__ == '__main__':
    session = requests.Session()
    login(session)
    edit_profile(session)
```
実行してResponse [200]が返ってくれば成功です。
each_with_objectの簡単なサンプルメモ

# メモ

> enum.each_with_object(object) {|item, memo| block }
each_with_indexメソッドは、要素を使って何らかのオブジェクトを操作するのに使います。要素の数だけブロックを繰り返し実行し、繰り返しごとにブロック引数itemには各要素を、memoには引数objectで指定したオブジェクトを入れます。戻り値は、objectのオブジェクトです。
https://ref.xaio.jp/ruby/classes/enumerable/each_with_object


# サンプル

## 配列→配列
```ruby
require "pp"

arr = [1, 2, 3]
result = arr.each_with_object([]) do |item, memo|
  p item # => 1...
  memo << 1
end
pp result # => [1, 1, 1]

result = arr.each_with_object([1, 2, 3]) do |item, memo|
  memo << 1
end
pp result # => [1, 2, 3, 1, 1, 1]

result = arr.each_with_object([1, 2, 3]) do |item, memo|
  memo << item + 1
end
pp result # => [1, 2, 3, 2, 3, 4]
```

## ハッシュ→ハッシュ

```
hash = { a: "A", b: "B", c: "C" }
result = hash.each_with_object({}) do |item, memo|
  p item # => [:a, "A"]...
  p item.class # => Array
end
pp result # => {}

result = hash.each_with_object({}) do |(k, v), memo|
  p k # => :a...
  p v # => "A"...
end
pp result # => {}

result = hash.each_with_object({aaa: "AAA"}) do |(k, v), memo|
  memo["#{k}XXX"] = "#{v}YYY"
end
pp result # => {:aaa=>"AAA", "aXXX"=>"AYYY", "bXXX"=>"BYYY", "cXXX"=>"CYYY"}
```

## 配列→ハッシュ

```ruby
arr = [1, 2, 3]

result = arr.each_with_object({}) do |item, memo|
  memo[item] = item + 1
end

pp result
```
あれやこれやしてても、たった3時間ぐらいで簡単なWEBアプリを作ってUnuboで公開できた話

簡単なwebアプリを1から作って、3時間ぐらいで完全無料ホスティングUnuboで公開までたどりついた話をします。

お名前で取得した独自ドメインを設定して、HTML/CSS/JavaScriptを使ったスタティックな簡単なwebアプリを公開しました。

##Unuboとは

<img width="1221" alt="スクリーンショット 2020-01-16 13.46.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208081/781966f5-92d8-ecc8-a1d9-f898c541c41b.png">

[■ Unubo - Cloud deployments made easy](https://unubo.com/)

Unuboとは、Webアプリ、DB、ブログを完全無料でホスティングできるサービスです。更にクレカ登録不要です。（2019/1現在）完全無料のホスティングを探していて、ここあたりの情報がでてきました。

[■ Node.js,Python,RubyなどのWebアプリを完全無料でホスティング可能な「Unubo」を使ってみた！](https://paiza.hatenablog.com/entry/2019/09/11/Node_js%2CPython%2CRuby%E3%81%AA%E3%81%A9%E3%81%AEWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E5%AE%8C%E5%85%A8%E7%84%A1%E6%96%99%E3%81%A7%E3%83%9B%E3%82%B9%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E5%8F%AF)
[■ Unuboを使ってみた話](https://qiita.com/tesstesstex/items/d81b323be241a4af8027)

Unuboっていうのがあるんだ〜と知ったのが、この記事を書き始めてから、昼飯挟んで約5時間ぐらい前のことです（笑）

実際に使った感想は、**めちゃくちゃ簡単！しかも無料！**です。

##やったこと

やったことは、webアプリ作成、Unuboでの公開設定と独自ドメイン設定です。

- webアプリ作成とUnuboでの公開設定

1. Unuboにサインイン
2. webアプリをGitHubにPUSH
3. GitHubとUnuboを連携
4. デプロイ、そして公開！

Unuboは、webアプリをGithubにPUSHすると自動的にデプロイしてくれます！

- 独自ドメイン設定

1. お名前でドメイン取得
2. お名前でDNS設定
3. Unuboにドメインを設定

##webアプリをGitHubにPUSH
GitHubの使い方は、ご存知かと思いますが、以下のサイトがわかりやすかったです。

[今さら聞けない！GitHubの使い方【超初心者向け】](https://techacademy.jp/magazine/6235)

##独自ドメイン設定方法

自身のアプリ管理画面のDomainsというところに独自ドメイン設定方法が書かれています。ドキュメント見てもここに書いてあるって書いてました。
<img width="1034" alt="スクリーンショット 2020-01-16 18.33.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208081/b3119ecf-a78c-cddb-4894-18315d06a468.png">

独自ドメインを取得した会社のDNSレコードに、Unuboの指定するアドレス登録した後、Unuboに独自ドメインを追加します。

まずは、お名前の管理画面から取得した独自ドメインのDNS設定をしました。

1. DNS設定/転送設定を開きます
2. DNSレコード設定を利用するの設定するボタンを押します。

<img width="924" alt="スクリーンショット 2020-01-16 18.34.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208081/245959df-69bf-d938-419d-a87dec0da095.png">

`$ dig asia.unubo.app`
asia.unubo.app. 34.87.61.225

CNAMEを使う場合は、Aレコードを追加しないといけないとのことなので、digで「asia.unubo.app」のIPアドレスを取得してAレコードに設定しました。AレコードとCNAMEレコードを次のように設定しました。

|ホスト名|TYPE |TTL|VALUE|
|:-----------------|------------------|:------------------|:------------------|
|tateyomi.xyz|A|3600|34.87.61.225|
|www.tateyomi.xyz|cname|3600|asia.unubo.app|

<img width="687" alt="スクリーンショット 2020-01-16 18.35.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208081/b81235f3-1838-b69c-2c0f-c0c992a831d2.png">

DNSレコード設定用ネームサーバー変更確認にチェック入れて、確認画面へ進んで、設定完了。

※既存ドメインでは、設定によって既存サイトがみれなくなってしまったりもあるので、自己責任のもと、きちんと確認して設定ください。

独自ドメインがインターネットに反映されるまで待ちます。

反映されたであろう、しばらくしてから、UnuboのDomainsの②から無料SSLと一緒に独自ドメインを追加します。

<img width="1050" alt="スクリーンショット 2020-01-16 18.33.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208081/44386b87-c473-61db-23f2-dea0af78abdc.png">

独自ドメインのDNS設定後、すぐにこれを設定するも、反映されていなかったのか一向に待っても無理でした。

独自ドメインのDNS設定したら、しばらく時間をあけて、この設定をしましょう！

設定終わってほっておくと、**いとも簡単にUnubo上で独自ドメインでサイト開設！**となりました。[Unubo](https://unubo.com/)、ほんとちょっとしたwebアプリをすぐ公開したいときには、ほんと便利ですね！

ちなみに公開したWebアプリは？というと、これです。
[TATEYOMITSUKURU 縦読み解読・作成アシストツール](https://www.tateyomi.xyz/)

ありがとうございました！
【Golang】mockgen で生成した *_mock.go のせいで Build がコケる場合の対処法

# 対象読者
 - Go の mockgen で生成した *_mock.go ファイルのせいで Build がコケている人
 - 自分

# 忙しい人のための結論
Build failed 時に、怒られているコード内の該当箇所を消せばよい。

# 事例
REST API を golang で書いていた。
テストコードを書くべく、mockgen でモックを生成したところ、それらのファイルにいちゃもんをつけられて Build が通らなくなった。

```
# hoge/fuga
fuga          | hoge/fuga_mock.go:**:*: m.ctrl.T undefined (type *gomock.Contr
oller has no field or method T)
```

m.ctrl.T で怒られるのは gomock の code generation が悪いからではないかと推測される。下記リンクによると gomock の version が関係していそう。
参考：https://github.com/openshift/openshift-azure/issues/870

下記リンクによると、同様の問題（m.ctrl.T undefined）が発生したが、gomock を v1.2.0 にしたところ動いたという。原因は構造体のフィールド t の表記を T と変更したことのようだ。
https://github.com/golang/mock/issues/255

では、go get で落とした gomock, mockgen の version を変更するには？

### Q. go get で落としたパッケージの version を変更する場合には？
A. $GOPATH 以下の src/ で、以下を実行し、使用するバージョン情報のブランチにチェックアウトする。

```
$ git tag -l #各バージョンのブランチが表示（tags/v1.2.0 など）
$ git checkout tags/v1.2.0 #v1.2.0 に切り替える場合
```

または glide などでパッケージ管理するといいらしい（Go version 1.5 以上）。
参考：https://qiita.com/usk81/items/8e192e68d6b18bec3b4a

だが、今回の問題に関してはより簡単な方法があった。。。

# 改めて結論

以下のようなメッセージが表示される箇所はコメントアウトしたところ、問題なく Build が成功した。下記の場合では、m.ctrl.T を含む行をコメントアウトした。

```
*****-*** | hoge/fuga_mock.go:37:8: m.ctrl.T undefined (type *gomock.Controller has no field or method T)
```
mockgen のバージョンを最新にすると通ったという声もある（詳細は未確認）。

## 余談：GOPATH が 2 つ以上指定されている場合
$GOPATH に指定した全ての箇所が有効なのは、 Go コンパイラが必要な外部のパッケージを探す場合のみ。逆に 1 つ目の GOPATH しか有効にならないのは、go get により外部のパッケージをダウンロード・インストールする場合らしい。
参考：https://qiita.com/chano2/items/ea76cc503e651f07bfb0


## 余談：mockgen で生成されたファイル一覧を表示
ついでに mockgen で生成したファイルの一覧を取得した。
日付表示でラフにスクリーニングし（```$7>15```）、ファイル名に mock を含むことを要求（```$9 ~ /.*mock.*/```）した。誰かもっとスマートな方法を教えてください。

```
$ ls -ulR $(find . -type f) | awk '{if($7>15 && $9 ~ /.*mock.*/){print $6" "$7" "$8" "$9}}’
```

# 余談の余談：GOPATH, GOROOT の表示

```
$ echo ${GOPATH}
$ echo ${GOROOT}
```
ではなく、

```
go env GOPATH
go env GOROOT
```
を用いた方がいい。デフォルト（環境変数として設定していない）の場合は echo では表示されないからだ。
参考：https://qiita.com/YumaInaura/items/3372186e2c11a45c65d8
Python#Snap7 Libray Import 問題

毎回も忘れ、毎回も時間かけて探し解決方法見つかる。
とりあえずメモしておく。

#Linux

https://stackoverflow.com/questions/24343557/cant-find-snap7-library-linux

- まずSNAP7ライブラリをダウンロードする(この例は1.2.1）
    - wget http://sourceforge.net/projects/snap7/files/1.2.1/snap7-full-1.2.1.tar.gz/download
- 解凍する
    - tar -zxvf snap7-full-1.2.1.tar.gz
- コンパイルする(arm_v6_linux.mk is used for RPI 1. For RPI 2 use arm_v7_linux.mk)
    - cd snap7-full-1.2.1/build/unix && sudo make -f arm_v6_linux.mk all
- コンパイル後のライブラリをlib へ
    - sudo cp ../bin/arm_v6-linux/libsnap7.so /usr/lib/libsnap7.so
    - sudo cp ../bin/arm_v6-linux/libsnap7.so /usr/local/lib/libsnap7.so
- 一応pipをInstall
    - sudo apt-get install python-pip
- python-snap7インストール
    - sudo pip install python-snap7

それでもなぜかImportできなかった。そしてもう一度エラーをみたら。
多分common.pyの中になにかあるかも！

```
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/usr/local/lib/python2.7/dist-packages/snap7/client.py", line 29, in __init__
   self.library = load_library()
   File "/usr/local/lib/python2.7/dist-packages/snap7/common.py", line 48, in  load_library
    return Snap7Library(lib_location).cdll
   File "/usr/local/lib/python2.7/dist-packages/snap7/common.py", line 40, in __init__
    raise Snap7Exception(msg)
snap7.exceptions.Snap7Exception: can't find snap7 library. If installed, try running ldconfig
```

こうしたら無事に行けました！

```Python

class Snap7Library(object):
    """
    Snap7 loader and encapsulator. We make this a singleton to make
    sure the library is loaded only once.
    """
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
            cls._instance.lib_location = None
            cls._instance.cdll = None
        return cls._instance

    def __init__(self, lib_location=None):
        if self.cdll:
            return
        #Change here
        #self.lib_location = lib_location or self.lib_location or find_library('snap7')
        self.lib_location = 'your lib location'
        if not self.lib_location:
            msg = "can't find snap7 library. If installed, try running ldconfig"
            raise Snap7Exception(msg)
        self.cdll = cdll.LoadLibrary(self.lib_location)
```

#Window

これです。
 >The folder where the snap7.dll and .lib file are located must be present in the Enviroment variables of Windows.

https://stackoverflow.com/questions/33697263/python-snap7-windows-cant-find-snap7-library
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/ad49dae2-96d8-c524-cb0f-49689847ac98.png)
PHPでURLからプロトコル + ドメイン取得


# プログラム
```php
$urls = [
  'a' => 'http://localhost:81/test.php?test_param=johi',
  'b' => 'http://localhost:81',
  'c' => 'http://localhost',
  'd' => 'http://localhost:8080',
  'e' => 'http://www.xn--e--testjoidiu.jp/',
  'f' => 'http://egegbfwork.blagebog10f2.fc2.com/',
  'g' => 'http://blogs.yahoo.co.jp/medidgecalg919e',
  'h' => 'http://227ebdw.net/kango/1/index.html',
  'i' => 'http://gebfa.test-search.net',
];
foreach ($urls as $url) {
  $result = preg_match('/(https?:\/\/(www\.)?[0-9a-z\-\.]+:?[0-9]{0,5})/', $url, $matches);
  echo $matches[0];
}

// 結果(普通見ないようなドメインもありますが、、、)
a: http://localhost:81
b: http://localhost:81
c: http://localhost
d: http://localhost:8080
e: http://www.xn--e--testjoidiu.jp
f: http://egegbfwork.blagebog10f2.fc2.com
g: http://blogs.yahoo.co.jp
h: http://227ebdw.net
i: http://gebfa.test-search.net
```
よく使うバージョン確認コマンド集

スキルシート等を書くときにバージョン確認コマンドを調べるのが、
結構手間だったので集めてみました。

Linux環境を想定していますが、
OS別などその限りではないのもあります。

#言語別

##Java
```
$ java -version
```

##Python
```
$ Python -V
```

##Flask
```
$ flask --version
```

##PHP
```
$ php -v
```

##Ruby
```
$ ruby -v
```

##Ruby on Rails
```
$ rails -v
```

##Perl
```
$ perl -v
```

#ミドルウェア別

##Apache
```
$ https -V
```

##Nginx
```
$ nginx -V
```

#OS別

##Windows
```
C:\>ver
```

##Mac OS X
```
$ sw_vers
```

##Amazon Linux
```
cat /etc/system-release
```

##CentOS
```
$ cat /etc/redhat-release
```

##Ubuntu
```
$ cat /etc/lsb-release
```

#SQL別

##MySQL 
```
$ mysql -V
```

##PostgreSQL
```
$ psql —version
```

##Oracle Database
```
SQL> select * from v$version;
```

##MongoDB
```
$ mongo -version
```

##SQLite
```
$ sqlite3 --version
```

##ソフトウェア別

##Git 
```
$ git --version
```

##Heroku
```
$ heroku --version
```

##Vagrant
```
$ vagrant version
```

##Docker
```
$ docker version
```

このコマンド追加して欲しいなどありましたら、
お気軽にコメント頂ければと思います。
WordPressのローカル環境の構築にどうぞ！怖くないdocker-compose

# Wordpressの爆速な環境構築

wordpressのローカル環境構築で手間取っているあなたへ
dockerを使っていますが、怖くないと思います。

## dockerとdocker-composeコマンドのインストール先

dockerのインストール方法

```
https://www.docker.com/products/docker-desktop
```

```
http://docs.docker.jp/compose/install.html
```

## リポジトリをクローンする

リポジトリを配置するディレクトリで行う
私の参考のリポジトリです。

```
git clone https://github.com/noracorn/bakusoku_wordpress
```

## WordPressを立ち上げる（docker-composeで立ち上げる）

```
cd bakusoku_wordpress
docker-compose up -d
```

## 立ち上がったことを確認する

ブラウザを立ち上げて、以下のURLにアクセスしてインストールする。

```
http://localhost:8080
```

<img width="807" alt=" 2020-01-16 23.24.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52386/f6b4ca7b-598e-806f-27c2-c4dbfb06650b.png">

インストール後に、ログインしもういちど、以下のURLにアクセスする

```
http://localhost:8080
```

<img width="1256" alt=" 2020-01-16 23.25.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52386/bf90a3f4-cdd1-b20f-8703-e7991a86cb12.png">

## WordPressを終了する（docker-composeを終了する）

```
docker-compose down
```

## さいごに

慣れたら、docker-compose.ymlと、config、wordpressフォルダを自分のPCのディレクトリにコピーして、自分用のGitなど登録してみましょう
【メモ】vCenter6.7をインストールする

vCenter Server Appliance 6.7 をインストールする画面流れ

#手順

ISOファイルをマウントするか、光学メディアに焼いて開く。

インストーラまでのパス
(光学ドライブ)¥vcsa-ui-installer¥win32¥installer.exe

インストーラを起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/98f7cbcc-be8e-718d-686a-7142e1bc4b3d.png)

#ステージ1

インストールをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/32711316-ed1b-70c8-9078-de42f2fbe77b.png)

次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/9e64965b-a0b1-5698-cdac-7dfda5800288.png)

同意にチェックを入れ、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/460e7150-c0cc-488f-5733-6a01b17db8ab.png)

組み込みPSCが選択された状態で、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/03361ea1-7ed2-5d24-064f-7b540dc6e5fe.png)

vcsaを収容するESXiホスト情報を入力し、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/02cc1710-9727-d6a7-d840-661ee8ff70ae.png)

はいをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/8e54c282-d80b-79bc-49b3-dea0db225582.png)

仮想マシンのrootアカウントを設定して、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/5ef9c46f-1610-bfde-7d88-1a04779746f5.png)

規模に応じた設定をして、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/5d728f7f-72dc-22e5-435a-7afe7187a799.png)

必要に応じてシンディスクモードの有効化をチェックし、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/112dede8-cfb0-29b5-5d09-98a1ed0fde3c.png)

ネットワーク設定を入力して、次へをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/b96b2826-771b-80e5-19dc-5fb3b19cb269.png)

内容を確認し、完了をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/386aa0e2-9b9d-960c-ab44-9d5564c8ab6b.png)


# ステージ２
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/fae81759-527c-6a5b-21ef-2df6991e5754.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/80c63be1-decb-eb47-dcbd-584627f53252.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/4948b0b3-0ad8-dc9d-9931-fd4d248afe5e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/ad2652c2-665f-d6b2-b1ab-7a0a9185240a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/cb53babc-14eb-1e78-48b3-885cf97ce56e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/89c5263f-cdf8-e1a4-170c-9fbbec12d746.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91280/4166b8ad-d2ca-7a7c-e549-f28a50981b18.png)

#テスト
vcenterのURLでアクセスする。
【改】Power Automateで効率よく電車の遅延情報を取得する

[前回の記事](https://qiita.com/h-nagao/items/4cdfaad8859c0113157f)では、Twitterで「新しくツイートがあったとき」のトリガーを利用して、電車の遅延情報を効率よく取得する方法を紹介しました。
早速今朝(1/16)遅延が発生して実動作の確認がとれたのですが・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/b9dd66e9-0d91-75c7-5332-86de77439bb6.png)
おわかりでしょうか。このラグ。
@hrfmjp おおたさんに教えていただいたのですが、Twitterトリガーはなんと1時間に1回のポーリングだそうです。(Docsは[こちら](https://docs.microsoft.com/en-us/connectors/twitter/))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/13996ac9-72f8-539c-8037-b26fd93b4801.png)

これは使えませんね。駅についたらもう駅がパンパンになっているなんてことになりかねません。実際私がそうでした。

## 定期実行で改良できる？
チェックしたいのは朝の通勤、駅に行く前くらいの時間に限られるので、そこに限定して、高頻度でポーリングできないかなと思っていたところ、 りなたむさん@rnakamuramartiny にスケジュールなら、特定の時間でだけFlowを定時実行できる旨教えてもらいました！ありがとう！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/70bce952-c9d8-37b7-9d33-472bf4f1247f.png)

今回は定期取得で**さらに効率よく**的確に遅延情報を取得する方法を紹介します。


# 定期取得で遅延情報をとるには？

考えかたは次のとおりです。

1. 朝の時間(7,8時ころ)に10分間隔でFlowを定期起動
2. 鉄道会社の運行情報ツイートの最新を1件取得
3. そのツイートが今日のものかを判定(昨晩の情報を回避するため)
4. 内容に「通常/平常」という文言がないか判定
5. モバイルのプッシュ通知
6. SharePointリストを参照して、今日1回目の通知かを確認
7. 1回目ならTeamsに遅刻連絡＆SharePointリストにアイテム登録 (これで2回目以降のポーリングは実質無視される)

これをAutomateで実現したものがこちらです。
基本的には数式も書かないのですが、ツイートの取得や、SharePointリストの取得が、どちらも配列で返ってくるので、少し補足します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/8323d8ee-8c47-e8b2-11ab-48006d35e37b.png)

###1. Convert time zone
ここではツイート取得した最初の1件のつぶやいた時間を日本時間に変換しています。
```body('Get_user_timeline')?[0]?['CreatedAtIso']```
Expressionにこれを入れてあげましょう。配列の0番目のCreatedAtIsoです。

###2. Convert time zone 2
これは比較用に「いま」の時刻を取得しています。
```utcNow()```
UTCで今の時刻をとって、日本時間に変換しています。

###3. Condition
鉄道会社のツイートの最新1件をとりますが、それが配列なので、0番目をとって、その内容を判定します。
```body('Get_user_timeline')?[0]?['TweetText']```
もう一つの条件は、```[Convert time zone] is equal [Convert time zone 2]```です。

###4. Send me a mobile notification
通知のテキストは何でもいいのですが、ツイートの本文を送るようにしています。
3.と同様に ```body('Get_user_timeline')?[0]?['TweetText']``` これをセットしています。

###5. Condition 2
その前段処理でSharePointからTitle = 今日の日付(yyyy/MM/dd)に一致するアイテムを取得していますが、この配列の長さが0 (つまりアイテムなし) かどうかを判定します。


``` length(body('Get_items')?['value']) ```


以上でちょっとした数式（アイテム取得）は終了です。

#結果
テストのために時間を変えていますが、見事定期的にツイートを取得できました！
このような感じで、少しだけ数式をかけば、自分の思ったような処理を実現できますので、ぜひ試してみてください！
※自動だから「あー、遅延で遅れるの報告しづらいなー」とかないですよね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/00994e49-f295-fe31-6ce6-2d99b19858e1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/4c0fc5ad-2723-9482-2e40-741b70d5ede5.png)
AIとは

根本に立ち返って
AIとはなんなのか書きます。

# AI・人工知能の定義
AIとはArtificial Intelligenceの略です。
専門家の間でもまだ定義は定まっていないです。

# 人工知能の種類

## 特化型人工知能
特化型人工知能とは、一つのことに特化した人工知能を指します。

例えば画像認識や音声認識 といった技術や自動運転技術も特化型人工知能と言えます。
人工知能関連の研究のほとんどがこの特化型人工知能の研究になっています。

## 汎用人工知能

汎用人工知能は、簡単に言うと、「なんでもできる人工知能」です。

特化型人工知能は一つのことしかできませんが、汎用人工知能は与えられた情報をもとに自ら考え
応用することができる人工知能のことを指します。人そのもののようなふるまいをする、といったイメージです。

# 人工知能のの強弱

## 強いAI
学者のジョン・サール氏によって作られた言葉であり、彼は強いAIについて「正しい入力と出力を備え、適切にプログラムを与えられたコンピュータは問題を本当の意味で理解することができる。それは人間と同じように意識・思考を持っている」としています。

## 弱いAI
意識・思考を持たないAIとしています。特化型人工知能と同じように
現在開発されている人工知能は意識を持っているものはなく、弱いAIに分類されます。

# シンギュラリティ
「技術的特異点」とも言います。

人間を超える知能をもつ人工知能が発明された時のことを指します。
電子ペーパーモジュールをToDoリストとして使う

#きっかけ
僕「電子ペーパーモジュール何かに使えないかな？」
僕「最近やること多くて忘れそうだからToDoリスト(メモ的な何か)として使おう」

※電子ペーパーのセットアップ(接続や画像の表示等)はこっちに書いてあります。
[Raspberry Piで電子ペーパーモジュールを動作させる
](https://qiita.com/_shin_/items/0e9e7804531368ff0e90)
今回は文字を電子ペーパーモジュールに表示させます

#用意したもの
・Raspberry Pi 3 model B+
・電子ペーパーモジュール (4.2inch e-Paper Module)
・スペーサー (お好みで)



#手順
こんなものをイメージ
・適当なテキストファイル(text.txt)にやること(文字)を箇条書きして保存
・Pythonでテキストファイルを読み出し、e-Paperに書き込み







pythonのソースコードを書く

```write.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
    sys.path.append(libdir)

import logging
from waveshare_epd import epd4in2bc
import time
from PIL import Image,ImageDraw,ImageFont
import traceback
import RPi.GPIO as GPIO
logging.basicConfig(level=logging.DEBUG)




try:
    #erase　e-paper
    logging.info("epd4in2bc Demo")
    epd = epd4in2bc.EPD()
    logging.info("init and Clear")
    epd.init()
    epd.Clear()
    time.sleep(1)
    
    #read text file
    f = open('text.txt', 'r')
    memo_text = []
    for line in f:
        memo_text.append(line)
    f.close()
    #print(memo_text)

    
    #make text figure
    im = Image.new("RGB",(400,300),"white")
    draw = ImageDraw.Draw(im)
    fig1 = Image.open('fig.png').convert("RGBA") #いらすとやの画像を読み込み
    draw.rectangle((0, 0, 399, 299), fill=(255, 255, 255), outline=(0, 0, 0), width=3) #外枠の四角形
    draw.rectangle((0, 0, 399, 50), fill=(0, 0, 0), outline=(0, 0, 0)) #To Doリストの部分の塗りつぶしの四角形
    im.paste(fig1, (200, 150),fig1.split()[3])    

    font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Light.ttc',30)
    text1 = "To Doリスト\n"
    draw.text((10, 10), text1 , fill=(255, 255, 255), font=font_path)
   
    
    font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Light.ttc',24)
    i = 0
    w = 0
    while i in range(len(memo_text)):
        draw.text((10, 50 + w), "・" + memo_text[i] , fill=(0, 0, 0), font=font_path)
        w = w + 35
        i = i + 1

    im.save("./../pic/hoge.bmp")


    # Drawing on the image
    logging.info("3.read bmp file")
    HBlackimage = Image.open(os.path.join(picdir, 'hoge.bmp'))
    HRYimage = Image.open(os.path.join(picdir, 'hoge.bmp'))
    epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRYimage))
    time.sleep(2)

    logging.info("Goto Sleep...")
    epd.sleep()
    

except IOError as e:
    logging.info(e)

except KeyboardInterrupt:
    logging.info("ctrl + c:")
    epd4in2bc.epdconfig.module_exit()
    exit()

```


テキストファイル内を以下のように編集し、`write.py`と同じディレクトリに配置

```text.txt
修論
予稿
不動産屋に連絡
明日飲み会
```

#やってみた

いらすとやのイラストを入れるとシュールな感じになった
<img width="600" alt="IMG_3433.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513034/b09d1bac-b82f-d05c-1c53-a0a15dd0a9c2.jpeg">

表示する項目を変えたい場合は、text.textを書き換えた後にもう一度Pythonのコードを走らせると変えた項目に更新される
Static website hosting な S3 バケットに SPA をアップロードしたが *.js の読み込みでエラーになった件

静的ホスティングを有効にした AWS S3 のバケット(その他諸々の権限も設定済)に、Angular で作成した SPA を aws cli でアップロードしたら、index.html の起動時に *.js が読み込めないというエラーが Chrome の Console に出力された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/3c761d6c-48e5-f3e2-5e14-e1b5b3e4bda9.png)

> Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". 
> Strict MIME type checking is enforced for module scripts per HTML spec.

「Angular の tsconfig.json の設定か？」などいろいろ調べた [^1] 結果、アップロードされた ``*.js`` ファイルの content-type が ``text/html`` になっていた事が原因だった。

[^1]: [この辺の情報](https://github.com/angular/angular/issues/30835) を辿ることに随分と時間を使ってしまった

なぜ発生したかというと、きっかけは aws cli の ``s3 sync`` コマンドを使っていた事。
このコマンドは既定ではファイルの種類に応じて自動的に content-type を設定してくれるという事(実際 ``*.ico`` ファイルには ``
image/x-icon`` が設定されていた)だが、どういうわけか ``*.js`` ファイルに期待する ``application/javascript`` は設定されず、``text/html`` が設定されていた。

ちなみに動作環境は Windows10 Pro x64。macOS や Linux ではまた異なる結果なのかも知れない。

環境によって content-type が変わるのがいやだったので、``*.js`` ファイルについては任意の content-type を指定することにした。

* [aws s3 sync on Windows wrongly sets Content-Type to text/plain for js files · Issue #3367 · aws/aws-cli](https://github.com/aws/aws-cli/issues/3367#issuecomment-531826747)

こちらの解決方法に習って、次のようなコマンドにした。

■Linux/macOS

```bash
aws s3 sync ＜アップロード元ディレクトリ 例: ./dist/ ＞ \
  s3://＜バケット名＞ \
  --acl public-read \
  --exclude "*.js" \
  --delete

aws s3 sync ＜アップロード元ディレクトリ 例: ./dist/ ＞ \
  s3://＜バケット名＞ \
  --acl public-read \
  --exclude "*" \
  --include "*.js" --content-type application/javascript
```

■Windows

```powershell
call aws s3 sync ＜アップロード元ディレクトリ 例: .\dist\ ＞ ^
  s3://＜バケット名＞ ^
  --acl public-read ^
  --exclude "*.js" ^
  --delete

call aws s3 sync ＜アップロード元ディレクトリ 例: .\dist\ ＞ ^
  s3://＜バケット名＞ ^
  --acl public-read ^
  --exclude "*" ^
  --include "*.js" --content-type application/javascript

```

1つ目の ``sync`` で ``*.js`` 以外をアップロード、2つ目で ``*.js`` のみをアップロードして content-type を明示的に ``application/javascript`` に設定する。
``--acl public-read`` は、バケット全体で公開にしてあれば不要と思われるのでお好みで。

s3 sync は、変更があったものだけがアップロードされるので、正しくない content-type でアップロードされたファイル群は手動で削除してから（あるいは ``s3 rm`` でバケット内を全削除してから）このスクリプトを実行した方が確実。
【unity】questで動くbloomを実装したい

<img width="853" alt="スクリーンショット 2020-01-16 22.46.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/40e512c7-7327-1dd2-4c0d-1fbd6e3b84c7.png">

---

## TL;DR
- 上の写真のような、ぼかしのかかった(?)物体を作りたいです
- ググると「postprocessing」という手法が出てくるのですが、クエストだと重くて使えません
- [FastMobileBloom](https://assetstore.unity.com/packages/vfx/shaders/fullscreen-camera-effects/fastmobilebloom-79310)という天才アセットを使ってみました

## はじめに
- 日本語の実装記事がなさそうだったので。
- また、unityの基本的な操作は触れませんが、やること自体簡単だと思います
- 2020/1/16の記事です。



##やったこと

[こちら](https://assetstore.unity.com/packages/vfx/shaders/fullscreen-camera-effects/fastmobilebloom-79310)からアセットをインポートします。
![3692a6b0-cd09-4e4e-b94b-20fe0e8db35f.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/e848221f-7142-0cf4-6714-63da30fe3d38.jpeg)
これですね。

FastMobileBloomの中身はこんな感じです。(2020年1月現在)

```
FastMobileBloom
┣ FastMobileBloom.cs
┣ FastMobileBloom.shader
┣ FastMobileBloom.mat
┣ readme
┗ testscene/
  ┣ Hotel/
  ┣ Hotel.unity
  ┣ Materials/
  ┗ Neon_light.fbx
```

Hotel.unityを開くとイメージがつかみやすいです。

...で、開けてみてびっくりです。
なんと、cameraオブジェクトの「add component」で「FastMobileBloom」を追加するだけでした
(postprocessingよりもかなり楽)
<img width="289" alt="スクリーンショット 2020-01-16 22.48.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/f315d267-ada7-2bf5-c13f-3967bb08a08b.png">
↑こんな感じで追加すればいいだけです。


before
<img width="300" alt="スクリーンショット 2020-01-16 22.47.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/5719019a-d7c7-8c62-835f-b4177a9d303e.png">



after
<img width="300" alt="スクリーンショット 2020-01-16 22.46.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/11014856-db12-5cf3-1485-030bf9d92aa7.png">

プロパティで変更できる
thresholdやintensityは、自分で値をいじってみるとわかりやすく変化するので、説明することがないです。

素晴らしいですね。~~(中身ない記事になりすぎて困惑している)~~
異なるAWSアカウント間でDNSを移行する手順

異なるAWSアカウント間でDNSを移行する必要があったため、手順を備忘録的に書いておきます。

1. 使用しているドメイン登録サービスにログインし、対象ドメインのネームサーバーを確認する
2. 1に移行元のRoute53のnsレコードが登録されていることを確認
3. 移行先のRoute53で新規にホストゾーンを作成
4. 作成したゾーンにレコードを移植
5. 1のネームサーバーを移行先のnsレコードに変更して切り換え

ネームサーバーは以下のコマンドでも確認できます。

```sh
$ dig <対象ドメイン名> ns
```

大丈夫だと思ってもちゃんと確認しよう。。
coder-serverをkubernetes上で動かすためのyaml

#yaml
```yaml:coder.yaml
---
apiVersion: v1
kind: Service
metadata:
 name: coder
spec:
 type: NodePort
 ports:
   - name: coder
     port: 8080
     nodePort: 32767
 selector:
   app: coder
---
apiVersion: v1
kind: Pod
metadata:
 name: coder
 labels:
   app: coder
spec:
 volumes:
 - name: settings
   hostPath:
     path: /mnt/coder/setting
 - name: project
   hostPath:
     path: /mnt/coder/project
 containers:
 - name: coder
   image: codercom/code-server:v2
   ports:
     - name: coder
       containerPort: 8080
   volumeMounts:
   - name: settings
     mountPath: /home/coder/.local/share/code-server
   - name: project
     mountPath: /home/coder/project
   resources:
     requests:
       memory: "1024Mi"
       cpu: "2000m"
     limits:
       memory: "1536Mi"
       cpu: "2000m"
```

#kubectl apply -f coder.yaml
```bash
# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
coder     1/1     Running   0          7s

# kubectl logs coder
info  Server listening on http://0.0.0.0:8080
info    - Password is 5890ac8b8abb2eb213121420
info      - To use your own password, set the PASSWORD environment variable
info      - To disable use `--auth none`
info    - Not serving HTTPS
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46533/045aa33a-a484-7374-04b8-748eeb223684.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46533/74bf188f-b9de-f853-502e-5fe57489f83c.png)
Githubでレポジトリの書き込み権限があるか調べる最も簡単な方法

## TL; DR
Github上で任意のテキストファイルを直接編集する。
書き込み権限がない場合は注意書きが表示される。

## 詳細
詳細といってもこれ以上書きようがないので、分かりやすいように画像を添付しておきます。
BitbucketやGitLabの場合は知りません。他にいい方法があればコメントで教えて下さい。

1. Github上で任意のテキストファイルを直接編集する。
<img width="1036" alt="Github.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215694/64338896-d1da-3ab2-328d-467165f56bd7.png">

2. 書き込み権限がない場合は注意書きが表示される。
以下のNoticeが表示されます。

>You’re editing a file in a project you don’t have write access to. We’ve created a fork of this project for you to commit your proposed changes to. Submitting a change to this file will write it to a new branch in your fork, so you can send a pull request.

<img width="1103" alt="Github2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215694/5e1d9a88-5125-d5dd-6809-69c2d08f05f9.png">





## 検索用
**1. 書き込み権限がないときのエラー**

```

ERROR: Permission to hogehoge.git denied to hayashi-ay.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

**2. 検索ワード対応**
Git Repository, Write Permission, ライト権限
【swift】ユーザーが任意のテーマカラーを設定できる機能

## 前置き
参考ページのまとめ集。

## 環境
xcode 11.3 
swift 5.1.3
CocoaPods 1.8.4

## 機能要件

テーマカラー選択機能
テーマカラー反映機能

## 仕様

- テーマカラー設定ボタンを押すと設定ページへ
- 設定ページには、色が並んでいる
- 色をクリックすると、設定ページの背景色が変わる
- 決定ボタンを押すと、選択された色がテーマカラーとなる
- もとの画面に戻ったのち、テーマカラーが反映されている

<img width="365" alt="スクリーンショット 2020-01-16 21.53.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270898/de39223e-fc91-82d8-ddc4-76acc0a37c78.png">
<img width="365" alt="スクリーンショット 2020-01-16 21.53.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270898/96bf32ea-8ee6-cafd-c520-9571515aa3ed.png">
<img width="365" alt="スクリーンショット 2020-01-16 21.53.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270898/2fc05178-5a89-47a8-536e-16587f8af77c.png">
<img width="365" alt="スクリーンショット 2020-01-16 21.53.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270898/f1ba9b04-d706-6194-ce2e-015fba96e353.png">



## 設計
### storyboard上に要素の追加

- コントローラー
- カラーパレット
- 決定ボタン

### カラーパレットの設置

以下の記事に従ってcollectionViewを作成
>[qiita : 【Swift・iOS】XcodeのCollectionViewの使い方。タイル型(カード型)のレイアウト方法を解説](https://rara-world.com/swift-collection-view-programming/)

以下の記事を参考に、タップアクションを追加
>[qiita : UICollectionViewのセルの強調・選択時にセルの見た目を変化させる](https://qiita.com/takehilo/items/06a9ec7ec634d86bd734)

以下の記事に従って形を整形
>[qiita : CollectionViewの基礎](https://qiita.com/azuma317/items/bf1a687f912159297cb1)
>[qiita : Swift UIViewの一部を角丸にしたい](https://qiita.com/t_kanade/items/a7e2228e592ee332323b)

### 選択カラーの保存
#### userDefaultsの設定
テーマカラー格納用にクラスを作っておく
>[【swift】userDefaultsへの書き込み・読み込みを簡易化する](https://qiita.com/ninoko1995/items/89c6f2b8db88f5cf9dc4)

#### UIColorの変換
userDefaultsにカラーを保存できるように、UIColorをData型に変換する

>[Swift 3でUserDefaultsにUIColorを保存する方法](https://www.webprofessional.jp/store-uicolor-with-userdefaults-in-swift-3/)
【RSpec】同じパターンのテストシナリオをJSONで定義して外出しする

# 解決できるケース

以下のようなケースに適用できると思います。
あくまで飛び道具的な手法なので、常用は良いと思いません。

* 同じ機能を複数のパラメータパターンで実行して結果を評価する場合、実装を軽量化できる。
* JSONファイルにパラメータ部分のみを外出しするため、RSpecを書けない人でもテストケースのメンテナンスが可能

# 経緯

ある案件で給与計算モジュールを実装した際に、深夜・残業・休日の手当や、勤務時間に関するモジュールなどを実装し、それぞれテストケースを作りました。
ただ、それだと心もとないため、給与計算モジュール群の統合テストケースを実装することとなりました。

例えば、
「時給¥1000で10:00~15:00勤務」「時給¥1001円で18:00~24:00勤務」・・・など
一定のパラメータに複数パターンを入力して結果を評価するテストケースが必要になりました。
そこで、ケースはJSONファイルに書き出しておき、テストの実装はループでやってみようということで、以下のようなRSpecを作成しました。

# 実装

contextをtest_caseの数分ループすることで、同じようなテストケースをずらずら書き並べる必要がなくなっています。
※内容は例なので簡略化しています。

## Rspec
```
  # 給与計算パターンの検証
  describe 'calculate salary' do

    # テストケースJSONファイルをロード
    test_cases = JSON.parse(IO.read(Rails.root.join("spec/json/salary_calculator_test_case.json")), symbolize_names: true)

    # テストケースの数分、テストを実行する
    test_cases.each do |test_case|

      # [:execution]がfalseのテストケースは無視する
      next unless test_case[:execution]

      # [:pattern]に設定してあるケース名を引用
      context "case [#{test_case[:pattern]}]" do

        # 勤務時間
        let(:worktimes) { test_case.key?(:worktimes) ? test_case[:worktimes] : [] }
        # 休憩時間
        let(:resttimes) { test_case.key?(:resttimes) ? test_case[:resttimes] : [] }
        # 給与
        let(:hourly_wage) { test_case.key?(:hourly_wage) ? test_case[:hourly_wage] : 1000 }

        # 計算処理の実行結果を評価対象とする
        subject { execute(worktimes, resttimes, amount)}

        # テスト結果の評価
        it 'calculate correctly ' do
            expect(subject).to eq test_case[:expect]
        end
      end
    end
  end
```

## テストケースJSON

```
[
    {
        "pattern": "work 10:00-15:00/rest 12:00-13:00/hourly_wage ¥1000",
        "worktimes": [
            { "start": "2020-01-06 10:00:00", "end": "2020-01-06 15:00:00" }
        ],
        "resttimes": [
            { "start": "2020-01-06 12:00:00", "end": "2020-01-06 13:00:00" }
        ],
        "hourly_wage": 1000,
        "expect": 4000,
        "execution": true,
        "comment": "通常"
    },
    {
        "pattern": "work 18:00-24:00/rest 20:00-21:00/hourly_wage ¥1001",
        "worktimes": [
            { "start": "2020-01-06 18:00:00", "end": "2020-01-07 00:00:00" }
        ],
        "resttimes": [
            { "start": "2020-01-06 20:00:00", "end": "2020-01-06 21:00:00" }
        ],
        "hourly_wage": 1001,
        "expect": 5501
        "execution": true,
        "comment": "深夜手当あり"
    },
    {
        ...
    }
    ...
]
```

JSONのテストケース中には、以下の項目を含んでおくと便利でした。

* "execution": テストケースを実行するかどうか。１ケースだけテストしたい時に他を全てfalseにして無駄な時間を食わずに済む。
* "comment": テストでは使用しないが、メンテナンス時にわかりやすくなる。テストケースを定義した資料に記載されているケース名を転記して、わかりやすくしたり。

# あとがき

ご参考になれば幸いです。
2本目：ホスト側のWebブラウザから仮想マシンに立てたdocker上のwebサーバーにアクセスする

#やりたいこと
　掲題の通り。

#環境
- ホストOS：Windows 10
- 仮想マシン：Virtual Box　
    - ゲストOS：Ubuntu(16.04.6)
    - docker

#前提条件
- ホスト側からゲスト側へアクセスするための設定ができている
  Key Word：**NAT + ホストオンリーアダプター**

- ゲストOSにdockerを動かすための環境が整っている

#やったこと
- Virtual Box：ネットワーク設定からアダプター１(NAT)のポートフォワーディングを以下のように設定

| 名前(任意) | プロトコル |ホストポート | ゲストポート |
|:----------|--------:|:-----------:|:-------------:|
| HTTP ※1   |  TCP  | 50080        |80   |
| HTTP ※2   |  TCP  | 58080       | 8080  |
| SSH       |  TCP  | 50022       | 22  |
※1 ゲストOS上にサーバー(Tomcat, apache2等)を立てた状態でホスト側から"http://ゲストOSのIPアド:50080"
   にアクセスがあると、立てたサーバーのWelcome Pageに遷移する
※2 docker上に立てたWebサーバーにアクセスするためのポートを指定(ポート番号は任意でOK)

- Webサーバーのイメージを作成する
    - 今回の目的はただホスト側のWebブラウザからdocker上のwebサーバー(on 仮想マシン)
　　　 にアクセスするだけなので、Webブラウザ上で"Hello world"を出力する単純なWebアプリの
　    イメージを作成する。（ここは今回の主眼ではないので手順の概要のみ残す）

　　　　※Dockerfileは任意のディレクトリ内に作成
　　　　※Dockerfileを作成したのと同じディレクトリ内にindex.html("Hello world"と記載)も用意しておく
　　　　※Dockerfileの記載内容は下記の記事を参考にした
　　　　https://qiita.com/nl0_blu/items/1de829288db2670276e8


>手順１：ゲストOS上に任意のディレクトリを作成
>手順２： 作成したディレクトリ上にDockerfileを作成する

```
#Dockerfileの中身
FROM centos
CMD echo "now running..."
RUN yum install -y httpd
ADD ./index.html /var/www/html/
#ポート80を開ける
EXPOSE 80
#起動した時にapache起動するコマンド
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
```

-  作成したDockerfileを元にコンテナを起動する
    - 以下のコマンドを実行しコンテナを起動する

```
$ docker run -d --name コンテナ名(任意) -p 8080:80 イメージ名(or ID)
```  

※ "-p 8080:80"とすることで、ゲストOS側の8080ポートとコンテナ側の80ポートが紐づく。
※ ゲストOS側の8080ポートはホスト側の58080ポートと紐づいているので、
　ホスト側からゲストOS側の58080ポートに受けるアクセスは、ゲストOSの8080ポートを経由して
　コンテナ側の80へのアクセスとなり、コンテナ上のWebサーバーへのアクセスが可能となる。


- 実際にアクセスしてみる

    ⚪︎ ホスト側からゲスト側へ50080ポート経由でアクセスした場合 
　　→ゲストOS上で起動しているapache2のデフォルトページが表示される。

![50080.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276607/3ffa628e-8865-ae4c-6ba2-8a9e95a54345.png)


   ⚪︎ ホスト側からゲスト側へ58080ポート経由でアクセスした場合 
　→"Hello world"が表示される。

![58080.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276607/3a1bf1a2-1673-76b0-5ef0-65c657f3c257.png)