OmniAICreator/Qiita-1.07M huggingface dataset:
Microsoft Teamsのレコーディングについて

# はじめに
Microsoft Teams(以下、Teams)でオンライン会議を行うことはありませんか？
遠隔地との打ち合わせを自社で済ませたいという場合にオンライン会議を行う機会が増えています。
また、最近はリモートワークを実施している企業も増えております。

今後ますますオンライン会議が増えていく中で、会議内容を欠席者にも共有したいとか、
エビデンスとして会議を残して置きたいというニーズが増えてきました。
Teamsにはオンライン会議をMicrosoft Stream(以下、Stream)に、
動画としてアップロードする機能があります。

#ライセンスについて
レコーディングを開始するには、以下のどれかのライセンスを保有している必要があります。
・ Office 365 Enterprise E1
・ Office 365 Enterprise E3
・ Office 365 Enterprise E5

また、レコーディングを行うユーザーは上記の中の Teams と Stream のライセンスを
持っている必要があります。レコーディングされた会議は Stream 上にアップロードされますが、
Stream のライセンスを持っていないユーザーは動画の閲覧もできませんので注意が必要です。

#動画のアップロード場所について
Teamsでチームを作成すると、自動的にOffice365グループが作成されます。(※ 設定によっては作成されません)
また、ここで作成されたOffice365グループと紐付くグループがStream上にも作成されます。
Teams でレコーディングを行うと、Office365グループと紐付いたStream上のグループに動画が投稿されます。

#動画の閲覧権限について
Stream上に投稿された会議動画は、既定でOffice365グループに所属するユーザーだけが見れる状態になります。
フルコントロール権限はレコーディングしたユーザーに割与えられ、それ以外のユーザーには閲覧権限が付与されます。
Office365グループに閲覧権限が付与されるので、Teams会議を行った時点で所属していなくとも、
その後に所属すれば閲覧できるようになります。

#注意点
レコーディングした動画が Streamのグループに紐付かずに投稿される場合があります。
これは、レコーディングを行うユーザーが **<font color="Red">初めてStreamにアクセスしてから最大24時間経過していない場合</font>**
に発生する可能性があります。
この問題が発生した場合、Stream上に問題が発生していない場合と同様の権限で投稿されます。
しかし、Streamのグループとは紐付いていないので、手動で紐付ける必要があります。

Streamのグループと紐付いていない動画には、以下のような！アイコンが表示されます。
![スクリーンショット 2019-06-29 13.14.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276299/dbf8fec7-1280-fa83-ebb7-55e2a29a0e72.png)

また、Teamsで**<font color="Red">チームを作成してから最大24時間経過していない場合</font>**も同様の問題が発生する場合があります。
さらに、動画にOffice365グループの閲覧権限が付与されてから実際に閲覧できるようになるにも
時間がかかるようで、権限を付与してからすぐに動画にアクセスするとアクセス拒否されてしまいます。

投稿された動画に全く関係のないユーザーは、**<font color="Red">明示的に権限を付与しない限り動画を見ることはできません</font>**
のでご安心ください。

#参考
会議と通話 - Office サポート　：
https://support.office.com/ja-jp/article/%e4%bc%9a%e8%ad%b0%e3%81%a8%e9%80%9a%e8%a9%b1-d92432d5-dd0f-4d17-8f69-06096b6b48a8?ui=ja-JP&rs=ja-JP&ad=JP
Firebaseのチュートリアルで Error reading rules file firestore.rulesと表示される場合

## Cloud Firestoreのセキュリティルールをローカルから更新しようとした際
/web-start下にfirestore.rulesが存在しなかったため、代わりにweb/firestore.rulesを確認し、下記のコマンドを実行するとエラーが発生しました。

```
firebase deploy --only firestore
```

```
⚠  functions: package.json indicates an outdated version of firebase-functions.
 Please upgrade using npm install --save firebase-functions@latest in your functions directory.

=== Deploying to 'friendlychat-23d6f'...

i  deploying firestore

Error: Error reading rules file firestore.rules
```
やはりweb-start下にファイルが必要だったらしく、web/firestore.rulesをコピーし配置することで、下記のように正常に更新できました。

```
=== Deploying to 'friendlychat-23d6f'...

i  deploying firestore
i  firestore: checking firestore.rules for compilation errors...
✔  firestore: rules file firestore.rules compiled successfully
i  firestore: uploading rules firestore.rules...
✔  firestore: released rules firestore.rules to cloud.firestore

✔  Deploy complete!
```
Rails6でcomposite_primary_keys(複合主キー)を使う

## 環境
Ruby 2.6.3
Rails 6.0.0.rc1
composite_primary_keys 12.0.0.rc5

## ActiveRecordで複合主キーを使いたい
SQLアンチパターンとしてもよく話題にあがる複合主キーですが
どうしても避けられない場合も有ると思います。
そんなあなたに[composite_primary_keys](https://github.com/composite-primary-keys/composite_primary_keys)

```
class User < A
  self.primary_key = %i[company_id company_user_id]

  has_one :email, foreign_key: %i[company_id company_user_id]
end
```

みたいな感じで使えます。

## 導入

``` Gemfile
gem 'rails', '=6.0.0.rc1'
gem 'composite_primary_keys'
```
上記の様に書いて `bundle install`

``` Gemfile.lock
composite_primary_keys (6.0.5)
```

`6．0．5` が入るのですがRailsを立ち上げると動きません。

理由が[ここ](https://github.com/composite-primary-keys/composite_primary_keys#versions)に書いて有りました

```
Version 12.x is designed to work with ActiveRecord 6.0.x
```

現在の12.xの最新は `12.0.0.rc5` の様子

``` Gemfile
gem 'rails', '=6.0.0.rc1'
gem 'composite_primary_keys', '=12.0.0.rc5' 
```

この様に設定することで使える様になりました。
リモートのサーバーにローカルのディレクトリをマウントする方法

#インストール方法
まずは、ローカルのPCに
・osxfuse
・sshfs
の二つをインストールします。

Macで、Homebrewが入って入れば以下でインストール可能です。

```shell
$brew cask install osxfuse
$brew install sshfs
```

#マウントする

###*マウント先のサーバーにはsshで接続できることが前提です。

###次に以下のコマンドで、実際にマウントします。

```shell
$sshfs username@hostname:/var/www/destination /Users/yourname/path/to/mountpoint -p ポート番号 -o IdentityFile=~/.ssh/samplesecret.pem
```

・username=マウント先サーバーのユーザー名
・hostname=マウント先サーバーのホスト名
・/var/www/destination＝マウント先サーバーのマウントしたいディレクトリ名
・/Users/yourname/path/to/mountpoint=ローカルPCでマウントしたいディレクトリ名
(ローカルの/Users/yourname/path/to/mountpointとリモートの/var/www/destinationがマウントされます。)
・IdentityFile=ssh接続する時の公開鍵


#host名を設定しているとき
configファイルで,Hostを設定しているとき,

例えば「ssh samplehost」だけでssh接続できるときは

```shell
$ssh samplehost
```
以下だけでOK

```shell
$sshfs samplehost:/var/www/destination /Users/yourname/path/to/mountpoint 
```


#アンマウントしたい時

アンマウントしたい時は以下のコマンドです。

アンマウントしたいローカルのディレクトリの絶対パスを指定します。

```shell
diskutil umount /Users/yourname/path/to/mountpoint
```

もし、これで失敗した場合は、プロセス確認し、killします。
そして、umount -fでアンマウントしてください

```shell
$ pgrep -lf sshfs
2449 sshfs root@*********:/var/www/xxxx /Users/yourname/path/to/mountpoint
$ kill -9 2449
$ umount -f /Users/yourname/path/to/mountpoint
```
自己紹介

これまでの活動内容と、これからの自己啓発内容を、重くない程度に載せていきたいと思います。

職業：システムエンジニア（約20年選手）
職歴：現職は日系大手SIerのAI&ロボティクス関連のビジネスを推進する部署
前職は大手ネット系企業、中堅SIer、ITベンチャーの起業、外資系SIerでフリーランスとWindows95が世の中に広まり始めるころから業界で地道に黙々頑張っていたオジサンの一人です。

得意なシステム：intra-mart、SFDC、AWS、GCP、java、Oracle、as400のどれかに刺さるエンタープライズシステムの構築が大好物です。

Python、Go、Ruby、vue.jsなどの新しい技術システム構築や、まだ日本語訳の少ない英文のみの技術選定、Ｒ＆Ｄ的な研究開発も過去には対応していた事があります。
最近ですとAI系のプロダクトやDocuSignなどのバックオフィス系サービスをエンタープライズシステムへ取り込むための製品選定、メリデメ整理、投資対効果の資産、As-IsとTo-Beの業務プロセス整理なども行っておりました。

どちらかというと古典的な3K（きつい、きまらない、かえれない）ITシステムを、我慢強くローンチさせて企業価値と競争力向上に貢献する方が自分にはあっているように思います。

Qiitaでは過去に製作したプロダクトの復習や、新しいTechnologyの予習したものなどを整理していきたいと思います。
DockerでRuby on Railsの実行環境を作成する

Dockerをインストール済みで、todoというアプリを作成する前提で以下を進める。

# Dockerfileを作成する

```docker:Dockerfile
# 
FROM ruby:2.6.3-stretch

RUN gem install rails

RUN apt-get update && apt-get install -y nodejs
```

# docker-compose.ymlを作成する。

```yml:docker-compose.yml
version: "3"
services:
  mysql:
    image: mysql:8.0.13
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - "./mysql-data:/var/lib/mysql"
    environment:
      MYSQL_ROOT_PASSWORD: root
  # コンテナの名前
  app:
    # Dockerfileの内容を元にビルドさせる
    build: .
    volumes:
      - ".:/app"
    ports:
      - "3000:3000"
    tty: true
    depends_on:
      - mysql
```

# コンテナの作成と開始を行う

以下のコマンドを叩くことで、docker-composeファイルに定義したコンテナの作成と開始をしてくれる。

```
$ docker-compose up
```

# Dockerを操作する

以下のコマンドを叩くことで、Dockerの中に入れる。

```
$ docker exec -it todo_app_1 /bin/bash

root/# ls
app  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

root/# cd app

root/app# ls
Dockerfile  docker-compose.yml  mysql-data
```

# railsをインストールする。

```
root/app# gem install rails
Successfully installed rails-5.2.3
1 gem installed
```

# アプリの雛形を作成する。

```
root/app# rails new .
root/app# bundle install
```

# サーバーを起動する

```
root/app# rails s -b 0.0.0.0
```

http://localhost:3000 にアクセスすると、Railsアプリが立ち上がる。

<img width="733" alt="スクリーンショット 2019-06-29 13.02.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41709/feabe90f-0469-3833-3545-189a30fbe4dd.png">

めでたし、めでたし！
【UiPath】不要なロボットを削除するロボットを開発した話

こんにちは！

僕はUipathでいろいろロボット作るのが好きですが、UiPath Robotにパブリッシュした後に「このロボットもういらんｗｗ」ってなることが多かったので、不要なロボットを削除するロボットを作りました

※「Orchestratorに接続していないこと」を前提としています

# どんなロボットか

Qiitaは動画を載せられないので、スクショを使いながら説明していきます。

## 1. 「test」という不要なロボットがあるとします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/e3a08aeb-aaeb-1f9c-fd56-ce2b4088ba5a.png)

## 2.  「指定のロボットを削除」というロボットを実行します

いま存在するロボットが表示され、「不要なロボットを選択してください」というダイアログが出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/63615d21-ad5d-ce6b-1be1-3a1ee9a997af.png)

## 3-1.  ダイアログで×を押す、もしくは「なし」を選択するとロボ終了

ダイアログで×ボタンを押すか、「なし」を選択すると、「削除したいロボットが選択されませんでした」というメッセージボックスが表示され、ロボットは処理を終了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/ee7e8048-ae93-4339-23ff-6b9b928c237b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/420f75e5-f54b-72a0-10f9-da55db955433.png)


## 3-2.  ダイアログでロボットを選択すると当該ロボットを削除し、ロボ終了

ダイアログで「test」ロボットを選択すると、「testが正常に削除されました」というメッセージボックスが表示され、ロボットは終了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/1d147945-e781-0693-48b3-986f3aa52ccc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/18ab79f1-a1b9-cb01-5998-8c75b4284efb.png)

この後、UiPath Robotを見に行くと、「test」ロボットは削除されています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/313ff9bb-2003-25f4-dfa0-af444b594043.png)


# おわりに

不要なロボットがUiPath Robot上にたまっていくと使いにくくなるし、見栄えが悪くなるので、このロボットは結構重宝しそうです。

他の人のPCでまだ試していないので、汎用性があるかどうかはまだわからず、XAMLファイルはまだ公開しないでおきます...！
trメソッドとは？(Ruby)

trメソッドとは、第一引数を第二引数に変換するメソッド。
つまり、**既存の文字を新しく違う文字に変換したい場合に便利となるメソッド**。

例えば、指定の文字列を小文字から大文字に変換した場合がこちら

```ruby:sample.rb
string = "abcde"
puts string.tr("a-z", "A-Z")

 #結果　=> ABCDE
```

ROT13のような形で、文字をずらしたい場合はこちら

```ruby:sample.rb
string = "abcde"
puts string.tr("a-zA-Z", "n-za-mN-ZA-M")
 #結果　=> nopqr
```
ちなみに、一部の文字の変換も可能！

```ruby:sample.rb
string = "abcde"
puts string.tr("bc", "BC")
#結果　=> aBCde
```
まだまだ勉強中なので、追記や違っているところ等ありましたら、コメントいただけると嬉しいです！
SSH通信の簡単な流れ

##SSH鍵使ってサーバーと接続してるってイマイチイメージできない。。。
githubのリポジトリとローカルを紐づけるときにSSH鍵公開鍵をgithub側に設定してみたいなことありますよね。
これまでは教材とかやってても書いてある通り進めたらいいやっ、ってことで誘導されるがままにコピペしてたきおくしかないので、流れだけでも整理できたらと思います。

1. 秘密鍵と公開鍵を生成
2. 接続相手のサーバーに公開鍵を登録
3. sshコマンドを使用してログイン 

3.の時には、
ローカルからサーバーに対してユーザーとIPを指定してログインを申請する。
サーバー側は乱数を生成して、設定された公開鍵を利用して暗号化してローカルに生成した暗号を送る。
ローカルは帰ってきた暗号を秘密鍵を利用して解読。解読した乱数を送り返す。
サーバー側は送り返された暗号が正しければログインを許可。

ってなことが裏で行われているみたいです。
## コマンドとしては
``$ssh-keygen``
で公開鍵と秘密鍵を取得。
秘密鍵は
``~/.ssh/id_rsa``
公開鍵は
``~/.ssh/id_rsa.pub``
のような~/.ssh/配下のファイルに保存されている。
```~ .ssh: $ssh -i(./ssh配下の秘密鍵のファイルを指定するオプション) name.pem ec2-user@12.345.678.910```
公開鍵をログインしたい相手サーバーの~/.ssh/authorized_keysへ登録する。
２パターン
1. サーバー側で
``ssh-copy-id ~/.ssh/id_rsa.pub``

2. ローカル側から
``cat ~/.ssh/id_rsa.pub | ssh ec2-user@12.345.678.910 'cat >> .ssh/authorized_keys'``
cat ~/.ssh/id_rsa.pub　でファイル内の情報を得ている。
|ssh ec2-user@12.345.678.910で情報をもってSSH認証でログインを行なっている。
かつ、cat >> .ssh/authorized_keysが実行され、指定したファイルの最終行にcatで得たファイル内の情報を書き込んでいる。（>>で上書き （>）でなく追加している）

これでパスワードなしで
``$ssh ec2-user@12.345.678.910``
コマンド補足： ssh user@server-hostname [command]←ログイン後に実行したいコマンドを指定できる


調べて何となくこんな感じかなと。
ファイルにchmodコマンドで権限与えたり、scpコマンドでSSHつかってファイルを転送したりするところはまた別の機会ってことで。
自分でも確認してみてね!

## 参考文献
https://qiita.com/naoki_mochizuki/items/aea14a65a4a513e4816f
https://qiita.com/nnahito/items/dbe6fbfe347cd66ae7e6
Emacs の ruby-mode で二重の式展開があるとハイライトが壊れる問題

# 問題

Emacs の ruby-mode で二重の式展開があるとハイライトが壊れてしまいます。たとえば下の ruby プログラムをみてください。
<img width="536" alt="before.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10508/1091a77c-fde8-76f7-ebfd-fe6301419c1a.png">
puts の引数に二重の式展開があり、それ以降の色付けがおかしくなっています。

# 解決策

ruby-mode のソースコードを開きます。私の場合は cask を使ってインストールしているので下記のパスにありました。

`/Applications/Emacs.app/Contents/Resources/lisp/progmodes/ruby-mode.el.gz`

これを開いて 108 行目付近を下記のように修正します。 **注意**：この修正は私が適当に考えた正規表現を使っているので、他の ruby プログラムのハイライトがおかしくなってしまう可能性があります。たとえば三重式展開は配慮していません。

```diff
  (defconst ruby-expression-expansion-re
-    "\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\|\\$[^a-zA-Z \n]\\)\\)"))
+    "\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#{[^{^}]*#{[^}]*}[^}]*}\\)\\|\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\|\\$[^a-zA-Z \n]\\)\\)"))
```

下記を実行してコンパイルし ruby-mode を再読込します。

```
M-x byte-compile-file /Applications/Emacs.app/Contents/Resources/lisp/progmodes/ruby-mode.el.gz
M-x load-file /Applications/Emacs.app/Contents/Resources/lisp/progmodes/ruby-mode.elc
```

さっきのファイルを閉じて開き直すと…
<img width="571" alt="after.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10508/60519f85-4080-0064-9567-57a959269259.png">
解決！

# 解決策2

会社でアドバイス頂戴したところによると、わざわざコンパイルしなくても定数を上書きできるそうです。

```init.el
 (defalias '~ruby-syntax-propertize-function
    (syntax-propertize-rules
     ;; 文字列2重展開があるとシンタックスハイライトがおかしくなるので、 ruby-expression-expansion-re を修正したやつを追加
     ("\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#{[^{^}]*#{[^}]*}[^}]*}\\)\\|\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\|\\$[^a-zA-Z \n]\\)\\)"
      (0 (ignore (ruby-syntax-propertize-expansion))))))

  (defun ~ruby-fix-syntax-propertize ()
    (add-function :before (local 'syntax-propertize-function) '~ruby-syntax-propertize-function))
  (add-hook 'ruby-mode-hook '~ruby-fix-syntax-propertize t)
```
electronでrequire() is not definedが出た時にやったこと

Electronでmain.jsからSettingsを開く処理を書いたが，Settings画面を開くと「require() is not defined」というエラーがコンソールに表示された。

いろいろ調べた結果，BrowserWindowのインスタンスを作る際に，{ webPreferences: { nodeIntegration: true　}}を加えてやればいいことが分かった。

```javascript:main.js
const showSettingsWindow = () => {
    settingsWindow = new BrowserWindow({width: 600, height: 400,
    webPreferences: {
        nodeIntegration: true
    }});
```

これを書くことで，「require() is not defined」のエラーが消えた。
pipxを使って、pip installで入るCLIコマンドをどのpython環境からも見えるようにする

mypyやflake8など、pipでインストールする便利なバイナリ・CLIコマンドがある。
pyenvやcondaを使ってpythonの仮想環境を分けて開発していると、pip installした場所が変わって前述のコマンドが見えなくなり、とても不便だった。

こういうのを防ぐために、pipxというのがある。
https://pipxproject.github.io/pipx/

pip installの代わりにpipx installとし、パスを通せば良い。

```bash
# pipxインストール
pip install pipx

# CLIコマンドをインストール（例えばmypy）
pipx install mypy

# パスを通す（より良いパスの通し方は「bashrc path」とかでググれば出てくる）
export PATH=$PATH:~/.local/bin
```

pipx用の仮想環境を作る仕組みらしい。
https://pipxproject.github.io/pipx/how-pipx-works/

環境変数PATHを通すのではなく、pythonのuser PATHを通す方を公式は推していたけど、userpathのドキュメントが見当たらないのとよくわからない挙動をしたので諦めた。
VS CodeのRemote Containersを使うときはdocker-composeのバージョンに気をつけよう

Visual Studio CodeのRemote Containersを使おうとしたところ、コンテナの生成から先に進まなくなってしまったので調査しました。

**2019/7/5追記**

[Remote - Containers - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) にdocker-compose.ymlのバージョンについて記述がありました。

> System Requirements
> Local: Docker Desktop 2.0+ for macOS/Windows or Docker CE/EE 18.06+ and Docker Compose 1.21+ for Linux. Docker Toolbox and Ubuntu snap packages are not supported. For Windows, Windows 10 Professional or Enterprise is required due to the requirements of Docker Desktop or Windows. See the minimum requirements for VS Code for additional details.

[Visual Studio Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) ばかり確認して気づいていなかったです。失礼いたしました。


# 結論

docker-compose **1.21** 以上を使いましょう。



# 作業環境

```
$ docker-compose --version
docker-compose version 1.20.1, build 5d8c71b
$ docker --version
Docker version 18.09.5, build e8ff056
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.6 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.6 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
```

プロジェクトは [Visual Studio CodeのRemote ContainersでC++開発環境構築 - Qiita](https://qiita.com/dbgso/items/6e2f317d6d13bdc387f8) で作成したものを利用しました。

# エラー内容

対策内容としては結論で書いたぐらいしかないのですが、どんな症状が出たのかを簡単に記録しておきます。

以下のキャプチのの通り、`Creating vscode-cpp-devcontainer_devcontainer_cpp_1 ... done`で停止してしまいました。

![Screenshot at 2019-06-29 11:20:00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/2abd275e-5bb0-8995-f85f-9613cbf89671.png)

正しく起動出来た場合は  `Run: docker exec df6486edb33df0f92dd9b283dbae022de9e0ea98ab7baff7b527aebcf017348b test -d /root/.vscode-server`とvscode serverの起動や拡張機能のインストールが始まります。

![Screenshot at 2019-06-29 11:42:51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/11c9637e-f868-553b-2df6-b95277fe9c78.png)

# 対応バージョン

`docker-compose 1.20.1`でエラーが出たので、周辺のバージョンで試してみました。
おそらく`1.21`以上であれば問題ないでしょう。
`1.21`のどの修正が効いているのかは確認できていませんが

|バージョン|起動可否|
|---|---|
|1.19|☓|
|1.20|☓|
|1.21|○|
|1.22|○|
|1.23|○|
|1.24|○|





# おわりに

今後新規に構築する場合は発生しにくい事象だとは思いますが、地味にハマったので記録しておきます
ページ内リンクと画像の挿入

「ページ内のリンクがジャンプしない」
「画像の挿入ができない」
このようになってしまった時の解決方法をご紹介します！


##ページ内リンクが作れない
リンク先にジャンプしない原因は2つありました。
*`<a>`タグに入っていない

```html
<div class="link link-intro"><a href=".intro"></a>自己紹介</div>
```
こんな感じで`<a>`タグの外に出ていたパターンです。

*指定するidのつづりが違っていた
これは自分の指定したidを確認して、直しましょう。

今見ると簡単なところでつまずいていたなと感じます（泣）

##画像の挿入が出来ない
これもできない原因が2つありました。
*画像の場所を指定できていない
画像を挿入するときはパソコンがどの位置にその画像があるかを把握してないといけません。
そのためには相対パス、絶対パスについて知っておく必要があります。(https://blog.codecamp.jp/programming-html-picture-arrangement)
こちらの画像ファイル名の書き方を参考にしましょう

*画像のサイズが大きすぎる
僕の場合、入れたい画像のサイズが大きすぎて読み込んでもらえな現象が起きていました。
なので画像を圧縮してサイズを小さくする必要がありました。
(https://compressjpeg.com/ja/)
画像がJPGだったのでこのサイトを利用しました。
他にも画像を圧縮できるサイトがいろいろあるので、サイズが大きい時は試してください。

以上になります。
間違いや指摘があればお願いします。
kelpnetの作法

# 概要

kelpnetの作法を調べてみた。

# 部品

```
ロス　- SoftmaxCrossEntropy　MeanSquaredError

オプチマイザー　-　MomentumSGD SGD　Adam AdaGrad

アクチベーション　-　Sigmoid　ReLU　TanhActivation

```


# サンプルコード
xor

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using KelpNet;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            const int learningCount = 10000;
            Real[][] trainData = {
                new Real[] { 0, 0 },
                new Real[] { 1, 0 },
                new Real[] { 0, 1 },
                new Real[] { 1, 1 }
            };
            Real[][] trainLabel = {
                new Real[] { 0 },
                new Real[] { 1 },
                new Real[] { 1 },
                new Real[] { 0 }
            };
            FunctionStack nn = new FunctionStack(new Linear(2, 2, name: "l1"), new TanhActivation(name: "act"), new Linear(2, 2, name: "l2"));
            nn.SetOptimizer(new SGD());
            Console.WriteLine("1 Training...");

            for (int i = 0; i < learningCount; i++)
            {
                Real loss = 0;
                for (int j = 0; j < trainData.Length; j++)
                {
                    loss += Trainer.Train(nn, trainData[j], trainLabel[j], new SoftmaxCrossEntropy());
                }
                if (i % 1000 == 0)
                {
                    Console.WriteLine("loss: " + loss / 4);
                }
            }
            Console.WriteLine("Test Start...");
            foreach (Real[] input in trainData)
            {
                NdArray result = nn.Predict(input)[0];
                int resultIndex = Array.IndexOf(result.Data, result.Data.Max());
                Console.WriteLine(input[0] + " xor " + input[1] + " = " + resultIndex + " " + result);
            }
            ModelIO.Save(nn, "test.nn");
            Function testnn = ModelIO.Load("test.nn");
            Console.WriteLine("Test Start...");
            foreach (Real[] input in trainData)
            {
                NdArray result = testnn.Predict(input)[0];
                int resultIndex = Array.IndexOf(result.Data, result.Data.Max());
                Console.WriteLine(input[0] + " xor " + input[1] + " = " + resultIndex + " " + result);
            }
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
}

```

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/02114df6-6b57-47ad-5223-49b967a74123.png)

以上。
for文でデータのindexの取得

Python言語で、コードを書いている時、とあるデータにインデックスを付与して、
データを取り出したりしたい時があるので、それについてまとめてみました。

インデックスの取得の仕方は２つあります。

###インデックスなし

```python

animals = ['cat', 'dog', 'tiger', 'rabbit']

for animal in animals: 
    print(animal)    
```
```:実行結果
cat  dog  tiger  rabbit
```
animal 空の変数
###enumerate関数(index&要素取得)
```python

animals = ['cat', 'dog', 'tiger', 'rabbit']

for i, animal in enumerate(animals):
    print(i)
    print(animal)
    print('{}:{}'.format(i, animal))
```
```python:実行結果
# print(i)
  0   1   2   3

#print(animal)
  cat  dog  tiger  rabbit

#print('{}:{}'.format(i, animal))
  0:cat  1:dog  2:tiger  3:rabbit
```
indexを指定した数字から始めたい場合は、第二引数に数字を指定する。

```python

for i, animal in enumerate(animals, 1):
```

ついでに　print('{}:{}'.format(n, animal))　の.formatは　format関数であり
変数の文字列への埋め込み時に使われます。また、別途記事で紹介します。

### range関数(index取得)
```python

animals = ['cat', 'dog', 'tiger', 'rabbit']

for index in range(len(animals)):
    print(index)
```
```:実行結果
  0   1   2   3
```

どちらの方法でもindexの取得は可能ですが、range関数はコードの可読性が低いです。
一般的には<font color="orange">enumerata関数</font>を使うべき。

可読性も意識しつつ、見やすくわかりやすいコードを書く事を意識しましょう。
【Javascript】KeyboardEventを理解する


今回も自分のメモ書き程度に。

##keyupイベントで押したキーを離したときにjavascriptを実行する
keyupイベントは、押したキーが離れた時にjavascriptが実行されます。

いいサンプルがW3Schoolにあったので、掲載します。
[This example uses the addEventListener() method to attach a "keyup" event to an input element.](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onkeyup_addeventlistener)

```html
<!DOCTYPE html>
<html>
<body>

<p>This example uses the addEventListener() method to attach a "keyup" event to an input element.</p>

<p>Press a key inside the text field and release it to set a red background color.</p>

Enter your name: <input type="text" id="fname">

<script>
document.getElementById("fname").addEventListener("keyup", myFunction);

function myFunction() {
  var x = document.getElementById("fname");
  x.value = x.value.toUpperCase();　　//フォームに入力すると全部大文字になるように設定してある
}
</script>
</body>
</html>
```


##（参考）keydownイベントとkeypressイベントもある

使い方は同じですが、keydownはキーを押した時、keypressはエンターキーを押した時にjavascriptが実行される。
"オブジェクト指向でなぜつくるのか"を読んで学んだこと①

# はじめに
RubyやJava等、現在主流になっているプログラミング言語の多くは
**"オブジェクト指向(OOP)のプログラミング言語"**　です！！
オブジェクト指向について理解しようとしても、抽象的な概念であり、目に見えない世界のものなので
なかなか理解するのが難しいと思います。
私も色々なサイトで調べてわからなかったので、
有名な【オブジェクト思考でなぜつくるのか】という本を購入しました！
実際そこで学んだ概要を数回に分けてざっくりとですがまとめていこうと思います。
今回は、OOPが誕生するまでのプログラミング言語の歴史についてまとめます！
![o.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419062/8e17662a-e0a3-18db-da88-24375a25b07a.jpeg)


#OOPの歴史を学ぶことが理解への近道
そもそもオブジェクト指向を生み出した先人の方々がどれだけすごいかも知らず、
私たちは普通にオブジェクト指向のプログラミング言語を使用しているかと思います。
でも、どこがすごくてなぜできたのか把握しないと有り難みがわかりませんよね。
この本ではオブジェクト指向ができるまでの歴史も説明してくれています。
ざっとですがOOPが出来るまでの流れは以下のような内容。

##:sunny:初期はプログラマ自身が機械語を書く時代
現代ではプログラミングを実行するのにまず、
私たちがソースコードを書いて、ビルドする際に機械語にコンパイルして実行します。
しかしプログラミング初期は、ソースコード自体存在せず、理解が難しい機械語で直接コードを書いていました。
※ビルドやコンパイル、ソースコードがわからない方はこちら
https://qiita.com/tomokichi_ruby/items/e1d52d3f34877389f905

```
A10010
機械語の例。全く何が書いてあるかわかりません。
```

##:sunny:アセンブリ言語の登場
機械語では難しすぎて理解できないので、人間にわかりやすいように記号に置き換えて書けるようにしたのがアセンブリ言語です！
記号に置き換えたと言っても、まだまだ書きやすいとは言えない状態です。

```
MOV AX,X

アセンブリ言語の例
機械語よりはましですがまだ理解はし辛いです
```
##:sunny:高級言語の登場
アセンブリ言語より、さらに人間が親しみやすい言語で書けるようにと考案されたのが、高級言語です！
数学の計算式と似たような形で書けるため、初心者でも理解しやすくなりました。
FORTRANやCOBOLがこれにあたります！
高級言語の登場で生産性がとても上がったのですが、それに負けじと社会のコンピュータへのニーズも大きくなります。
より生産性を上げる言語が求められます。

```
Z = X + Y
数式に近くなり解読しやすくなりました
```

##:sunny:構造化プログラミング理論の登場
より生産性を上げるため、様々な言語が考案された中で、より注目を集めたのが**構造化プログラミング理論**という考え方です。
今までの機能の中で、プログラムをわかり辛くしているものはむしろ無くしてしまおう！
という考えで、GOTO文を廃止し順次進行・条件分岐・繰り返しの３つを基本構造にしよう！というものでした。
条件分岐は今のif文、繰り返しはwhile文です！

##:sunny:さらにサブルーチン(関数)の独立性を高める動きも
サブルーチンとは、関数のことです。
共通の処理をひとまとめにして管理することですね。
初期から関数は存在していました。
しかし関数で使用する変数は、どこでも使用できるグローバル変数しかありませんでした。
そのため保守性が低く、変数の値が不正だと発覚した際にどこを調べたら良いかわからないというデメリットがありました。
そこでサブルーチンそれぞれの独立性を高めるために、ローカル変数が生み出されたのです！

※グローバル変数やローカル変数がわからない方はこちら
https://qiita.com/tomokichi_ruby/items/a2548176d85457f622a4

##:sunny: 構造化言語の登場
"構造化プログラミング理論"と"サブルーチンの独立性"を取り入れた言語として、**構造化言語**が登場します。
代表的なものだとC言語がこれにあたります。
if文やcase文while文やfor文などの命令を使用して、明確な制御構造の記述が出来るようになりました！
しかしここまで来ても、社会のニーズには追いつかず、より改良が必要となります。
今までは、いかにわかりやすく生産性を上げるかが重視されてきましたが、
これからは**いかに保守性を上げるか**に着目して改良していく必要が出てきました。
なぜならプログラム自体の寿命が、当初の想定を遥かに上回っていたからです。
そして問題視されたのが**グローバル変数と再利用性の貧弱さ**でした。

##:umbrella: 保守性を上げるための問題
###①グローバル変数
すでにグローバル変数の保守性の低さ対策として、ローカル変数は考案されていました。
しかしサブルーチンの呼び出しが終わるとローカル変数は消えてしまうデメリットがあり、
サブルーチン内の変数を外でも使用したい場合はどうしてもまだまだグローバル変数に頼るしかなかったのです。

##②貧弱な再利用性
構造化言語で再利用できるのは当時、サブルーチン（関数）のみでした。
サブルーチンだけでは再利用出来る範囲が狭すぎるので、より大きな再利用できる部品のような仕組みが必要でした。

##:sunny:これを改善したのがオブジェクト指向プログラミング(OOP)
上記の問題点を踏まえ、インスタンス変数やメソッド、クラスなどが考案され、より生産的に且つ保守性も向上した言語がOOPです！
オブジェクト指向のプログラミング言語を使用されている方はご存知の通り、
メソッドはもちろんクラスも共通の処理をまとめたものであり、より大きな枠で共通処理をまとめることが可能になっていますね。
またprivateメソッドやpublicメソッド等によりメソッドの適用範囲も自由に指定できることで、保守性も向上しています。
インスタンスやクラス、メソッドなどのオブジェクト指向の特徴についてはまた別途記事を作成する予定です。

#さいごに
以上がOOPが生まれるまでのざっくりとした歴史の流れです。
改良が何回も重ねられ、今のOOPが生まれたことがお分かりいただけたかと思います。
グローバル変数しかなかった時代、それどころか機械語で直接コードを書いていた時代。
想像するだけで大変そうです。。
今でもプログラミングは難しく感じるけれど、先人の方々の知恵によりだいぶ楽させてもらってるんだなーということがわかりました！
ありがたいですね！:grin:
オブジェクト指向の特徴についてはまた別記事で掘り下げていこうと思います。
最後までご覧いただきありがとうございました:relaxed:
Go ModulesはGitのバージョンが古いと動かなくてハマった件

Goの標準パッケージ管理であるGo Modulesを使って手元(Mac)で開発し、それをサーバーに移してビルドしたところ、以下のようなエラーが出てしまいました。

```
go: finding github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94
go: github.com/streadway/amqp@v0.0.0-20190404075320-75d898a42a94: unknown revision 75d898a42a94
go: error loading module requirements
```

`unknown revision` は検索すると特殊なことをやっていても出るようなのですが、今回は単純にパッケージを読み込んでいるだけでごく基本的な使い方をしていました。そもそもこの設定、Macでは動いていましたし。

理由は簡単、サーバーがCentOS 6でgitのバージョンが古く、その関係で不思議なエラーが出ているようでした。Gitを更新したところあっさり解決しましたが、ちょっとハマったのでメモとして残しておきます。（今更CentOS 6はどうなのかという話ではありますが、順次リプレース中なのです…）
LaravelのHTTPテストでダミーCSVファイルを作ってPOST送信したい

例えば、LaravelでCSVファイルをアップロードしてその中身の値をつかって何かのレスポンスを返す。
みたいな処理のときのHTTPテスト。

テスト用で任意のダミーCSVをアップロードしたい。
そのときに、CSVの中身もテストコードに含めたい。

こんな感じでやってみました。

```php:UploadCsvTest.php

///・・・・・

/**
* CSVアップロードテスト
* アップロードされたCSVを処理するコントローラなどのテスト
*
* @return void
*/
public function testCsvUpload()
{
    // 一時ファイルを作成
    $tmp_fp = tmpfile();

    // CSVファイルとして書き込む
    $csv_rows = [
        [
            'なまえ1',
            '住所1',
            '電話番号1',
        ],
        [
            'なまえ2',
            '住所2',
            '電話番号2',
        ]
    ];
    foreach ($csv_rows as $csv_row) {
        fputcsv($tmp_fp, $csv_row);
    }

    // 一時ファイルのパスを取得
    $tmp_meta = stream_get_meta_data($tmp_fp);
    $tmp_path = $tmp_meta["uri"];

    // 一時ファイルからアップロードファイルを作成
    $file = new UploadedFile($tmp_path, 'upload.csv', 'text/plain', filesize($tmp_path), null, true);
    
    // POSTリクエスト送信してレスポンス取得
    $response = $this->json('POST', '/upload', [ 
        'csv_file' => $file,
    ]);

    // 何かしら検証する
    // $response->assertStatus(200);
}

```

- わかりやすくテストメソッド内で書いたけど、ほんとは`setUp()` 内とかで一時CSVファイルをつくれば各メソッドで使い回せる。
- 一時ファイルの削除はスクリプト終了時に自動的にされるらしいけど、明示的に書いたほうがいいのかな？
- 大きなCSVを使いたいときはコードに書くと長くなるので、別にテスト用ファイルを用意して以下のようにすればよい。

```php

// strage/test/data/dumy.csv からアップロードファイルを作成
$file = new UploadedFile(storage_path('test/data/dumy.csv'), 'upload.csv', 'text/plain', null, null, true);
```

※第4引数はファイルサイズですが、nullでも動くみたい？
Pythonデータベース連携(index.py)

前回の続きで、これまで蓄積した全てのデータを表示させるために、こんな感じでindex.pyファイルをつくりました。

```
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import io
import sqlite3
import cgi

# データベースに接続する
conn = sqlite3.connect('sample.db')
c = conn.cursor()

htmlTable = ""

try:
   c.execute("select * from users;")
except sqlite3.Error as e:
   print("ERROR:", e.args[0])

rows = c.fetchall()

# データベースから値を取り出す
if not rows:
   htmlTable = "No Data"
else:
   for row in rows:
       htmlTable += str(row[0]) + "|" + str(row[1]) + "|" + str(row[2]) + "|" + str(row[3]) + "</br>"

c.close()

# 以下のコードを書かないと、htmlとして読み込んでもらえない。
print("Content-type: text/html; charset=utf-8")

# htmlの部分。printでHTMLコードを表示させることで、ブラウザがHTMLコードとして認識してくれる。
print(
(
'''
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>学生一覧画面</title>
  </head>
  <body>


<h1>学生一覧</h1> <br> <br>

%s

  <a href="input.py">自分の学生情報を記入する</a>
  </body>
</html>
'''
) % htmlTable )
```

<img width="364" alt="スクリーンショット 2019-06-15 17.28.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276221/ac95676e-5795-1106-c036-f87b61c27810.png">

こんな感じで表示されます！ぜひみなさんもやってみてください！
RailsのDBをmysqlにするときにでるエラーを解決する魔法のコマンド

#概要
最近Railsの勉強をしているのですが、データベースをデフォルトのSQLiteからmysqlに変えるのにめちゃくちゃハマりましたので自分用メモです。
ちなみに`mysql`のバージョンは`0.8.16`です。ここが１番ハマるポイントになるのですが。。。

```terminal
mysql --version

mysql  Ver 8.0.16 for osx10.14 on x86_64 (Homebrew)
```

#rails newコマンドでエラー
rails newコマンドをするとこんなメッセージが帰ってきます。

```terminal
rails new sample -d mysql

An error occurred while installing mysql2 (0.5.2), and Bundler cannot
continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  mysql2
         run  bundle exec spring binstub --all
bundler: command not found: spring
Install missing gem executables with `bundle install`
```
作られたsampleのGemfileのmysqlのところをみてみると、

```vim:Gemfile
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
```

要するに自分のローカルのmysqlは0.8.16なのに、範囲が間違っているということですね。
書き換えます。

```vim:Gemfile
gem 'mysql2', '>= 0.4.4', '<= 0.8.16'
```
#bundle installでエラー

ここまできたら、`bundle install`で設定を更新します。

```terminal
bundle install


An error occurred while installing mysql2 (0.5.2), and Bundler cannot
continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  mysql2
```
またエラーが出てきました。ここで詰まってググったらどうやら魔法のコマンドがあるらしい。

それがこちら。

```terminal
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"
```
意味は全くわからないが、どうやらこれでいけるらしい。

もう一度`bundle install`

```terminal
bundle install

Bundle complete! 18 Gemfile dependencies, 78 gems now installed.
Bundled gems are installed into `./vendor/bundle`
```

通った！！！！！

#余談
解決するのにめちゃくちゃ時間かかりました。
`mysql`のバージョンを下げることも考えたのですが、めんどくさそうなのでやめました。
同じく苦しんでいる人に届けば幸いです。

もし`sequel pro`で繋げる場合は、`mysql`のバージョン８からは認証方法が変わっているので変更しないといけません。以下をみるとわかると思います。

参考：　https://pqtomblog.com/2018/09/20/connecting_mysql_by_sequelpro/
microsoft edgeのjavascript文字化け対策

edgeにてjavascriptを使用して日本語を挿入した際に文字化けが発生した場合の対処方法

```js:comment_count.js
//コメント欄の文字数をカウントするためのjsです。
$(function(){
    $('.comment').keyup(function(){
        let count = 255 - $(this).val().length;
        $('.comment').text("コメントはあと" + count + "文字入力できます");
        if(count <= 0){
            $('.comment').text("コメントは255文字までです");
        }
    });
});
```

edge環境でのみ以下のような文字化けが発生
![文字化け.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297660/568d6153-9cf0-c8d8-6267-5a8bd6ddc816.png)

対処方法

1.javascriptをBOM付UTF-8に変換する
(使用ツールはCotEditor)
<img width="668" alt="スクリーンショット 2019-06-30 11.36.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297660/ec9dbb80-e869-04b6-a14f-5c81f4e61d04.png">


2.javascriptを読み込む時にcharset='UTF-8'を指定する
(順番をcharset, srcの順にしないだめかも)
```<script charset='UTF-8' src="comment_count.js"/>```

edge環境でも文字化けせず表示されました！
![修正後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297660/908a1e94-21f0-a6c2-825b-0b52a9408545.png)
Deep Learning推論用デバイスその２ NVIDIA Jetson Nano

## はじめに
この記事はDeepLearning推論用デバイスまとめ記事の第二弾です。第二弾ではNVIDIAが提供しているJetson Nanoについて紹介します。他のデバイスに関しては下記にまとめられています。

* [Deep Learning推論用デバイスその１ Intel NCS2](https://qiita.com/habakan/private/41763b92ae20e91c4138)
* [Deep Learning推論用デバイスその２ Nvidia Jetson Nano](https://qiita.com/habakan/private/5643681c8faf367cc764)
* [Deep Learning推論用デバイスその３ Google Edge TPU](https://qiita.com/habakan/items/72f05734be2290537aff)

## NVIDIA Jetson Nano
![](https://developer.nvidia.com/sites/default/files/akamai/embedded/images/jetsonNano/Jetson-Nano_3QTR-Front_Left_trimmed.jpg)
(引用：https://developer.nvidia.com/sites/default/files/akamai/embedded/images/jetsonNano/Jetson-Nano_3QTR-Front_Left_trimmed.jpg)
JetsonシリーズはNVIDIAが提供しているGPUデバイスの一つで、DeepLearningモデルの学習ではなく推論に特化したハードウェアです。Jetsonは以前紹介したIntel Nural Compute Stick2とは異なり推論プロセッサのみをUSBで接続するのではなく、開発ボード全体をデバイスとして提供しています。以下がスペック表です。

|要素|Spec|
|:--:|:--:|
| GPU | 128-core Maxwell |
| CPU | Quad-core ARM A57 @ 1.43 GHz |
| Memory | 4 GB 64-bit LPDDR4 25.6 GB/s |
| Storage | microSD (not included) |
| Video Encode | 4K @ 30 | 4x 1080p @ 30 | 9x 720p @ 30 (H.264/H.265) |
| Video Decode | 4K @ 60 | 2x 4K @ 30 | 8x 1080p @ 30 | 18x 720p @ 30 (H.264/H.265) |
| Camera | 1x MIPI CSI-2 DPHY lanes |
| Connectivity | Gigabit Ethernet, M.2 Key E |
| Display | HDMI 2.0 and eDP 1.4 |
| USB | 4x USB 3.0, USB 2.0 Micro-B |
| Others | GPIO, I2C, I2S, SPI, UART |
| Mechanical | 100 mm x 80 mm x 29 mm |
（引用：https://developer.nvidia.com/embedded/jetson-nano-developer-kit）

気になる点について紹介していきます。

### 128-core Maxwell
MaxwellとはNVIDIA GPUのマイクロアーキテクチャのコードネームです。Tesla, Fermi, Kepler, Maxwell, Pascal, Voltaと世代ごとに名付けられていて、Jetson NanoではMaxwellマイクロアーキテクチャ仕様のCUDAコアが128個搭載されています。同じJetsonシリーズで以前から発売されているJetson TX系統は**256-core Pascal**が搭載されているのでその部分で見ると、Jetson Nanoは性能を落としています。価格と必要なスペックによってTXとNanoを選択する形になります。

### Memory
Jetson NanoにはGPUだけでなく、CPUも搭載されております。また、Memoryに関しては4GB積まれておりこのRAMをCPU・GPUともに共有して利用します。

その他周辺環境について紹介していきます。

## NVIDIA Jetpack
JetpackとはJetsonシリーズのデバイス向けのSDKです。NVIDIA製のGPUをDeepLearningの学習などで利用するためにはCUDAやCUDNNなどといったライブラリが必要でした。それらのライブラリをJetsonシリーズ向けにまとめられているのがJetpackです。なおJetpackの中に推論をNVIDIA GPUに最適化するためのライブラリであるTensorRTが入っています

## 推論速度
JetsonNanoの推論速度の評価に関しては[NVIDIA社の技術ブログ](https://devblogs.nvidia.com/jetson-nano-ai-computing/)で紹介されています。
こちらがJetsonNano上でTensorRTを利用したモデルに対してのFPSを計測したヒストグラムです。
![](https://devblogs.nvidia.com/wp-content/uploads/2019/03/imageLikeEmbed-1024x510.png)
(引用：https://devblogs.nvidia.com/wp-content/uploads/2019/03/imageLikeEmbed-1024x510.png)
SSD-MobileNet-v2: 39FPS、Inception V4: 11FPS 達成しているそうです。また記事の後半にはGoogleが提供しているデバイスであるEdgeTPUとの性能評価が掲載されています。画像分類タスクにおけるMobile-Netv2や物体検出のSSD-Mobile-Netv2などを見るとEdgeTPUのほうがFPSが勝っています。ただ、多くのモデルについてはそもそもEdgeTPUで推論することができないものが多くDNR(did not run)と評価されています。この結果を見ると推論速度のみの観点ではEdgeTPUに載せられるモデルはEdgeTPU、載せられない場合はJetson Nanoという順番になりそうです。


## 参考文献

- [NVIDIA Jetson Nano Developer Kit | NVIDIA Developer](https://developer.nvidia.com/embedded/jetson-nano-developer-kit)
- [JetPack | NVIDIA Developer](https://developer.nvidia.com/embedded/jetpack)
Android の Camera2 API を使って ズームする

[Android の Camera2 API を使って カメラのプレビュー画面を表示する](https://qiita.com/ohwada/items/7bb65a566114066c8ced)
の続きです。


下記の記事を参考にした。

[Camera2のズーム指定](https://moewe-net.com/android/camera2-zoom)

### ズームをサポートしているか

ズームに関するパラメータには、
ズームのタイプと最大値がある。

ズームのタイプには、 中央でズームする TYPE_CENTER_ONLYと2任意の位置でズームする TYPE_FREEFORM の２つがある。

ズームの最大値が　!.0 以上の時は、その大きさまでズームできる。

[reference: SCALER_CROPPING_TYPE](https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_CROPPING_TYPE)

[reference: SCALER_AVAILABLE_MAX_DIGITAL_ZOOM](https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)

``` Java
// ズームのタイプ
int type = characteristics.get(CameraCharacteristics.SCALER_CROPPING_TYPE);
// ズームの最大値
float mazZoom = characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
```

Nexus 5 は、ズームのタイプは TYPE_CENTER_ONLY です。
最大値は　4.0　です。

### ズームを要求する

センサの領域の中の長方形(Rectangle) を指定して、要求する。
センサの領域の大きさと長方形の大きさの比率がズームの比率になる。
ズームの比率の値ではないので、一手間かかる。

[reference: CaptureRequest#SCALER_CROP_REGION](https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html#SCALER_CROP_REGION)

``` Java
    //　長方形を計算して求める
    Size activeArraySize;
    //　センサの中心の座標
    int cx = activeArraySize.centerX();
    int cy = activeArraySize.centerY();
    //　長方形の大きさ
    int w = activeArraySize.width() / zoomLevel;
    int h = activeArraySize.height()  / zoomLevel;
    //　長方形の座標
    int left= cx - w/2;
    int right= cx + w/2;
    int top= cy - h/2;
    int bottom = cy + h/2;
    Rect cropRegion = new rect(left, top, right, bottom);

// ズームを要求する
    captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegion);
    captureSession.capture(captureBuilder.build(), captureCallback, backgroundHandler);
```

### ズームした写真を撮る

プレビューと写真は、必ずしも連動していない。
写真を撮る時に、ImageReader をターゲットにしてズームを要求する。


``` Java
    CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
    captureBuilder.addTarget(mImageReaderStill.getSurface());
    captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegion);
    captureSession.capture(captureBuilder.build(),  captureCallback, backgroundHandler);
```

### ズームのユーザーインターフェイス

以下のものが考えられる。

- Viewのボタン
- ボリュームの物理ボタン
- スクリーン画面を指で広げる操作

Nexus 5 の最大ズーム４倍なので段階的にズームするほどでもないか。
ボタンをクリックした時に、最大ズームにするので、十分かな。

サンプルコードを GitHub に公開した。
https://github.com/ohwada/Android_Samples/tree/master/Camera215
【Go】Visual Studio Code で Go のデバッグが突然できなくなった件 (2019/06/28)

## 症状

まずはこちらを。

![スクリーンショット 2019-06-29 9.43.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237863/e2869741-2aa2-2365-88af-a66a379de468.png)

この画像のように、とある時点を境に左のデバッグタブで変数の値が表示されなくなりました。

関連 Issue も上がっていました。

[Remote debugging to Docker container gives empty values for all variables #2601](https://github.com/microsoft/vscode-go/issues/2601)

## 動作環境

- macOS Mojave v10.14.2
- VSCode v1.35.1
- VSCode Go 拡張機能 (`ms-vscode.go`) v0.11.0
- go v1.12.1

また、プログラムは Google App Engine の Local Dev Server で稼働させていて、リモートデバッグをしているという形でした。

## 原因

探ったところ、どうやら原因は __VSCode v1.35.1__ 及び __拡張機能 Go (`ms-vscode.go`) v0.11.0__ のようでした。

どちらか片方のバージョンを変えただけでは正常にデバッグが動作せず、両方ともバージョンを変更したところ正常に動作するようになりました。

## VSCode をバージョン指定してインストールする

VSCode のバージョンを v1.35 から v1.34 に落とします。

公式サイトのここからダウンロードできます。

![スクリーンショット 2019-06-29 10.14.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237863/19c165b4-833b-6c73-73c8-e335e8acc2fd.png)

zip ファイルがダウンロードできるので、あとはいい感じにインストール。

## 拡張機能 Go をバージョン指定してインストールする

拡張機能 Go のバージョンを v0.11.0 から v0.10.2 に落とします。

こんな感じで。

![スクリーンショット 2019-06-29 10.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237863/ae2d97d4-88d2-feb3-58f6-cb4a19d06752.png)

![スクリーンショット 2019-06-29 10.21.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237863/9a0de106-fb5a-6aed-cc51-fefd386e9792.png)

## 拡張機能が自動でアップデートされないようにする

`Command` + `,` で設定ファイルを開き、ユーザー設定の `Extensions: Auto Update` のチェックを外して無効にします。

![スクリーンショット 2019-06-29 10.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237863/971955c9-ddda-9d39-688d-f8a746a3b96e.png)

## 結果

変数の中身をデバッガで覗けるようになりました。今後の fix に期待ですが、とりあえずはめでたしめでたし。

![スクリーンショット 2019-06-29 10.36.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237863/c49ee73a-c121-b783-51d9-0dc76833559e.png)
VuetifyとBootstrap4 ～ ブレイクポイント

開発時には、今までフロントエンドフレームワークとしてBootstrap4をメインとして使ってきていましたが、フロントエンドにVue.jsを取り入れることになり、それならばと、Vuetifyを使ってみることにしました。

この記事では何回かに分けて、Bootstrap4 と Vuetify の違いを検証していきます。

今回は、それぞれのブレイクポイントを見てみましょう。


## ブレイクポイント

### Vuetify

```
    xs: 0, // 0px ~ 599px
    sm: 600px, // 600px ~ 959px
    md: 960px, // 960px ~ 1263px
    lg: 1264px, // 1264px ~ 1903px
    xl: 1904px // 1904px ~ 
```

### Bootstrap4

```
    (xs): 0, // 0px ~ 575px
    sm: 576px, // 576px ~ 767px
    md: 768px, // 768px ~ 991px
    lg: 992px, // 992px ~ 1199px
    xl: 1200px // 1200px ~
```

ついでに、Bootstrap3 も。

### Bootstrap3

```
    xs: 0, // 0px ~ 767px
    sm: 768px, // 768px ~ 991px
    md: 992px, // 992px ~ 1199px
    lg: 1200px // 1200px ~
```

768pxというサイズは、iPadを縦持ちした時のサイズなのですが、Bootstrap3までは、それ以下をすべてスマートフォンとして一括りになっていました。

Bootstrap4になって、0 ～ 768px の間に576px という新たなブレークポイントが追加され、スマートフォンの横持ちやファブレットなどの小型タブレットで分けることもできるようになりました。

Bootstrap3からBootstrap4へ移行する際に気を付けないといけないポイントですね。

また、Bootstrap4になって、xsという表記がなくなりました。

Vuetifyのほうは、smのブレイクポイントは600pxとなりBootstrap4のsmとほぼ一緒です。ただ、mdのブレイクポイントは960pxとなってますので、範囲が 600px ~ 959px となり、スマートフォンの横持ちや小型タブレットも全てタブレットに含む扱いとなっています。

そして、Vuetifyだけの特徴として、xl: 1904px があり、4kやウルトラワイドモニターに対応しています。

Vuetifyは、マテリアルデザインを取り入れていますので、マテリアルデザイン公式サイトのガイダンスに従って構築されています。
  
  
「MATERIAL DESIGN」
https://material.io/design/layout/responsive-layout-grid.html#breakpoints




## カスタマイズ

Vuetifyでは、Stylus、Bootstrap4では、SASSを使って、このブレイクポイントをカスタマイズすることができます。


### Vuetify

```_variables.styl
    $grid-breakpoints := {
        xs: 0
        sm: 600px
        md: 960px
        lg: (1280px - 16px)
        xl: (1920px - 16px)
    }
```

### Bootstrap4

```_variables.scss

    $grid-breakpoints: (
        xs: 0,
        sm: 576px,
        md: 768px,
        lg: 992px,
        xl: 1200px
    ) !default;
```


カスタマイズの詳しいやり方は別の回で書きます。
JAVAが入っていない環境のWindows10PCにOWASP ZAP 2.8.0をインストールする方法メモ

#はじめに
ひさしぶりにZAP触るかーと思いインストールしようと思ったらうまくいかなかったのでメモを残しておきます。
##インストール対象
Windows10
##必要な物
JAVA8 (64bit_JRE)

#JAVAをインストールする
インストール！
###JAVAがインストールされているか確認する。
[https://java.com/ja/download/help/version_manual.xml](https://java.com/ja/download/help/version_manual.xml)
まずここのページに従いJAVAがインストールされているかを確認する
→JRE1.8.0以上がインストールされていることが確認出来たらJAVAをインストールする作業は飛ばしてOK
###インストーラーをダウンロードし、実行
次に[https://www.java.com/ja/download/manual.jsp](https://www.java.com/ja/download/manual.jsp)ページの
`Windows オフライン (64ビット)`
をクリックし、ダウンロード。
あとは実行して画面通りに進める。(全部YESでおっけー。)
#OWASP_ZAPをインストール
インストール！
###インストーラーをダウンロードし、実行する
[https://github.com/zaproxy/zaproxy/wiki/Downloads](https://github.com/zaproxy/zaproxy/wiki/Downloads)
このページからダウンロードする。
あとは実行して画面通りに進める。(全部YESでおっけー。)

以上。
.NetデコンパイルツールdotPeekを試してみる

# 概要
JetBrains社の.Net言語デコンパイルツール **dotPeek** を試してみたメモです。


## 更新履歴
| 日付 | 内容 |
|:----|:-----|
|2021/04/01| デコンパイル結果についての記述を修正。 |

## 環境
Windows10
VisualStudio2017
JetBrains dotPeek 2019.1.2

## 参考
https://pleiades.io/help/decompiler/dotPeek_Introduction.html


# インストール
## ダウンロード&インストール
JetBrains社のサイトからダウンロードします。
https://www.jetbrains.com/decompiler/

インストーラーexeファイルを起動します。
とりあえず dotPeekをInstallにします。

![Install00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/dd0a7e8c-4b5f-c148-d0b6-cc914ccbea5a.png)

画面下部のライセンス同意にチェックを入れて[Next]をクリック、インストールが始まります。
![Install01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/e9542a96-74a1-4b27-2ddf-23ec0efa8937.png)

完了です、特に問題になることはありませんでした。

# 起動
dotPeekを起動してみます。

## 起動画面
起動直後は以下の様になります。

![dotPeek_Startup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/53a18466-0a86-4b58-de91-3cbdde9ec560.png)

exeやdllをドラッグ＆ドロップすると以下のような画面になります。
pdb が使用可能な場合はデコンパイル結果ではなくソースファイルが表示されます。

![dotPeek_Decompile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/df69f5f2-fcc7-9d1d-4c1c-72c8e5ae85f1.png)

表示はC#のみのようですが、元ソースがVBとかの場合はどうなるのかは試していません。


## 操作メモ
いくつか操作を試したメモです。

### File Structure
[windows] -> [File Structure]
で現在開いているファイルの変数リストが見られます。

![filestructure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/baa77b64-180b-c867-37c2-f597d723cd88.png)


### プロパティ
右クリック -> [Properties] でアセンブリ情報が見られます。

![property.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/86c89031-a2f7-266b-0255-386124146ac3.png)


### Find Usages
Assembly Explorer のツリーから右クリック -> [Find Usages]を選択すると、使用されている箇所が表示されます。

![findusages.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/70442ce7-da45-1971-0d22-5620032995ee.png)


### IL Viewer
[windows] -> [IL Viewer] で中間言語を見ることができます。

![ILViewer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/20b62fbb-3849-3373-2619-8c2ef3544901.png)


### Show Compiler-generated Code
これを有効にすると、コンパイラが生成したコードが見られるようです。

```c#:元ソース
namespace ConsoleApp1
{
    class Program
    {
        // ラムダ式
        static public Func<int, int> func = x => x * 10;

        static void Main(string[] args)
        {
            
            Console.WriteLine("Result : {0}", func(5));

        }
    }
}
```

![generatedcode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/e45920e4-95a6-84db-edd4-fd30908576ed.png)


<.cctor>b__3_0(int x):int というのが元ソースのラムダ式から生成されたコードの様です。


# まとめ
ドラッグ＆ドロップで手軽にデコンパイルできたので、すごいツールだと思います。
リリースノートを見ると、細かくアップデートされているようです。
デコンパイルした後の表示はC#のみのようですが、F#などの関数言語コードはどんな感じに表示されるのかが気になります。
POSTするデータを標準入力から取り込ませてそのままWebサーバにPOSTさせる方法


`elasticsearch`でタイプを追加する際などに使用。
POSTする際のデータをファイルに作成しておいて、標準出力からそのままcurlのデータを付与してリクエストする方法。

#@-をつける
POSTする本体を標準入力から取り込ませてそのままWebサーバにPOSTさせるには、
オプションとして`-d @- `をつける。

```
cat foo.txt | curl  http://www.example.com/ -XPOST -d @-
```

`foo.txt`にはデータを記載している。
作業履歴を残すためにも、catで出力しているのかも？

ちなみに、ファイル名を直接指定する方法もある。

```
curl  http://www.example.com/ -XPOST -d foo.txt
```


参照：https://hydrocul.github.io/wiki/commands/curl.html
Splunkで行列をつくる

#つくりました。
```java:SPL
| makeresults count=20
| streamstats  count
| eval iterate="abcdefghijklmnopqrstuvwxyz"
| eval tmp="column"
| foreach tmp
    [eval <<FIELD>> = <<FIELD>> + "_" +substr(iterate,count,1)]
| xyseries count tmp _time  
| sort count
| foreach column*
    [eval <<FIELD>> = random() % 1000 + 1]
```
![qiita.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/16d4943a-6d7b-72a1-e122-b09d01e5b832.jpeg)

#解説
1. とりあえず20＊20の行列を作ろうということで、`makeresults`の`count`で20を指定
2. `streamstats`で行番号を作成
3. 最初は数字でやっていたが、最後のフィールドの整列が数字だと、_column1_,_column10_,_column11_,...と格好が悪くなったため、アルファベットの準備（最後`fields`できちんと書けばいいのだけどめんどくさくなりました。）
4. 列名の準備。今回はcolumn
5. `foreach`をtmpで回して、`substr`で列名に、アルファベットを順番にくっつける。`mvindex`だと0から始まるが、`substr`は1からなのね。
6. `xyseries`で縦横変換
7. `sort`で整列
8. `foreach`を_column\_*_の列でまわして、各列に適当な数をいれる。
9. 完成

#順番に数をいれた列を作ってみる
```java:SPL
| makeresults count=10
| streamstats  count
| eval iterate="abcdefghijklmnopqrstuvwxyz"
| eval tmp="column"
| foreach tmp
    [eval <<FIELD>> = <<FIELD>> + "_" +substr(iterate,count,1)]
| xyseries count tmp _time  
| sort count
| rename COMMENT as "行を減らしたいときはここで　| head 必要な行数"
| eventstats max(count) as _linecount
| foreach column_* 
    [eval <<FIELD>>=mvfind(split("abcdefghijklmnopqrstuvwxyz",""),"<<MATCHSTR>>")  ]
| foreach column_*
    [eval <<FIELD>>=count + ( _linecount * '<<FIELD>>')]
    | rename count as No
    | rename column_* as *
```

| No | a | b | c | d | e | f | g | h | i | j |
|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
| 1 | 1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 | 91 |
| 2 | 2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 | 92 |
| 3 | 3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 | 93 |
| 4 | 4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 | 94 |
| 5 | 5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 | 95 |
| 6 | 6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 | 96 |
| 7 | 7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 | 97 |
| 8 | 8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 | 98 |
| 9 | 9 | 19 | 29 | 39 | 49 | 59 | 69 | 79 | 89 | 99 |
| 10 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 |

縦に順番に入れてみた。
コメントに書いた通り、行を減らしたいときは`head`、列を減らしたいときは最後に`table`で残したい列名を書く。

`foreach`が一つに出来なかったのはなんでだろう:thinking:
`mvfind`の結果は数字(Number)のはずなんだけど、`foreach`の中だと微妙な扱い。`tonumber`も使えなかったし。

#まとめ
今回は適当な列名ということで作ったが、

```sjava:SPL
| eval field_name="A,B,C,D,E"
| makemv field_name delim=","
| mvexpand field_name
```
というようにきちんと書いて作るのもありだと思う。

:sweat:ダミーデータばかりなり
ChromeをAWS Workspace Linux(Amazon Linux2)にインストールするスクリプト


ChromeをAWS Workspace Linux(Amazon Linux2)にインストールするスクリプトです。Amazon Linux2以外でも、yum系が使えるOSなら動くと思います。たぶん。

以下の内容をファイル名```setup-chrome.sh```で保存して、```$ sh setup-chrome.sh```で実行。


```bash
################################################
# Install Google Chrome via repo
################################################

# repo
cat << EOF | sudo tee /etc/yum.repos.d/google.chrome.repo
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64
enabled=1
gpgcheck=1
gpgkey=https://dl.google.com/linux/linux_signing_key.pub
EOF

# install
sudo yum update
sudo yum install google-chrome-stable -y
```
マイポータル

ICカードで施錠 https://qiita.com/carpenders/items/94d29098127faaffe1fc
ガジェット https://qiita.com/carpenders/items/2bf93e9889814670764a
Wahoo GPS bicycle computer https://qiita.com/carpenders/items/870daf4e8cf375cdf509
Power On Ethernet https://qiita.com/carpenders/items/f84a7b7f03b14d46b85e
SV3C動画ファイル https://qiita.com/carpenders/items/bd11a5445ff6663e383d
LANIO https://qiita.com/carpenders/items/976b7d4f1ecaf9dd4e20
[Rails]submit時のエラー

railsのsubmit時に出たエラーについての忘備録です。

##エラー内容

コード：f.submitでレコードを追加、変更する。このコードはレコード追加時のものを使用しています。

```new.html.erb
<%= form_for(@article) do |f|  %>
<%= f.submit "送信"%>
<% end %>
```

ルーティングに登録ヨ。とエラーが出る。

![スクリーンショット (44).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203857/e951cf5a-83e3-8340-5d3c-ad3b58eed55d.png)


form_for(@～～)を使えば、自動でルーティングが割り当てられるんじゃなかったけ？と思い、色々調べたんですが、なかなか解決しませんでした。。

##解決方法

解決策自体はここに記述されています。

https://www.pikawaka.com/rails/form_for#form_for%E3%81%A8%E3%81%AF

ルーティングエラーなので、form_forにコントローラとアクション名を指定すれば、urlをうまく引き渡すことができます。
下記のコードでうまくいきます。

```
<%= form_for(@article,  url: {controller: 'article', action: 'create'}) do |f|  %>
```

##エラーの原因

form_for(@～～)のルーティングの自動生成はされないのかい？？

urlの指定方法が良くなくて、自動生成されないみたいです。下記の記事とチュートリアルを参考にしてください。

https://qiita.com/yoskmr/items/cc8a2dc51c928aa1c87a

https://railsguides.jp/routing.html#%E5%8D%98%E6%95%B0%E5%BD%A2%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9

単数形のurlの指定方法だと、form_for(@～～)でルーティングが自動生成されないようです。
例えば、urlの指定方法が

article/create

だと、ルーティングの自動生成が行われなくて、

articles/create

だと自動生成が行われるみたいです。

なので、コントローラを作成する際は、複数系にしたほうが無難です。