OmniAICreator/Qiita-1.07M huggingface dataset:
お名前.comで取得したドメインをRoute53で管理する

Rails+Unicorn+Nginxで個人開発でアプリケーションをEC2にデプロイしたのですが、ドメインを取得したなかったのでその手順を備忘録的に書いていきたいと思います。

## 前提

- Rails+Unicorn+Nginx環境でEC2にアプリケーションをデプロイ済であること。
- 固定IP(Elastic IP)をEC2のIPアドレスに紐づけていること

## ドメイン取得
今回はテスト的にドメインを取得したいので、一番安い```.work```のドメインを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/a5bcf575-5587-733a-84c7-d9b124c82608.png)

クレカ情報を入力して、ドメインを購入します。

## Route53との紐付け

AWSコンソールにログインします。
「Route53」→「ホストゾーンの作成」　　

「ドメイン名」の部分に、先ほどお名前.comで取得したドメインを入力します。
「パブリックホストゾーン」にチェック→「ホストゾーンの作成」でホストゾーンを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/95f391cb-fdcf-f2ef-9896-b5cb93050736.png)

作成後、下記のような形になっていると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/cec663ae-84d8-f18f-a4aa-324e37c91492.png)

**タイプNSの、「値」部分に４行アドレスが存在していると思います。そこをクリップボードにコピーしておきます。**

## サブドメインのレコード作成

「ホストゾーン」の画面から、「レコードを作成」→「シンプルルーティング」→「シンプルなレコードを定義」

「レコード名」 = 任意のサブドメイン名を入力
「値/トラフィックのルーティング先」 = EC2の固定IPアドレス
「レコードタイプ」 = A

「シンプルなレコードを定義」でレコードを新規に作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/4001b29c-2dca-0e18-d296-7af94fed9af5.png)

## ネームサーバーの設定

ドメインを取得したお名前.comに行きます。
「ドメイン」→「ドメイン設定」→「ネームサーバー設定」から、作成したドメイン名を選択

「その他のネームサーバーを使う」の部分で、先ほどコピーしておいた４行のアドレスを入力していきます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/d392ed41-c326-556f-d5a3-ab44cab0d4e9.png)

これで、ドメインを取得→Route53での管理の設定が完了になります。

## Nginxの修正

EC2にSSHでログインしている状態で、

```
$ cd /etc/nginx/conf.d/
$ sudo vim {アプリ名}.conf
```

デプロイ時のNginxの設定で、server_nameを指定している部分があると思います。
ドメイン取得前は、

```
server {
  listen 80;
  server_name *******(固定IPアドレス);
==================省略
```
と記述していましたが、server_nameの部分をサブドメイン名に変えます。

```
server {
  listen 80;
  server_name myapp-test.work(サブドメイン名)
==================省略
```

Nginx、Unicornの再起動で完了です。

サブドメイン名でアクセスしてみると、ページが表示できると思います。
情報セキュリティの3要素とは

#情報セキュリティとは

- Webシステムを運営していくのに、悪意を持ったユーザーから攻撃を受ける可能性も出てくる。そのため、セキュリティ対策が必須となる。

- **情報セキュリティ**とは、情報の**`「機密性」`**、**`「完全性」`**、**`「可用性」`**を維持することと定義されている。この３つを**情報セキュリティの3要素**と呼ぶ。

#機密性(Confidentiality)とは

- アクセスを認められた者だけが、その情報にアクセスできる状態を確保すること。つまり関係ない者に情報を見せないことを意味する。

#完全性（Integrity）とは

- 情報が破壊・改ざん・消去されていない状態を確保すること。

#可用性（Availability）とは

- 必要な時はいつでも情報にアクセスできる状態を確保すること。
Node-REDのflowを公開した話

### 発端
私の所属する会社では毎年インターンシップを受け入れています。
本年度はNode-REDを利用してプログラミング入門を実施することに決定。

* [Raspberry Pi4](https://raspberry-pi.ksyic.com/main/index/pdp.category/2/pdp.names/Pi4%20B)
* [RPZ-IR-Sensor](https://www.indoorcorgielec.com/products/rpz-ir-sensor/)

を購入して準備を進めていたのですが...

RPZ-IR-Sensor搭載センサーを簡単に使いたいのでflowはあるかな？
と検索したところ

BME280 → https://www.npmjs.com/package/node-red-contrib-bme280
TSL2572 → 公開されていない....(Pythonスクリプトは存在)

**『TSL2572用のflowが無いなら作ってしまいましょう』**という事で....
Indoor CorgiさんにPythonスクリプトの情報を元にflowを作成＆公開の
許可を頂きNode-RED用のflowを公開した話です。


### 1. 製作
TSL2572はI2Cで制御する光センサーでして、BME280のソースを参考に進める。
Node-RED公式の開発手順とBME280のソースを一通り眺めてポイントを理解。
実作業時間としては約1日程度でした。

**躓きポイント(1)**
`~/.node-red/node_modules/**/package.json`に謎のエントリーがありますが
Node-REDにノードを追加すると勝手に編集される様子なので無視することに。

**躓きポイント(2)**

```bash
$ cd $HOME/.node-red
$ npm install $HOME/tsl2572
```
のようにして導入すると tsl2572/node_modules 配下にファイルが配置されるのが気に入らない。

```
$ npm install t-kawamorita/node-red-contrib-tsl2572
```
のようにgithub(npmjs)経由で導入すると問題なかったので気にしない事にした。


### 2. 公開
Node-REDのメニューから「ノードを追加」できれば社内の布教も
楽なので公開することにした。

github → npmjs → nodered という手順を踏む必要がありそうなので行動開始。

#### 2.1. githubに登録

githubにリポジトリを使ってpush。
https://github.com/t-kawamorita/node-red-contrib-tsl2572


#### 2.2. npmjsに登録

npmjsにアカウントを持っていなかったのでアカウントを作成。

##### 2.2.1. npmjsにpublishするための準備

```bash
$ npm set init.author.name "みょうじ なまえ"
$ npm set init.author.email "メールアドレス"
$ npm set init.author.url "https://github.com/アカウント"

$ npm adduser
Username: アカウント
Password:
Email: (this IS public) メールアドレス
Logged in as アカウント on https://registry.npmjs.org/.
```

作成したソースコードのあるディレクトリに移動して下記を実行。

```bash
$ npm publish
```

https://www.npmjs.com/package/node-red-contrib-tsl2572
に登録されました。

**実際にはspamとして判定されたので、サポートにspam解除してと依頼するひと手間がありました。**

#### 2.4. noderedに登録

**[登録ページ](https://flows.nodered.org/add/node)**を開き

1と2の内容通りになっているか確認。
3のテキストボックスに **node-red-contrib-tsl2572** と入力。
**add node** を押すと即座に登録されて、Node-REDからも追加できるようになりました。

https://flows.nodered.org/node/node-red-contrib-tsl2572

### 余談

Node-REDはプロトタイプ開発に向いているという記事を目にしますが、
確かに、その通りで作りたい機能に集中して開発できるのが気持ちいいですね。

調子に乗って会議室のプロジェクターの遠隔操作アプリが30分ほどで出来ました。
恐るべし＆楽しいぞNode-RED

さて、IoTハジメマスカ。
【Ruby】rbenvの使い方(version `x.x.x' is not installed)

#rubyのバージョンエラー
昔Githubに入れてたRailsのプロダクトを引っ張り出して動かそうとしたら、

```sh
version `x.x.x' is not installed
```
rubyのバージョンが違うらしい。。

# rbenvコマンド

```
# リストを確認する
rbenv install --list

# インストールする
rbenv install x.x.x

# デフォルトで使用するバージョンを設定する
rbenv global x.x.x

## インストールしたRubyx.x.xを使用可能な状態にする
rbenv rehash
```

これで好きなバージョンのrubyで開発できます！

Railsも必要な人はこちらも追加

```sh
sudo gem install rails
```

# おまけ
長くなりそうなので、省略しましたがこんなエラーも出てきました。
いくらインストール(sudo gem install rails)しても無限に出てくる、
有名なエラーなようです。
Macにデフォルトで入っているrubyとの干渉をしているので、、

```sh

Rails is not currently installed on this system. To get the latest version, simply type:

    $ sudo gem install rails

You can then rerun your "rails" command.
```

下記のコマンドでrbenvとruby-buildをインストール後、
本記事の設定を行うことで解消することが可能です。

```sh

brew install rbenv ruby-build
```




参考になれば幸いです。
【初心者でもわかる】cssを意味と見た目で分けて、綺麗に書く方法

# どうも7noteです。cssを綺麗に書くための手法を紹介していきます。

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/coding/beautifulcss/
トランプがHuawei、TikTokを排除するワケ: ポストGAFAの行方

#トランプの中国排除は選挙のため?
本日('20/8/1)、トランプはHuaweiに続き、TikTokもアメリカ国内での利用を禁じました。理由は、個人情報流出のセキュリティリスクがあるから、と回答しています。

Huawei, TikTokの禁止の背景に、今年('20)の選挙が行われる上で、コロナ対策に失敗したと見做されてしまっている状況を打破するため、中国を敵国に祭り上げた、という見方をされてますが、本当にそんな短絡的な話なのでしょうか?

**実は、「アメリカのテクノロジー業界を守るために行っている」、とは考えられないでしょうか?**

#Google, Facebookが稼げるワケ
多くの方がGoogleの検索やYouTube、FacebookやInstagramのサービスを無償でお使いだと思いますが、なぜ無償で使い続けられるのでしょうか?

この答えは簡単で、この2社は広告費を稼げるので、ユーザーから利用料を貰わなくても経営できるからです。では、なぜ莫大な広告費を稼げるのでしょうか?

理由は、この2社が、ネット検索、投稿動画、個人向けSNS、写真SNSのシェアがトップで、その地位を利用し、効率的な[行動ターゲティング広告](https://ja.wikipedia.org/wiki/行動ターゲティング広告)の仕組みを作り上げたためです。

#行動ターゲッティング広告の効率を上げるには?
行動ターゲッティング広告の効率を上げるには、

- 多くの情報を集められること
- 詳細な情報を集められること
- それらのデータが分析できること

が必要になります。

これらを達成するために、Googleは、下記のようなことを行ってきました。

- Gmailを開発し、メール情報を収集
- Google mapを開発し、個人の位置情報に関する興味関心の情報を収集
- Androidを買収し、携帯電話を通して様々な個人の情報を収集
- YouTubeを買収し、閲覧者だけでなく動画投稿者の情報も収集

また、Facebookは、下記のようなことを行ってきました。

- WhatsAppを買収し、メッセージ情報を収集
- Instagramを買収し、写真情報を収集

#情報収集方法の根本を変えるHuaweiの戦略

GoogleとFacebookに共通しているのは、情報収集の方法は、消費者に各種情報をターゲッティング広告に使う旨が書かれた誓約書に同意をもらった上で、あくまで消費者の**能動的な行動**を情報収集していることです。

言い換えると、**受動的な行動**を勝手に情報収集し、それをターゲッティング広告に使う行為は、欧米諸国から制限をかけられてきました。

- Fitbitの買収条件が、「健康ログ情報ををターゲッチング広告に使わないこと」になったこと
- LibraにNGが出たこと(ただ、これはステーブルコインとしたことの方が大きいと思いますが。)

これをひっくり返そうと考えているように見えてるのがHuaweiの基地局戦略です。

要は、Huaweiの基地局を通った携帯電話の情報を、Huaweiがターゲッティング広告に利用する、という戦略です。消費者は携帯電話を使う際に、どの基地局を使うかなんて知る由も無い訳で、つまりは、欧米諸国が禁止と定めてきた消費者の受動的な行動の情報収集を行おうとしているように見える、と言う訳です。

これが行われてしまうと、Huaweiが入手できる情報量は、Google, Facebookを遥かに上回ることが容易に想像できます。行動ターゲッティング広告の成功に必要な2つの項目

- 多くの情報を集められること
- 詳細な情報を集められること

を、HuaweiがGoogle, Facebookを上回れてしまう事態になります。

#Huaweiに留まらない中国企業の情報収集企業の台頭
近年は、Huaweiに止まらず、情報収集力を持つ中国企業も増えてきました。

- ショート動画SNS: TikTok
- 動画チャットアプリ: Zoom
- ネットワークゲーム: Tencent(LoLの開発元のriot game, Fortniteの開発元のEpic gameの親会社)

対するアメリカは、ここ10年位、GAFAを喰らうような企業は現れていません。

この状況は、ポストGAFAは中国企業のものになる、を意味します。アメリカとしては、難癖つけてでも阻止したかった、というのが、今のトランプの気持ちにあったのではないでしょうか?
(「セキュリティリスク」は、根拠となる事実がまだ明確になっていない以上、今は「難癖」としかいいようがありません。)

#二重苦のアメリカを救うのは誰?
本来は、勝手に中国に対抗できるサービスを提供できる企業が生まれてくるのがアメリカという国なのですが、残念ながら、今のアメリカには、様々な理由で、その力がありません。Uber, Airbnbなど、既存のサービスに関わる人材をコストとしか捉えられないような企業が台頭してしまったのが、その一例です(日本も陥ったコストカット病。アップルも半分位落ちかけている病)。前回の選挙でトランプが勝ったのは、この状況を打破したいアメリカの意思だと捉えましたが、コロナという別の病も抱えてしまった今、トランプという劇薬を打ち続けていいのか、冷静に判断できる状況では無くなってしまいました。

今年の選挙でトランプが負けるようなことがあれば、確実にポストGAFAは中国企業のものになるでしょう。少なくともStay homeで最も強みを出せる分野であるゲームの分野において、アメリカは、マインクラフト、GTA以降、全く存在感を示せていません。(LoL、FortniteはTencent運用で成功したと見做しています。)

今年のアメリカ選挙は、テクノロジー業界においても目が離せないものと捉え、見守っていきましょう。
mini_magickでmini_magick_processing_errorが出る

##画像ファイルを選択して、登録ボタンをおすもエラーが出る。
エラー文には以下の文章が含まれていた。

```
mini_magick_processing_error
```

解決方法
ターミナルで以下のコマンドを入力してからサーバーを再起動したら直った。

```
brew install imageMagick 
```

参考
http://cojirooo777.blog.fc2.com/blog-entry-37.html
JSのfor in,for ofについて

最近までfor inしか使ってなかったのでまとめるよ
###for inの場合

for inはインデックス番号が入るだけ

```JS
const users = [
    {
        id: 1,
        name: 'hiroto',
        age: 21,
    },
    {
        id: 2,
        name: 'hiroko',
        age: 40,
    },
    {
        id: 3,
        name: 'hiroshi',
        age: 12,
    }
]

for (let i in users) {
    console.log(i);
}

//結果

0
1
2
```

###for ofの場合

値が入る

```JS
const users = [
    {
        id: 1,
        name: 'hiroto',
        age: 21,
    },
    {
        id: 2,
        name: 'hiroko',
        age: 40,
    },
    {
        id: 3,
        name: 'hiroshi',
        age: 12,
    }
]

for(let user of users) {
    console.log(user);
}

//結果

{id: 1, name: "hiroto", age: 21}
{id: 2, name: "hiroko", age: 40}
{id: 3, name: "hiroshi", age: 12}
```

単純明快、for inばっかり使ってたからなんか汚かったんだなぁ
scopeでnilを返すとallが適用される

scopeで`find`や`find_by`、`first`や`last`メソッドは使うべきではない

```ruby:user.rb
scope :normal, -> (type) { where(type: type).first }
```
このようなscopeでnilを返すと、allが適用されてしまい、`User.all`が返ってしまう。
これを防ぐためには、scopeでは、ActiveRecord::Relationオブジェクトを返すようにする。
なので、ここでは、`first`メソッドを付けずに`where`メソッドで取得する。
whereメソッドでは対象のデータない場合は、nilは返さず、`[]`を返す。
この`[]`はActiveRecord::Relationオブジェクト。

```ruby:user.rb
scope :normal, -> (type) { where(type: type) }

def normal_record(type)
  normal(type).first
end
```
もしくは、scopeの呼び出し先で、`first`メソッドを使うのもあり。
`normal(type).first`

#### 参考記事
- https://techracho.bpsinc.jp/hachi8833/2018_11_13/64284
【Python】データサイエンス100本ノック（構造化データ加工編） 018 解説

- データサイエンス100本ノックをやりきる会を作りました🎉
- こちらの[Slack招待URL](https://join.slack.com/t/data-science-100nocks/shared_invite/zt-gfncg9vm-8W8b3UrDg8R~TKaqUkQpgw)からご参加ください！！
- ぜひ一緒に励まし合いながら、データサイエンス100本ノックをやり切りたいと思っています！

##Youtube
[動画解説](https://youtu.be/7ceMjih3vOs)もしています。

##問題
P-018: 顧客データフレーム（df_customer）を生年月日（birth_day）で若い順にソートし、先頭10件を全項目表示せよ。

##解答
```:コード
df_customer.sort_values('birth_day', ascending=False).head(10)
```

##出力
|  | customer_id | customer_name | gender_cd | gender | birth_day | age | postal_cd | address | application_store_cd | application_date | status_cd |
|--:|:--|:--|--:|:--|:--|--:|:--|:--|:--|--:|:--|
| 15639 | CS035114000004 | 大村 美里 | 1 | 女性 | 2007-11-25 | 11 | 156-0053 | 東京都世田谷区桜********** | S13035 | 20150619 | 6-20091205-6 |
| 7468 | CS022103000002 | 福山 はじめ | 9 | 不明 | 2007-10-02 | 11 | 249-0006 | 神奈川県逗子市逗子********** | S14022 | 20160909 | 0-00000000-0 |
| 10745 | CS002113000009 | 柴田 真悠子 | 1 | 女性 | 2007-09-17 | 11 | 184-0014 | 東京都小金井市貫井南町********** | S13002 | 20160304 | 0-00000000-0 |
| 19811 | CS004115000014 | 松井 京子 | 1 | 女性 | 2007-08-09 | 11 | 165-0031 | 東京都中野区上鷺宮********** | S13004 | 20161120 | 1-20081231-1 |
| 7039 | CS002114000010 | 山内 遥 | 1 | 女性 | 2007-06-03 | 11 | 184-0015 | 東京都小金井市貫井北町********** | S13002 | 20160920 | 6-20100510-1 |
| 3670 | CS025115000002 | 小柳 夏希 | 1 | 女性 | 2007-04-18 | 11 | 245-0018 | 神奈川県横浜市泉区上飯田町********** | S14025 | 20160116 | D-20100913-D |
| 12493 | CS002113000025 | 広末 まなみ | 1 | 女性 | 2007-03-30 | 12 | 184-0015 | 東京都小金井市貫井北町********** | S13002 | 20171030 | 0-00000000-0 |
| 15977 | CS033112000003 | 長野 美紀 | 1 | 女性 | 2007-03-22 | 12 | 245-0051 | 神奈川県横浜市戸塚区名瀬町********** | S14033 | 20150606 | 0-00000000-0 |
| 5716 | CS007115000006 | 福岡 瞬 | 1 | 女性 | 2007-03-10 | 12 | 285-0845 | 千葉県佐倉市西志津********** | S12007 | 20151118 | F-20101016-F |
| 15097 | CS014113000008 | 矢口 莉緒 | 1 | 女性 | 2007-03-05 | 12 | 260-0041 | 千葉県千葉市中央区東千葉********** | S12014 | 20150622 | 3-20091108-6 |

##解説
・PandasのDataFrame/Seriesにて、データをソートする方法です。
・情報を昇順あるいは降順に並べ替えて見たい時に使用します。
・**'sort_values(<文字列>)'は、指定した文字列を昇順あるいは降順に並べ替える関数**です。
・今回の場合、birth_day を降順に並べ替える（=若い順に並べ替える）ため、'sort_values('birth_day',ascending=False)'と記載しています。

※sort_valuesの参考記事は[こちら](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sort_values.html)です。
画面解像度を４Ｋとワイドの切替とWindowsに関するヌルゲーマーの愚痴

## ここにコードは書いてないです

あまりにも書くことないので、参考にしたことを書きます。

## 結論

解像度の切替えを簡単にするにはこれを使おう。

### 参考元

[PowerShellを使って、画面解像度をワンタッチで切り替えるアイコンをデスクトップに作成する \- Qiita](https://qiita.com/zamaezaaa/items/c4482fed9b391e3cb54a)

### 参考元の参考元

[スクリプト Set\-ScreenResolution](https://gallery.technet.microsoft.com/scriptcenter/2a631d72-206d-4036-a3f2-2e150f297515#content)

## 解説

参考元の参考元であるSet-ScreenResolutionは、[Scripting Blog \| A place to learn about PowerShell and share stories of automation](https://devblogs.microsoft.com/scripting/)で公開されているPowerShellスクリプトである。

こいつをps1スクリプトとしてローカルのPowerShellスクリプトとして作ってあげる。

それをbatファイルから読み込むことでデスクトップ上でアイコンダブルクリックで切替て簡単！というのが、参考元の記事の意図である。

実際にGUIでしようとすると、右クリック→画面の設定→解像度の変更→適用…と面倒くさいことこのうえない。そりゃまあ、頻繁に切り替えるものではないからね。

補足として、なぜbatファイルからPowerShellを呼び出すの？という面倒くさいことをしなければならない理由が、参考元の記事で一番キーなところ。

理由は、bat時でExcectionPolicy（実行権限）をUnrestrictedに指定してやることで実行するためなのだ。平たく言うとUnrestrictedでローカル上で作ったファイルは証明書とかの処理を無視することができる。

PowerShellではそれ以外の方法もあるけど、セキュリティが落とす設定をしたりしないといけないし、証明書作ったりとか面倒臭いことこの上ないので、こういうことをしていると理解いただきたい。

### 愚痴

Windowsの画面設定とかこの手の内部設定を変えるための技術って、結構レガシーになっている感じがある。そういうとき、過去のスクリプトから探っていくっていう方法しかないよね。そもそも、WindowsはWin32API以外を使う方法をちゃんと提供してほしい。一応、.NetFrameworkでも提供している部分はあるけど、ホント部分的。

でも、レガシーがちゃんと残されるかすごく不安よね…。

[TechNetギャラリーの終了\| Microsoftドキュメント](https://docs.microsoft.com/ja-jp/teamblog/technet-gallery-retirement)

MicrosoftでWindowsの仕様ってちゃんと残ってるのかな？　何にせよ、こういうサイトは残していかないとWindowsの仕様ってオーパーツ化するだろうな、って思う。

あと、PowerShell実行をps1ファイルから実行しようとするとちゃんと証明書とか作らないといけなくて結構面倒くさい。

セキュリティを考えた結果、証明書作らせたりとかしたりしてるんだろうけど、不便でこういうところがセキュティホールにつながってるんじゃね？　こういうところがUNIX系のShellと比べて極めて劣っているってすごく思ってるんだけど、とりあえず話をおいておく。

## なぜ解像度を変えるのか

**４Ｋディスプレイで映画みたりゲームしたい！**

けど、結構４Ｋ（3840\*2160）の解像度で作業するのって細かさ過ぎて面倒くさいのよね。まだ４Ｋが普及しているわけでもないし、４ＫってだけでGUIのスペックも食うので、通常はFull-HDの解像度（1920\*1080）で作業をしているのです。

その切替のためですね。やっぱり４Ｋ画質はすごくキレイ！　今後８Ｋも使われるんだろうけど、まだ一般人が使うような価格帯にはならないよねえ。

という、ただの愚痴でした。
[rails]deviseで登録・ログインができない問題

#deviseで登録・ログインができない
deviseでユーザー登録とログイン画面を作成した後に、
デフォルト(email)以外の情報で登録・ログインをしたい時用の方法です。

viewページのフォームを編集したのに、登録・ログインできないトラップがありますので、
参考にしてください。

以下の場合、sing_upとaccount_updateのkeyを変更しています。


```app/controllers/application.controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
    def configure_permitted_parameters
		if resource_class == User
   			devise_parameter_sanitizer.permit(:sign_up, keys: [:name,:email])
   			devise_parameter_sanitizer.permit(:sign_in,keys:[:email])
   			devise_parameter_sanitizer.permit(:account_update,keys:[:name,:email])
    end
  end
end

```

###defore _action


```
before_action :configure_permitted_parameters, if: :devise_controller?
```

before_actionは一種のフィルターのようなもので、application.contollerに記述することで、全てのコントローラーに対して、実行されます。

:devise_contoller?とはdeviseを生成した際にできるヘルパーメソッドの一つで、
deviseに関連する画面に飛ぶなら、ということです。
こうすることで全てのdevise画面でconfigure_permitted_parametersが起動します。

つまりもしそれがdeviseのコントローラーだったら（devise_controller?というメソッドの返り値がtrueだったら）configure_permitted_parametersを呼び出すということです。
CadQueryを使って、3Dプリンタデータ(STLファイル)を作成する

# はじめに

本記事は、CadQueryを使って、3Dプリンタデータ(STLファイル)を作成する方法について紹介します。
CadQueryとは、3Dモデルを作れるpythonのライブラリです。

![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/decc7dd9-ca55-d506-2290-5e3154d67d46.jpeg)


# きっかけ

電子工作の幅を広げるために、3Dプリンタを購入しました。
3D CADツール自体は使ったことはなかったので、いろいろと調べたところ、
自分にはCadQueryとFreeCadが使いやすかったです。
（今回は、CadQueryのみ）


# CadQueryについて

以下が公式の情報となります。
日本語の記事が極端に少ないです。

## 情報

- CadQuery / cadquery
  - https://github.com/CadQuery/cadquery
- CadQuery 2.0 Documentation
  - https://cadquery.readthedocs.io/en/latest/
- CQ-editor
  - https://github.com/CadQuery/CQ-editor

## インストール・起動

インストール方法は複数ありますが、今回は一番簡単な
CQ-editorをダウンロードする方法で実施します。

※windows10 64bit Homeの場合

[CQ-editor](https://github.com/CadQuery/CQ-editor)より、
"Installation" - "RC1 Windows"よりダウンロードします。

"CQ-editor-0.1RC1-win64.zip"を解凍し、"CQ-editor.exe"を実行し起動します。


## 立方体を作成する

### ①コードの作成

エディタ部①に、下記のコードを貼り付けます。

```python:test.py
import cadquery as cq

result = cq.Workplane("front").box(2.0, 2.0, 0.5)
show_object(result)
```

### ②コードの実行

再生ボタンを押して、コードを実行します。
立方体が作成されます。

![0001.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/fbe8e49f-5f75-4020-e96b-69cc5175a563.png)


# タッキング穴付きフックをつくる

ページの先頭に記載した写真のフックを作成します。

## コードの作成

```python:test.py
# This is a CadQuery script
import cadquery as cq
import itertools

# 長さと厚さの定義
X1 = 40.0
X2 = 2.0
X3 = 2.0
Y1 = 40.0
Y2 = 2.0
Y3 = 10.0
Z1 = 40.0

# xy平面で記述する
result0 = (cq.Workplane("XY")
           .moveTo(0,0)
           .lineTo(X1,0)
           .lineTo(X1,Y1)
           .lineTo(X1-X2,Y1)
           .lineTo(X1-X2,Y2)
           .lineTo(X3,Y2)
           .lineTo(X3,Y3)
           .lineTo(0,Y3)
           .close())

# z軸方向に押し出す
result = result0.extrude(Z1)

# タッキング用穴
# yz平面 and xz平面への穴の定義
HOLE_Xs = [9*1, 9*3, 9*5, 9*7, 9*9, 9*11]
HOLE_Ys = [9*1, 9*3, 9*5, 9*7, 9*9, 9*11]
HOLE = 5.0

# 穴あけ
for hole_crd in itertools.product(HOLE_Xs, HOLE_Ys):
    result = result.faces(">X").workplane().rect(hole_crd[0], hole_crd[1], forConstruction=True).vertices().hole(HOLE)
    result = result.faces(">Y").workplane().rect(hole_crd[0], hole_crd[1], forConstruction=True).vertices().hole(HOLE)

# オブジェクトの表示
show_object(result)
```

## xy平面のコードとの紐づけ

長さと厚さの定義との座標の関係は以下となります。
![0002.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/96dfe1ff-810e-dfc6-81c6-6d3fc5676d83.png)


## コードの実行

コードを実行すると、フック付きのモデルが作成できます。

![0003.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/91ce11f7-db95-5d4a-3416-d0716b88fb6a.png)


## STLファイルを出力する

オブジェクトを選択した後、"Tools" - "Export as STL"を選択します。

![0004.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/1645a919-d5d6-aacc-8d88-16f2589d9721.png)

ファイル名を指定し、保存します。


あとは、3Dプリンタで印刷します。

![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/decc7dd9-ca55-d506-2290-5e3154d67d46.jpeg)


# さいごに

3Dモデルをコードでかけるのは非常に助かります。
【SQL】コマンド一覧

#目次
- データベースの確認
- データベースの作成
- データベースの指定
- テーブルの作成
- テーブルの確認
- カラムの確認
- テーブルにデータを挿入
- テーブルのデータ検索
- 条件を指定して検索
- 複数の条件
- データの更新
- データの削除
- SQLの正常に実行されたかの確認

#データベースの確認

```
SHOW DATABASES;
```

#データベースの作成

```
CREATE DATABASE データベース名; 
```

#データベースの指定
テーブルを作成する際のDBの指定

```
USE データベース名; 
```

#テーブルの作成

```
CREATE TABLE テーブル名 (カラム名1 カラム型,カラム名2, カラム型,カラム名n, カラム型);　　
例：CREATE TABLE meibo (id INT, name VARCHAR(100), name_kana VARCHAR(200), prefecture VARCHAR(50), address TEXT, age INT);　
```

#テーブルの確認

```
 SHOW TABLES;
```

#カラムの確認
カラム名：Field
カラム型：Type

```
DESC テーブル名;
例：DESC meibo;
```

#テーブルにデータを挿入
※文字データは「'」で囲む

```
INSERT INTO テーブル名 (カラム名1, カラム名2, ...) VALUES (値1, 値2, ...); 
例：INSERT INTO meibo (id, name, name_kana, prefecture, address, age) VALUES (1, 'テスト　太郎', 'てすと たろう', '東京都', '東京都千代田区丸の内１丁目', 25);
```

#テーブルのデータ検索
※＊はワイルドカードですべてを表示する場合に使用

```
SELECT * FROM テーブル名; 
```

#必要なカラムのデータのみ抽出
```
SELECT カラム名1, カラム名2, ..., カラム名n FROM テーブル名; 
例：SELECT id, name FROM meibo;
```

#条件を指定して検索

```
SELECT * FROM テーブル名 WHERE 条件
例：SELECT * FROM meibo WHERE age >= 32;
```

#複数の条件

```
SELECT * FROM テーブル名 WHERE 条件　AND 条件（ORでも）
例：SELECT * FROM meibo WHERE prefecture='東京都' OR age >= 35;
```

#データの更新、追加

```
UPDATE テーブル名 SET カラム名1 = 値1, カラム名2 = 値2, ..., カラム名n = 値n WHERE 条件文; 
例：UPDATE meibo SET age = 25 WHERE id = 3;
```
この場合ID3のageを25に変更or追加

#データの削除

```
DELETE FROM テーブル名 WHERE 条件文; 
DELETE FROM meibo WHERE id > 7;
```

この場合ID7以上のIDデータは削除する
間違って消してしまった場合INSERTで追加

#SQLの正常に実行されたかの確認
下記コードが出ていると正常に実行されたとみなされる

```
Query OK
```
VirtualBox上で動くUbuntuの解像度を変更する


# 環境

VirtualBox 6.1
Ubuntu 18.04

注意：日本語ではなく英語環境でUbuntuをインストールしています。

# 解像度の変更方法

提示した画像に沿って操作すれば問題なく変更できると思います。
英語環境のため、テキストは適宜読み替えてください。



## デスクトップ画面の左下、"Show Applications"を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/460d00ef-665d-5bb5-c630-a0bd9acc8591.png)

検索ボックスに"dis"と入力し、SettingsのDisplaysを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/da9d8e17-3906-767c-a3ec-6515c1902d19.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/46020a9a-289d-c9ed-b2d4-0d94d921e52a.png)


## Displays内のResolutionから、任意の解像度を選択する


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/01a0454f-97e1-cd1e-db92-bc7cb878e368.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/c8a218e5-8de6-8378-47c3-fec6693b3d6a.png)

## 変更した内容を適用する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/45a625f3-590f-dbba-f864-e0fbe5ab7569.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/99c2191c-0dad-51a9-86cd-75d317a20e74.png)
不安定なテストを書いてはいけない3つの理由

# はじめに
不安定なテストはITエンジニアの敵であると言っても過言ではありません。今後不安定なテストが生み出されなくなるといいなという願いを込め、この記事では不安定なテストがいかに問題があるかについて皆様と一緒に考えることができたらと思います。
普段、不安定なテストに悩まされている方にとっては目新しい内容ではないと思います。

# 不安定なテストとは？
一般的に使われている言葉かどうかはよくわからないのですが、とりあえずこの記事では「コードを何も変更していないのにテスト結果が変わる場合があるテスト」のことを「不安定なテスト」と呼ぶことにしています。
テスト結果が変わる、とはつまり「普段は成功するが、コードを変更していないのに気まぐれに失敗することがある」みたいな感じです。
なお、ここで言う「テスト」とは手動テストではなく、主にユニットテストのことを想定しています。

以下、早速本題に入っていきます。

# 3つの理由
## 理由1 テストの失敗が軽視されるようになる
テストが失敗するということは、通常であれば何かバグがあることを示します。しかし、不安定なテストが存在する場合はどうでしょうか？
本来、テストの失敗とは異常事態であるべきと思います。しかし、不安定なテストが存在するとテストの失敗が「普通のこと」になってしまいます。
不安定なテストが存在しなければ「テスト失敗 = バグの発生」と言えると思います[^bug]が、不安定なテストが一つでも存在すればこの等式は崩れます。不安定なテストは、バグがなくても失敗することがあるためです。
するとどうなるか。テストの失敗がバグ発生を示すとは限らないことになるため、テストが失敗してもあまり真剣に捉えられなくなります。「あーはいはい、どうせいつものアレが失敗してるんでしょ」みたいな感じで。
そうしてテスト失敗が軽視されるようになると、テストが失敗した時にその内容の確認を怠ることに繋がり、バグが見逃されるようになる恐れがあります。
[^bug]: 単にテストコードの修正漏れということもありますが、それはテストコードのバグってことで…
また、そのようにテストの失敗が「普通のこと」になるとテストの失敗に対してあまり抵抗がなくなるため、修正の影響でテストが失敗することがあっても、それを修正する気があまり起こらないなんてことにもなりかねません。

## 理由2 テスト結果を通知する仕組みが機能不全に陥る
偉そうなことを書いていますが、残念ながらうちのチームも不安定なテストをいくつも抱えています。個々のテストの失敗率はそれほど高くなくても、不安定なテストの数が多いと毎日のように何かしらのテストは失敗します。
うちのチームではテストが失敗したらSlackに通知されるようになっているのですが、毎日のように何らかのテストが失敗するということは、毎日のようにSlackに失敗通知が来るということであり、正直ウザいです。
また、私はテスト失敗通知が来たら自分の担当でない場合でも結果を確認するようにしているのですが、毎日のように確認しなければならないのでうんざりすることもあります。
するとどうなるか。失敗を通知するチャンネルを抜けてしまうとか、通知を切るとか、そういった形でテスト結果を確認しなくなってしまう恐れがあります。
幸い、うちのチームではそこまでの事態にはなっていないので想像も含んでいますが、不安定なテストの数が増えてしまうといずれそうなるという可能性は否定できません。

## 理由3 そもそもテストが機能しない
そもそもなぜテストを実行するのかというと、コードの修正に問題がないかどうかを確認するためです。通常であれば、修正に問題がなければテストが一件も失敗せず、とりあえずは安心できます。（あくまでもとりあえずは）
しかし不安定なテストが一件でも存在すると、本当は修正には問題ないのに不安定なテストがたまたま失敗し、原因調査で時間を無駄にしたり、原因がわからなくて辛い思いをしたりするなんてことになりかねません。
また、「一見するとコードの修正と関係なさそうに見えるが、実は修正の影響で失敗したテスト」なんてものがあった場合に、「いつもの不安定なテストが失敗しただけで、修正には問題ない」と判断してしまってバグを見逃すという恐れもあります。まあ、その場合はその後該当のテストが常に失敗し続けるはずなのでそのうち気づくかもしれませんが、気づくのが遅くなるというだけでも十分に悪いことです。
こうなるとコードの修正に問題ないかどうかをテストの結果から読み取ることが難しくなるため、そもそものテストの目的を果たせてるのかどうかすら怪しくなります。

# テストを不安定にさせやすいコード
「処理時間に依存するテスト」や「ファイルやDBなどの外部リソースに依存するテスト」、「マルチスレッドで実行されるテスト」などは不安定なテストになりやすいので、そういったテストを書く場合は十分に注意する必要があります。
この節はちゃんと書こうとすると膨大な量になってしまうのと、それ以前にこの記事の主な目的は「不安定なテストがいかに問題があるか認識していただく」ことなので、ここは敢えてさらっと流します。
ただ、むしろここが肝心だろうと思われる方も多いかもしれないので、別の記事として書けるといいですね。（書くとは言っていない）

# 不安定なテストを見つけた時の対処
もちろんテスト結果が安定するテストするように修正するのがベストなので、可能な限り修正するべきです。しかし、簡単には修正できない場合もあると思います。
その場合はテストの趣旨を確認して、不要だと判断できれば消すなり実行をスキップさせるなりするといいですね。でも、不要と判断できるケースは少ないでしょうね…
修正も実行スキップも難しいのであれば、せめてそのテストが不安定であるということを記録するのがおすすめです。私は、不安定なテストを見つけたらRedmineでチケットを発行するようにしています。何か記録があれば、テストが失敗した際にそれが既知の不安定なテストなのかどうかを確認できるため、多少はマシになります。
本当はこの節の内容ももう少しちゃんと書くべきなのかもしれないですが…それも書くとしたら別の記事ですね。（書くとは（ｒｙ）

# 終わりに
これまで見てきたように、不安定なテストは問題を多く含みます。できるだけそのようなテストを書かないように心がけたいところですね。（もちろん私も）
具体的にどうすればいいのかということはこの記事ではあまり書いていないのですが、まずは心がけるところから始めるのが重要だと思います。
uipath 3次元配列について

uipathで3次元配列を使う必要がでたので試してみた。

まず3次元のstring配列の変数を設定する。(hensuu string[][][])
![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/848866c2-a238-56ac-3ff9-415e63740910.png)


そしてinvoke codeアクティビティでこのように書く。
注意点としては最初に3次元配列をNEWしているが、
その下位の2次元目にあたるところもNEWしないと「実体がない」とエラーがでる。
![qiita2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/52f6c16c-e062-a5fe-1dc7-e56476e4ab99.png)


その後繰り返しアクティビティでセットしたデータを読み出す。
![qiita3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/cbabbe66-797a-59c9-f520-8cf0ae621628.png)
![qiita4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495919/bf617b2f-17d3-760d-47d6-6b7e02ed2ddb.png)

これで設定した文字列をメッセージボックスアクティビティですべて呼び出せた。
大きさが奇数の時の numpy, scipy の irfft

`scipy.fft.rfftn` が実数値のn次元フーリエ変換 (FFT)、`scipy.fft.irfftn` はその逆変換なので、普通

```python
irfftn(rfftn(a)) == a
```

を浮動小数点数の精度の範囲内で期待するけど、aの大きさが奇数の時そうはならない。

```python
import numpy as np
from scipy.fft import rfft2, irfft2

a = np.eye(5)            # 5 x 5 
irfft2(rfft2(a)).shape   # => (5, 4)
```

`rfft2(a)` は複素数の shape=(5,3) になるけど、これが shape=(5, 5) の実数から来たという情報が失われているので元の大きさを irfftn に渡さないといけない:

```python
a = np.eye(5)            # 5 x 5 
aa = irfft2(rfft2(a), a.shape)  # => a == aa
```

これで期待通り `a == aa` になる（もちろん浮動小数点数の範囲内で）
MySQLとPostgreSQLでのtimezoneの取り扱いの違い

#環境
 - MySQL 5.6
 - PostgreSQL 12
 - Grafana 7.0.0
 - Windows
 - DB,クライアントのタイムゾーンはAsia/Tokyo

# 内容
DATE型カラム(hogedate)に'2020-07-20'が入っている場合
MySQLでそのカラムをUNIX_TIMESTAMP(hogedate)すると2020-07-19  15:00:00のUNIX TIMESTAMPが得られる。
PostgreSQLでそのカラムをEXTRACT(EPOCH FROM hogedate)すると、2020-07-20 00:00:00のUNIX TIMESTAMPが得られる。


PostgreSQLは全体的にtimezoneを考慮しない方針の様子
SELECT EXTRACT(EPOCH FROM timestamp '2020-07-20 00:00:00')
 => 1595203200   (2020-07-20 00:00:00UTCのUNIX時間)
SELECT EXTRACT(EPOCH FROM timestamp with time zone '2020-07-20 00:00:00')
 => 1595170800　   (2020-07-19 15:00:00UTCのUNIX時間)

試してないけど、普通にテーブルに入れて試しても同じ結果になるだろう。
日本国内に閉じたシステムであれば、　無理に考慮してくれない方が扱いやすい。


# 調べた経緯
GrafanaでMySQL内に入っている日時データを取得してグラフ表示しているが、どうも数が合わない。

DATEカラムを時間軸にするようなグラフを書く場合、$__timeGroupAlias(hogedatecol, '1d', 0)などとGrafanaマクロを使ってると、UNIX_TIMESTAMP(hogedatecol)が取られるが、この場合は、9時間前のUNIX時間が返ってしまう。
例）カラムの値が'2020-07-20'だと、MySQLでその値をUNIX_TIMESTAMP()すると、'2020-07-19 15:00:00'のUNIX時間が帰ってくる。そのあとで、上記例だと1日で丸めるために、86400(1日の秒数)で割って、掛け戻してるため、2020-7-19で丸められてしまう。。。

対応としてはどうするべきなのだろうか？
- Grafanaのマクロを使用しない
　 => 基本これかな。面倒だけど。　
- DBのタイムゾーンの設定をしない
　 => 今回は扱う必要がないのでこれでもいいけど、DBがUTC、クライアントがAsia/Tokyoの場合の動きを確認？
- PostgreSQLを使う
　 => 今回はお遊びツールなのでこれでもいいけど、ちょっと今から返るの面倒だな。
　　　プロダクトはMySQL/MariaDBなのでDBを2つ入れるのは非力マシンなので避けたいし。
- その他
ec2にdocker環境を構築してみた

railsアプリをec2を利用して本番環境でデプロイした際に、dockerを導入してみました。
ec2にdocker及びdocker-composeをインストールするには以下を参考にしました。

https://qiita.com/y-do/items/e127211b32296d65803a

ec2にsshログインし、ｍｙｓｑｌにマイグレーションするまでは以下が詳しく書いてあります。

https://qiita.com/naoki_mochizuki/items/f795fe3e661a3349a7ce

## MySQLの設定以降
amazon linuxではデフォルトがmariadbのため以下のエラーが出ます。

```
$ sudo service mysqld start
Redirecting to /bin/systemctl start mysqld.service
Failed to start mysqld.service: Unit not found.
```
該当する方は以下を参考にmysqlをインストールしてください。

https://qiita.com/hamham/items/fd77bb0bb167a150dc8e#mysql57%E3%81%AE%E5%B0%8E%E5%85%A5


また、ここまで手順どおり進めても以下のコマンドでエラーが出ます。

```
$ rake db:create RAILS_ENV=production
rake db:migrate RAILS_ENV=production
rake aborted!
Mysql2::Error::ConnectionError: Unknown MySQL server host 'db' (2)
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
```
こちらはdockerの導入のためにdatabase.ymlの設定を以下のように変更したためです。

```
host: localhost #変更前
host: db #変更後
```

そのため、データベースの作成にはdockerコマンドで実行する必要があります。
しかし、dockerコマンドを実行しようとすると以下のエラーになります。

```
ERROR: Couldn’t connect to Docker daemon at http+docker://localhost – is it running?
```
権限不足によるエラーのため、以下を参考に権限を変更してください。
https://qiita.com/dnnnn_yu/items/14a31721a2870b735938

ここまで進んだらdockerコマンドが使用できると思いますので以下のコマンドを実行して下さい。

```
$ docker-compose up -d　コンテナの作成(バックグラウンドで起動モード)
$ docker ps -a 起動しているかの確認
```

データベースを作成しようとするとエラーが出ます。

```
$ docker-compose run web rails db:create RAILS_ENV=production
Mysql2::Error::ConnectionError: Access denied for user 'root'@'172.18.0.5' (using password: NO)
```

これは参考サイトでdatabase.ymlのproduction環境のpasswordが設定されていないからです。
以下のように設定してあげましょう。

```
// database.yml
production:
  <<: *default
  host: <%= ENV['DB_HOST'] %>
  database: <%= ENV['DB_DATABASE'] %>
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
```
これでデータベースの作成ができると思います。

```
$ docker-compose run web rails db:create RAILS_ENV=production
```
[rails]deviseで作成したviewページの編集が反映されない

#deivseで作成したviewページの編集が反映されない
deviseでデフォルトのログインページを編集し、画面を確認したところ、
編集内容が反映されていない問題が発生したので、解決方法を記録しておきます。

```config/initializers/devise.rb
#config.scoped_views = false の記述箇所のコメントアウトを外し、falseをtrueに変更だけ
config.scoped_views = true
```

これだけで解決しました。
Docker+rails環境におけるGemfileの更新方法（初学者向け）

rails-tutorial２週目&開発は、Docker+rails5の環境でやる事に致しました。

そんな中で、ここは気をつけるべきというのを、自分の備忘録も兼ねて書くことにしようと思います。（もし、間違った認識等があれば初学者であるため強めに指摘いただけるとすごく嬉しいです）

##そもそもDocker環境では”ただの”railsコマンドは使えない
多分知ってる人からしたら当たり前だし、「何言ってんだこいつ？」状態だと思うのですが、これがわからなくてかなりハマりました。

Docker上で構築したrails環境では、ただのrailsコマンドは使えません。

例えば、新しくコントローラーを作成する際なんかは、

`rails g controller nanigasi(コントローラー名)　nanigasi（アクション名）`

みたいな作り方すると思うのですが、このコマンドDockerで構築したrails環境でそのままターミナルで打ってもエラーが出てしまいます。

基本的にDocker環境でrailsコマンドを叩く時は、

`docker-compose run web rails g controller nanigasi(コントローラー名)　nanigasi（アクション名）`
のように、railsコマンドを叩く前に、`docker-compose run web ~`が必要になります。

もちろんですが、テストを走らせる時も`docker-compose run web rails test`となります。

##ではGemfileを編集するときは？

これも先ほどと同じです。

任意のGemfileを編集して、

`docker-compose run web bundle install`

コードを実行し、アプデをしろと怒られたら、

`docker-compose run web bundle update`

になります。そして再びインストール致します。

そして忘れていけないのは、gemを編集したら必ずコンテナを再buildする必要があります。

なのでこちらのコード。

`docker-compose up --build`

必ずこの手順を踏んで、実行しましょう。
adb コマンド - Android Debug Bridge

# はじめに
Android 開発に欠かせない adbコマンドについて基本的なことをまとめます。
Android の SDK には ADB(Android Debug Bridge)というツールが用意されており、
Android 開発をしていれば一度は使う機会があります。

# adb とは
Android Debug Bridge は adb と省略されます。
これはAndroid SDK の platform-tools に含まれるツールです。
このツールを用いると、現在利用可能なデバイス・エミュレータの列挙、シェルコマンドの発行、ファイルの転送などが行えます。
Android 端末を adb コマンドで操作できます。

# 基本

## バージョンを表示
```sh:コマンド
adb version
```
```shell-session:結果
Android Debug Bridge version 1.0.41
Version 30.0.3-6597393
Installed as {インストールディレクトリ}/adb.exe
```

## 端末の確認
```sh:コマンド
adb devices
```
```shell-session:結果
List of devices attached
emulator-5554   device
```

## アプリのインストール
デバイスにインストール

```sh:コマンド
adb install xxxxx.apk
```
デバイスに上書きインストール

```sh:コマンド
adb install -r xxxxx.apk
```
複数のデバイスを接続している時は、端末を指定

```sh:コマンド
adb -s {デバイス} install -r xxxxx.apk
# 例 adb -s emulator-5554 install -r xxxxx.apk
```

## ログ

```sh:コマンド
adb logcat
```
## shell

```sh:コマンド
adb shell
```
画像処理で賢く飛ぶドローンを作りたい(2)〜Pixhawkの初期設定をQGroundControlで実施する〜

# Pixhawkの初期設定
QGroundControlがインストールできて、ドローンに載せたPixhawkを繋いで認識するようになったら（[参考記事](https://qiita.com/ezokitsune/items/a9c2bfdd9d8af50bafdc)）、Pixhawkの初期設定というか、ドローンが飛ぶための初期設定を実施する。QGroundControl(PC)とPixhawkの間はUSBケーブルで繋いだ。設定中に機体をぐるぐる回したりするので、USBケーブルは可能な限り長いものが良い。

Linux PC(ubutu 18.04)でQGroundControlを起動する

```command:端末
$ cd [QGroundControlをおいたディレクトリ]
$ ./QGroundControl.AppImage
```

ウィンドウで赤くなっているところがなくなるようにひたすら設定していく。

## Airframe

Aurframeの設定ではドローンの形状を選択する。普通の４つプロペラのクアッドコプターであれば、Generic Quadcopterでいいと思う。このリストの中に買った機体があればラッキーなのでそれを選べば良いと思う。
![Screenshot from 2020-08-01 02-02-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/0861ae3e-0270-5c79-f38b-77339ffa7a3c.png)

## Sensors

Pixhawkに内蔵されている、加速度、ジャイロ、磁気コンパス、気圧の各種センサの初期化をしていく。
![Screenshot from 2020-08-01 02-07-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/3bc19270-747d-9c11-726e-35fef0932657.png)

- Compass
コンパスなので方位磁針（地磁気センサ）。Pixhawkはドローンに矢印を頭の方に向けて水平に取り付けているので、Autopilot OrientationはROTATION_NONEに設定してOKとする。このとき、ドローンは水平においておく。
![Screenshot from 2020-08-01 21-04-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/d77d1137-96c3-799e-7e0f-03a7ac19714d.png)
飛行機の絵が6種類（水平・逆さま（背面下）・下向き・上向き・左を下・右を下）出てきて、まず水平状態で置いておくと和枠が赤から黄色に変わって、回すように矢印が表示されるので、水平をキープしたままその矢印の方向に機体をぐるぐると回してやる。しばらく回すと枠が緑になるので、次の姿勢で同じように静止→ぐるぐる回すを繰り返して、すべての姿勢の枠を緑色にする。

- Gyroscope
水平に置いたまま静かにしていると、青のバーが伸びて完了する。

- Acceleromet
Compassと同じく６種類の飛行機の絵が表示されるので、それぞれ姿勢をキープしたままCompletedになるまで静かにして、枠の色を黄色→緑に変えていく。
![Screenshot from 2020-08-01 21-23-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/996f3bbb-b8ac-cc42-e083-a5f209278b6a.png)

- Level Horizon
ドローンの高さの基準なので、飛ばすところの離陸地点と同じ高さに置いてキャリブレーションするのが理想だと思う。

## Radio
プロポの操作をして設定する。ちゃんと接続できていれば、レバー操作やスイッチ操作に反応するはず。
[Calibrate]をクリックして開始。右側に表示される黄色の丸にあわせてプロポのスティックを操作してやれば進んでいく。スイッチや対応するプロポのチャネルは機体にあわせて調整する。
やばいときにモータを止める緊急停止は

## Flight Modes
とりあえず、人の操作の反応が穏やかで安定して飛んでくれるStabilized Modeが主に選択できるように設定。
（将来的に、Jetsonからの指示で自動飛行するときはOffboard modeにする）

## Power
接続するバッテリー背のセル数を入力する。その他の数字はとりあえずデフォルト。しょっちゅうバッテリー残量ゼロの警告になったりして困らない限りそのままでいいと思う。

# Pixhawkを再起動

ウィンドウ左下[Parameters]→右上[Tools]→[Reboot Vehicle]→[OK]と選択してPixhawkを再起動する。
設定したところが反映されて、赤色表示ではなくなっているはず。この再起動動作は、この先パラメータを変えたときや初期化したいときなど、しょっちゅうやることになるはず。
（この画像はRadio（プロポ）とFlight Modesがまだ設定されていない図で、再起動しようとしているところ）
![Screenshot from 2020-08-01 21-45-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/fe8dadf1-d01d-2b85-8481-a0b9a1c25e0e.png)
Intel Realsense D455とD435を実機比較～実機テストするよ～レビュー編

IntelからRealSenseD455が販売されました。
前回のIntel Realsense D455 発表 ～D435とD455をスペック比較する～に続き、今回は、実機比較を行います。
https://qiita.com/usashirou/items/8468799a45dcc926407d

##D455とD435の比較
###・D455とD435のパッケージ比較
![D455とD435のパッケージ比較](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ecb71aad-960f-94ff-756d-145d67494cee.jpeg)
###・D455とD435の正面の比較
![D455とD435の正面比較](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/92961332-fea2-2005-b092-08b771b6cb51.jpeg)
###・D455とD435の背面の比較
![D455とD435の背面比較](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ff2a9fe3-5d51-c5ce-68f9-c3ce00fabee6.jpeg)
###・D455とD435の下面の比較
タップのサイズが異なります。
![D455とD435の下面比較](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/c1d5bc22-d740-a10d-8866-9ee32ef38f6c.jpeg)
###・D455とD435の上面の比較
![D455とD435の上面比較](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d1b5e9fa-710e-3c35-9f54-76f63b00718c.jpeg)

##RealSense Viewer
RealSense Viewerで画像比較をしましょう。
RealSense Viewerの古いバージョンではD455を認識しないので、新しいバージョンをダウンロードします。
https://www.intelrealsense.com/sdk-2/
Download Intel RealSense ViewerをクリックしてRealsenseViewerをダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3efa24d0-408a-39c9-d8f9-50012b0627a4.png)
 RealSense Viewerを起動します
落としてきたExeファイルを起動すればRealSense Viewerが起動されます。
![RealsenseViewer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ac2c79b6-b41d-dc87-9922-e83e3b3a4bfe.jpeg)
アラートが出たらEnableにすればつながると思います。
接続した状態です。
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/bba57bd9-d0b9-d735-da39-fd0493844a0d.jpeg)
##画像比較
###RealSenseD455の画像
もちろんIMUの値も表示されています。
![D455](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d184daea-7dd3-79e5-69e0-170a28358152.jpeg)
###RealSenseD435の画像
![D435.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3d0344b4-2b81-08d8-f304-e4b0037bd334.jpeg)

###比較結果
まったく画角が異なります。
そして、深度が違いますね。

ちなみに、LaserAutoにするとかなり手前で深度計測できず黒色になってしまいます。
デプス（深度）のヒートマップは、青が近く、赤が遠くを表しており
黒色は計測範囲を超えている事を表しています。

画角がかなり広いため、ロボット等で使用する際には、RealsenseD455単体か
複数のRealsenseを使用するのが良いのではないでしょうか？
（3個のD43Xを搭載したロボットもありますので）
mailコマンドでメールを送信する

# はじめに
サーバーからメール送信するため、mailコマンドを使えるようにします。

# 環境
CentOS 8

# パッケージのインストール

```
$ sudo dnf install mailx msmtp
```

mailxはmailコマンド、msmtpはSMTPクライアントです。

# mailxの設定
mail.rcファイルの最後に以下の内容を追記します。

```
$ tail -n 1 /etc/mail.rc
set sendmail="/usr/bin/msmpt"
```

# msmtpの設定

サンプルファイルをコピーしてパーミッションを変更します。

```
$ cp /usr/share/doc/msmtp/msmtprc-user.example ~/.msmtprc
```

GmailのSMTPサーバーを設定します。

```
$ cat ~/.msmtprc
# Set default values for all following accounts.
defaults
port 587
tls on
tls_trust_file /etc/ssl/certs/ca-bundle.crt

# Gmail
account gmail
host smtp.gmail.com　　←SMTPサーバー
from user@gmail.com　　←送信元
auth on
user user@gmail.com　　←ユーザー名
password password　　←パスワード

# Set a default account
account default : gmail
```

パスワードが含まれているのでパーミッションを変更します。

```
$ chmod 600 ~/.msmtprc
```

# メールの送信テスト

```
$ echo "test mail" | mail -s "test mail" user@gmail.com
```

受信できることを確認します。
![mailtest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561682/8085202d-bdb0-291a-fb04-c744408f92ae.png)
C++の参照とRustの参照

C++の参照 `T&` と Rustの参照 `&'a T` は割と使い勝手が違うよという話

C++の参照
--------

```cpp
#include <iostream>
#include <vector>

class A {
    std::string name;
public:
    A(std::string name): name(name) {}
    const std::string& get_name() const {
        return this->name;
    }
};

int main() {
    A* a = new A("a");
    auto& name_ref = a->get_name();
    delete a;
    
    std::cout << name_ref << std::endl;
    return 0;
}
```

C++でこの様に構造体内のオブジェクトの参照を返すと、先にオブジェクトが解放されても依然参照にアクセス出来てしまうので簡単にバグってしまいます。なのでC++ユーザーはこのようなコードは普段避けているはずで、例えば値を複製して返したりしているはずです。

Rustの参照
----------

一方Rustではこの様なことが起こらないようになっています

```rust
struct A {
  name: String,
}

impl A {
    fn new(name: String) -> Self {
        A { name }
    }
    
    fn get_name(&self) -> &str {
        &self.name
    }
}

fn main() {
    let a = A::new("a".into());
    let name = a.get_name();
    drop(a);
    println!("{}", name);
}
```

同じように構造体 `A` の内部のメンバへの参照を返して、その後に参照へアクセスしようとするコードですが、これはコンパイルエラーになります：

```
error[E0505]: cannot move out of `a` because it is borrowed
  --> src/main.rs:18:10
   |
17 |     let name = a.get_name();
   |                - borrow of `a` occurs here
18 |     drop(a);
   |          ^ move out of `a` occurs here
19 |     println!("{}", name);
   |                    ---- borrow later used here

error: aborting due to previous error
```

これは省略されているlifetimeを表示すると少しわかりやすくなるでしょう：


```rust
    fn get_name<'life>(&'life self) -> &'life str {
        &self.name
    }
```

このように明示的に書くことも出来ますが、いくつか省略するルールがあり良く使う場合はあまり明示的に書かなくてもいいようになっています。これは雑に言えば「`self`を借りた時の生存時間` 'life` で参照 `&'life str` を作れ」という事です。参照にいつまで有効かどうかの情報が型レベルで入っているわけですね。

なので `main` のコードは `get_name` を読んだとき、まず `a` がいつまで借りることができるかを判断して、その生存期間で `name` の型を決めようとします。大事な事ですが、これはスクリプト言語のように、上から順番に行を評価をするだけでは決まりません。

一見 `a` を借りることができるのは次の `drop(a)` が起こるまでの様に見えます：

```rust
fn main() {
    let a = A::new("a".into()); // ここから
    let name = a.get_name();
    drop(a);                    // ここまで？
    println!("{}", name);
}
```

なのでこの範囲でしか生きれない生存時間 `'life` を使って参照 `name` が定義されるのでしょうか？すると次の `println!` で `name` を使おうとしたとき、この `name` は型で定められた生存範囲より外で使われているのでエラーになります。

これではダメなのでコンパイラは `name` が使われる範囲も含めて `'life` にしようとします

```rust
fn main() {
    let a = A::new("a".into()); // ここから
    let name = a.get_name();
    drop(a);
    println!("{}", name);       // ここまで使えないとまずい
}
```

しかしそうすると `drop(a)` と矛盾してしまいます。ここで諦めてコンパイラは上の様にエラーを吐いているわけです。

まとめ
-----
このようにRustのコンパイラは参照についている生存期間まで含めて推論してくれています。このおかげでC++では危険だった参照の使い方が安全になるため、参照でなく値を返す事を避ける事ができる場合もあります。
githubに大きすぎるデータをpushしてしまったときの対処

自分用メモ

githubでは100MB以上のファイルはアップロードできません。
大きすぎるデータをpushしてしまった場合、履歴に残っているとアップロードできない状態が続くので、
履歴から削除する必要があります。

### エラー文から大きすぎるファイルを確認
```remote: error: File "大きすぎるファイルのパス" is 110.52 MB; this exceeds GitHub's file size limit of 100.00 MB```

###リポジトリからファイル削除
```git filter-branch --tree-filter "rm -f "大きすぎるファイルのパス" HEAD```

```Cannot rewrite branches: You have unstaged changes.```
が出たらgit commitしてからもう一度実行する

```Cannot create a new backup.```
が出たら.git/refs/originalを削除してもう一度実行する

###.gitignoreに大きすぎるファイルを記載する
gitの管理対象から外さないとまた同じことになるので、大きすぎるファイルのパスを.gitignoreに記載する。


再度git add git commitしてからgit pushすると正常にpushできるはず
PowerShell 7のCRC32クラスと作成時の覚書

PowerShell 7でCRC32の計算機能を提供するクラスのサンプルコードとその作成時に学んだことの覚書きです。

# CRC32クラスのソースコード

```powershell
class CRC32 {
  [uint[]]$CrcTable

  CRC32() {
    $this.CrcTable = [uint[]]::CreateInstance([uint], 256);
    for ([uint]$n = 0; $n -lt 256; $n++)
    {
        [uint]$c = $n;
        for ([uint]$k = 0; $k -lt 8; $k++)
        {
            $c = (($c -band 1) -ne 0) ? (0xedb88320u -bxor ($c -shr 1)) : ($c -shr 1);
        }
        $this.CrcTable[$n] = $c;
    }
  }

  [uint]Calculate([byte[]]$array) {
    return $this.Calculate($array, 0, $array.Length)
  }

  [uint]Calculate([byte[]]$array, [int]$start) {
    return $this.Calculate($array, $start, $array.Length)
  }

  [uint]Calculate([byte[]]$array, [int]$start, [int]$length) {
      if ($start -lt 0) {
        throw [ArgumentOutOfRangeException]::New();
      }
      if ($length -lt 0) {
        $length = $array.Length - $start;
      }

      [uint]$c = 0xffffffffu;
      for ([uint]$n = 0; $n -lt $length; $n++) {
          $c = $this.CrcTable[($c -bxor $array[$start + $n]) -band 0xff] -bxor ($c -shr 8);
      }
      return $c -bxor 0xffffffffu;
  }
}

$Crc32 = [CRC32]::New()
$Crc32.Calculate([byte[]](0x00, 0x01, 0x02)).ToString("X08")
```

# 覚書き

- 全般事項
  - 変数は`$var`。大小演算子は`-lt`(<)、`-gt`(>)。
  - ビット論理演算は`-bor`、`-band`、`-bxor`。論理演算`-or`、`-and`、`-xor`とは異なる。
  - ビットシフト演算子は`-shl`、`-shr`。
  - リテラルの型はサフィックスで指定。`uint`のサフィックスは`u`。
  - クラスのインスタンス作成は`[ClassName]::New()`。
  - 長さを指定した特定型の配列作成は`[type[]]::CreateInstance([type], length)`。例えば`[uint[]]::CreateInstance([uint], 256)`。
  - 値を指定した特定型の配列作成は`[type[]](...)`。例えば`[byte[]](0x00, 0x01, 0x02)`。
- クラス関係の注意
  - クラスは`class ClassName {...}`で作成。
  - コンストラクタはクラス名と同名の関数`ClassName() {...}`。
  - クラスのメンバ変数は`class ClassName {...}`の`...`に`[type]$name`として宣言。
  - クラスのメンバ変数は引数の既定値が指定不可能（paramを指定できない）。ただし、オーバーロード可能。
  - クラスのメンバ関数はオーバーロードできる。例えば関数`f() {...}`、`f([int]x) {...}`、`f([int]x, [int]y) {...}`を同時に定義できる。
  - クラス内で自身のメンバ変数、メンバ関数は`$this.name`で参照。
clang-cl(clang) で case-insensitive でヘッダファイルを読み込む

# 背景

1. Windows native の clang-cl では, Windows filesytem 上では case insensitive であるが, しかし case sensitive なファイル名を使わないとワーニング or error が出たりする(e.g. `windows.h` ではなく `Windows.h`が正しい)

2. Linux 上の clang-cl で, Windows アプリをクロスコンパイルする場合, Linux のファイルシステムが case sensitive(e.g. Ubuntu + EXT4)のため, 一部ファイルが読めないケースがある.

たとえば Windows SDK にあるヘッダファイルだと, 必ずしも include が case sensitive を考慮して記述されているわけではない
(e.g. `Windows.h` 内で include される `SpecString.h` はファイルシステム上は `specstring.h`)

## `-ivfsoverlay`

1 の制約および多くの Linux 環境でクロスコンパイルのため Case sensitive でヘッダファイル名を記述します.
しかし, 2 の Windows SDK ヘッダの問題から, 一部 case insensitive で扱わねばらならないケースが出てきます.
 
clang 独自で, ファイルの扱いを制御できます. ここで case sensitive かどうかも設定できます.
(本来は, VFS(Virtual File System)用で特定のファイルを別のファイルにリダイレクトとかするのに使われるっぽい)

ちょっとめんどいですが, 以下のように yaml に制御したいファイルパス列挙と, `case sensitive: false` を記入し

```yaml
version: 0
case-sensitive: false
roots:
  - name: "/mnt/c/winsdk/Include/10.0.18362.0/um"
    type: directory
      - name: "Windows.h"
        type: file
        external-contents: "/mnt/c/winsdk/Include/10.0.18362.0/um/Windows.h"
...
```

clang 独自オプションの `-ivfsoverlay` で yaml ファイルを指定します.
 
`-Xclang -ivfsoverlay -Xclang vfs_overlay.yaml`

clang 独自オプションの場合は 毎回 `-Xclang` を prefix として付与が必要です(後続のオプションが clang 独自のオプションであることを指定)

yaml の作り方など詳細は LLVM の WinMsvc.cmake generate_winsdk_vfs_overlay を参照ください.

https://github.com/llvm-mirror/llvm/blob/master/cmake/platforms/WinMsvc.cmake


## MinGW との兼ね合い

ちなみに MinGW gcc/clang の場合は全部小文字でないとだめかもしれません(clang VFS overlay 的な機能は無さそうなので).
現状, mingw gcc, llvm-mingw など MinGW ヘッダベースのコンパイラ環境は, ヘッダファイルを全部小文字化しているため,

```
#ifdef __MINGW32__ // mingw gcc, llvm-mingw(clang)
#include "windows.h"
#else // MSVC, clang-cl
#include "Windows.h"
#endif
```

のようにして切り分けで対応するしかなさそうです.
minio を同じサーバーの別dockerコンポーネントで立ち上げ、それをnginxプロキシーで外向きの https:// で設置して、fogでそのhttps:// URL をendpoint あるいはasset_hostとして指定すると、IPアドレスになって、サービスを検知できない問題

自分メモです。
正確には、minio を同じサーバーのdockerコンポーネントで立ち上げdocker network経由でも使えるようにした上で、それを同時にnginxプロキシーで外向きの https:// に設定しているので、CarrierWaveのfogでは、その https:// URL をendpointあるいはasset_hostとして指定した場合、Railsで画像アップロードしようとすると、その指定した https:// URL がIPアドレスに変換されてしまい、サービスを検知できない問題……
とにかくこの問題は起こりました。

解決策は、StackOverflow の下記ページにありました。でも、たどり着くのに少し時間がかかった。
asset_hostはそれでいい。しかし、endpointはdockerのコンテナ名を指定すべきと。

[StackOverflow: Can't upload file through carrierwave fog-aws to minio (docker-compose)](https://stackoverflow.com/questions/45950162/cant-upload-file-through-carrierwave-fog-aws-to-minio-docker-compose)

```ruby:qiita.rb
CarrierWave.configure do |config|
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
      provider:              'AWS',
      aws_access_key_id:     'development',
      aws_secret_access_key: 'development',
      region:                'us-east-1',
      host:                  'minio',  # <- ここをコンテナ名に/サービスのURL(ドメイン名)だとIPアドレスになってしまう
      endpoint:              'http://minio:9000'  # <- ここも
  }
  config.fog_directory  = 'test'
  config.fog_public     = false

end
```
msvc(cl.exe)と clang-cl の違いのメモ


## clang-cl が未対応

`/MP` はエラーが出る(ソースコードをマルチプロセスでビルド)

https://docs.microsoft.com/en-us/cpp/build/reference/mp-build-with-multiple-processes?view=vs-2019

`/MP` 対応は, clang-10 の時点ではマージされていない模様.
https://reviews.llvm.org/D52193
WebViewの表示方法

＃WebViewをサクッと表示！！

まず、ViewController.fileにWebKitをimportします。

```ViewController.swift
import UIKit
import WebKit
 
class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!

    override func viewDidAppear(_ animated: Bool){
        }
    } 
```



次に、main.storyboardへ。
WebKit Viewを右上の「＋」　ボタンから選択し、ViewControllerへ貼り付け。

<img width="661" alt="スクリーンショット 2020-08-01 21.04.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562721/57525f1b-a43b-a96e-2d03-4cfbc5ab59d3.png">

次にwebViewを表示させるコードを書きます。


```ViewController.swift
import UIKit
import WebKit
 
class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!
    var topPadding:CGFloat = 0

    override func viewDidAppear(_ animated: Bool){
        print("viewDidAppear")
        
        if #available(iOS 11.0, *) {
            // 'keyWindow' was deprecated in iOS 13.0: Should not be used for applications
            let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
            topPadding = window!.safeAreaInsets.top
        }

        let webUrl = URL(string: "https://www.google.com/")!
        let myRequest = URLRequest(url: webUrl)
        webView.load(myRequest)
 
        // インスタンスをビューに追加
        self.view.addSubview(webView)
}
```
これでオッケーです！
ただ、これでシュミレーターを立ち上げると・・・

<img width="1398" alt="スクリーンショット 2020-08-01 21.20.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562721/ff6d7be0-6bfd-123b-9e6c-4cc5025e9ca2.png">
この様に、エラーが出てしまいます。
どうやら原因はフレームワークが追加されていないからとのこと。
ということで、追加。
<img width="962" alt="スクリーンショット 2020-08-01 21.03.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562721/08875053-9301-4021-42e4-a6a12081de11.png">


これで完成です！
webViewを表示するのは非常に簡単ですね！
ビューアーなどの記事サイトを表示させる時に活躍しそうですね。
webkitViewの使用方法でした！ありがとうございました。
　　　　　　　　　　　　<img width="434" alt="スクリーンショット 2020-08-01 21.25.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562721/c52ebb04-2502-f49a-0765-a98ef94d4cff.png">
はてなブログのレイアウトをスマホ版に反映させる方法

はてなブログには、ブログのCSSを編集するための仕組みが用意されています。

最も分かりやすいのは「デザインCSS」を編集する方法で、私も以前に[説明記事を投稿しました](https://qiita.com/emoriiin979/items/1a32505b0603597430c6)が、この方法では以下のような問題が発生します。

- CSSの設定がスマホ版に反映されない。  
- GitHubなどでCSSファイルを複数人で管理できない。  

そこで、今回の記事では、外部のCSSファイルをはてなブログHTMLに直接呼び出す方法について説明します。

### HTMLのheadから外部CSSファイルを呼び出す

はてなブログには、HTMLのhead要素を編集する機能があります。

「ダッシュボード」の「設定」から「詳細設定」のタブを開くと、「headに要素を追加」という機能が見つかります。

![imagd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509941/9fdbb13a-406e-e5c8-a73c-3e7cee2998e2.png)

ここに、**外部CSSファイルのリンク先を記述します**。

やり方は一般的なCSSファイルの読み込み方法と全く同じなので、ここでは説明しません。よく分からない人は私と同じように書くと良いと思います。

```
<link type="text/css" rel="stylesheet" href="CSSファイルのリンク先">
```

このようにCSSを指定すると、PC版だけでなく、スマホ版でもCSS設定が反映されるようになります。

### CSSをgithub.ioで管理する

次に、参照先のCSSファイルをどこに置くかを決めなければなりません。

自分でWebサーバーを構築してそこに置くのも一つの手です。しかし、**github.ioを使えば自前のWebサーバー無しでCSSファイルを外部参照させることができます**。

![imgddd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509941/ebd2f595-51f5-fd1a-3a0e-68aa112a9ce9.png)

やり方は簡単で、「(アカウント名).github.io」というリポジトリを作成し、そこにCSSファイルを置けば外部から呼び出すことができます。

この方法の利点は大人数で一つのCSSファイルを編集できる点です。例えば、自分でCSSを編集しなくても、誰かが代わりに編集してくれることを期待してプルリクエストを待つことに専念するなどができます。

### まとめ

- HTMLのhead要素から外部のCSSファイルを呼び出す。  
- github.ioにCSSファイルを置くことで外部から呼び出すことができる。

これらの手順を踏むことで、スマホ版にCSSを反映させるだけでなく、GitHub上で大人数でCSSファイルを編集することが可能になります。

もし、上述の問題に悩んでいる方がおられましたら、ぜひとも今回紹介した方法を試してみてください。

### 参考文献

基本的には、これらの記事をそのまま参考にしています。

- [はてなブログのスマホ版ページをカスタマイズしてみた](https://align-centre.hatenablog.com/entry/2014/04/30/235326)  
- [意外と簡単！はてなブログのCSS外部化をGitHub Pagesでしてみた！](https://www.lisz-works.com/entry/hatenablog-css-github-pages)