OmniAICreator/Qiita-1.07M huggingface dataset:
カフェの混雑度アプリを作ろうと思ったが諦めた話

個人でカフェの混雑度アプリを作ろうと思ったが諦めた話


SIerでSEをしている者です。
今回は初心者なりにiOS(言語はSwift)でカフェまで行かなくてもそのカフェの混雑具合が分かるアプリを作ろうとしたのですが自分の実力では無理だと察し諦めた話です。
間違っている点多々あると思います。ご指摘いただければ幸いです。

##カフェの混雑度アプリを作ろうとした背景
私はよく様々なカフェに行くことが好きでよくカフェで作業をする事もあるのですが、カフェは大体混んでおり、席が取れないといった経験を何度も繰り返してきました。
カフェまで行かないとその時その時間の混雑度が分からないのは不便だと感じておりカフェの混雑度が分かるアプリが欲しいと思い制作に取り掛かろうとしました。

##やってみた事
以下の手順で実装に向けての調査をしました。

①カフェの混雑度やそのカフェの場所が分かるAPIがないか
②BELで混雑度を取得できないか

###①カフェの混雑度やそのカフェの場所が分かるAPIがないか
結論から言うとカフェの混雑度が分かるAPIはありませんでした。
カフェの場所だけの場合はGoogleのAPIが該当すると思います。

###② BELで混雑度を取得できないか
BEL(Bluetooth Low Energy)とは、Bluetoothの規格の一部のことです。
低電力消費・低コスト化に特化した規格です。
この案についてはこちらの記事(https://qiita.com/Rabbit_Program/items/3c1aec6e30eb646d78a1 )を読んだ際に思いつきました。三蜜を計測することができるのであればどれだけ混雑しているのかの取得は可能だと思い、BELを用いて実装する方針にしましたが、ここで2つの問題に直面しました。

　ⅰ「カフェ内であるかどうかの判定」ができない
　ⅱBEL検索ではBluetoothがオンになっているデバイスを検出する事はできない
　ⅲバックグラウンドでBEL検索ができない

####ⅰ「カフェ内であるかどうかの判定」ができない
ユーザの現在地がカフェ内であるかどうかの定義ができませんでした。
ユーザの現在地付近にあるカフェの位置を常に取得し続ける事はGoogle APIにユーザが移動する度にカフェ位置を取得させることになるだろうと思いました。こちらに関してはカフェを「スターバックス」に限定するなどして予めカフェ位置を登録しておく方針に変える事で実装の難易度を下げられると思いました。

####ⅱBEL検索ではBluetoothがオンになっているデバイスを検出する事はできない
BLEには「セントラル」と「ペリフェラル」があります。
こちらについての説明は割愛しますが、一例をあげますと、Bluetoothイヤホンがペリフェラル、接続するスマートフォンがセントラルとなります。
BLE検索はセントラルがペリフェラルを検出することを指します。
(ペリフェラルからセントラルを検出する事はできません。)

今回、Bluetoothがオンになっているデバイスがペリフェラルであれば、BLE検索で検出可能だと思ったのですが、Bluetoothがオンになっているデバイスはセントラルでした。
その為、BLE検索で周囲のデバイス数をカウントする事はできないという結論に達しました。

####ⅱiバックグラウンドでBELが動作しない
こちらはiOS独自の話となります。iOSはバックグラウンドで周囲にあるBELを検索することができません。フランス政府がApple側にバックグランドでのBEL検索をできるようにして欲しいとの要請をしているようですが進展なしとの事です。
バックエンドでBEL検索ができなければ周囲にどれだけ多くの人がいるかどうかの取得ができません。

##結論、諦めました
上記ii,iiiを突破できる方法を探す事ができず今回は諦める事にしました。
iiiの理由に関してはiOS独自なのでandroidであれば問題ない点のようです。
再チャレンジする際はandroidで挑もうと思います。
備忘録：Railsによるコメント機能実装

#はじめに
Rubu on Railsでオリジナルアプリを作成しています。そのアプリにコメント機能を実装しました。そのため忘れないように書き記します。

#手順
・commentモデル、テーブルの作成
・commentsコントローラーとルーティングの設定
・各コントローラーのアクション設定

#commentモデル、テーブルの作成
はじめに下記のようにターミナルでcommentモデルを作成します。

```bash
rails g model comment
```

その後マイグレーションファイルに、textカラムを追加します(このtextカラムにはコメントが保存されます)。

```ruby:2020*********_create_comments.rb
class CreateComments < ActiveRecord::Migration[6.0]
  def change
    create_table :comments do |t|
      t.text :text, null: false
      t.references :user, foreign_key: true
      t.references :desk, foreign_key: true
      t.timestamps
    end
  end
end
```
userとdeskを外部キー設定します。このコメントは誰が、どのdesk(画像)にしたものか管理するためです。同様にcommentモデルにもバリデーションの他、アソシエーションを設定する必要があります。

```ruby:desk.rb
  validates :text, presence: true
  belongs_to :user
  belongs_to :desk
```
userモデル、deskモデルにもアソシエーションを追加します。なお、今回のバリデーションはコメントが空だと保存できないような設定です。

#commentsコントローラーとルーティングの設定
ターミナルでコメントのコントローラーを作成します。この時、コントローラー名は複数形にする(いつもどっちだっけ？って悩んでます😅)。

```bash
rails g controller comments
```
お次は作成したcommentsコントローラーにcreateアクションを設定します。このとき、中身は空で一旦OKです。

```ruby:comments_controller.rb
def create
end
```

最後にルーティングを。コメントはdesk(画像)と紐付けします。なのでネスト(入れ子構造)にします。

```ruby:route.rb
resources :desks do
    resources :comments, only: :create
end 
```
くどくなりますが、どの画像に対するコメントなのかをパスから判断できるようにすることが重要です。

#各コントローラーのアクション設定
今回はdesks(画像)コントローラーのshowアクションに対するレスポンスページでコメント保存、表示します(元々このページは、投稿された画像の詳細ページです)。なので、まずはdeskコントローラーのshowアクションに@commentのインスタンス変数を定義します。

```ruby:desks.controller.rb
def show
    @desk = Desk.find(params[:id])
    @comment = Comment.new
    @comments = @desk.comments
end
```
なお画像に付けられたコメントを一覧で表示するため。@commentsでコメントを取得しています。


今度はcommentsコントローラーへの設定です。こちらではストロングパラメータを設定します。requireにモデル名、permitに保存カラムを設定します。アソシエーション関係にあるものはmergeに記述します。なおdevise Gemがインストールされているので、current_userメソッドを使用しています。これによりコメントが誰が(user_id)、何に(desk_id)にされたものか管理できます。

```ruby:comments.controller.rb
def create
    @comment = Comment.new(comment_params)
    if @comment.save
      redirect_to desk_path(@comment.desk)
    else
      @desk = @comment.desk
      @comments = @desk.comments
      render "desks/show"
    end
end
  private

  def comment_params
    params.require(:comment).permit(:text).merge(user_id: current_user.id, desk_id: params[:desk_id])
  end
```

以上
MacVimでウェイトの軽いフォントを使えるようになってチョーしあわせなんですけど。

# 背景

MacVimのフォントを、ウェイトを軽めにしたかったのだけど、指定する「名前」がわからなくて困っていた。

Edit > Font > Show Fonts　で選んでも、うまく指定できないし、.gvimrcに書いても「ダメ」って言われるし。


# できたこと

- 日本語は、ヒラギノ角ゴシック W1
- ラテン文字は、Iconsolataのライト

できあがりはこんなかんじ。チョーしあわせ。

![スクリーンショット 2020-11-08 16.33.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/f0e76a95-0fb8-768d-7bc9-e4844b92fe11.png)

ちなみにbeforeはこんなかんじ。スクショではあんまりわからんか……。画面で見ているとずいぶんちがう。

![スクリーンショット 2020-11-08 16.47.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/24399a6a-47dd-d4e0-0488-f7eb74816356.png)


拡大してみる。
before:
![A-z.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/249d62c3-8626-4aae-33c5-819efbe95e68.png)

after:
![B-z.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/d78d6835-2371-8fd7-c399-f6e0d3b7a2a1.png)

圧迫感が弱まったのがうれしい。

gvimrcはこんなかんじ。

```vim:gvimrc
set guifont=Inconsolata\ Regular\ Light:h18
set guifontwide=ヒラギノ角ゴシック\ W1:h16
```

# わかったこと

- フォント名の空白は、`\`でエスケープする
- フォント名は、Font Book.appで調べる

![fb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/96237563-13e5-5283-1e08-744ec0706e9b.png)

　↓

![fbのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/51ec6410-6b2f-91db-a69d-76da00c31104.png)


いや、これで、フォント選びが楽しくなるわー。


# 環境など

MacVim Custom Version 8.2.1719 (166)　brew caskでインストール
macOS Catalina バージョン 10.15.7（19H2）
MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)

カラースキームはNord

フォント選びは、結城浩先生の「ヒラギノ明朝＋Inconsorata」のマネ。
プロジェクトのディレクトリ構成を表示する

```
tree -L 2 -d -a -I 'node_modules|dist'
```


| option name | 意味 |
|-------------|------|
| -L N | 何回層まで再帰的に掘るか |
| -d | ファイルを除外する |
| -a | .ファイルを含める |
| -I 'directoryName1&#124;directoryName2' | 表示対象から除外する |


## docs

[Linux tree command](https://www.computerhope.com/unix/tree.htm)
C言語でカレンダー

#はじめに
久しぶりの投稿です。前作を見てくださったみなさん、ありがとうございます。今後ともよろしくお願いします。
今回はC言語を用いたカレンダー作りです。WSLのUbuntuでcalコマンドの存在を知り、Windowsでも使いたいと思い、この記事を書くに至りました。なんちゃってcalコマンドですが...

#条件
今回の条件は以下のとおりです。

- コマンドライン引数で年月を取得
- 日曜始まり

#ソースコード

```C:cal.c
#include <stdio.h>
#include <stdlib.h>

int check_leap(int year){
	if (year % 4 != 0) return 0;
	else if (year % 100 != 0) return 1;
	else if (year % 400 != 0) return 0;
	else return 1;
}

void return_error(int status, int num){
	switch (status){
		case 0: fprintf(stderr, "Usage: cal [month] [year]"); break;
		case 1: fprintf(stderr, "cal: year \'%d\' is not in range 1..9999", num); break;
		case 2: fprintf(stderr, "cal: month \'%d\' is not in range 1..12", num); break;
		default: fprintf(stderr, "cal: unknown error");
	}
	exit(1);
}

int print_cal(int month, int year){
	int gap = 0, i, cnt;
	const int days[12] = {31, 28+check_leap(year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	const char name[37] = "JanFebMarAprMayJunJulAugSepOctNovDec";
	for (i = 1; i < year; i++) gap += 1+check_leap(i);
	for (i = 0; i < month-1; i++) gap += days[i]-28;
	printf("      ");
	for (i = 0; i < 3; i++) printf("%c", name[3*(month-1)+i]);
	printf(" %-4d\n", year);
	printf("Su Mo Tu We Th Fr Sa\n");
	for (cnt = 0; cnt < (gap+1)%7; cnt++) printf("   ");
	for (i = 1; i <= days[month-1]; i++, cnt++){
		if (cnt % 7 == 0 && cnt != 0) printf("\n");
		printf("%2d ", i);
	}
	printf("\n");
	return 0;
}

int main(int argc, char *argv[]){
	int month, year;
	if (argc < 3) return_error(0, 0);
	month = atoi(argv[1]);
	year = atoi(argv[2]);
	if (year < 1 || year > 9999) return_error(1, year);
	if (month < 1 || month > 12) return_error(2, month);
	print_cal(month, year);
	return 0;
}
```

#解説

##check_leap関数
引数の年がうるう年(leap year)かを調べる関数です。
西暦n年がうるう年であるための条件は、
(n % 4 == 0 NOT n % 100 == 0) OR n % 400 == 0
です。返り値はこの後使います。

##return_error関数
トラブルがあった際に呼び出す関数です。それだけです。
メッセージは標準エラー出力に出されます。

##print_cal関数
このプログラムのコアです。

###使用変数
- days：毎月の日数を管理します。check_leap関数の戻り値はdays[1]（2月）に加算されます。
- gap： 365 = 7 * 52 + 1 より、1年で元日は1日ずれます（うるう年は2日）。西暦1年から西暦n-1年までのズレを足し合わせることで、西暦n年の元日が西暦1年のそれから何曜日分ずれているのかを計算できます。また、西暦n年m月1日と元日のズレも計算します(なお西暦1年の元日は月曜日)。
- name：各月名の3文字をまとめています。name[36]には自動でヌル文字が入り、これで確認できます。`if (name[36] == '\0') printf("NULL!\n");`
- cnt：出力の際、7日ごとに改行するためのカウンター変数です。

###具体例
2020年11月の場合

1. 1年1月1日から2020年1月1日までのgap：2508日
1. 2020年1月1日から2020年11月1日までのgap：25日
1. (2508 + 25) % 7 = 6 より、2020年11月1日は1年の元日から6日のずれ、ゆえに日曜日

## main関数
コマンドライン引数の管理を行います。
argcは引数の数、argvは各引数の先頭文字のポインタを示します。なお、argcはプログラム名も含みます。例えば "cal 11 2020" と入力した場合、argc = 3 です。
stdlib.h 内のatoi関数で、argv[1]（月）とargv[2]（年）の文字列を整数型に変換し、条件を満たしていれば、print_cal関数を呼び出します。

##出力の順番

1. name\[3*(month-1)+i\] (0 <= i <= 2) で取得できる月名3文字
2. printf(" %-4d\n", year) で西暦年の右詰め（4ケタ）
3. パディング用スペースを (gap+1) % 7 回（+1を+0に変更すれば月曜始まり）
4. 1, 2, 3, ..., days[month-1] で日付
5. cnt == 7 なら改行

これを繰り返します。

#使用例
```
> cal 11 2020
      Nov 2020
Su Mo Tu We Th Fr Sa
 1  2  3  4  5  6  7 
 8  9 10 11 12 13 14 
15 16 17 18 19 20 21 
22 23 24 25 26 27 28 
29 30 
```

#おわりに
このプログラムが、みなさんの役にたてば幸いです。ご一読ありがとうございました。
Railsでいいね機能のAjax処理を実装してみた

# はじめに
Railsでいいね機能を実装していたのですが、この機能を使うと下記のような問題が発生していました。

- ページ全体をレンダリングし直すため、無駄な処理を伴ってしまう。
- ページ遷移が伴ってしまうため、ページ下部でlikeやコメントをしてもページの一番上に遷移してしまい、ユーザービリティを下げている。

そのため、Ajax機能追加し、ページ遷移を伴わないようにしてユーザービリティをあげようと思いました。

最初考えた実装方法は、JavaScript・jQueryを使って、Ajax処理を発火していく方法がベストなのかなと思ったのですが、調べていくと、Railsには、```link_to```などのメソッドに```remote: true```を引数で付けるとAjax処理を使えるようになるとのことでした。最初考えてた実装方法と違って、簡潔だったので、さっそくその方法で実装してみました。



# 前提

- 投稿機能・いいね機能は既に実装済み。
- 実装しているいいね機能は、いいねボタンを押下すると、ページ遷移が伴うタイプのもの。
- 上記に対して、Ajax処理で、非同期通信で実装を行うものとします。この記事はその実装で行った手順の紹介です。


# 環境・バージョン

- Ruby 2.6.3
- Rails 6.0.2.1
- jQuery 3.5.1


# 実装


まず、```app/views/posts/show.html.erb```にいいねボタン```app/views/likes/_like.html.erb```を```render```させます。


```erb:app/views/posts/show.html.erb
# ・・・省略

<div class="post-like mr-auto">
  <%= render partial: 'likes/like', locals: { post: @post, like: @like } %>
</div>

# ・・・省略

```

いいね機能の```delete```と```post```の引数に```remote: true```を追加してAjax機能を追加します。

```erb:app/views/likes/_like.html.erb
<% if current_user.already_liked?(post) %>
  <%= link_to 'Like', post_like_path(post, like), method: :delete, class:'post-like__cancel', remote: true %>
<% else %>
  <%= link_to 'Like', post_likes_path(post), method: :post, class:'post-like__enable', remote: true %>
<% end %>

```

追加することで、それぞれのリンク押下後に下記の処理を実行することができようになります。

- ```delete```メソッド→```app/views/likes/destroy.js.erb ```のファイルを実行
- ```post```メソッド→```app/views/likes/create.js.erb```のファイルを実行


次に、```js.erb```ファイルは、下記のコードのように```@post```や```@like```などの```Controller```のメソッドで定義されたインスタンス変数を使うことができます。これは便利ですね。


```erb:app/views/likes/destroy.js.erb
$('.post-like').html('<%= j(render partial: 'likes/like', locals: { post: @post, like: @like }) %>');

```

```erb:app/views/likes/create.js.erb
$('.post-like').html('<%= j(render partial: 'likes/like', locals: { post: @post, like: @like }) %>');

```

# できたもの
できたものは下記です。
ページ遷移せずに動いていることを確認できました。

![like-ajax.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261027/b203afd1-b34d-3467-f9bf-ad6f138a9310.gif)

# 上記の実装で動作しない場合

動作しない原因は、ViewでjQueryが使えないということが考えられるので、下記の実装がされているか確認しましょう。

参考：[jQuery and $ not defined in like.js.erb returned from AJAX call](https://stackoverflow.com/questions/58743392/jquery-and-not-defined-in-like-js-erb-returned-from-ajax-call)

```js:app/javascript/packs/application.js
// Enable jQuery in the .js.erb file
global.$ = jQuery;
```

```js:config/webpack/environment.js

//jQuery & Bootstap's JavaScript
const webpack = require('webpack')
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery', //<= 記述されているか確認
    Popper: 'popper.js'
  })
)

```

# さいごに

他にも応用して、フォロー機能やコメントも実装できました。
今後は、検索機能も作っていくので、Ajaxも使っていこうと思います。

# 参考記事

[Railsで remote: true と js.erbを使って簡単にAjax(非同期通信)を実装しよう！(いいね機能のデモ付)](https://qiita.com/__tambo__/items/45211df065e0c037d032)

[jQuery and $ not defined in like.js.erb returned from AJAX call](https://stackoverflow.com/questions/58743392/jquery-and-not-defined-in-like-js-erb-returned-from-ajax-call)
Pandas.DataFrame 小技集 (行列操作編)

# 空のデータフレームを作成

```python:sample.py
    import pandas as pd

    # カラム名の設定
    cols = ['id', 'name']
    # 空のデータフレームを作成
    df = pd.DataFrame(index=[], columns=cols)
    # データ内容作成
    data = [1, 'test']
    # データフレームにデータを追加
    df.loc[len(df)] = data
    print(df)
    '''
      id  name
    0  1  test
    '''
```

# リストを使って複数行をデータフレームに追加

```python:sample.py
    # カラム名の設定
    cols = ['id', 'name']
    # 空のデータフレームを作成
    df = pd.DataFrame(index=[], columns=cols)
    # リストを作成
    id_list = [1, 2, 3, 4, 5]
    name_list = ['Taro', 'Hanako', 'Akira', 'Hitomi', 'Kenta']
    # 連結用のデータフレーム作成
    df_tmp = pd.DataFrame({'id': id_list ,'name': name_list})
    # データフレームを縦に連結
    df = df.concat([df, df_tmp])
    print(df)
    '''
      id    name
    0  1    Taro
    1  2  Hanako
    2  3   Akira
    3  4  Hitomi
    4  5   Kenta
    '''
```
いつもintな初心者のBigDecimal備忘録

## はじめに
Java学習歴3ヶ月の者です。
研修でSpringをやっているのですが、データ型がNumberのものは
整数にしかならないものもintではなくBigDecimalを使いました。
数値といえばintかdoubleしか使ってこず、BigDecimalの処理にとまどいました。
BigDecimalについてきちんとまとめられている記事は多くありますが、
実際使ったものだけ備忘録としてまとめてみます。

## 計算したい
四則演算は「+」、「-」、「*」、「/」ではありません。

| 演算 | メソッド |   例  |
|:----------:|:---------:|:------------:|
| 加算（A + B）| add      | A.add(B)     |
| 減算（A - B）| subtract | A.subtract(B)|
| 乗算（A * B）| multiply | A.multiply(B)|
| 徐算（A / B）| divide   | A.divide(B)  |

徐算は使ったことないですが、少数になる場合は引数が3つ必要です。
A.divide(B, 小数点以下の桁数, 丸め方法（切り上げ、切り捨て、四捨五入など）)
今回は使ってないので割愛します。

## 比較したい
「compareTo」を使います。

| 比較演算子 | 戻り値 | 例  |
|:----------:|:---------:|:---------:|
| A < B | AがBより小さい場合は-1を返す | A.compareTo(B) < 0 | 
| A > B | AがBより大きい場合は1を返す | A.compareTo(B) > 0  | 
| A == B | AとBが等しい場合は0を返す | A.compareTo(B) == 0 | 

研修で調べた時は「より小さい（<）」ではなく、「以下（<=）」にしたかったのでこんな感じで書きましたが

```
// 「より大きい」ではない（頭ぐちゃぐちゃになるわ）
if (!(A.compareTo(B) == 1)) {
}

// これでよかったみたい
if (A.compareTo(B) <= 0) {
}
```

## BigDecimal↔︎Stringの変換
String型で入力値を受けて、処理のためにBigDecimalに変換するということもしたので記載します。

### BigDecimal→String
```
String String型変数名 = BigDecimal型.toString();
```

### String→BigDecimal
```
BigDecimal BigDecimal型変数名 = new BigDecimal(String型);
```


## 参考
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/math/BigDecimal.html
https://www.sejuku.net/blog/25564
https://techacademy.jp/magazine/31915
Arduinoでラジコン受信機のパルスを計測するのに苦労した話

# 問題の概要
Arduinoで受信機の信号を受信して処理したい場合、pulseIn()関数を用いることが多いが、以下の理由で困ったことが起きる。
- 受信機メーカによっては同時にパルスが送られるため、同時に計測できない（例：タミヤ）。
- 各チャネルが五月雨式に送られるため、パルス計測開始の遅れで計測値がばらつく（[参考](https://plaza.rakuten.co.jp/cpu4edu/diary/201206060000/)）。
- 受信チャンネル数を増やすと、メイン処理を回す時間がなくなる。
本来ではマイコンに内蔵されたタイマのパルス幅計測機能を使いたいところだが、delayやtoneなんかの脳死で使えるタイマ機能と被りが気になるところ。そこで次に述べる解決手段を使用した。

# 解決方法
1. attachInterrupt()により、両エッジの外部端子入力割り込みを設定する
2. 割り込み関数の中で、立ち上がり、立ち下がりエッジを判定。micros()で取得した時間を保存する。
3. 立ち下がりエッジで立ち下がりエッジ～立ち下がりエッジの時間間隔を計測する。

# コード例

```C++
#define         bit_read(portdat, portconf)          ((portdat & portconf) ? 1 : 0)  
#define         bit_write(portdat, portconf, hilo)   (portdat = (hilo ? (portdat | portconf) : (portdat & ~portconf)))  

// STR_RCV = PA0
#define         PINDIR_STR      (VPORTA.DIR) 
#define         PINRAM_STR      (VPORTA.IN) 
#define         PIN_STRRSV      (0x01)
#define         INTR_STRRSV     (2)

// ESC_RCV = PF5
#define         PINDIR_ESC      (VPORTF.DIR) 
#define         PINRAM_ESC      (VPORTF.IN) 
#define         PIN_ESCRSV      (0x20)
#define         INTR_ESCRSV     (3)

volatile unsigned long     time;
volatile unsigned long     strFallingUs;
volatile unsigned long     strRisingUs;
volatile unsigned long     strPlsWdhUs;
volatile unsigned long     escFallingUs;
volatile unsigned long     escRisingUs;
volatile unsigned long     escPlsWdhUs;

// セットアップ
void setup()
{
    //  入出力設定
    bit_write(PINDIR_STR,   PIN_STRRSV, 0);
    bit_write(PINDIR_ESC,   PIN_ESCRSV, 0);

    // 外部割り込み設定。INTRNo（0～45）を直接指示してもうまく行かない。digitalPinToInterruptを使用するのが推奨されるらしい。
    attachInterrupt(digitalPinToInterrupt(INTR_STRRSV), fnc_intr_irqStr, CHANGE);
    attachInterrupt(digitalPinToInterrupt(INTR_ESCRSV), fnc_intr_irqEsc, CHANGE);

    // デバッグ用コンソール
    Serial.begin(115200);
    Serial.print("Start");
    Serial.println();
    Serial.print("time,Sterring, ESC");
}

// メインループ
void loop()
{
    Serial.print(time);
    Serial.print(",");
    Serial.print(strPlsWdhUs);
    Serial.print(",");
    Serial.print(escPlsWdhUs);
    Serial.println();
    time++;
    delay(100);
}

void fnc_intr_irqStr()
{
    noInterrupts();
    if (bit_read(PINRAM_STR,PIN_STRRSV) )
    {
        // RISING
        strRisingUs = micros();
    }
    else
    {
        // Falling
        strFallingUs = micros();
        strPlsWdhUs = strFallingUs - strRisingUs;
    }
    interrupts();
}

void fnc_intr_irqEsc()
{
    noInterrupts();
    if (bit_read(PINRAM_ESC,PIN_ESCRSV) )
    {
        // RISING
        escRisingUs = micros();
    }
    else
    {
        escFallingUs = micros();
        // オーバーフローしても正しく計算可能
        escPlsWdhUs = escFallingUs - escRisingUs;
    }
    interrupts();
}
```
# 結果
青がハンドル。オレンジがスロットル。少々ばらつきがあるのが気になるところだが、フィルタ処理を行えば良さそう。なお、受信機のスイッチを切るとパルスが来なくなるため、値が更新されなくなる。

![スクリーンショット 2020-11-08 16.29.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/c52e5796-503d-b954-bddf-d8cf8908d111.png)


# ポイント
- 時間のかかるdigitalRead()を使わず、レジスタを直接参照する。
- ビット操作を楽にするためのマクロを使う（作る）。
- micros()のオーバーフロー対策として、unsignedでそのまま引き算する。
評価の平均値を星で表示する

各店舗の評価の平均値を一覧表示ページで表示する方法を記述します！
イメージはこんな感じです。
![1b1a25ccb85f56b8e0a1b46837bd6cd6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700117/07240198-8a72-59fa-2ba7-23b8fc3fc21f.png)

こちらの実装は
``Farstep【プログラミング講座】``さんの[【Ruby on Rails】星レビュー機能を作ろう（PART1）How To Create a Star Rating with Ruby on Rails](https://www.youtube.com/watch?v=NOOYABsAip0)を参考にしています。

### 使用環境
ruby 2.6.5
Ruby on Rails 6.0.3.3
一部、余白の指定でBootstrap4を使用しています。


## 実装内容
###モデルの実装
```ruby:model

class Laundry < ApplicationRecord
  def avg_score
    unless self.comments.empty?
      comments.average(:rate_id).round(1)
    else
      0.0
    end
  end
  
 def avg_score_percentage
   unless self.comments.empty?
     comments.average(:rate_id).round(1).to_f*100/5
   else
     0.0
   end
 end
end
```

はじめにコメントが空かどうかで場合分けをして存在している場合は平均値の計算を行います。
averageメソッドを使用してカラム名の平均値を出します。
``round(1)``とすることで小数点第2位に対して四捨五入をします。

``avg_score_percentage``メソッドではパーセンテージの計算をしてビューに渡します。

###ビューの実装
コードは以下の通りです。

```ruby:html
<div class="average-score mb-3">
 <div class="star-rating ml-2">
   <div class="star-rating-front" style="width: <%= laundry.avg_score_percentage %>%">★★★★★</div>
   <div class="star-rating-back">★★★★★</div>
 </div>
 <div class="average-score-display">
   （<%= laundry.avg_score %>点）
 </div>
</div>
```

```css:css

.average-score {
  display: flex;　// ★と点数を横並びにする
  justify-content: center;
}

.star-rating {
  position: relative;
  width: 5em;
  height: 1em;
  font-size: 17px;

}
.star-rating-front {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden; // 指定幅からはみ出した部分を隠す。
  white-space: nowrap;　// widthが足りない時に、折り返さないようにする。
  color: #ffcc33;
  height: 25px;
}
.star-rating-back {
  color: #ccc;
}
```

２つの５つ星(★★★★★)を用意してその２つを重ね合わせることで実装を行います。
・``.star-rating-front``・・・黄色い星の部分、上に重ねて``"width: <%= laundry.avg_score_percentage %>%``とすることで幅を指定する。
・``.star-rating-back``・・・灰色の星の部分、下におくことで黄色くならなかった部分を埋める。

ポイントとして以下の２点だと思います。
1.``overflow: hidden;``を指定。
``overflow: hidden;``を指定することで指定幅からはみ出した部分を隠して後ろの灰色の星を表示させます。
ここを指定しないと、せっかく幅を指定しても幅からはみ出した部分が隠れていないため必ず星５つの評価になってしまいます。
``overflow: hidden;``なし
![2609974bbcd16eb7c656c6b0494fe206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700117/9b4b9071-6842-3d1c-e35e-0796749035e4.png)


２.``white-space: nowrap;``とすることでwidthが足りない時に、折り返さないようにしてくれます。
これを指定することで小数点以下の点数も星に反映されます。
``white-space: nowrap;``あり
![44bdcca4dc3ecd2c6133f7dd72db666b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700117/631c55ca-4338-b4f3-5858-12a8a0c35e81.png)

``white-space: nowrap;``なし
![ea00e4658620d7173e5f742fd6b5a946.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700117/169358b4-9e3b-f067-9dae-4f1813ba4786.png)


これで評価の平均値を星で表示することができました！
CentOS8のサーバーに古いAnsibleでつないだ話

最近になってようやくCentOS8のサーバーを構築し始め、ansibleで一発と思っていたら一発じゃなかったのでメモです。

Ansibleのバージョンを上げれば終わる話な気がしますが、上から「影響範囲が...」と言われたので、バージョンを上げずに対応しました。

## 環境
##### Ansibleサーバー
* Cnetos 7.3
* Ansible 2.3

##### 構築先サーバー
* Centos 8.2

## 何が起こったか
EC2でCentOS8を起動し、`ansible playbook`でプレイブックを実行したところこんな感じのエラーが発生しました

```
fatal: [サーバー名]: FAILED! => {
    "changed": false, "failed": true, 
    "module_stderr": "Shared connection to [サーバー名] closed.\r\n", 
    "module_stdout": "/bin/sh: /usr/bin/python: No such file or directory\r\n", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}
```


## 原因
ansible2.3は__python2__で動作しますが、CentOS8にはデフォルトでpython2系がインストール__されていません__
/usr/bin/pythonにインストールされているpython3のリンクを張っても、バージョンの差異から動作の保証はできません(やってないのでわかりません)


## 対策
最初に書いた通り、バージョン上げての対応はNGと言われたのでpython2をインストールして対応をします。


構築先のCentOS8サーバーにpython2.7をインストール

```bash
dnf install python2
```

インストール後、python2.7のシンボリックリンクを作成します

```bash
ln -s /usr/bin/python2.7 /usr/bin/python
```

こんな感じで`python -> /usr/bin/python2.7`のリンクが貼られていれば大丈夫です

```
[root@hoge:~]$ll /usr/bin | grep python | grep -e "^l"
lrwxrwxrwx  1 root root       18 Oct  1 16:17 python -> /usr/bin/python2.7
lrwxrwxrwx. 1 root root        9 Jun  5 12:38 python2 -> python2.7
lrwxrwxrwx. 1 root root       25 Oct  1 16:04 python3 -> /etc/alternatives/python3
lrwxrwxrwx. 1 root root       31 Nov 21  2019 python3.6 -> /usr/libexec/platform-python3.6
lrwxrwxrwx. 1 root root       32 Nov 21  2019 python3.6m -> /usr/libexec/platform-python3.6m
lrwxrwxrwx. 1 root root       24 Oct  1 16:10 unversioned-python -> /etc/alternatives/python
```

これで古いAnsibleからでもプレイブックを実行できるようになります。

ただ、この状態だと新しめのバージョンのAnsibleでエラーが発生します。
新しいバージョンのAnsibleのhostsファイルに`ansible_python_interpreter=/usr/bin/python3`を記載しておくと回避できます。

```
[hoge-sv]
hoge001.net ansible_python_interpreter=/usr/bin/python3
```

## まとめ
python2系がデフォルトでインストールされていないCentOS8でも、python2をインストールすることでansibleを実行できるようになりました。
基本的にはバージョン上げて対応するのが良いと思います。
Vimのキーバインドを体系的に覚えたい

# Vimのキーバインドはやっぱり便利
インフラ系だと手元にViしかなく触らなければならないことがあるのはもちろんのこと、その他の機会でもやっぱりVimのキーバインドは便利なのでVimっぽく操作できたらいいのに。。みたいな機会は多いと思います。実際筆者もVScodeを使いつつ、キーバインドはVimのものを利用しています。

しかしながら、その種類が多くて覚えにくかったり体系的にまとまっているものが少なかったので、自分用にまとめました。

## これは最初に覚える
* `!`は強制の意味。強制的に保存とか、強制的に終了とか。
* `ZZ`保存して閉じる。
* `w`は書き込み、`q`は終了、`e`はファイルを開く。
* `.`は直前の操作を繰り返す。
* `Ctrl`+`g`でファイル情報の閲覧
* `u`はUndo。
* `Ctrl`+`r`はReDo。
* `Ctrl`+`n`は後方補完。（前方補完は`Ctrl`+`p`）

## 選択系コマンド
効率的にビジュアルモードを使いこなしましょう。なおViにはこの概念はありません。

* `v`は領域選択スタート
* `V`は行選択スタート
* `Ctrl`+`v`は矩形選択スタート
* `y`を押せばヤンク、`d`を押せば消せるけど、1行しか処理しない時には、ダブルコマンドするとよい。

## 移動系コマンド
テキスト編集の肝は「移動」して「選択」だから、以下のコマンドもかなり重要。

* `^`は行頭に移動(本当の行頭はO、これは非空白文字までの移動)
* `$`は行末に移動
* `gg`はページ最初に移動（ページ最後に移動は`G`）
* `H`はその画面の最初に移動（`L`は画面の最後に）
* `{`は空白行を目印に移動（小かっこ・中かっこならなんでもOK）
* `%`は対応するかっこまで飛ぶ。
* `3gj`は３行下に移動。
* `w`は単語ごとに前に移動（うしろへ移動は`b`）
* `(`は現在の文の先頭へ。

## 「選択」して「処理」まで一括系コマンド
文字や文章の削除をしたいときにわざわざ選択してから、処理のコマンドを更に打ち込むのは大変なので、よく使うものに対しては割り当てられています。

* `D`はカーソル位置から行末まで削除
* `dd`はカーソルのある行を切り取り。
* `~`は小文字と大文字を相互に変換
* `*`はカーソルのある単語を検索
* `/`は下方検索（上方検索なら`?`）
* `Ctrl`+`a`はインクリメント（`x`ならデクリメント）
* `x`は1文字だけ消すことができる（`Shift`を押しながらはBackspaceと同等）
* `3dd` は３行消す。
* `yy`でカーソルのある行をヤンク。
* `p`は貼り付け。
* `>>`はインデント。
* `=`は範囲を自分で選んで自動インデント。
* `J`はカーソル行のある行を次の行と結合。


## マーク機能
* 簡単に言うと現在地の登録と登録したポイントへのジャンプ機能。
* `:marks`でマーク箇所一覧。
* `m[a-zA-Z]`でマーキング。
* `:b [1-99]`で番号指定してバッファを開くことができる。
* `:bw [1-99]`でバッファを完全に削除
* `:bd [1-99]`は`:ls!`では残っているがバッファに関連する変数やマーカーを消すだけ。
* `:delmarks!`はマークの一括削除。
* `Ctrl`+`o`で古いマークへ移動
* `Ctrl`+`i`で新しいマークへ移動。
* `\ [a-zA-Z]`で移動できるの忘れがち。
* こういうファイルの編集情報はviminfoに入っているよ。

## アウトライン機能
* 領域選択して`zf`でたためる。スペースで開ける。
* `zo`で開く、`zO`ですべて開く、`zc`で閉じる、`zC`ですべて閉じる。

## コマンド
ちょっと込み入った操作や、Vim全体の設定に関わる（=つまりテキストの操作以外の部分）はコマンドを実行して行います。

* `:split`（spも可）は水平画面分割。
* `:vsplit`（vstも可）は垂直画面分割。
* `:close`は今開いている画面分割を閉じることができる。
* `:bn`や`:bf`でバッファをいったりきたり、いま開いているバッファは`:ls`で閲覧することが可能。
* `:pwd`でカレントディレクトリ表示
* `:reg`でレジスタに入っているもの一覧、呼び出しは`"2p`みたいな感じで
* `:%s/置換前/置換後/g`は定型文として覚えよう。`%`はファイル全体に適用の意。本来の`:s`は一部にのみ適用される置換コマンド。`ｇ`は1個だけ置換ではなくすべて置換の意味。最後のオプション値は`gc`にすると置換をいちいち確認してくれる。
* ウィンドウ分割状態で`:q`は消える。`:hide`はウィンドウを閉じるけどバッファにはのこる。
* ファイルをエンコーディングも可能。`:e ++enc=cp932`。
* `:wa`は開いているファイルをすべて保存。
* `:Ex`はvim標準のエクスローラを開く。

## Vimを使い倒すための中級編
ここから先は上の基本コマンドを使いこなせるようになってから進めてみてください。

### 奥が深いね、挿入モード
Vimには挿入モードというモードがあり、いわゆる普通のテキストエディタのカーソルを移動して書き込む画面がVimでは挿入モードに相当します。つまりVimのニュートラルな画面はカーソルが画面上をスケートのように滑って選択ができる画面です。なんでしょうPhotoshopでエフェクトをかける範囲をまず選択して、編集コマンドを差し込むのと同じ感覚です。

* `i`はカーソル位置から入力開始。
* `a`はカーソルの次の位置から入力開始。
* `o`はカーソルの次の行の先頭から入力開始。
* `I`は行の先頭から入力開始。
* `A`は行の終わりから入力開始。
* `O`はカーソルの前の行の先頭から入力開始。

ちなみに、挿入モードでは`Ctrl`+`t`や`Ctrl`+`d`でインデントができます。

### テキストオブジェクトとオペレータ
Vim特有のテキストオブジェクトのイメージは、チャンクとか単語単位でメソッドを適用すれば作業効率あがるよねって感じです。

* オペレータは`c`（切り取って挿入モード）とか`d`（切り取り）とか`y`（コピー）とか。
* `di"`とすると"～"の中身だけ切り取り。`da"`だと括弧ごと切り取り。
* テキストオブジェクトの`i`はinnnerで中身の、`a`はa wordで全体という意味。
Glacierと Glacier Deep Archive

Glacierと Glacier Deep Archiveのメモです。
主な目的は取り出し期間をまとめたかっただけです。

# Glacierとは
- バックアップなど中長期保存用の**S3よりも安価**なストレージ(大切)
- 99.999999999％％ の耐久性
- 毎月わずか 1 USD/テラバイトでデータを保存
- 1 つのアーカイブの最大サイズは 40 TB
- 保存可能なアーカイブ数とデータ量に制限なし

## Glacierの取り出しタイプ
### 迅速
- 通常1〜5分以内(早い)

### 標準
- 3〜5時間

### 大容量
- 大量のデータを1日以内に低コストで取得
- 大体5〜12時間で完了

### プロビジョニングキャパシティ 
- 迅速取り出しの取得容量を必要なと きに利用できることを保証する仕組み

# Glacier Deep Archiveとは
- 中長期保存用ストレージタイプ
- Glacierよりも値段が安い
- データ取得はGlacierより遅い
- 最小保存期間は180日
- 基本的なデータモデル・管理はGlacierと同じ

## データの取り出し
- 標準取り出しで、データは12時間以内 (Glacierの場合は標準で3〜5時間)
- 大量取り出しで、48 時間以内にデータを取り出す大容量取り出しをすることで取得 コストを低減

# ポイント
- 1-5分以内ならGlacier(迅速)
- 3-5時間以内ならGlacier(標準)
- 12時間以内でOKならGlacier Deep Archive
AWS(Organizations)

#はじめに
こちらではAWS機能について書いていきたいと思います。
公式ドキュメントやAWS認定試験（ソリューションアーキテクトやDevOpsなど）の勉強教材など細かい内容をかかず、ざっくりとした内容で。
試験などに興味はないし！公式ドキュメントなど長ったらしくて読めん！
という方に向けに作っていきたいと思います。
(私の備忘録も兼ねて)

写真はつけられればつけます。(Qiitaの制限の範囲内で)

環境
AWS

ドキュメント
https://docs.aws.amazon.com/index.html


#Organizationsとは？
IAMのアクセス管理を大きな組織でもらくに実施できるよにするマネージド型サービス
つまり複数アカウントを運用するうえで楽をする仕組み
主にできること
・複数のアカウントの一元管理
・新アカウントの作成の自動化
・一括請求

#設定
・マスターアカウントの設定
・組織にアカウントを追加(招待)
・組織単位(OU)の作成
・サービスコントロールポリシー(SCP)を設立

#手順
###マスターアカウントの設定
Organizationsへ
↓
組織の作成
↓
メールが送られるので確認

###招待
アカウントの追加
↓
アカウントの招待
↓
招待された側は承認

###OUの作成
アカウントの管理
↓
組織単位の作成
↓
名前の入力
↓
アカウントの移動
↓
移動する組織を選択

###サービスコントロールポリシー(SCP)の設定
設定JSONドキュメント
https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_policies_scps_syntax.html
タブのポリシー選択
↓
サービスコントロールポリシーの有効化
↓
ポリシーの作成
↓
ポリシー名と説明を入力
↓
サービスを選択
↓
リソースを選択
↓
条件の追加
↓
条件キーなどの設定
↓
ポリシーの作成
↓
右のサービスコントロールポリシーの有効化
↓
作った組織を選択
↓
右のサービスコントロールポリシー
↓
設定したいポリシーをアタッチ
JavaScript: 配列の直積を返すジェネレータを作ってみた

[前の記事](https://qiita.com/ttatsf/items/a98719ad9e1f72ddecca)のついでにやってみた。
多重ループとかの時に便利そう。

```js:
// 直積を返すジェネレータの内部再帰関数
const innerProdG = selected => (xs, ...xss) => function*(){
  if (xs === undefined ) {
      yield selected
      return
  }
  for (const x of xs) yield* innerProdG( [...selected, x] )( ...xss )
}()

// 複数の配列をとって直積を返すジェネレータ
const prodG = 
  innerProdG([])

// 使用例：
const a = [0, 1]
const b = [2, 3]
const c = [4, 5]

for(const e of prodG(a, b, c)) console.log(e)
/* 
[ 0, 2, 4 ]
[ 0, 2, 5 ]
[ 0, 3, 4 ]
[ 0, 3, 5 ]
[ 1, 2, 4 ]
[ 1, 2, 5 ]
[ 1, 3, 4 ]
[ 1, 3, 5 ]
 */
```
【Vue.js】他で並列処理(axios)させていたものをgetするまで待ちたい

# はじめに
とりあえず力技で実装しました。
※もっと良い書き方があれば教えてください！

# やりたいこと
* `template`を読み込むとき、`axios`で値Aを取得
* 取得したAを画面に表示（つまりAの取得は下記のボタンを押す前から開始していたい）
* `button @click`で発火したとき、Aをstoreに保管

# 問題
* `@click`発火時、Aを取得しているとは限らない

### 参考コード

```html:vue
<template>
<div>
  <p>{{ a }}</p>
  <button @click="storeAction">登録</button>  
</div>
</template>

<script>
import axios from 'axios'
export default {
  data() {
    return {
      a: ""
    }
  },
  created() {
    axios(param).then(el => {//param: header,urlなどの情報モジュール
      this.a = el
    })
  },
  methods: {
    storeAction() {
      this.$store.dispatch('module/set', this.a)//aをstore.stateにセットする
    }
  },
}
</script>
```

#解決方針
* `axios`が完了するまでdispatchを待たせる
* setIntervalを利用し、値がAに入っているか、定期的に確認する。

### 参考コード

```js:vue
    storeAction() {
      //（略）「読み込み中」のモーダルを表示する処理
      const id = setInterval(() => {
        if(!isEmpty(a)) {//aが空ではない場合
          this.$store.dispatch('module/set', this.a)//aをstore.stateにセットする
          // (略)モーダル解除処理
          clearInterval(id)
        }
      }, 500);
    }
```
  
# 課題
値を取得するまで繰り返し処理させるの・・・カッコ悪い・・・
他で並列処理させているものが完了したことを良い感じに教えてくれるものがないか色々ググってみたんだけど、良い方法が見つからなくてこんな力技になりました。
もっと良い書き方、そもそもやりたいことがメソッドで提供されている場合は教えてくださると嬉しいです。
FreeBSDのpkgコマンドで`repository meta has wrong version 2`エラー

# 事象

久しぶりにVagrantのFreeBSDをビルドすると`repository meta has wrong version 2`というエラーが発生しました。rsyncで同期していたのでそれが原因かと思い、Vagrantfileからrsyncを外すと起動はしましたが、pkgコマンドを使用すると同じエラーが出ました。しょうがないのでpkgコマンドは無視してApacheをソースからインストールしましたが、今度は別のエラーが出ました。

## Boxファイル

generic/freebsd11

FreeBSDのバージョンは11.3

## エラー内容

### pkgコマンドのエラー

```shell
==> default: Installing rsync to the VM...
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

pkg install -y rsync

Stdout from the command:

Updating FreeBSD repository catalogue...
Fetching meta.txz: . done
repository FreeBSD has no meta file, using default settings
Fetching packagesite.txz: .......... done
Unable to open created repository FreeBSD
Unable to update repository FreeBSD
Error updating repositories!


Stderr from the command:

pkg: repository meta has wrong version 2
pkg: Repository FreeBSD load error: meta cannot be loaded No error: 0
pkg: repository meta has wrong version 2
pkg: repository meta has wrong version 2
```

### makeコマンドのエラー

```shell
===> Building/installing dialog4ports as it is required for the config dialog
===>  Cleaning for dialog4ports-0.1.6
===> Skipping 'config' as NO_DIALOG is defined
/!\ ERROR:/!\
Ports Collection support for your FreeBSD version has ended and no ports are guaranteed to build on this system.Please upgrade to a supported release.

No support will be provided if you silence this message by defining
ALLOW_UNSUPPORTED_SYSTEM.

***Error code 1

Stop. 
make[3]: stopped in /usr/ports/ports-mgmt/dialog4ports
***Error code 1

Stop.
make[2]:stopped in /usr/ports/ports-mgmt/dialog4ports
===> Options unchanged
/!\ ERROR:/!\
Ports Collection support for your FreeBSD version has ended and no ports are guaranteed to build on this system.Please upgrade to a supported release.

No support will be provided if you silence this message by defining
ALLOW_UNSUPPORTED_SYSTEM.

***Error code 1
Stop.
make[1]:stopped in /usr/ports/www/apache24/
**Error code 1

Stop.
make:stopped in /usr/ports/www/apache24
```

# 原因

makeのコマンドにあるようにOSのバージョンのサポートが終了したためです。

> Ports Collection support for your FreeBSD version has ended and no ports are guaranteed to build on this system.Please upgrade to a supported release.

[FreeBSDでmakeコマンドでエラーが出る](https://teratail.com/questions/116013)

> 現在のサポートモデルでは、各メジャーバージョンの stable ブランチは、 明示的に 5 年間サポートされますが、各ポイントリリースのサポート期間は、 次のポイントリリースの公開後 3 ヵ月までとなります。

[サポートされている FreeBSD のリリース](https://www.freebsd.org/ja/security/security.html#sup)

# 対応方法

方法は２つあります、OSのバージョンを上げるか、古いバージョンでも無視する方法です。
エラーを無視するには`ALLOW_UNSUPPORTED_SYSTEM`という環境変数に1をセットします。

```
export ALLOW_UNSUPPORTED_SYSTEM=1
```
Apacheのアクセスログから、アタック試行しているIPアドレスの範囲をFirewalldに自動設定する

# 手当たり次第に GET 要求するのやめてほしい
とりあえず、脆弱性のあるリソースがあるかを探しに来るやからがたくさんいますね。
まぁ、ボットの類なんでしょうけど、こういうのホント迷惑です。

```
193.27.229.26 - - [08/Nov/2020:09:38:36 +0900] "POST /api/jsonws/invoke HTTP/1.1" 404
193.27.229.26 - - [08/Nov/2020:09:38:36 +0900] "POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 404 193.27.229.26 - - [08/Nov/2020:09:38:37 +0900] "GET /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 404
193.27.229.26 - - [08/Nov/2020:09:38:37 +0900] "GET /solr/admin/info/system?wt=json HTTP/1.1" 404
193.27.229.26 - - [08/Nov/2020:09:38:37 +0900] "GET /index.php?s=/Index/\\think\\app/invokefunction&function=call_user_fun
c_array&vars[0]=md5&vars[1][]=HelloThinkPHP21 HTTP/1.1" 404
193.27.229.26 - - [08/Nov/2020:09:38:37 +0900] "GET /?a=fetch&content=<php>die(@md5(HelloThinkCMF))</php> HTTP/1.1" 200
193.27.229.26 - - [08/Nov/2020:09:38:38 +0900] "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1" 200
193.27.229.26 - - [08/Nov/2020:09:38:38 +0900] "GET /wp-content/plugins/wp-file-manager/readme.txt HTTP/1.1" 404
193.27.229.26 - - [08/Nov/2020:09:38:38 +0900] "GET /console/ HTTP/1.1" 404
192.241.239.119 - - [08/Nov/2020:12:27:48 +0900] "GET /portal/redlion HTTP/1.1" 404
185.239.242.196 - - [08/Nov/2020:13:35:45 +0900] "GET /config/getuser?index=0 HTTP/1.1" 404
80.82.65.80 - - [08/Nov/2020:14:26:03 +0900] "GET ../../proc/ HTTP" 400 226 "-" "-"
```

気を付けないと、踏み台にされたりしますし、リソース壊されても面倒。ましてやサービス停止なんてなったら、収入に響きます。
ボットにあきらめてもらうには、HTTPサーバが返答しないようにした方がよさそうですね。

- ホストが存在しないかのように見せる
- 通信レベルでアクセスを拒否する

どっちがいいかというと前者だと思うんですが、一度はアクセスを受け入れているわけだし、もしかしたらまともな人がそのIPを使ってくれて、まっとうにアクセスしてくれる日が来るかもしれません。

そういうことも踏まえ、できるだけ手数を掛けずに対策したかったんですよね。

# Script を cron で定期実行して、ログからFirewalldを設定する
ということで作りました。
https://github.com/technokuro/checkAccessLogAndSettingDrop

## 必要環境
- Whois
- Firewalld

## 実行方法
```shell
# usage
perl checkAccessLogAndSettingDrop.pl [*accessLogFilePath*] [*count*] [*isPermanent(null or 0 or else)*]
```

# 引数

## accessLogFilePath
ファイルパス


## count
この指定以上の 40x エラーを出しているIPをWhois から範囲を割り出して拒否

## isPermanent
permanent 指定するときは null でも 0 でもない値をセットします

# 注意
permanent 無指定だと、メモリ上に記録されます。
従って、firewalld が reload restart すると、フラッシュされます。

# 課題
あくまで whois が返す範囲IPを拒否しますから、誰かのせいで、まっとうな人のアクセスも拒否します。
まぁ、だいたいは海外IPなので、こうした方がいいかと思ってそうしています。

色々考えはあるかと思いますが、どうぞご意見ください。
【HTML】HTMLだけで入力を確認する方法

#プログラミング勉強日記
2020年11月8日
スクリプトを使わずに入力チェックする方法を初めて知ったのでまとめる。

#入力必須項目の作成
　input要素に属性値`required`を使うとその入力欄は入力必須項目になり、空欄のままで送信ボタンが押されても警告メッセージが出る。

```html
<form>
	名前：
	<input type="text" required >
	<br>
	<input type="submit" value="送信">
</form>
```

実行結果(chrome)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/c1db4905-dd27-7957-d84f-416019135143.png)

　※chromeではこのように実行できているが、required属性に非対応の古いブラウザでは警告メッセージが出ずそのまま送信されてしまうことがあるので注意する。

#メールアドレスの確認
　input要素のtype属性の値を`email`にすると、メールアドレスの入力欄になる。見た目は他のテキスト入力欄と変わらないがメールアドレスではない文字列が入力されると警告メッセージが出る。これだけだと空欄の場合には警告メッセージは出ず、そのまま送信されるので空欄を避けるためには先ほどの`required`も合わせて使う。


```html
<form>
	メールアドレス：
	<input type="email" required>
	<br>
	<input type="submit" value="送信">
</form>

```

実行結果(chrome)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/cf7f32ad-8e6a-56df-626b-1f010717c654.png)

#URLの確認
　メールアドレスと同様にinput要素のtype属性を`url`にすると、URLの入力欄になる。使い方はメールアドレスの場合と同じで、URLでない文字列が入力されると警告メッセージが出る。(`required`を合わせて使うと必須入力項目になる)

実行結果(chrome)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/64a9f2c9-2e99-0500-84f6-c57f381100b0.png)

#電話番号の確認
　input要素のtype属性を`tel`にすると、電話番号の入力欄になる。pattern属性を使って入力規則を正規表現で書くことで電話番号かどうかをチェックしてくれる。

```html
<form>
	電話番号(ハイフンなし)：
        <!-- 数字が10回以上繰り返される場合をチェック -->
	<input type="tel" pattern="[\d]{10,}" required>
	<br>
	<input type="submit" value="送信">
</form>
```


実行結果(chrome)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/574dd975-3368-bd0c-1909-502c74155c07.png)

#テキスト入力欄の確認
　正規表現で入力規則を指定できるpattern属性はinput要素のtype属性の値がtext, search , tel, url, email, passwordといった1行テキストの入力欄を作る場合に使える。
　pattern属性の記述だけでは入力チェックはできるが、記述形式を指定することは難しいので、title属性の値に案内を示しておくことで警告メッセージの差異に合わせて表示される。

```html
<form>
	パスワード：
	<input type="text" pattern="[A-Z]*" title="英大文字のみで入力して下さい" required>
	<br>
	<input type="submit" value="送信">
</form>
```

実行結果(chrome)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/9f4f2467-b9bc-7242-6488-293017cefb52.png)



#参考文献
[正規表現：文字の「繰り返し」と、回数の指定](https://www-creators.com/archives/2679#i-3)
[スクリプトを使わずに、HTMLだけで入力チェックする方法](https://allabout.co.jp/gm/gc/23854/#aa23854nojavascript)zi
highlight.jsを動的に使ってみた - CodePen

# まえがき

最終的にやりたいこと：コーディングの様子を動画っぽく表示したい。コードはシンタックスハイライトしたい。（先は長そう（？））
できたっ → [ハッカーっぽいやつ作ってみた ～ コーディングを記録して動画風に再生する - Qiita](https://qiita.com/kob58im/items/f6a0cdfa4de1308e5431)

<b>今回やったこと：ユーザが入力しているコードにシンタックスハイライトを適用して表示する。</b>（入力用の領域とは別の領域に表示する。）

# やってみた

<p class="codepen" data-height="555" data-theme-id="light" data-default-tab="result" data-user="kob58im" data-slug-hash="PozdgMX" style="height: 555px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="DynamicCodeHighlight">
  <span>See the Pen <a href="https://codepen.io/kob58im/pen/PozdgMX">
  DynamicCodeHighlight</a> by kob58im (<a href="https://codepen.io/kob58im">@kob58im</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

version 9.15.10を使用しましたが、現時点(2020.11.8)ではversion 10.1.2が最新のようです。

# スタイルを変えたい場合

スタイルを変更したい場合は、参考サイトの2（※バージョンは適宜選択して変更ください）から探して、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/ff75786a-ab8f-df0e-2c55-e51f8681a656.png)
「Copy Link Tag」をクリックして得られたHTMLのタグ(`link`タグ)を埋め込む（置き換える）と変更できます。

# 参考サイト

 1. [コードのハイライト表示用 JS ライブラリ highlight.js の使い方 - Qiita](https://qiita.com/tadnakam/items/99088d78512a20e75ff3)
 2. [highlight.js - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers](https://cdnjs.com/libraries/highlight.js/9.15.10)
jQueryいろいろ(wrapAll, MutationObserverなど)

復習のため、無駄に遊んでみました。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555201/2c7516a5-2315-a37f-1f0e-e8d90ccc70be.gif)



```sample.js

// Bootstrap, jQueryは各自読み込んでください。
$(() => {
  const main = $('<div id="main"></div>');
  $('body').html(main);
  const cat = 'https://drive.google.com/uc?export=view&id=1vhfW5iAbMOnkM5nGsYDmEAntikVMWKw4';
  const img_tag = `<div class="img-wrapper" style="text-align: center"><img src="${cat}" style="width: 100px;"></div>`;
  for (let i = 0; i < 6; i++) {
    $('#main').append(`${img_tag}`)
  }
  
  // スリープ
  setTimeout(() => {
    $('.img-wrapper').wrapAll('<div class="container"></div>');
    
  // 3つずつrowで囲む
  do {
    $('#main').children('.container').children('.img-wrapper:lt(3)').wrapAll('<div class="row"></div>')
  } while($('.container').children('.img-wrapper').length)
    
  // .col-4を付与  
  $('#main').find('.img-wrapper').addClass('col-4');
  }, 4000)
  
  // スリープ
  setTimeout(() => {
  
  // タイトルを挿入
  $('#main').prepend('<h2 id="title">猫ですがなにか？</h2>');
  
  // MutationObserverをタイトルにセット
  let observer = new MutationObserver(() => {
    let new_title = "猫アレルギーなんですか？"
    $('#title').text(new_title);
  });
  
  // 属性の変化を検知
  const conf = {
    attributes: true,
    attributesFilter: ['style']
  };
  
  const title = document.getElementById('title');
  observer.observe(title, conf);
  }, 8000)
  
  // スリープ
  setTimeout(() => {
  $('#title').css({'text-align': 'center'});
  
  $('#main').find('.img-wrapper').removeClass('col-4');
  
  $('.img-wrapper').each((index, element) => {
    $(element).wrap('<div class="cat-wrapper col-4"></div>');
  });

  $('.cat-wrapper').append('<p class="neko_text">猫ですが？</p>');
  $('.neko_text').css({'text-align': 'center'})
  }, 12000)
  
  // スリープ
  setTimeout(()=> {
    $('.neko_text').each((index, element) => {
    let text = $(element).text();
    let new_text = text.replace('猫です', '犬じゃないんです');
    $(element).text(new_text);
  });
  }, 16000)
});

/*wrapAll,wrapInner
children,find
$(function() {})　は　$(document).ready(function{})と一緒
do {} while()
length
each(function(index, element) {})
.text(), replace(),
document.getElementById(),$()
MutationObserver
append, prepend
*/
```
高機能なSQL開発ツール「A5:SQL Mk-2」をUbuntuで使う

## A5:SQL Mk-2 とは?

https://a5m2.mmatsubara.com/

> A5:SQL Mk-2は複雑化するデータベース開発を支援するために開発されたフリーのSQL開発ツールです。
> 高機能かつ軽量で、使い方が分かりやすいことを目標に開発されています。
> SQLを実行したり、テーブルを編集するほかに、SQLの実行計画を取得したり、ER図を作成したりすることが出来ます。

### A5:SQL Mk-2の特徴

* GUIでER図が作図できる
* ER図からMySQLやPostgreSQLなどのデータベース用のDDLが生成できる
* ER図からExcelやHTML形式でエンティティ定義書が生成できる
* データベースに接続して、テーブル情報からER図やエンティティ定義書をリバース生成できる
* 保存ファイルがバイナリではなくテキストのでGitで管理できる

他にも様々な機能があり、データベースの設計で重宝する素晴らしいツールです。

## A5:SQL Mk-2をUbuntuで使う

上記の通り、とても便利なツールですが、Windowsアプリとなっており、MacやUbuntuで使うには少し工夫が必要です。
今回はUbuntuでA5:SQL Mk-2を使う方法を紹介します。

Ubuntuのバージョン

```bash
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
...
```

### Wineのインストール

https://www.winehq.org/

> Wine （ワイン）は、オープンソースの Windows API 実装を通じて、主としてx86アーキテクチャ上のUnix系オペレーティングシステム (POSIX準拠OS) においてWindows用アプリケーションをネイティブ動作させることを目標とするプログラム群である。

Wineを使ってWindowsアプリをUbuntu上で実行できるようにします。
そのままだと日本語フォントが文字化けするので、フォントのインストールなどの設定ができるwinetricksと合わせてインストールします。

```bash
$ sudo apt install wine winetricks
```

32bit版の環境で無いとフォントのインストールに失敗するようだったので、環境変数をし指定して、winetricksを起動します。

```bash
$ export WINEARCH=win32
$ winetricks
```

![スクリーンショット 2020-11-08 14-54-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71453/84ef81fc-447e-5ee4-353d-a275891d5e77.png)

「Select the defalut wineprefix」を選択

![スクリーンショット 2020-11-08 14-53-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71453/99d04a77-9d2c-fb6b-4707-56ea47d54096.png)


「Install a font」を選択

![スクリーンショット 2020-11-08 14-53-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71453/a5afcdd7-07c4-5ede-fa0d-d004d3ed7695.png)

「cjkfonts」を選択し、インストールを実行

インストールで、警告が出る場合もありますが、そのまま進めてください。

## A5:SQL Mk-2の起動

公式サイトからA5:SQL Mk-2をダウンロードします。
32bit版の環境で実行するので、x86 editionを選択してください。

ダウンロード後、解凍したフォルダ内に「A5M2.exe」というexeファイルがあるので、wineから起動します。


```bash
$ wine A5M2.exe 
```

![スクリーンショット 2020-11-08 15-03-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71453/e70f830c-dce1-27e7-22eb-9b3389e6bed5.png)

Ubuntu上で、A5:SQL Mk-2で起動できました。
文字化けなく表示されていて、日本語入力も無事にできました。

## 注意点、制約など

UbuntuでA5:SQL Mk-2が使えるようになりましたが、Wineで実行している都合上、制約があります。

* 印刷やPDF出力が正しく機能しない
* Excel出力が機能しない（HTML出力は機能する）

確認できていませんが、他のも制約があるかもしれません。
現状は、Ubuntuからはファイルの編集のみを行い、ドキュメント化する場合はWindows版を使うことになるかと思います。

## その他、補足事項

* Macで使いたい人はEasyWineを使うのが良いかもしれません（未検証）
    * https://hirubokari.booth.pm/items/1669411
* 上記の制約があるので、自分はUbuntuにKVMでインストールしたWindows上にA5:SQL Mk-2を入れて、Ubuntu側からリモートデスクトップで繋いで使用しています。
    * フル機能を使いたい方は、こちらがオススメです:thumbsup:

## まとめ

A5:SQL Mk-2をUbuntuで使う方法を紹介しました。
とても便利なオススメのツールなので、Windowsユーザー以外の方も、ぜひ使ってみてください:grinning:
Goの継承っぽい書き方でできないこと

Goは継承の概念がないので、オブジェクト指向的な振る舞いを期待して書くとあれ？ってことがあります。
Goの継承っぽい書き方は何ができるの？できないの？というのを調べてみた備忘です。

# できること

先に書いたように、継承っぽい書き方はできるのです。
たとえば、猫のような振る舞いをするクラスを書いてみます。

```Go
//親クラス
//インターフェースSpeaker
type Speaker interface {
    Call()
}
//構造体Cat
type Cat struct {
}
//Catの振る舞いを定義
func (c Cat) Call() {
    fmt.Println("にゃー")
}
```

クラスが無いので、構造体にインターフェースを埋め込むことで継承のように扱おうとします。

それでは、猫クラスをタマに継承させてみましょう。

```Go
//子クラス
//Cat構造体を継承
type Tama struct {
    Cat
}
```

タマは猫クラスを継承しているので、にゃーと鳴くはずです。

```Go
func main() {
    var t Speaker

    t = Tama{
    }
    
    t.Call()
}

> go run main.go
にゃー
```

にゃーと鳴きました。
この調子で、同じく猫クラスを継承するひろしも作ってみます。


ひろしはにゃーと鳴かずポーツマス！を2回言うので、Voice()を再定義します

```Go
type Hiroshi struct {
    Cat
}
//子クラスのCall()を再定義
func (h Hiroshi) Call() {
    fmt.Println("ポーツマス！ポーツマス！")
}
```

ひろしはポーツマス！ポーツマス！と鳴くはずです。

```Go
func main() {
    var h Speaker

    h = Hiroshi{
    }
    
    h.Call()
}

> go run main.go
ポーツマス！ポーツマス！
```

Goではこのような形で継承を書くことができます。

# できないこと

一見うまくいっているように見えますが、期待通りに動かないものがあります。
親クラスのメソッドが子クラスのメソッドを呼ぶ入れ子構造の場合です。

やってみましょう。
猫クラスに、Call()を呼ぶだけのCry()メソッドを作ります。
タマがCry()するとにゃーと鳴きます。

```Go
type Speaker interface {
    Call()
    Cry()
}
func (c Cat) Cry() {
    c.Call()
}

t.Cry()

にゃー
```

ひろしがCry()するとどうなるでしょう。
ポーツマス！ポーツマス！と鳴くと思いますよね。
ところがならないのです。

```Go
h.Cry()

にゃー
```

Cry()を呼んだときのレシーバーを見てみると、分かりやすいかも知れません。

```Go
func (c Cat) Cry() {
    fmt.Printf("レシーバー：%p\n", c)
    c.Call()
}

h.Cry()

レシーバー：%!p(main.Cat={})
にゃー
```

hiroshiをレシーバーとしてCry()を呼んでいるのに、親クラスを呼んだことになっています。
構造体にインターフェースを埋め込んでもインターフェースそのものが変化するわけではなく、そもそも親子関係など無いのです。
ひろしがCry()してもレシーバーが親クラスなので、子クラスのCall()を呼びに戻ったりはしないってことです。

# まとめ
インターフェースの埋め込みは継承っぽく見えるけど、メソッドが再利用できるだけで継承できるわけじゃないのです。

# 参考にさせていただいた記事

[埋め込み型としての構造体 ( Goは継承を使わない )](https://qiita.com/keiya01/items/435890473465a9b6c470)
[Goのinterfaceがわからない人へ](https://qiita.com/rtok/items/46eadbf7b0b7a1b0eb08)
[Goで学ぶポインタとアドレス](https://qiita.com/Sekky0905/items/447efa04a95e3fec217f)
Windows Terminal などで Ctrl+C が[プロセスはコード 3221225786 で終了しました]になるときの対処法

Windows Terminal や VSCode などでターミナルを開くとき、pwsh や nyagos の中で時間のかかる処理を`Ctrl+C`するとターミナルのプロセスごと落ちてしまうときがある。

pwsh や nyagos を Scoop でインストールした場合、以下の方法で解決できる。

## 対処法
`scoop/shims`ではなく`scoop/apps`以下の `.exe` を指定する。

Windows Terminal の場合の例

```json
"commandline": "%USERPROFILE%\\scoop\\apps\\pwsh\\current\\pwsh.exe"
```

## 関連Issue
* https://github.com/PowerShell/PowerShell/issues/11314#issuecomment-625885483
* https://github.com/lukesampson/scoop/issues/3634
Factory Method Pattern

#Factory Method Pattern
<font color="#00f">packageが異なるケースなど、newでインスタンスを生成できないケースでは、Factory Method Patternを利用して、インスタンスを取得する<br>
factory抽象クラスはインスタンス化する骨組みを定義し
factory抽象クラスのサブクラスが実際のインスタンスを生成する
userはfactory抽象クラスを通じてインスタンスを受け取る
</font>

[Design Pattarm MENU](https://qiita.com/old_cat/items/852d980bedb9100dd7e3)
<br>
このページは下記の構成となってます
コードを確認するだけなら２番目に飛んでください
・new でインスタンスを生成できないケース
・Factory Method Pattern の確認

##new でインスタンスを生成できないケース
以下のクラス構成で確認します

|パッケージ名|クラス|アクセス修飾子|説明|
|-----|-----|-----|-----|
|Default|user(Main.class)|public|動作を確認する|
|implement|sam.class|Default|特になし|

```java:package.implement.sam
package implement;

class sam{}
```
```java:user(Main.class)
import implement.*;
public static void main(String[] args){
  sam s = new sam();
}
```
結果

```java:
sam cannot be resolved to a type
```
sam.classのアクセス修飾子はDefaultですから
所属パッケージに所属するクラスからしかアクセスできません

従ってuserから、sam.classは完全に独立し、触れることができません
例えば、このようなケースでFactory Method Patternを使います

##Factory Method Pattern の確認
以下の構成で確認します

|パッケージ名|アクセス修飾子|クラス|import|説明|
|-----|-----|-----|-----|-----|
|framework|public|abstract samFramework.class|なし|userが利用するオブジェクトの抽象クラス|
|framework|public|abstract factoryFramwork.class|なし|インスタンス生成を定義する抽象クラス|
|implement|Default|sam.class|import framework.samFramework|userはsam()のインスタンスを利用する|
|implement|public|factory.class|import framework.samFramework<br>import framework.factoryFramework|sam.classのインスタンスを生成する|
|Default|public|user(Main.class)|import framework.samFramework<br>import framework.factoryFramework<br>import implement.factory
＊user　他の開発者がこのパターンを利用する、という意味合いを含みます

<font color="#f00">
samFramework.classとfactoryFramework.classは
何もimportしていません
また user（Main.class) は sam( )をimportできませんので
new sam( )でsamインスタンスを取得できません</font>

ではクラスを作っていきます

```java:samFramework.class
package framework;

public abstract class samFramework{
  public abstract void show();
}
```
```java:factoryFramework.class
package framework;

public abstract class factoryFramework{
  public abstract samFramework newInstance();
}
```
```java:sam.class
package implement;
import framework.samFramework;

class sam extends samFramework {
  public void show(){System.out.println("sam");}
}
```
```java:factory.class
package implement;
import framework.factoryFramework;
import framework.samFramework;

public class factory extends factoryFramework {
  public samFramework newInstance(){return new sam();}
}
```
```java:user(Main.class)
import framework.factoryFramework;
import framework.samFramework;
import implement.factory;

class Main {
public static void main(String[] args){
  factoryFramework factory = new factory();
  samFramework sam = factory.newInstance();
  sam.show();
}}
```
vs2017でPythonのunittestモジュール実行

vs2017にてunittestモジュールを使用した際にエラーが発生した。

##エラー内容
unittest.main()にて例外が発生。
例外内容はFalseとだけ書いてある


##対策
ツールバー->デバッグ->オプション->python->デバッグ
レガシーデバッグの使用にチェックを入れる
SkyWay チュートリアル カメラ映らない

SkyWayの"JavaScriptSDK"チュートリアルやってる時に起きた事件。

チュートリアル進めててカメラ写るか確認したら記述合ってるのにカメラが映らない(T_T)


【諸悪の根元】
通信がHttpsじゃなかった。

どうやらSkyWayのAPIはHttps通信じゃなきゃ動かないのか？と思った。



・通信をのhttps化
参考記事
https://qiita.com/Sub_Tanabe/items/f5fc04d1db57152f69bf