OmniAICreator/Qiita-1.07M huggingface dataset:
自分がやっている技術書の読み方

### 初めに

皆さん技術書に限らずですが、本をどのように読んでいますでしょうか？
本っていいですよね、読んでる時はそれ以外何も考えなくていいというか、その世界に没頭できるので僕は好きです : )
たまに自分のスキルにあっていない本を買ってしまい分からなすぎて、絶望してしまう部分も含めて好きです。
自分のことでいうとO'Reillyとかまさにですね、プログラミング始めよう！って思って色々書籍を調べてたらO'Reillyが色々なサイトで勧められていて買ってみたものの全く理解できず「あー、俺ってこんな馬鹿なんだぁ」って思ったものです。

ここでは昔効率的な本の読み方を調べてた時に自分がまとめたメモがあったのでQiitaにも投稿しようと思います。

### 自分が実践している方法
####1. ビジュアライジング(視覚的にイメージする)

論理構造を絵で想像するというやり方です。
もの凄い簡単に言うと学んだことを自分で絵として想像してみるということですね。

漫画とか映画とかって一度見ただけでも結構鮮明に内容を思い出せると思います。
ストーリー性がありそしてテキストより映像、絵の方がそりゃあ分かりやすいですよね。
まさにそれを本(テキストばかりの)でもやってみよう！って感じです
技術書でも漫画で分かるシリーズとかがあると思いますがそれを読んで全く内容分かんない〜とかって事はあんまないと思います

本を読んだ時内容をパーツでイメージしてそれぞれの繋がりを考えるだけでもいいと思います。
個人的にはマインドマップ的なものを自分で想像してみるのもとてもいいと思います。

内容を忘れてるわけではなく組み合わせを忘れてるだけな事が多いです
（例え）
![pose_souzou_man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257500/cdf9452a-2409-1c8d-36ee-e4edd9312c64.png)
#### 2. コネクティング
**読んでる本を別の本に結びつける**
記憶は結びつきが大切です、イメージとしては天井に知識をぶら下げていくイメージです。~~(これ分かりやすいのかな)~~
ここで結びつける時は別の本の内容でなくても問題はありません、要は「他のとこにこんなこと書いてあったな」「あんなことあったな」って思い出す事が大切
天井繋がりで言うとひとつの線で知識をぶら下げていても不安定だけど様々な方向から線として吊るす事でより強固になるっていうイメージですかね。
関連性をつけるのが大切だよーってことですね。

自分の過去の体験と本の内容を結びつけるのも非常によいと思います。
「前先輩に教えてもらった部分だ」とか「あの人もこんなこと言ってたな」とかですね。

そこで自分のした体験と本の内容がどう違うのか、それは納得するものなのかどうかもしっかり考えてみてください。
![book_tsubuse_man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257500/797ec5ed-ec26-79b3-5bc0-689b3f09f291.png)
#### 3.サマライジング
これは本の内容を自分の言葉で「要するにこういうことでしょ？」「こう言う事が書いてあるんでしょ」っていうのを考えていくってイメージですね。
この方法は自分的にも結構有効な方法だと思ってます。
これを各セクションやっていきます。
要するに読書術とか言われたりしてますね。

**ここで大切な事は要するにができない部分は再度じっくり読みましょう**
自分の興味のある、又はあまり理解が出来ていない部分だと思います。

#### 4.クエッショニング
これは方法としては非常に簡単です。
読書の前、途中、後に自分に本の内容の質問をして、自分で答えるっていう方法です。
「あのセクションにはどんな事が書いてあったか？」
「あの部分はどういう仕組みで動いているか」等、
あくまで例なので内容に合わせて質問は自分で考えてくださいね。
![school_test_enpitsu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257500/3a9372c5-e5ee-5d72-8ce4-4e5c2429b6cf.png)



#### 最後に大切なことを
・読み飛ばす部分は読み飛ばす（自分の知っている内容はサッと読む）
・本は全部重要なわけではない。
・絶対にどうでもいい部分はあるはず。
・いい本だったら要するにが書いてある。
・何書いてあるか分かれば飛ばしてもいい。
・わからないのに飛ばしたら意味ないよ。

~~ここまで書いておいて、自分も全てやれてるかと言われると微妙なんですけどね。(特にクエッショニングとか)~~

ここに書いてある事以外にもテクニック的なものはあった気がしますがとりあえず自分がまとめていたのはこれだけなので一旦これだけでー！

以上自分のやっている本の読み方のご紹介でしたー！
テキストだけだと読む気にならないかなって思って[いらすとや様](https://www.irasutoya.com/)から画像をお借りしてきましたがどうでしょう...？
読みやすいかな。

昔evernoteにまとめてた内容をQiitaに持ってきただけなので間違い等あるかもしれませんがご容赦ください。
ご指摘等頂けますと嬉しいです！
h5pyのcompressionのベンチマークをとってみた


今回はデカい画像データをh5形式で保存しなおしました．
h5pyでは，以下の様に書くと変数をgzipで圧縮できます．

``` python
x = cv2.imread("デカい画像1.png")
y = cv2.imread("デカい画像2.png")
with h5py.File("out.h5", "w") as f:
    f.create_dataset("data1", data=X, compression="gzip", compression_level=4)
    f.create_dataset("data2", data=y, compression="gzip", compression_level=4)
```

何度かやった結果の平均とかではないので，時間については不確かです．

|圧縮レベル|出力ファイルサイズ(GB)|出力時間(sec)|読み込み時間(sec)|
|---|---|---|---|
|無圧縮|6.83|7.7|10.1|
|1|1.48|81.3|53.7|
|4(デフォルト)|1.47|107.8|57.2|
|9|1.46|204.3|56.6|


データが変わると結果も変わるのかもしれませんが，

- 圧縮なしと圧縮ありでは，ファイルサイズに大きな差があるが，入出力にかかる時間も大幅に増える．
- 圧縮レベルを上げると，処理時間は割と長くなるが，圧縮率はそんなに上がらない
- 読み込み時間は圧縮レベルに関わらずあんまり変わらない

シンプルにgzipのベンチマークと同じような傾向だと思いますが，
圧縮有り，無しの入出力時間の差は気になるケースがありそうですね．
倫理委員会で却下された臨床研究のためのコードの記録

下記のコードは麻酔科の臨床研究用に作成した物です。
　テーマは「顔認証による術前気道評価（仮）」でした。企画自体は倫理委員会で却下となりました。別機関様で似た臨床研究が進行していますが当方とは関係ありません。

　用途は、顔の正面画像を認識し、仮の座標点を作成し、そこから顔パーツデータを取得する事です。
　利用意図に関して
 全身麻酔では人工呼吸につなげる気管挿管が必要なのですが,難易度が患者個人によって異なります。麻酔で眠ってもらった後に気道チューブを入れる時、cormackという数値で実際に気道がどれくらい見えているかを分類します。
　これをアウトプットのデータとして、顔パーツデータとの相関関係を調べたり、機械学習を行いで術前診察に役立てられないかと思い作成しました。

```py
#
import cv2
import pandas as pd
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import dlib
detector = dlib.get_frontal_face_detector()
predictor =
dlib.shape_predictor('filepath/shape_predictor_68_face_landmarks.dat')
frame = cv2.imread('filepathofimage.jpg')
dets = detector(frame[:, :, ::-1])
print(predictor)

dets=detector(frame[:,:,::-1])
if len(dets)>0:
    parts=predictor(frame,dets[0]).parts()

#確認
img = frame*0
for i in parts:
    cv2.circle(img,(i.x,i.y),3,(255,0,0),-1)

#cv2imshowが無理なのでpltで
plt.imshow(img)
dets=detector(frame[:,:,::-1])

if len(dets)>0:
    parts=predictor(frame,dets[0]).parts()

#確認用
img = frame*0
for i in parts:
    cv2.circle(img,(i.x,i.y),3,(255,0,0),-1)

print(parts)
pd.DataFrame(data=parts)
```

最後にデータフレームに格納されます。

参考にしたhpが多数あり、それを複合カスタムした物です。先人の方々に感謝致します。著作権のあるhpではありませんでしたが問題があるようでしたらご指摘ください。
[iOS]XcodeのUIButtonを接続した時に、IBOutletになるか、IBActionになるかの条件

超小ネタ
前から疑問だったんですが、UIStoryboardからUIButtonをUIViewControllerなどに接続した時

viewDidLoadより上に持ってきたらIBOutlet
![スクリーンショット 2020-09-11 12.11.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20784/30bf5f57-7984-2e90-33d4-6efee24495e5.png)

viewDidLoadより下に持ってきたらIBAction
![スクリーンショット 2020-09-11 12.11.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20784/d0eeb12b-027b-e75a-2a99-3ebc4193007e.png)

がデフォルトで表示される模様。
viewDidLoadがない場合はIBOutletになりました

UIViewの場合
awakeFromNibより上に持ってきたらIBOutlet
awakeFromNibより下に持ってきたらIBAction
でした

何だその仕様・・・
つまり

IBOutlet
viewDidLoad or awakeFromNib
IBAction

の順でコードを書こうね！ by Apple
ってことですかね？
使用FRP搭建Socks5穿透目标边界

frps.ini

```ini
[common]
bind_port = 9009
token = thisismyfucktoken
tls_enable = true
```

frpc.ini 启用token校验、tls、压缩、加密

```ini
[common]
server_addr = 172.16.1.1
server_port = 9009
token = thisismyfucktoken

[socks5]
type = tcp
remote_port = 9000
plugin = socks5
use_encryption = true
use_compression = true
tls_enable = true
dns_server = 8.8.8.8
```

运行`frps.exe -c frps.ini`，跳板机运行`frpc.exe -c frpc.exe`

172.16.1.1:9000就是socks5地址
JavaScriptの条件分岐 if文について

今回はJavaScriptにおける、条件分岐と繰り返し処理について説明します。

Rubyと同様に条件を満たしているかどうかで実行処理を分岐します。

Rubyとの違う点は条件式を()で囲み、条件式の後を{}で囲みます。
また、elsifはelse ifと記述します。

分かりにくいのでコードに書くとこのような感じになります。
![スクリーンショット 2020-09-11 11.18.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698652/6e11abce-6de7-f6e3-e8cb-e50817436627.png)

![スクリーンショット 2020-09-11 11.19.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698652/6691e831-841a-49c9-1118-189cfd15921e.png)

![スクリーンショット 2020-09-11 11.20.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698652/e1c6b1a7-efed-3653-c962-1ea2f6505f7d.png)

また、JavaScriptにはテンポラリーリテラルというものがありまして、ダブルクォートやシングルクォートの代わりにバッククォートで囲むことで文字列ないに変数を埋め込むことができます。

バッククォートはshift+@で入力できます

まず、テンポラリーリテラルなしの場合
![スクリーンショット 2020-09-11 11.34.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698652/8f69cb86-4edf-ebd0-d0c2-e70ac5e97439.png)

テンポラリーリテラルありの場合
![スクリーンショット 2020-09-11 11.35.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698652/a9e77a75-9722-8465-6585-f5447e4cbc22.png)

となり、シンプルで見やすくなります。

テンポラリーリテラルには他にも改行したりできます。

参考資料
https://qiita.com/kura07/items/c9fa858870ad56dfec12
[ASP.NET Core] Webアプリのルーティングについての理解

# 対象ソフト

以下公式のリアルタイムのWebアプリのチュートリアルで作成したもの
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/signalr?view=aspnetcore-3.1&tabs=visual-studio-code

これは`dotnet new webapp`で作成したWebアプリになります。

# ルートパスのView

アプリケーションを起動し、ブラウザから`http://localhost:xxxx/`にアクセスすると、
`/Pages/Index.cshtml`が表示さます。

これはASP.NET Core 2.0 以降、Razor Pages の機構によるもののようです。

# Hub、WebSocket周りの関連性

以下コードの`endpoints.MapHub<ChatHub>("/chatHub");`部分ですが、
`<ChatHub>`はハブのクラスを指定し、
`("/chatHub")`でWebSocket接続を待ち受けるURLを指定しています。

```c#:Startup.cs

　　　　// ... 省略

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages(); // Razor Pages有効化
            services.AddSignalR();
            services.AddSingleton<app>();
        }

　　　　// ... 省略

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // ... 省略

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapHub<ChatHub>("/chatHub");
            });
        }
```
ルートパスにアクセスした際に表示される`Index.cshtml`には対応するスクリプトとして
`chat.js`が指定されています。

```html:Index.cshtml

<!-- 省略 -->

<script src="~/js/chat.js"></script>
```



`chat.js`には`/chatHub`に対してWebSocketを接続する処理があります。

```javascript:chat.js
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

// ...省略

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});
```




# MVCの場合

対象のソフトとしては、以下のチュートリアルで作成したものです。
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-3.1&tabs=visual-studio

`dotnet new mvc`でプロジェクトを作成しています。
こちらはRazor Pages の機構を使用していない作りになっています。

以下コードの`pattern: "{controller=Home}/{action=Index}/{id?}");`でURLパターンを指定していますが、`controller=Home`で指定される`Home`は、URLで指定されなかった場合のデフォルト値になります。
`action=Index`で指定している`Index`についても同様にデフォルト値です。

`pattern: "{controller}/{action}/{id?}");`でも問題ありません。
その場合、URLとしては`localhost:xxxx/Home/Index`のようにアクセスすることになります。

```c#:Startup.cs
// ...省略

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // ...省略

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
```

`controller=Home`の`Home`とは、
Controllersフォルダ以下のHomeController.csになります。
`action=Index`の`Index`とは、以下コードのIndex関数になります。

```
// 省略

    public class HomeController : Controller
    {
        // ...省略

        public IActionResult Index()
        {
            return View();
        }

     // ...省略
    }
```

また上記コードで実行している`return View();`によって、
Views/Home/Index.cshtmlがクライアントに返却されます。

以上によって、`localhost:xxxx/`にアクセスした際にViews/Home/Index.cshtmlの内容が表示されます。

以下のようにページを返さないパターンもあります。

```
        public string Index()
        {
            return "This is my default action...";
        }
```
Slack で UI 上で表示されなくなった機能を使う

# 環境

- Ubuntu Linux 18.04 LTS
- slack-desktop-4.0.2-amd64.deb

# テキストフォーマットのクリア


いつしかテキストフォーマットのクリアボタンが無くなっていた。
どうやら機能として無くなっているみたい。

Preferences - Advanced - Format messages with markup
をONにするとそもそも余計なテキストフォーマットをしなくなるので幸せになれた。


# text snippet の作成

昔は入力エリアの＋ボタンから作成していたが、＋ボタンが無くなった。
↓
入力エリアのイナズママーク - Create code or text snippet

または入力エリアでCtrl+Shift+Enter



# 常駐終了

昔は常駐アイコンをクリックで終了が選択できたができなくなっている
↓
GUIで終了する方法は無い？

# ワークスペースアイコンリストのスクロール

以前はスクロールバーがあったが無くなっている
↓
マウスホイールトスクロール
またはキーボードフォーカスを合わせてキー操作
ASTERIA WarpでNest HubにYouTube動画を再生してみた

CATTが面白すぎるので、調子に乗ってASTERIA Warpからも連携してみた

# 使用環境
* Windows 10 1909 (18363.1049)
* ASTERIA Warp 1912 Standard Edition
* Python 3.8.5
* CATT v0.11.3

# CATT、ASTERIA Warpの準備
CATTの準備はこちら。
* [GravioでChromecastに動画を流す: Windows編](https://qiita.com/zrock/items/eccb40f9c96455a9e6a9)
* [GravioでChromecastに動画を流す: ラズパイ/Linux編](https://qiita.com/zrock/items/5ff126bf64d2716299a4)
* [CATTを使ってラズパイからChromecastやNest Hubに動画やWebサイトをキャストしてみる](https://qiita.com/zrock/items/522a629262222645aefe)

ASTERIA Warpは普通にインストールしてください。EXEコンポーネントを使うのでStandard以上で。

# ASTERIA Warpのフローを作る
![warp-catt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/5eb93933-e421-7b37-4bd6-cbbe9d6c72d5.png)
簡単です。EXEコンポーネントをおいて、ファイルはパスを通してある`catt`コマンドを指定。引数にそのままいつものYouTube動画のURLもろもろを引数として渡します。

|プロパティ|値|
|----:|:--|
|ファイルパス|catt|
|引数|-d <デバイス名> cast <動画のURL>|

# こんなふうになります
![warp-catt.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/9004e42d-531f-4ce8-c53e-f697b84a5100.gif)
シェルコマンドをansibleで自動化する学習手順と各種学習リソースまとめ




# ansibleとは？

インフラを構成管理して、いざという時の手動コマンドポチポチ作業を
自動化するためのツール。
コマンドをyaml化するにはそうとうな理解が必要



# ansibleの公式
ここを読んで理解できるなら、以下の記事は読まなくても良いよ！

#### ansible公式github
https://yteraoka.github.io/ansible-tutorial/


#### ansible公式tarball
https://docs.ansible.com/ansible/2.9_ja/installation_guide/intro_installation.html


# 今回のハンズオン

コントロールノード（ansibleを実行する側）とターゲットノード（ansibleによるコマンド実行の対象になる側）
物理サーバ２台でも、仮想サーバ２台でも、繋げれば何でもよい。

今回は簡単に実験するため、awsのEC2を二つ立てて実験する







# ansibleインストール手順

## OSマネージャからのインストール

```
(centosの場合)
sudo yum install -y ansible


(ubuntu・debianの場合)
sudo apt-get install yum install -y ansible
```


## 今回のハンズオンではamazon linux2にansibleを入れるので以下の記事を参考にすべし

https://qiita.com/yreckless/items/6446c4f73872c9243c4e


--------------------------------------------------------


ssh hands-on-user01@ターゲットIP



--------------------------------------------------------

# ANSIBLEでターゲット側にユーザを作る！

https://blog.serverworks.co.jp/tech/2019/09/09/post-73961/
上記のリンクの内容で行った自動化は、下記のyamlにて
クライアント側に、ユーザーを作る処理を反映させるだけ


```roles/hands-on/tasks/main.yml
---
- name: create user
  user:
    name: hands-on-user01
    createhome: yes
    state: present
    password: "{{ 'hands-on' | password_hash('sha512') }}"

- name: modify sshd_config
  lineinfile:
    dest: /etc/ssh/sshd_config
    state: present
    backrefs: yes
    regexp: '^PasswordAuthentication no'
    line: 'PasswordAuthentication yes'
  notify:
    - restart sshd
```


```roles/hands-on/handlers/main.yml
---
- name: restart sshd
  service:
    name: sshd
    state: restarted
    enabled: yes
```

--------------------------------------------------------

# ANSIBLEでターゲット側にユーザを作る！（変数を用いた命令編）


https://blog.serverworks.co.jp/tech/2019/10/18/post-74608/




sudo ansible-playbook -i inventory/hosts site.yml
ssh hands-on-user01@ターゲットIP



```roles/hands-on/tasks/main.yml
---
- name: create users
  user:
    name: "{{ item.name }}"
    createhome: "{{ item.home }}"
    state: "{{ item.state }}"
    remove: "{{ item.remove }}"
    password: "{{ item.password | password_hash('sha512') }}"
  with_items: "{{ users }}"

- name: change hostname
  hostname:
    name: "{{ inventory_hostname }}"

- name: modify sshd_config
  lineinfile:
    dest: /etc/ssh/sshd_config
    state: present
    backrefs: yes
    regexp: '^PasswordAuthentication no'
    line: 'PasswordAuthentication yes'
  notify:
    - restart sshd
```

-------------------------


## 各種yamlの記述の解説：





## [Ansible][yum]複数パッケージを同時に/一発でインストールする方法

https://blog.trippyboy.com/2020/ansible/ansible%E3%81%A7%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%82%B5%E3%83%BC%E3%83%90%E4%B8%8A%E3%81%AE%E7%89%B9%E5%AE%9A%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E9%85%8D%E4%B8%8B%E3%81%AErpm/
【Python3】画像を特定のサイズで切り出したいときに使えるコード

備忘録やOUTPUT的な意味での蓄積

#作成目的
作業用の画像をすべてcropingしたいときに利用するコード

#作成環境
・windows10
・Anaconda3
・python3.7
・Jupyter Notebook

#ドキュメント
①cropしたいフォルダ名を入力
②folderがなければcurrent_folder内に、crop_folder を作成し画像をcropする
③すでに同じフォルダ名がある場合、誤操作を防ぐためにErrorになる

#ライブラリの読み込み

```python:All&nbsp;Necessary&nbsp;Libraries.py
import pathlib
import os
import shutil
import pprint
import numpy as np
from glob import glob
from PIL import Image
from tqdm import tqdm
from pathlib import Path
```

#PG

```python:crop_code
# フォルダー名を入力
folder_name = input('Enter the folder name :')
p = Path('C:/Users/H3051411/OUT/' + folder_name)
new_folder_name = '_crop_folder'
# 現在のpathから新しいpng_folderを作成
new_folder_path = os.path.join(p, new_folder_name)

# フォルダーがなければコピーして作成
if not os.path.exists(new_folder_path):
    # ディレクトリ内のファイルを取得
    os.makedirs(new_folder_path)
    
    # 新たなpathの拡張子をpngファイルに変換
    new_p = Path(new_folder_path)
    files = list(p.glob('*.*'))
    
    for i,f in tqdm(enumerate(files)):
        print('画像トリミング数：{0}/{1}'.format(i+1,len(files)))
        img = Image.open(f)
        imgname = os.path.basename(f)
        newfname = 'crop_' + imgname
        
        # .crop((左上x,左上y,右下x,右下y))で指定.
        # 左上の座標が(x, y) = (left, upper)、右下の座標が(x, y) = (right, lower)に対応する。    
        img_resize = img.resize((634, 9606), Image.LANCZOS)
        img_resize.crop((0, 0, 634, 935)).save(new_p/newfname, quality=95)
else:
    print('すでにfolderが存在します.')
```

# 課題
・関数化していない
・特定のサイズに切り出しているので汎用性は低い
・画像数が増えると時間かかりそう(未テスト)

# まとめ
作業時間が1時間から1分になりました。
あと、もっといい書き方がある気がする。
Automation Anywhere Automation360  - 楽天トラベルの日付をUI使って設定してみる

#UIを使った日付の指定

題材としては、何でも良かったというか、テキスト入力が可能な楽天トラベルでないほうが適切だったのかもしれませんが（笑）
下記の様にカレンダー表示されたものをUIから選択して見ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/86032173-fd3e-2a3e-3fef-fe7b02ec56dc.png)

##ボットはこんな感じ

設定したい月と日にちを変数に入れて置き、
レコーダーでキャプチャしたオブジェクトに対する操作をしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/a44f21f9-fa25-fbe0-9ac3-5798ea36401d.png)

###月の指定
月の指定は、ドロップダウンボックスになっています。
オブジェクトとしてこのドロップダウンボックスを選択しました。
すると、アクションに「テキストで項目を選択」という良さそうなものが。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/4304a96b-ecc1-6666-dfe5-ea9cd09fa869.png)

###日にちの指定
日にちの指定の方は、どうやらカレンダーが表形式になっているようで、
そのままテーブルとして認識されましたので、それを選択してみました。
すると、アクションに「テキストでセルをクリック」という、
これまたちょうど良さそうなものが！
変数に入れて置いた値が入るように設定してします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/f6ca5b5a-c13f-81b6-d14b-0fa4aa23d148.png)

###実行！
まぁ、画像だと何がどうなったかは分かりませんが、
こんな感じで、指定した日付になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/aeb07260-d53c-8be1-448a-c9e9773f44f0.png)

##まとめ
カレンダーは、年・月が異なると、その位置が異なってきますので一見すると対応難しそうですが、HTMLで表として設定されていれば、今回使ったような形で自動化は非常に簡単にできる事が分かりました。

何か自動化したいことがあった時は、まずはやってみる。
もしかすると、今回の様に開発UIにヒントがあるかもしれません。
それでも出来なかった時は、コミュニティで聞いてみたり、Webを検索してみると良いかと思います。
MySQL8: systemdでPassword Reset

MySQLのrootパスワードリセットの情報はmysqld_safeを使ったものが多いです。
systemdを使っているとハマるので備忘録としました。

```vim:環境変数の変更からの再起動でセーフモードにする
# systemctl stop mysqld
"セーフモードの環境変数設定
# systemctl set-environment MYSQLD_OPTS="--skip-grant-tables"
"セーフモードで起動
# systemctl start mysqld
```

```vim:パスワードの消去
"rootでログイン
# mysql -u root
"データベースの選択
mysql> use mysql
"root権限ユーザーの表示
mysql> SELECT user, host, authentication_string FROM user;
"rootのパスワードを消去
mysql> UPDATE user SET authentication_string=null WHERE User='root';
"書き込み
mysql> FLUSH PRIVILEGES;
mysql> exit
```

```vim:環境変数を元に戻す。
# systemctl unset-environment MYSQLD_OPTS
```

```vim:MySQLの起動とパスワードの再設定
# systemctl start mysqld
"起動確認
# systemctl status mysqld
"ログイン
# mysql -u root
"パスワードの再設定
mysql> ALTER USER 'root'@'localhost' identified BY '{新パスワード}';
mysql> exit
```
LGTMお願いします！
モチベーションがあがります！
APIを利用したアプリをMVCで書く際につまずいたところ(Swift)

##はじめに
今回僕は、位置情報から国土地理院のAPIを使って標高を取得し、表示するという簡単なアプリをMVCで書こうと思った際にあるところでつまずきました。MVCで書こうと思ったのはなんとなくかっこいいし、きれいだから。

具体的に言うと、**Model**ファイルでAPIを利用して取得した標高を**Controller**ファイルに渡す際につまずきました。**非同期通信**らへんの問題です。どうしてもうまく行かなくて、teratailで質問してみたところ親切な人に丁寧な回答をもらい解決することができました。ありがとうございました。

回答には**クロージャ**を使っていました。初心者の敵**クロージャ**です。しかし今回始めてその**クロージャ**の使い道と便利さがわかったような気がしたので、よかったら最後まで見てください。


##大まかな流れ
Modelで標高を取得し、それをControllerを通じてViewにわたすという操作をしています

```Swift:Controller
//位置情報が更新されたときに呼ばれるメソッド
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    DispatchQueue.main.async {//UIの更新はメインスレッドで行う
        //位置情報が入ったlocationsをModelに渡して標高を取得し
        //その情報をViewに渡してUIを更新する
        customView.elevation = model.getElevation(locations)
    }
}
```

```Swift:Model 
var elevation = 0.0

func getElevation(_ Locations: [CLLocation]) -> Double {
    //通信処理の準備

    APIを使った通信処理 { (data, response, error ) in
        //デコードしたりなんやかんやで標高を取得する
        elevation = 取得した標高
    }

    //取得した標高を返す
    return elevation
}
```

##つまずきポイント
どうやってもgetElevationで取得した標高をControllerを通じてViewにわたすことができない。
非同期通信についてたくさん調べてやってみたが全然うまく行かない。通信処理からelevationに標高を代入する前に**getElevationメソッド**が終了してしまい、取得した標高をUIに表示することができませんでした。そんなときに助けてくれたのがクロージャでした。

##ここで役に立つのかクロージャ！
以前クロージャの記事を書いたが、いまいち使い所がわからなかった。
[Swiftクロージャ　これいつどうやって使うの？](https://qiita.com/groot/items/db36b8a5029b79c3add5)
ところが今回なんとなくわかった、気がする。

まず今回うまく行かなかった原因は、取得した標高を変数に代入する前にメソッドが終了して、意図した戻り値を返すことができていなかったからです。
![IMG_E903CC116E29-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622952/e69f6fd9-93d7-be9f-a3c3-826ee99584b4.jpeg)


これを解決するためにreturnを使うのをやめ、通信処理が完了したらクロージャを実行して値を返すようにします。

##クロージャの出番
今までのコードを以下のように書き換えます

```Swift:Controller
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    model.getElevation(locations, completionHandler: { (elevationString) in
        DispatchQueue.main.async {
            self.customView.elevation = elevationString ?? "標高を取得できませんでした"
        }
    })
}
```

```swift:Model
var elevationString = "0.0m"
func getElevation(_ Locations: [CLLocation], completionHandler: @escaping (String?) -> Void) {
    //通信処理の準備

    APIを使った通信処理 { (data, response, error) in
        //デコードしたりなんやかんやで標高を取得
        elevationString = 取得した標高
        completionHandler(elevationString)
```

##解説
最初にこの書き方を見たときは少し怯んだのですが、自分なりにコードの解説をしてみます。

![IMG_89A8AD4E3EDE-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622952/f6e95ae9-abe7-c51f-52ad-4011003d8163.jpeg)

###①クロージャの設置
まずクロージャを使って**completionHandler**というものを定義しています。このcompletionHandlerは**String?型**の変数を持っています。

###②クロージャに値を代入
国土地理院から標高を取得するという通信処理が完了したら、クロージャを呼び出してもらってその標高を代入します。

###③代入された値を利用する
代入された値を利用して、Viewに渡します。

実は③の部分は最初から使っていた以下のコードと同じ操作をしています。

```Swift:Model
APIを使った通信処理 { (data, response, error) in
    //dataを解析したり
    //errorが返ってきたら出力したり
}
```

今回だと通信処理が完了するまではクロージャは呼び出されず、何も値を持っていません。通信処理が完了したらクロージャが呼び出され値を代入し、その値をViewに渡すというふうになっています。
##まとめ
まだまだ理解しきれていないところはたくさんあります。

1. ``@escaping``について　
2. 循環参照について

クロージャの使い所を実感できただけでも成長したなと思いました。修正やもっとこんなふうに書いたほうがいいよなどありましたらお願いします。
μT-Kernel 3.0を「B-L475E-IOT01A - STM32L4 Discovery kit IoT node」に移植してみた

# 目的

μT-Kernel 3.0の移植例を通し、その勘どころ（みたいなもの）を知っていただこうという記事です。

# μT-Kernel

## μT-Kernelとは

μT-Kernelとは、ずばり組み込み向けのRTOSです。高いリアルタイム性・軽量・移植しやすさが特徴。

**μT-Kernel | トロンフォーラム**
https://www.tron.org/ja/tron-project/what-is-t-kernel/mt-kernel/

## μT-Kernel 3.0

その最新バージョン、μT-Kernel 3.0が2019年12月にリリースされています。

[仕様書](https://www.tron.org/ja/specifications/#TEF020-S004-03.00.00)
[ソースコード（GitHub）](https://github.com/tron-forum)

なお残念ながら、対応ボードは以下の2種類のみ。

- TX03 M367 IoT-Engine
- RX231 IoT-Engine

ただ、このバージョンでは更に移植性が増したとのこと。
ということで、手持ちのボード「B-L475E-IOT01A - STM32L4 Discovery kit IoT node」に移植してみることにしました。

# 成果物と解説

## ソースコード

先に紹介してしまいますが（笑）、以下です。

**imagou/mtkernel_3: micro T-Kernel 3.0**
https://github.com/imagou/mtkernel_3/

## 実装手順

### おことわり

実装レベルは、以下の最低限なものとしてあります。
製品に載せるには色々と不足・問題がありますが、取っ掛かりとしてはよいかと・・・。

- UARTでデバッグログが出力できる
- RTOSとして期待通り（？）に動く（ディスパッチ、タイマ）

### 1. 移植対象ディレクトリをコピーして作成

移植対象ディレクトリは、以下の3つがあります。

- 対象ボード（今回の場合、「B-L475E-IOT01A」）
- 対象マイコン（今回の場合、「STM32L475」）
- 対象マイコンのコア（今回の場合、「ARM Cortex-M4」）

これらを、既存のディレクトリをコピーし、作成します。
今回は「TX03 M367 IoT-Engine」をコピー元として選択しました（ARM Cortex-M3ベースなため、近しい）。

### 2. ビルドを通す

対象のボード、マイコン、コアに対応するよう、オプション定義をします。
（そうしないと、ビルド対象が切り替わらない）

以下のmakefile差分が参考になるかと思います。

**Comparing tron-forum:master...imagou:develop_B-L475E-IOT01A · tron-forum/mtkernel_3**
https://github.com/tron-forum/mtkernel_3/compare/master...imagou:develop_B-L475E-IOT01A#diff-1b00c5e169d416dfd6d5ad9b7aa4d23f

ビルド方法は、上記makefileが配置されているディレクトリにて、makeと打つだけです。

### 3. IDEへの取り込み

デバッグは必須なため、IDEに取り込みます。

私は以下を参考にし（手前味噌）、STマイクロのIDE、STM32CubeIDEに取り込みました。

**STM32CubeIDEでTOPPERS/ASPカーネルを動かす - 本編 - Qiita**
https://qiita.com/imagou/items/1a09d9afecc3f62e22d1


### 4. リセット後の動作確認

IDEにて、リセット後にハンドラが呼び出されることを確認しておきます。
（ここがまともじゃないと、デバッグどころではありません）

今回はマッピング（ベクタテーブルとハンドラ）の調整が必要でした。

### 5. ひたすら実装

以降は、コピーしたままでは当然動かないので、頑張って実装します。

といってもゼロベースは辛いので、今回は以下を参考にしました。

- STM32CubeIDEで、実動作するプロジェクト
- TOPPERS ASP-Kernel STM32L476 discoveryプロジェクト
- STマイクロ H/W仕様書（当然）

ポイントを絞り、かつIDEデバッグをしながら進めれば、時間は掛かったとしても、間違いなく動くモノはできます！

# おわりに

雑な紹介ではありますが、目的の通り、勘どころが伝われば幸いに思います！
Macのターミナルからhttp-serverコマンドを使って Webサイトを検証できるようにした

Macが突然壊れたので新しいMacを購入した。
現在、Webサイトを運営中でそれの更新作業を新しいMacでしようとした時に、ローカル環境で検証できないようになっていた。

具体的には、ターミナルでhttp-serverコマンドを打ってもエラーが出てくる。
新しいMacを購入してから環境構築をして無いねんから、そりゃ当然ですね。

とうことで、環境構築をすることにしましたが、ちょこちょこ詰まったので、ここに残しておきます。

主にこちらの記事を参考にさせていただきました。
https://qiita.com/standard-software/items/1afe7b64c4c644fdd9e4

#とりあえずhttp-server コマンドのインストール
とにもかくにも、まずインストールを試みる

```
% npm install http-server -g
```

しかし、下記応答が。。。


```
zsh: command not found: npm
```

#command not found: npmと出た時の対処
npmコマンドが使えないよ。とのことなので、以下の記事を参考にして進める。
https://qiita.com/sinmetal/items/154e81823f386279b33c

基本的には上記のリンク先通りにすればオッケー
ここでは、その過程で詰まったところを記載します。

##source ~/.bash_profileコマンドで大量のエラー

.bash_profile が見当たらなかったので、下のサイトを見ながら、ホームに.bash_profile を作成。
http://banker0507.blogspot.com/2012/11/macbashprofile.html

https://qiita.com/sinmetal/items/154e81823f386279b33c
上記リンクに沿って下記コマンドを実行

```
% source ~/.bash_profile
```

すると下記のエラーが

```
command not found: rtf1ansiansicpg932cocoartf2513
command not found: cocoatextscaling0cocoaplatform0{fonttblf0fmodernfcharset0
command not found: colortbl
command not found: red255green255blue255
command not found: red255green255blue255
command not found: red83green83blue83
parse error near `;;'
```

なんだこれは？とりあえず.bash_profileの中身を見てみる

```
% cat .bash_profile

{\rtf1\ansi\ansicpg932\cocoartf2513
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red255\green255\blue255;\red83\green83\blue83;}
{\*\expandedcolortbl;;\cssrgb\c100000\c100000\c100000;\cssrgb\c40000\c40000\c40000;}
\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
\deftab720
\pard\pardeftab720\sl380\partightenfactor0

\f0\fs26 \cf2 \cb3 \expnd0\expndtw0\kerning0

\outl0\strokewidth0 \strokec2 export PATH="/usr/local/bin:$PATH:/usr/local/sbin"\
export PATH=$HOME/.nodebrew/current/bin:$PATH
}
```

なぜかよくわからない文がたくさん、、、
viで中身を編集し、下記の状態にする。

```
% cat .bash_profile

export PATH="/usr/local/bin:$PATH:/usr/local/sbin"
export PATH=$HOME/.nodebrew/current/bin:$PATH
```

もう一度

```
% source ~/.bash_profile
```

無事エラーなしで解決

#http-server実行でローカル環境での検証環境構築成功
その後もせこせこと参考ページを見ながらインストール等を実施し、最後に

```
% http-server

Starting up http-server, serving ./
Available on:
  http://127.0.0.1:8080
  http://192.168.10.7:8080
Hit CTRL-C to stop the server
```
http://localhost:8080/
にアクセスすると、、、、

無事、ローカルでの検証環境を構築することができました！

上記のサーバを停止したいときはcontrolキーとCを同時に押してください。
Rubyの細かい文法: 同名の変数とメソッドがある場合

※ 09/12 コメントの指摘を受けて書き足し。

Ruby では変数とメソッドに同じ名前をつけられます。同名の変数とメソッドがある場合、変数のほうが優先されます。定義の順序とは関係ありません。

`()` を付ければ、メソッドと見なされます。引数を指定しても、メソッド呼び出しになります。

```ruby
def foo(n = 1)
  "method" * n
end

foo = "variable"

# これは変数
foo #=> "variable"
# これはメソッド呼び出し
foo() #=> "method"
# これもメソッド呼び出し
foo 2 #=> "methodmethod"
```

`.` を付けてレシーバを指定したときも、メソッドと見なされます。

```ruby
public  # Ruby 2.6まで: private だと . で呼び出せない / 2.7以降: publicなしでもOK
def foo(n = 1)
  "method" * n
end

foo = "variable"

# これは変数
foo #=> "variable"
# これはメソッド呼び出し
self.foo #=> "method"
```

Rubyのクラス名は定数名、つまり変数の一種なので、同じ名前のクラスとメソッドがあるときは上記と同じ動作になります。

```ruby
public
def Foo(n = 1)
  "method" * n
end

class Foo
end

# これはクラス
Foo #=> Foo
# これはメソッド呼び出し
Foo() #=> "method"
# これもメソッド呼び出し
Foo 2 #=> "methodmethod"
# これもメソッド呼び出し
self.Foo #=> "method"
```

[Kernelモジュール](https://ruby-doc.org/core-2.7.1/Kernel.html) には、ArrayとかStringという名前のメソッドがあります。

```ruby
# Stringクラスじゃなくて、KernelモジュールのStringメソッドの呼び出し。
String(1) #=> "1"
```
JavaにおけるfinalとImmutableの違い

#JavaにおけるfinalとImmutableの違いって？

最近GuavaのImmutable Listを使う機会があったのですが、ふとImmutableとfinalの違いってなんだ？と疑問になって調べてみました。

##Immutableの特徴
・オブジェクトの値そのものを変更することを禁止
・参照先を変更することは可能

##finalの特長
・参照先の変更をすることを禁止
・変数の値そのものを変更することは可能

では、JavaではImmutableで代表的なStringとMutableなStringBuilderを使って検証してみます。

```Java
class Main
{
	public static void main (String[] args) throws java.lang.Exception
	{
		 final String str = "apple";
		 final StringBuilder sb= new StringBuilder("ringo");
		
 		str = str + "ringo";　//コンパイルエラー。Stringの+は参照先変更を伴う。
                String s = "ringo";
                str = s;             //コンパイルエラー 
		sb.append("apple");
		sb = new StringBuilder("ringo");　///コンパイルエラー。参照先変更。
		System.out.println(str);
		System.out.println(sb);
	}
}
```

こうやって比較してみると割と単純ですが、finalは値が不変であることと勘違いしていたのと、意外と日本語記事がなかったので書いてみました。
AndroidにLaravelなどをインストール

UserLandを使用してAndroid端末にLaravelなどをインストールします。

Laravel

~~~~
sudo apt install -y php php-zip php-mbstring php-xml ;
curl https://getcomposer.org/installer | php ;
sudo mv -i composer.phar /usr/local/bin/composer ;
composer global require "laravel/installer" ;
~~~~

以下はおまけです。

php-imagick

~~~~
sudo apt install -y imagemagick ;
sudo apt install -y libmagickwand-dev ;
sudo apt install -y pkg-config ;
sudo apt install -y php-dev ;
sudo pecl install imagick ;
sudo apt install -y php-pear ;
~~~~

php-gd

~~~~
sudo apt install -y php-gd ;
~~~~

VNC（初期のUIが微妙だからなんとかしたい）

~~~~
sudo apt install -y xfce4 ;
sudo apt -y install vnc4server ;
~~~~

参考リンク

Andoird端末上で Linux を遊ぶ 1 - Qiita 
https://qiita.com/syuzabu/items/e0cf3b07fc241ddafc4f
Pythonで指数表現のfloatをstrに変換する

Pythonでは、数値型を文字列型に変更するためにはstr()でキャストすればよいが、指数表現のfloatをstr()でキャストすると何だかイケてない結果になった。

```
Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 0.1
>>> str(a)
'0.1'
>>> b = 0.00000000000000000000000000000000000000001
>>> str(b)
'1e-41'
```

この時、str(b)は
'0.00000000000000000000000000000000000000001'
となってほしい。

以下に記載されている関数を使わせていただくと、うまくできた。

[参考]https://stackoverflow.com/questions/38847690/convert-float-to-string-in-positional-format-without-scientific-notation-and-fa/38983595#38983595

```python
def float_to_str(f):
    float_string = repr(f)
    if 'e' in float_string:  # detect scientific notation
        digits, exp = float_string.split('e')
        digits = digits.replace('.', '').replace('-', '')
        exp = int(exp)
        zero_padding = '0' * (abs(int(exp)) - 1)  # minus 1 for decimal point in the sci notation
        sign = '-' if f < 0 else ''
        if exp > 0:
            float_string = '{}{}{}.0'.format(sign, digits, zero_padding)
        else:
            float_string = '{}0.{}{}'.format(sign, zero_padding, digits)
    return float_string
```

```
Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 0.1
>>> str(a)
'0.1'
>>> b = 0.00000000000000000000000000000000000000001
>>> str(b)
'1e-41'
>>> def float_to_str(f):
...     float_string = repr(f)
...     if 'e' in float_string:  # detect scientific notation
...         digits, exp = float_string.split('e')
...         digits = digits.replace('.', '').replace('-', '')
...         exp = int(exp)
...         zero_padding = '0' * (abs(int(exp)) - 1)  # minus 1 for decimal point in the sci notation
...         sign = '-' if f < 0 else ''
...         if exp > 0:
...             float_string = '{}{}{}.0'.format(sign, digits, zero_padding)
...         else:
...             float_string = '{}0.{}{}'.format(sign, zero_padding, digits)
...     return float_string
...
>>> float_to_str(b)
'0.00000000000000000000000000000000000000001'
```
RHEL7にCentOS 7 repositoryからPacemakerを導入

# RHEL7にCentOS 7 repositoryからPacemakerを導入

# 環境

OS: Red Hat Enterprise Linux Server  VERSION 7.8 (Maipo)
追加repo: CentOS7

# 導入手順

Pacemakerは、HA Add-onサブスクリプションが無い状態の場合、CentOS Baseのリポジトリーを追加し、そこから導入可能。(Red Hat社のサポート無し)

以下に手順の記載があるが、若干不足情報があるので注意。

ClusterLabs  RHEL 7 Quickstart
RHEL 7
https://clusterlabs.org/quickstart-redhat.html

## repo追加

```
# cat <<'EOF' > /etc/yum.repos.d/centos.repo
[centos-7-base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-$releasever
enabled=0
EOF 
```

- gpgkeyの指定を追加
    - gpgkey=を記載せず、gpgcheck=0としても良い。
    - gpgkey=を記載せず、別途以下のコマンドなどによりgpgkeyを追加する対応等も可能

```
# rpm --import http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-7
```


- enabled=0にて、他のリポジトリーとコンフリクトしない様にdisableとしている
    - yum-config-manager --disable centos-7-base によっても指定可能
    - yum repolistにて有効(|無効|all)であるリポジトリーを確認可能



## 導入

```
# yum \
--disablerepo='*' \
--enablerepo=centos-7-base \
--releasever=7 \
install -y pacemaker pcs resource-agents
```

- 一時的に、通常使用するリポジトリーを無効化、centos-7-baseを有効化して導入を試みる。
- --releasever=7を指定 (もしくは/etc/yum.repos.d/centos.repoにて$releaseを7としておく)
    - 注: RHEL7において$releaseが展開されていた7Serverでは問題。他のRHEL系repoとの同時使用を考慮すると、/etc/yum.repos.d/centos.repo直接編集の方が良いと思われる。


# crmshの導入(オプション)

Linux-HAなどで推奨しているcrmコマンドを使用するには、別のレポジトリーから導入する必要がある。

参照
https://crmsh.github.io/download/#_red_hat_centos_fedora

## crmshのrepo追加

```
# yum-config-manager --add-repo http://download.opensuse.org/repositories/network:/ha-clustering:/Stable/CentOS_CentOS-7/network:ha-clustering:Stable.repo

# yum-config-manager --disable network_ha-clustering_Stable
```

- (元の手順には無いが、)こちらもdesableにしておいている。

## pacemakerとcrmshを同時に導入する例

```
# yum \
--disablerepo='*' \
--enablerepo=centos-7-base,network_ha-clustering_Stable \
--releasever=7 \
install -y pacemaker pcs resource-agents crmsh
```

## Ansible Playbook(task)の例

```yaml

- yum_repository:
    name: centos-7-base
    description: CentOS-7 - Base
    mirrorlist: http://mirrorlist.centos.org/?release=7&arch=$basearch&repo=os
    gpgkey: http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-7

- shell: |-
    set -x
    exec 2>&1
    yum-config-manager --add-repo http://download.opensuse.org/repositories/network:/ha-clustering:/Stable/CentOS_CentOS-7/network:ha-clustering:Stable.repo
  register: r

- debug:
    var: r.stdout_lines

- yum:
    name:
    - pcs
    - pacemaker
    - corosync
    - resource-agents
    - corosync-qdevice
    - corosync-qnetd
    - crmsh
    #releasever: 7
    #disablerepo: '*'
    #enablerepo:
      #- centos-base
      #- network_ha-clustering_Stable

```
メモ：Exment on Lightsail + Docker(nginx)環境で、CORSするためのnginx.conf設定

先日、[Lightsail + Dockerという組み合わせで、ExmentというOSS WebDBシステムを構築したという話](https://qiita.com/kohki-shikata/items/5f274d3f842c07e26282)を書きました。

んで、その後にも[ExmentとMFクラウド請求書をAPIで組み合わせる記事](https://qiita.com/kohki-shikata/items/5f274d3f842c07e26282)も書きました。

で、両者の記事で大事なことを書き忘れていたんですね。

## ExmentのAPIが通らない

Postmanでは通るんだけど、Node.jsで通らない。なぜだ…　そうか、CORSか…

ということで、Exmentを運用しているDocker-composeはこちらなのですが、Webサーバーはnginxで動いています。

というわけで、nginx用のCORS設定を追記しました。

```nginx.conf
server {
    listen 8080;
    server_name _;

    root  /var/www/exment/public;
    index index.php index.html;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin '*';
            add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE';
            add_header Access-Control-Allow-Headers 'Origin, Authorization, Accept, Content-Type';
            add_header Access-Control-Max-Age 3600;

            add_header Content-Type 'text/plain charset=UTF-8';
            add_header Content-Length 0;

            return 204;
         }

        try_files $uri /index.php?$query_string;
    }

    location ~ \.php$ {
        add_header Access-Control-Allow-Origin '*' always;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

```

- 参考：[APIサーバを立てるためのCORS設定決定版](https://qiita.com/hirohero/items/886733f50f37404235db)
PHPStromのPHP language levelを更新しても戻ってしまう。

# やりたこと
PHPStromのPHP language levelを変更したら次回起動時も、変更した値を保持していて欲しい。

# 環境(今回の作業に関連ないものも記載)
* PHP7.4
* PHPStorm2020.2

# 設定
PHP language levelはcomposer.jsonを参照している。
なので例えば、composer.jsonが以下のように7.2になっていると、PHPStormのPHP language levelを7.4に変えても次回起動時に元に戻ってしまう。

```
    "require": {
        "php": ">=7.2",
```

composer.jsonを7.4に変更して`composer update`をすると解決する。
（そもそも自分のDockerのPHPが7.4なので7.4にしておくのが正しかった。）

# 参照
こちらのようにcomposer.jsonとの同期を切るという手もある。
（こちらの対応をするシチュエーション想像つかないけど）

https://qiita.com/ponsuke0531/items/7b6667366c55e3217150
ありがとうございます。
iges igsファイルについてちょっと調べてみた

# 目的

- iges igsファイルについて軽く調べたので簡単にまとめる

# IGESとは？

- データの共通規格のことである。
- 主にCADソフト間でデータをやり取りする際に、本規格にあったデータを用いることにより異なるCADソフトでも同じ様に図形を表示することができる。
- 「Initial Graphics Exchange Specification」を略してIGESとなる。
- 自動車部品のCADデータの中間データとして用いられることが多いらしい。
- 若干違うがJSONになんだか似ていると感じた。

# igesとigsファイルの違いは？

- 確証の得られるエビデンスは得られなかったが内容に違いはないと感じられた。
- jpegとjpgと同じ様に拡張子が別ながら同じJPEG規格の画像ファイルであるのと同じである。
- ただしCADソフトの都合上、インポートファイルをigesもしくはigsで限定している場合がある。

# iges igsファイルとは？

- IGES規格に準じたCADの中間データのファイル形式のことである。
- 「ファイル名.iges」や「ファイル名.igs」の様なファイルのことである。

# iges igsファイルの内容

- 一行80文字で構成されたアスキーテキストファイルである。
- データは5個のセクションに分けて構成されている。
    - スタートセクション
    - グローバルセクション
    - ディレクトリエントリセクション
    - パラメータデータセクション
    - ターミネートセクション
- テキストファイルなので原理上エディターでの編集が可能である。

# IGES規格のファイルが欲しい方

- 金属パーツなどのメーカーさんのWebページではCADデータをIGES規格で公開してくださっている企業さんがある。
- 筆者が試しに取得してみたigsファイルの公開場所を下記に記載する。
    - [オザック精工株式会社 CADデータダウンロード](https://www.ozak.co.jp/caddata-j/#c01)

# 参考文献

- [IGESデータの基礎知識](https://www.cgsys.co.jp/g/rf/product/glossary/images/iges.pdf)
- [https://www.alphacox.com/blog/798-2/](https://www.alphacox.com/blog/798-2/)
- [IGESデータ比較について](http://www.dtcorp.co.jp/share/digital_compare/iges.html)
【Go】time.Format() の使い方が分かりにくかった

## TL; DR
time.Format()の第一引数で 年,月,日... に対応する文字列は決まっているものがある。

| 単位 | 文字列 |
|:-:|:-:|
|年|2006|
|月|01|
|日|02|
|時|03|
|分|04|
|秒|05|
|マイクロ秒|0700|

つまり、`年-月-日` のようにフォーマットしたいときは下記のように指定します。(このときに使う数字が重要)

```:go
n := time.Now()    // 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
f := n.Format("2006-01-02")
fmt.Print(f)       // 2009-11-10
```
https://play.golang.org/p/-lTrt8knKPQ

根拠はtimeパッケージのソースコードに書いてあります。(73行目〜, RFC3339が日本人的に見やすいと思います。)
https://golang.org/src/time/format.go

これを使えばフォーマットできるのか！とか思って初見では適当に下記のようにしたら訳のわからない文字列が返ってきて少しハマりました。

```:go
n := time.Now()     // 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
f := n.Format("2000-01-01")
fmt.Print(f)        // 10000-11-11
```
https://play.golang.org/p/SLDi10SgTsl

ちなみに、なんで2006なんだ？と思い知人に聞いてみたところ、アメリカ式の日時の記法では
`月 日 時 分 秒 年 (マイクロ秒)` となるらしく、これに順番に数字を当てはめると...
`01 02 03 04 05 2006 (0700)` となるため、このような対応関係になっているそうです。

## ひとこと
timeパッケージはクセがあってちょっと面倒ですね :frowning2:
DatabricksのNotebookの単体テストを行う

# はじめに
以下のNotebookの単体テストを行います

```python:MyNotebook
def hoge(i):
  return 'hoge'*i

def fuga(i):
  return 'fuga'*i
```

#テスト用Notebookの作成
Notebook`MyNotebook`と同じフォルダに、テスト用Notebook`MyNotebookTest`を作成します

```python:MyNotebookTest
# Cmd1 
%run "./MyNotebook"

# Cmd2
import unittest

class MyNotebookTests(unittest.TestCase):
  
  def test_hoge(self):
    self.assertEqual(hoge(3), 'hogehogehoge')
    self.assertNotEqual(hoge(2), 'hoge')

  def test_fuga(self):
    self.assertEqual(fuga(3), 'fugafugafuga')
    self.assertNotEqual(fuga(2), 'fuga')

suite = unittest.TestLoader().loadTestsFromTestCase(MyNotebookTests)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
```

作成するポイントとして、

- `Cmd 1`で先に`%run`コマンドを実行してテスト対象となるNotebookを実行します

```python
%run "./MyUnittest"
```
- `Cmd 2`以降でpythonテストフレームワークである[unittest](https://docs.python.org/ja/3/library/unittest.html)を用いてテストケースを書きます


# 実行結果
以下のようにテストOKとなることを確認します

```
test_fuga (__main__.MyNotebookTests) ... ok
test_hoge (__main__.MyNotebookTests) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
Out[50]: <unittest.runner.TextTestResult run=2 errors=0 failures=0>
```
研究者におすすめ　サイエンスマガジンを日本語でチラ読みする

<h1>研究者におすすめ　サイエンスマガジンを日本語でチラ読みする</h1>
<p>3大科学雑誌（Nature, Science, Cell)のひとつ、「サイエンス誌」。
幅広い分野で世界最高峰の研究に触れることができます。
サイエンス誌にはＥメールアラートとＲＳＳ購読のサービスが充実しています。　 </P>
<link>https://www.sciencemag.org/about/email-alerts-and-rss-feeds</link>
<p>
このサイエンスのＲＳＳをＧｏｏｇｌｅ翻訳した後、エクセルにまとめ、自分のＷＥＢページにアーカイブしています。今回は、ＲＳＳを翻訳し、エクセルにまとめるコードを紹介します。
<h3>目的</h3>
<p>サイエンスマガジンのＲＳＳを読みこみ、自動翻訳をかけ、エクセルファイルに落とす。</p>
<h3>方法</h3>
<code>python3
pandas
feedparser
googleapiclient</code>

<h3>コード</h3>
<p>https://github.com/isamimasi/sciencemagazine</h3>

<h3>応用</h3>
エクセルファイルに修正をいれて、Twitterにあげています。
<link>https://twitter.com/hashtag/サイエンス誌</link>
<br>
ワードプレスに自動投稿しています
<link>http://sciencekids.tokyo/noni/?cat=26</link>
部内バチャ解説 2020.09.11

## [B - Uneven Numbers](https://atcoder.jp/contests/abc136/tasks/abc136_b)

```cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
  // 入力部
  int n;
  cin >> n;

  // 桁数が奇数であるようなものの個数をカウントする変数
  int ans=0;

  // 1 ~ N までの全ての数字で全探索
  for(int i = 1; i <= n; i++){

    // cp: 現在のiの値(判定したい数値)をコピー
    // digit: 桁数をカウントするための変数
    int cp=i, digit=0;

    // cp(iのコピー) が 0になるまで 10 で割るをを繰り返す。
    // 10で割るたびにcpに1を加算して桁数を数えていく。
    while(cp){
      digit++;
      cp /= 10;
    }

    // 桁数が2で割り切れない場合、最終的な答えに1を加算する。
    if(digit % 2) ans++;
  }
  cout << ans << endl;
}

```


## [B - ATCoder](https://atcoder.jp/contests/abc122/tasks/abc122_b)

> イメージで言うと音ゲーとかの『ゲーム終了時の最大コンボ数』を出力するイメージが近いです。

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  // 入力部
  string s;
  cin >> s;

  // ans: 最も長い ACGT 文字列 の長さをカウントする
  // now: 連続で 'a', 'c', 'g', 't' があった回数をカウントする。
  //      それ以外の文字が途中に入った場合は0に戻す。
  int ans = 0, now = 0;

  // 文字列回数分だけループする。
  for(int i=0; i<s.size(); i++) {

    // 確認している文字が 'a', 'c', 'g', 't' であった場合は now に 1を加算。
    // それ以外なら now に 0 に戻す。
    if(s.at(i) == 'A' || s.at(i) == 'C' || s.at(i) == 'G' || s.at(i) == 'T') {
      now++;
    } else {
      now = 0;
    }

    // ansに『今までの最長のACGT文字列の長さ』と『現在の連続したAGCT文字列の長さ』を比較して長い方を格納する。
    ans = max(ans, now);
  }
  cout << ans << endl;
}

```

## [B - Grid Compression](https://atcoder.jp/contests/abc107/tasks/abc107_b)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int H, W;
  cin >> H >> W;

  vector<vector<char>> vec(H, vector<char>(W)); // H x W のchar型の二次元配列

  vector<bool> vecH(H, false); // i行目に＃があるならtrue, ないならfalse
  vector<bool> vecW(W, false); // j列目に＃があるならtrue, ないならfalse


  for(int i=0; i<H; i++) {
      for(int j=0; j<W; j++) {
          // char型の二次元配列に文字を入力
          cin >> vec.at(i).at(j);

          // '#' があるのであれば、その行と列のフラグを true にする。
          if(vec.at(i).at(j) == '#') {
              vecH.at(i) = true;
              vecW.at(j) = true;
          }

      }
  }

  for(int i=0; i<H; i++) {
      for(int j=0; j<W; j++) {
          // 参照してるマスの列と行のフラグがどちらもtrueならその文字のマスの文字を出力する。
          // vecH.at(i) が true なのは、i行目に '#' が存在することを示す。
          // vecW.at(i) が true なのは、i列目に '#' が存在することを示す。
          if(vecH.at(i) && vecW.at(j)) {
              cout << vec.at(i).at(j);
          }
      }
      // i行目のフラグがtrue(i行目に'#'が一つ以上存在する)のであれば改行する。
      // falseの場合に改行すると、何も表示していない行なのに改行しています。
      if(vecH.at(i)) cout << endl;
  }
}

```

## [B - Sum of Three Integers](https://atcoder.jp/contests/abc051/tasks/abc051_b)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  // 入力部
  int k, s;
  cin >> k >> s;

  // ansは、条件を満たす x, y, z の組み合わせの数
  int ans = 0;

  // x と y の あり得る全てのパターンを試す。
  for(int x = 0; x <= k; x++) {
    for(int y = 0; y <= k; y++) {
      // x と y が定まれば s = x + y + z を満たす z は一意に定まるので以下の通り。
      int z = s - x - y;

      // 求まった z が0以上9以下か判定
      if(0 <= z && z <= k) {
        ans++;
      }
    }
  }
  cout << ans << endl;
}

```
Laravelのバージョンアップを正しく理解する ~Laravel8へのバージョンアップは別に早くない~

# はじめに
2020年9月。Laravel8がリリースされました。このことについて「もう8なの！？」って驚きの声をいくつか見かけましたが、Laravelのバージョンアップは元々半年ごとに行なわれていたので特にそれ自体驚くことではないです。なので、おそらくそういった感想を漏らす人というのは、Laravel6以前の感覚でバージョンアップを眺めてしまっているのではないかと思います。

# 実は6以前のバージョン管理はいけてなかった
Laravelのバージョンの変遷を振り返ってみます。私は半年に1回バージョンアップしていると書きましたが、果たして本当でしょうか？

| バージョン | リリース日 | LTS？ |
| ---- | ---- | ---- |
| 5.0 | 2015/02 | No |
| 5.1 | 2015/09 | Yes |
| 5.2 | 2015/12 | No |
| 5.3 | 2016/08 | No |
| 5.4 | 2017/01 | No |
| 5.5 | 2017/08 | Yes |
| 5.6 | 2018/02 | No |
| 5.7 | 2018/09 | No |
| 5.8 | 2019/02 | No |
| 6.0 | 2019/09 | Yes |
| 7.0 | 2020/02 | No |
| 8.0 | 2020/09 | No |

少なくとも2015年以降、概ね半年に1回のバージョンアップを繰り返していることが分かりますね。しかし、バージョン6以降、それまでとバージョンの上がり方が違っているのに気づくでしょう。

そもそも、それまでバージョンは`5.1、5.2…`と半年ごとに`0.1`ずつしかあがっていませんでした。マイナーバージョンアップなら、その表記で良いでしょう。しかし、古参のLaravel使いはご存知の通り、これらのバージョンアップは後方互換性の無いメジャーバージョンアップです。特に`5.8`の変更なんて……。

# セマンティックバージョンニング
では、なぜ上のような認識の違いが生まれていたのかというと、単純にバージョン管理の仕様がプロジェクトごとに自由に策定されていたからです。しかし、それでは不便だと気づいたLaravelのコントリビューターの方々は、`6` にした際に、「[セマンティックバージョンニング](https://semver.org/lang/ja/)」という、バージョン管理の標準仕様を取り入れたのです。

このことについては、Laravel6のリリースノートで説明されています。

>Laravel and its other first-party packages follow Semantic Versioning. Major framework releases are released every six months (February and August), while minor and patch releases may be released as often as every week. Minor and patch releases should never contain breaking changes.

>When referencing the Laravel framework or its components from your application or package, you should always use a version constraint such as ^6.0, since major releases of Laravel do include breaking changes. However, we strive to always ensure you may update to a new major release in one day or less.

https://laravel.com/docs/6.x/releases#versioning-scheme

# さいごに
以上、Laravelのバージョン管理について説明しました。ちなみにバージョン6からセマンティックバージョニングを取り入れたことで、次のLTSはバージョン10(2021/08リリース見込み)というキリの良い数値となります。Laravel8はDXに考慮した非常に進歩的な仕様変更がいくつも取り入れられているので、興味深いバージョンです。しかしLTSではないので、商用利用でのバージョンアップはバージョン10まで待つという方針で良いかもしれませんね。
javascript関数ドリル　初級編drop関数の実相のアウトプット

##drop関数の課題内容
　　　↓
https://js-drills.com/blog/drop/

##drop関数の取り組む前の状態
functionの中をどうすればいいのかわからないがとりあえずコードを書こうとした

##drop関数に取り組んだ後の状態
size=1のところが理解できないです。

##drop関数の実装コード（答えを見る前）
```js

function drop (array,number){
    const dropArray=[]
for(let number=0;){}
return dropArray
}

// _.drop([1, 2, 3], 0);

// // => [1, 2, 3]
```

##drop関数の実装コード（答えを見た後）
```js
function drop(array, size = 1) {
  if (size === 0) {
    return [...array];
  }
  if (array.length <= size) {
    return [];
  }

  const droppedArray = [];
  for(let i = size; i < array.length; i++) {
    droppedArray.push( array[i] );
  }

  return droppedArray;
}


const numbers = [1, 2, 3];

console.log( drop(numbers), numbers );
// => [2, 3]

// _.drop([1, 2, 3], 2);
console.log( drop(numbers, 2), numbers );
// // => [3]

// _.drop([1, 2, 3], 5);
console.log( drop(numbers, 5), numbers );
// // => []

// _.drop([1, 2, 3], 0);
console.log( drop(numbers, 0), numbers );
// // => [1, 2, 3]
```
WSL(ubuntu)からWindowsのディレクトリのPermissionをいじりたい

### やりたいこと
WSlで動くubuntu上のターミナルから、Windowsのディレクトリ・ファイルのpermission(chmod, chown)をいじりたい！

WSLで、`chmod` コマンド等をsudo権限でうったとしても、全然permissionが変わらない、、

### 原因
Windowsディレクトリ(`/mnt/c`) をmountするときに、metadataの設定がないため、出来ないみたい


```
$ mount | grep -i ^C:
result: C:\ on /mnt/c type drvfs (rw,noatime,uid=1000,gid=1000,case=off)
```


### やること
1. mountオプションに、metadataを追加。`etc/wsl.conf` を作成する

```
$ sudo tee /etc/wsl.conf <<EOF >/dev/null
[automount]
options = "metadata"
EOF
```

2.　 `/mnt/c` をmountしなおすか、Windowsの再起動をする


### その他
`/mnt/c` ディレクトリ以下を、ubuntuの `/c` 以下にmountしたいときのコマンド

```

$ sudo mount --bind /mnt/c /c
```
＜企画・計画・設計＞　動く標的を動きながら狙う

**ビジネス環境は刻々変化しています。ユーザーのニーズも日々変化しています。それは従来の様に企画・計画に時間を掛ける事では時代の変化に追従できないばかりでなく、企業生命にも深刻な影を落としかねません。**
私たちはこれまで企画や計画にも正解を求めてきました。その結果、慎重になり突拍子もないような奇抜なアイデアは生まれなくなり、従来の焼き直しとなり、安全策を求めるあまり、動きは鈍重になってきました。時間を掛ければ正解を得られる時代はとっくに終わりました。これからは、決められた時間で出来るものをスピーディに提供し、評価しそのフィードバックで改善する方法、即ち**仮説＆実行＆検証の繰り返し**であり、その**サイクルを短くする**ことが肝になります。極端な言い方をすれば、このサイクルこそが計画であると言ってしまってよいのです。その期間は**最大でも6ヶ月を超えず、出来れば企業活動の四半期相当（すなわち3か月）に収めます。**言い換えると、その**期間に収まらないものは、対象（機能・サービス）を軽量化・少なくする**ように強制します。こうすることで、**過剰要求や実施（実行）しなければ価値が明確に判らないような機能・サービスを保険的に実装要求することも抑制**できるようになります。**タイムボックス思考**に切り替えることになります。
フィードバックする項目についてはリスクでの評価も必要です。リスクについては次の“リスクは絶えず変化する”で解説します。
また、企画を練っている時点で下記項目についての当初の見込みを明らかにしておくのも、評価の役に立ちます。
**企画そのもの魅力度と適社度**です。
**魅力度とはその企画自身の評価**で、売上・利益の可能性、成長の可能性、競争状況、リスク分散度、業界再構築の可能性、特別な社会状況（特許・優遇制度・認可制）といったものです。
**適社度とは、その企画に対する現時点での自社での適応能力の評価**です。どんなに魅力的なアイデアでも、自社のチャレンジ労力の評価で、資金力（自社にみあった資金力があるか）、現有マーケティング力の適合性、現有施設、現有人財とノウハウの適合性、現有技術・サービス企画力の適合性、原材料・部品・商品・情報の入手力、事業に対してマネージメントのサポートが十分に得られるか（例えば会社トップの思い入れが強い企画である）といった項目です。これは**VeriSMのマネジメントメッシュへ続く項目の候補**になり得ます。
もう一つ**ACDM（アーキテクチャ中心設計）の四つのアーキテクチャドライバ**をサイクル（仮説＆実行＆検証の繰り返し）によって明確にしていく方法もあります。アーキテクチャドライバとはハイレベルな機能要求、品質特性要求、技術制約、ビジネス制約の四つです。
この**アーキテクチャドライバもVeriSMのマネジメントメッシュの導出項目**となります。

また、これまでの机上論のような紙（電子版も含む）資料ではなく**製造物（ここでは機能・サービスを提供するシステム）で実現しようとする機能・サービスを確認**できるようにします。これは従来のプロトタイプとは全く違うもので、ビジネスデータや手続きを確り動作できるシステム（プログラム）であることです。机上で議論しても、**実際に製造物を前にすると、意見・要望・評価が変わる**のです。これを事前（机上で論じている期間）に抑え込むことは全くできないのです。『正しく要求を捉えれば品質が上がる』とは成りません。アジャイル開発のプラクティスを応用適応すれば実現可能です。
また、PowerAPPSやPowerBIといった**シチズンデベロッパーが利用するツールを使用して企画立案者が自ら動作する機能やサービスを作ってステークホルダーと議論**して進行させる方法も可能です。
要はJITでの重要項目をクイックに実現し、変化に対応できるコンパクトであることです。
そして、**リスクや状況が不明・見えない場合は仮説・検証を最短距離（時間軸）で行う**事です。このようになると、従来手法では太刀打ちできないのが明らかです。
Rails　アプリケーションの作成準備

##アプリケーションの作成##

```command:command
% rails _6.0.0_ new application -d mysql
```

・「6.0.0」でバージョンを指定しています。
・「application」は作成したいアプリケーション名を示します。
・「- d mysql」のオプションをつけることで、
　　データ管理ツールとしてMYSQLを使用します。
<br/>

##データベースの作成##
```ruby:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
```
「utf8」のようにエンコーディングの設定を行うことができます。
<br/>

```command:command
% rails db:create 
```
railsコマンドでデータベースを作成。
<br/>

##ルーティングの設定##

```ruby:config/route.rb
Rails.application.routes.draw do
  root to: "notes#index"
end
```
ルートパスへのアクセスがあったら、notes_controllerのindexアクションが呼び出されるようになる。
<br/>

##ビューとコントローラーの設定##

```ruby:config/application.rb
# 省略
 config.load_defaults 6.0
# 中略
 config.generators do |g|
   g.stylesheets false
   g.javascripts false
   g.helper false
   g.test_framework false
 end
```
rails gコマンドでコントローラーを作成する前に、必要のないファイルを生成しないように設定。
<br/>

```command:commnad
% rails g controller notes index
```
コントローラー作成時にコントローラ名に続けてアクション名を指定すると、
・notesコントローラーにindexアクションが作られる
・viewsのnotesフォルダにindex.html.erbファイルが作られる