OmniAICreator/Qiita-1.07M huggingface dataset:
Basic認証を交えたテストコードの書き方

【概要】
----------------------------------------
<b>1.結論</b>

<b>2.どのように記載するのか</b>

<b>補足：開発環境</b>




1.結論
----------------------------------------
<b>環境変数を変数に埋め込み、visitでその環境変数を埋め込んだURLに飛ぶ</b>ようにする！
<br>

2.どのように記載するのか
----------------------------------------

```ruby
def basic_pass(path) #---❶
  username = ENV["STUDY"] 
  password = ENV["STUDY_password"]
  visit "http://#{username}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}#{path}"
end

RSpec.describe 'コメント投稿', type: :system do
  before do
    @time = FactoryBot.create(:time)
    @comment = Faker::Lorem.sentence
  end

  it 'ログインしたユーザーは自己学習投稿の詳細ページでコメントできる' do
    # ログインする
    basic_pass new_user_session_path #---❷
    fill_in 'Email', with: @time_report.user.email
    fill_in 'Password', with: @time_report.user.password
    find('input[name="commit"]').click
    expect(current_path).to eq root_path
  end
end
```
上記のように記載しました！

❶下記のURLの具体例は環境変数になっていないので、変数に環境変数を代入する形にしました。あとは下記のURLを真似させていただきました。
❷basic_passメソッドを結合テストコードが読み込まれる前に記載しないとBasic認証テストのID,パスワードを通過できません。なので、結合テストコードの内容の一番最初にコーディングし、新規登録画面(devise gem使用)に遷移するようにしています。

かなり参考にしたURL:
<a href="https://obel.hatenablog.jp/entry/20190721/1563652800">Capybara + Headless Chrome (System Spec) で Basic認証 を通過する方法</a>



補足：開発環境
----------------
Ruby 2.6.5</br>
Rails 6.0.3.3</br>
MySQL</br>
Visual Studio Code</br>
(Caprybara,Rspec,GoogleChrome)
Windows の初期化方法　Surfaceユーザー　（回復ドライブ作成編）　（2020年9月）

#まず、下記のWEBサイトにマイクロソフトアカウントにてサインインしてください。

>[Microsoft Webサイト](https://support.microsoft.com/ja-jp/surfacerecoveryimage)

![2020-09-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/8a9325ff-4bcd-95fb-4860-fa8ad3991f5c.png)

#はじめに

個人データを保存したUSBメモリとは別の、
16GB以上、32GB以下の空のUSBメモリをご用意ください。
※FAT32にフォーマットする必要があるためご使用いただくUSBメモリ内のデータはすべて削除されます。

#■USBメモリフォーマット方法■

>手順1.エクスプローラー → PC → リムーバブルディスクを右クリック します。

>手順2.オプションメニューより「 フォーマット 」を選択します。

>手順3.ファイルシステム の項目にて「 FAT32 」を選択し、開始をクリックします。

「 FAT32 」の選択ができない場合は、ごちらをご覧ください➡[FAT32](https://qiita.com/iwasaki-hub/items/2462de9ce3a803ab3360)


#■USB回復ドライブ作成手順■

まず、下記のWEBサイトにマイクロソフトアカウントにてサインインしてください。

**https://support.microsoft.com/ja-jp/surfacerecoveryimage**

>手順 1: [ 1.Surface デバイスの選択 ] より
[ オプション 2: Surface の製品シリアル番号を入力する ] の項目で
該当する[ 製品 ] をお選びいただき [ シリアル番号 ] を入力、[ 続行 ] をクリックします
 　
>手順 2: [ 2.Surface 回復イメージをダウンロードする ] より
ダウンロードできるOSが表示されるため、該当の OS をクリックします。
 　
>手順 3: 使用しているブラウザーや端末によりますが
画面下部にダウンロード 用ポップアップが求められるため[ 保存 ] や [名前を付けて保存 ] をクリックします。
 　
>※ ダウンロードには、1時間〜3時間ほどお時間がかかることが予想されます。
 　
>手順 4: USBメモリーに[USB 回復 ドライブ]の作成をお願いします。
ダウンロードされた Zipファイル（フォルダ形式）を右クリックし、 「すべて展開」をクリックします。

>※「 展開 」でなく、「 解凍 」と表示される場合がございますが、その際は「 デスクトップに解凍 」を選択していただきます。
展開したフォルダ内を開き、その内部を全てUSBメモリにコピーします。

>※この際、展開したフォルダそのものをコピーしないようご注意ください

#■USB回復ドライブを使用したリセット方法■

下記のページを参照ください。

https://support.microsoft.com/ja-jp/help/4023512/surface-creating-and-using-a-usb-recovery-drive

ダウンロードした回復イメージを使って Surface を工場出荷時の状態にリセットする方法

>手順 1: Surface の電源がオフになっており、電源に接続されていることを確認します。

>手順 2: USB 回復ドライブを USB ポートに挿入します。

>手順 3: 音量を下げるボタンを押したまま、電源ボタンを押して電源ボタンだけ離します。

>手順 4: Surface のロゴが表示されたら、音量ボタンを離します。

>手順 5: プロンプトが表示されたら、使用する言語「日本」とキーボード レイアウトは「Microsoft IME
」をクリックします。

>手順 6: Windows 10 USB 回復ドライブを使用している場合は、以下を実行します。
[トラブルシューティング] > [ドライブから回復する] をクリックします。
回復キーの入力を求められた場合は、画面の下部にある [このドライブをスキップする] をクリックします。

>手順 7: リセットする対象のオペレーティング システムをクリックします。(これは Surface にインストールされている現在のオペレーティング システムを指します。)

>手順 8: [ファイルの削除のみ行う] または [ドライブを完全にクリーンアップする] のどちらかを選びます。
ドライブをクリーンアップするオプションを使用する方が安全ですが、所要時間が長くなります。Surface を引き続き使用する場合は、ファイルの削除のみでかまいません。
 
>手順 9: [回復] を選択します。
Surface が再起動し、リセット処理の続行中は Surface のロゴが表示されます。これには数分かかります。
Xcode12インストール後にCarthageでのframeworkのビルドが失敗する時の対策

自作アプリで使用しているライブラリをCarthageを使って管理しています。
Xcode12をインストール後、いつものようにライブラリを更新しようとしたら下記のエラーが発生し、ビルドが失敗しました。

```
Build Failed
	Task failed with exit code 1:
	/usr/bin/xcrun lipo -create (省略)...

This usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/9q/y4brxkg55vx1qv9n3wm3_h6w0000gn/T/carthage-xcodebuild.ty453u.log
```
　
なお、この記事を記述している時点の環境は以下となります。

- macOS Catalina 10.15.6
- Xcode 12.0.1(12A7300)
- Carthage 0.36.0

検索して見つけた対処法をいくつか実施してみたけど、同じエラーでビルドできず。
使用していたライブラリはたまたま更新がなかったので、更新する必要はなかったのですが、このエラーのせいでiOSシミュレータへのビルドができませんでした。
(コマンド実行する前にoutdatedオプションで確認しておけば良かったんですけどね...)
実機ではビルドできたので仕方なくiOS14の稼働確認などを行っていました。
　

少ししてシミュレータでApp Store用のスクリーンショットを撮影したくなったのでまた再調査したところ、過去に実施した対応とは内容がちょっと違いそうな対策を見つけました。

Carthage Issues #3019
https://github.com/Carthage/Carthage/issues/3019#issuecomment-665136323

詳細はリンク先を参照していただけばと思います。
手順は簡単で、以下を行います。

1.提示されたスクリプトを保存
2.そのままでは実行できないので、所有者に実行権限を付与
3.いつものCarthageのコマンドでビルド

　
これで私は無事、ライブラリのビルドができてシミュレーターを動かすことが出来ました。
ちなみにリンク先のコマンド実行ではライブラリによってはMacOSやWatchOSのものもビルドされてしまい、時間がかかるので「--platform iOS」のオプションをつけて実行しました。
Svelte 3.28.0で追加された{#key}を使ってみた

# `{#key}`
Svelte 3.28.0で`{#key}`が追加されました。

![svelte3.28.0](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325401/56585caa-4aba-5d46-8f1e-cc8a545f9901.png)


`{#key}`は指定した値が変わったときにブロック内の要素も更新してくれるみたいです。

いままでは`{#each}`を使って実現してたようです。

```javascript
<script>
	import { fade, slide } from 'svelte/transition';
	let ary = ['cat', 'dog', 'fox', 'wolf', 'panda'];
	let count = 0;
	setInterval(() => {
		count ++;
    if (count >= ary.length) {
        count = 0;
    }
	}, 1500);	
</script>

{#each [count] as count (count)}
	<span in:fade="{{delay: 150}}" out:slide>{ary[count]}</span>
{/each}

<style>
	span {
		position: absolute;
	}
</style>
```

Svelte 3.28.0

```javascript

<script>
	import { fade, slide } from 'svelte/transition';
	let ary = ['cat', 'dog', 'fox', 'wolf', 'panda'];
	let count = 0;
	setInterval(() => {
		count ++;
    if (count >= ary.length) {
        count = 0;
    }
	}, 1500);	
</script>

{#key count}
	<span in:fade="{{delay: 150}}" out:slide>{ary[count]}</span>
{/key}

<style>
	span {
		position: absolute;
	}
</style>
```

実際の動き

![key](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325401/a59ed0ec-ec84-cace-e1f5-338f58693075.gif)


# 参考資料
[Twitter:Svelte Society](https://twitter.com/SvelteSociety/status/1309765553062461441)
【rails】HTTPClientを用いて外部APIに接続する方法(QiitaAPIに接続してみた)

## はじめに
railsで外部APIに接続する際にはgemのHTTPClientを使用します。
今回は例としてQiitaのAPIに接続して、記事一覧を取得(get)してみます。


### HTTPClientをインストール
```:Gemfile
gem 'httpclient'
```

```:ターミナル 
$ bundle install
```

### route.rbに追加
エンドポイントは `/api/qiita`とします。

```routes.rb
Rails.application.routes.draw do 
  namespace :api do 
    get '/qiita' to: 'qiita#index'
  end
end
```

### QiitaAPIに接続する(Controller)
まず、最も基本的な形です。(headerやqueryを指定しないgetリクエスト)

```controllers/api/qiita_controller.rb
class Api::QiitaController < ApplicationController
  # HTTPClientを呼び出す
  require 'httpclient'

  def index
    url = "https://qiita.com/api/v2/items"  # URLを設定
    client = HTTPClient.new                 # インスタンスを生成
    response = client.get(url)              # Getリクエスト
    render json: JSON.parse(response.body)  # 結果をjsonにパースして表示
  end
end
```

http://localhost:3000/api/qiita にアクセスするとこんな感じでデータの一覧がjsonで返ってきます。
整形していないので非常に見づらいですね。

![スクリーンショット 2020-09-27 13.39.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497683/4f8edf10-ab98-9e6b-86ed-de8207c97b5e.png)


次にheaderやqueryを指定する場合です。

```controllers/api/qiita_controller.rb
class Api::QiitaController < ApplicationController
  # HTTPClientを呼び出す
  require 'httpclient'

  def index
    url = "https://qiita.com/api/v2/items"
    header = { Authorization: "Bearer xxxxx" } # 例) ヘッダーに"Bearer xxxxx"を付与
    query = { page: 1, per_page: 20 }          # 例) 1ページ目、1ページごとのデータ取得数を20件にするquery       
    client = HTTPClient.new
    response = client.get(url, header: header, query: query) #headerとqueryを指定
    render json: JSON.parse(response.body)
  end
end
```

## 終わりに
今回はgetリクエストのみだけの説明にしましたが、HTTPClientではPostなど他のリクエストも送れるので調べてみてください。

QiitaのAPIの詳細は下記を参照しました。
[Qiita API v2 documentation - Qiita:Developer](https://qiita.com/api/v2/docs)
[Qiita API v2 の概要(非公式)](https://qiita.com/tag1216/items/b0b90e30c7e581aa2b00)
【VR日記③】VRギャラリーを建設します

VRど素人ですが、自分のHubsを持ちたい あいちゃんです！今日も元気です！
[【VR日記②】](https://qiita.com/web500/items/386222fe6fb569adc455)で、Mozilla Hubs:hatching_chick:の体験会に参加したことを書きました。
あれから「自分のHubsを作るにはどーしたらいいんだろう？」とずっと考えてました。

#見よう見まねで部屋を作ってみた
知識もなく、英語も読めないなりに、なんとなくログインして なんとなく既成アバターと既成ルームを選んで作ってみました。
[![2020-09-21-ANIMATION.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/79ab20b4-952f-4cb0-5d0a-2cde5e83813a.gif)](https://www.youtube.com/embed/suGgmGnjDxs)

#夢のVRギャラリーが建設できるんじゃないか？
こ、これは…！
テキトーに作って、こんなすごい空間が作れるんだから、Hubsをちゃんと勉強して、しっかり設計して作り込めば、**夢のギャラリー**（オンラインのイラスト置き場）が作れるんじゃないだろうか？！

実は、あいちゃんは、ITインストラクターでありながらイラストを描く仕事もしています。イラストのジャンルは妖怪👻なので名刺の肩書きは「**妖怪絵師**」となっています。

ただ、ビンボー絵描きなので、ギャラリーは持っていません。
[Googleフォト](https://photos.app.goo.gl/JsE3q85WuN3Dxsd4A)や[Pinterest](https://www.pinterest.jp/web500/my-hand-drawn-illustration/)などのクラウド倉庫に作品を置いておくだけの**オンラインギャラリー**で作品を発表してました。
![seto1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/90426c42-8842-209d-2d4e-3b4da1372eef.jpeg)
※最手前があいちゃんの作品「[ToDo Lunch & Cafe](https://www.facebook.com/photo.php?fbid=565093080203391)」

#オンライン上に建設するとはいえ…

やっぱり**時間**と**お金**はかかります…。
VRサーバ、VRソフトウェア（アプリ？）、VR機材の準備…、それ以前に、VRに関する知識を得るために専門の学校に通うとか、東京へ行って特別な研修を受講するとかの必要がありそうです…。

**資金**に関しては、地元（瀬戸市）の「アーティスト活動支援事業 助成金」を頼ることにしました。
![logoc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/75a8cebf-80c7-f0bd-ecd9-b8dd052c8da7.jpeg)
無事採択されたので、この9月から年末にかけて、こんな事業を行います！
>```
あいちゃんの制作現場ぜんぶ見せます！オンラインギャラリー
〜VRアニメからアイキャッチデザインまで〜
```

早速、ギャラリー建設にとりかかりました！
![20200908-k.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/da9bcb01-f347-d61d-445d-5d57ecc2a806.png)

問題は、**時間**です…。
HubsとかSpokeとか…、私のようなVRのド素人がイチから勉強していたのでは10年経っても完工する気がしません。

そこで………

#その道のプロに相談してみよう
私がHubsに興味を持ったキッカケとなった[イベント](https://vrm-nagoya.connpass.com/event/175544/)の主催者**むろまちくん**に相談してみようと思い、[xR Tech Nagoya](https://twitter.com/xRTechNagoya)（Discode）経由でむろまちくんにアポをとりました。
[![Hubs_Scrum.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/e65a73e1-7e23-0bfe-31f5-69e6cceebf0d.jpeg)]
(https://twitter.com/xRTechNagoya)

名古屋・伏見の某秘密基地（？！）**xR House**！
ピンク色の扉まで案内してくれたのは、なんと中学生男子でした。
中学生で、コワーキングスペースを借りて仕事っぽいことしてるのに驚きました。
私も10代からパソコン（なかったけど）やVR（単語もなかったけど）を始めてたら、今頃は戦闘能力が超高いプログラマーになってたんだろうなと思います。
![xR-House.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/32c7e19f-70c6-e10e-591c-5d2f7db47d3a.jpeg)


#ギャラリー建設に向けて着工します！

むろまちくんとお話しして、希望が見えてきました。
ギャラリー建築のサポートをしていただくことと、xR Houseで研修を受けさせてもらうことになり、今から完成が楽しみで仕方ありません:smiley:

**私が研修についていけるかどうか**がいちばんの不安ですが、**夢のVRギャラリー建設**に向けてがんばります！<br>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587320/3c4765ef-86b2-4238-600c-45111b1baf82.png" width=10%> ＞＞＞ということで、今回は事業予告でした。[【VR日記④】](https://qiita.com/web500/items/9c7b3f58ca1cc95efc1d)へ続く・・・
SQLの個人的備忘録3

##サブクエリ
クエリの中に他のクエリを入れることができることで、2つ以上のクエリを1つにまとめることができる。これにより複雑なデータを取得することができる。

```haml
-# 平均得点数より高いレコードからデータを取得している。
SELECT name,goals
FROM players
WHERE goals > (
  SELECT AVG(goals)
  FROM players
);
```

##AS
カラム名などに別名を定義することができる。
-# カラム名が身長180cm以上の選手と表示され、180cm以上のデータを取得している。

```haml
SELECT name AS "身長180cm以上の選手"
FROM players
WHERE height >= 180;
```
##JOIN
複数のテーブルを1つに結合したい時に使用。ONで条件を指定して、1つのテーブルとしてデータを取得する。

```haml
-# playersテーブルとcountriesデーブルを結合し、NULL以外のデータを取得。
SELECT *
FROM players
JOIN countries
ON players.country_id = countries.id;
```

##LEFT JOIN
テーブルのレコードを全て取得する。外部キーがNULLのレコードもNULLのまま実行結果に表示する。

```haml
-# playersテーブルとcountriesデーブルを結合し、NULLを含めたデータを取得。
SELECT *
FROM players
LEFT JOIN teams
ON players.previous_team_id = teams.id;
```

##複数テーブルのJOIN
JOINを複数書くことで、複数のテーブルをつなげることができる。

```haml
-# playersテーブルと、countriesテーブルと、teamsテーブルをつなげている。
SELECT *
FROM players
JOIN countries
ON players.country_id = countries.id
LEFT JOIN teams
ON teams.id = players.previous_team_id;
```

##INSERT
テーブルにレコードを挿入したい時に使用。多くの場合、IDカラムにはAUTO INCREMENTという機能があり、データが作成される時に自動で値が割り当てられる。

```haml
-# studentsテーブルにnameがKate, courseがJavaのデータを追加する。
INSERT INTO students (name, course)
VALUES ("Kate", "Java");
select * from students;
```

##UPDATE
データを更新したい時に使用。複数変更したいカラムがある場合、コンマ(,)で区切る。WHEREで更新するレコードを指定しないとカラム内の全データが更新される。

```haml
-# studentsテーブルのIDが6のデータにnameがJordan, courseがHTMLのデータを更新する。
UPDATE students
SET name = "Jordan", course = "HTML"
WHERE id = 6;
SELECT * FROM students WHERE id=6;
```

##DELETE 
レコードを削除するときはDELETEを使用。WHEREでレコードを指定しないとテーブル内の全レコードが削除される。

```haml
-# studentsテーブルのIDが7のデータを削除する
DELETE FROM students
WHERE id = 7;
SELECT * FROM students;
```
ドロップダウンリストの実装方法


ドロップダウンリストの実装方法
---

ドロップダウンリストの実装をJQueryで簡単に行うことができるのですが、
今回は泥臭い方法で、実装していきます。(全て0から実装しました笑)
ほぼCssメインといっても、過言ではないのですが、
JQueyとCssで実装する２パターンを紹介させて頂きます。


```index.html

<script>
//ここからは、JQuery！
 $(function(){
//nav ul liをマウスでホバーさせるとnav ul ul が出現する。
   $("nav ul li").mouseenter(function(){
//nav ul li(this)の兄弟要素にnav ul ulを含んでいるのかを調査する。
   $(this).siblings().find("nav ul ul");
//nav ul liの子要素であるnav ul ulをdisplay:blockで目に見えるようにする。
   $(this).children().slideDown(150);
   });
//body内をクリックしたら、nav ul ulをdisplay:noneにして表示させないようにする。
   $("body").click(function() {
      $('nav ul ul').slideUp(150);
   });
});
</script>

ここからHTML領域になります。
<div id="nav">
 <ul>
      <li class ="first"><a href="./index.html">トップページ<br>HOME</a></li>

      <li class="clinic"><a href="#clinic">医院紹介<br>CLINIC</a>

       <ul>
        <li><a href="#">新宿</a></li>
        <li><a href="#">渋谷</a></li>
        <li ><a href="#">赤羽</a></li>
       </ul>
      </li>

      <li><a href="#service">診察案内<br>SERVICE</a></li>
      <li><a href="#staff">院長／スタッフ紹介<br>STAFF</a>

        <ul>
         <li><a href="#">院長紹介</a></li>

         <li class = "parent"><a href="#">スタッフ紹介</a>
           <ul class ="children">
            <li><a href="#">赤羽茜</a></li>
            <li><a href="#">宇田川茂良</a></li>
            <li><a href="#">渋谷真知子</a></li>
           </ul>
         </li>

         <li class = "parent"><a href="#">中途採用</a>
             <ul class ="children">
              <li><a href="#">正社員</a></li>
              <li><a href="#">受付アルバイト</a></li>
              <li><a href="#">契約社員</a></li>
             </ul>
           </li>

        </ul>
      </li>
      <li class ="last"><a href="#access">アクセス/Q&A<br>Access</a>

        <ul>
         <li><a href="#">アクセス</a></li>
         <li><a href="#">営業時間</a></li>
        </ul>
      </li>
 </ul>
</div>

```

```css:style.css
nav ul{
display:flex;
width:1050px;
margin: 0 auto;
}

nav ul ul{
position: absolute;
width:100%;
top: 100%;
left:0;
display: none;
}

nav ul ul li{
width: 100%;
background-color: navy;
border-bottom:1px solid #fff;
right: 0px;
width: 190px;
z-index: 999;
position: relative;
}

nav ul>li{
justify-content: center;
background-color: #6CC6C4;
width:20%;
padding:10px;
text-align:center;
border-right:1px solid white;
position: relative;
}

nav ul li a{
font-size:0.85em;
}

nav ul li a{
color:white;
text-decoration:none;
}

nav ul > ul > li{
background-color: #6CC6C4;
width:200px;
display: block;
padding:10px;
text-align:center;
border-right:1px solid white;
}

li.parent{
position: relative;
}

ul.children{
left:100.8%;
top:0;
position:absolute;
display: none;
}

/*li.parentをhoverすると、子要素のul.childrenが、出現する！*/
li.parent:hover ul.children{
display: block;
opacity: 0.87;
}

```


完成イメージ図
https://www.nxworld.net/wp-content/uploads/2016/06/css-simple-hoverable-dropdown.png

色や幅に関しては、お好みで調整してみてくださいね！では、アディオス！
SoundFlowerとLadioCastとOBSのおさらい

備忘録レベルの記事で失礼。

SoundFlowerとLadioCastとOBSと3tenePro同時起動および設定確認動画
https://youtu.be/Wb9FYCyC_hQ

Macの入力設定
![スクリーンショット 2020-09-27 12.26.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/85d12825-1a04-0768-03ed-1141842276e7.png)

Macの出力設定
![スクリーンショット 2020-09-27 12.26.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/c8d0df58-d95c-67d1-5e77-b646a2751265.png)

LadioCasetの設定
実況の場合は入力2に追加します。(今回はテスト撮影だったので入力2なし)
![スクリーンショット 2020-09-27 12.26.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/a2aea03e-ffe5-aa85-950e-e47806b1145e.png)

OBSの設定
![スクリーンショット 2020-09-27 12.27.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/9ed3d2d4-b653-7d0e-ad66-c78608fece68.png)
リリースした個人開発アプリ（Android）がダウンロードされない方法


私ほどAndroidアプリがダウンロードされない開発者は存在しないことを願うが、
同じ境遇の方に向けて、状況と考察を述べる。
ダウンロードされなかった方法が分かっているだけであり、ダウンロードされる方法については一切分からない。

##先に結論
人望のない開発者が単にSNSを使ってリリース報告をしただけでは、
アプリケーションがダウンロードされるということはない。

##状況
・Flutterでアプリを開発して、Google Playに公開
（Appleにもdeveloper申請したが、承認に掛かる時間が長くてAndroid版のみ先行リリース）
・人生初めてのGoogle Playへの公開
・筆者には友達が~~いない~~少ない

##リリースしたアプリ
・する/しない
・今日何をするか
・おみくじ
・筋トレメニュー
・ランダム数字
のメニューを選んでもらい、
乱数で決断を代行するシンプルなアプリケーション

アプリケーションの配信先
[決断代行（Google Play）](https://play.google.com/store/apps/details?id=com.yorozuya_shoma.flutter_app)

<img width="300" alt="omikuji.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653909/bb41902e-e767-9166-e938-ef92cd308ecf.png">
<img width="300" alt="omikuji.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653909/7a4c596b-35ad-52ec-b46e-62d1f365e95c.png">


##ダウンロードしてもらうために行ったこと及び結果
SNSへ投稿
・twitterにリリースしたことを投稿する → 効果なし
・Facebookにリリースしたことを投稿する → 効果なし
・LINEのタイムラインにリリースしたことを投稿する → 効果なし
・LINEの親しいグループにリリースしたことを発表する → 1ダウンロード獲得！
以上。

Google Play Consoleでダウンロード数を把握できるが、
私を含めてダウンロード数は2であった。

##考察
~~日本はiOSユーザに満たされてしまっていると考えられる~~
ここまでダウンロードされなかった者を他に知らないため、何か根本的に間違ったアプローチをしてしまったのだと思う。
今回の場合、1ダウンロードを獲得できただけでも上出来だったのかもしれない。

あまり意味ないかもしれないが、個別に振り返る。
###twitter
フォロワー数が130くらいのアカウント。
TLに埋もれて見られる機会がなかった可能性もあるが、
「1いいね」を獲得出来た。
~~初めてのFlutter、初めてのGoogle Playへの公開だったためもっといいねされたかった。
どうでもいい投稿がいいねされまくってるのに、
エンジニアとしての挑戦や資格取得を褒めてくれないのがtwitter
そんな中、1いいねしてくれた方は神~~

###Facebook
見てる人がそもそも少ないと思われる。
友達75人くらいのアカウントで「0いいね」を獲得した。

###LINEのタイムライン
こちらも見ている人がそもそも少ないと思われる。
8割以上はツムツムで繋がっただけの友達600人くらいのアカウントで「0いいね」を獲得した。

###LINEの親しいグループ
高校同期の9人グループ（男only）で報告したところ、
1人にダウンロードして貰えた。
~~あれ、他はiOSユーザってことだよね？、、~~

###総合的な要因
~~・筆者に友達がいな・・~~
~~・良いアプリを作れば使われるという幻想があった~~
・アプリケーションのメリット（面白さ）を伝えられる投稿内容になっていない
　→投稿に分かりやすい動画を使っていない
　　→写真を添付して投稿したが内容がぱっと見分かりづらい
・そのアプリケーションが相手に求められていない
・投稿を閲覧されている数が少ない
・投稿にいいねを付けてはいけないような雰囲気が滲み出ている
・自分に合った適切なプロモーション手段を知らない（←結局、これが全て）

何かアドバイスや考察し切れていないダメな部分が他にございましたら、
ご指摘やコメントいただけましたら幸いです。

##今後
動画やキャッチーなフレーズを使ったり、あるいは別のメディアを使ったりして、
どうすればダウンロードして貰えるかを検証していきたい。
CORSについて

dockerでnuxtとlaravelのコンテナを作成した際の話。

#やっていたこと
nuxtからlaravelに向かってリクエストを送ったがエラーが発生。

```
Access to XMLHttpRequest at 'http://0.0.0.0:23450/api/register' from origin 'http://0.0.0.0' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

corsポリシーに反しているから、ブロックしたぞと言われている。
corsで調べると「別々のoriginがやりとりできるようにすること」だとか。
originとはドメイン+ポート+urlのこと。
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

#解決方法
laravel側で受け取れるようにmiddlewareを設定する。
参考は[CORSについて理解してLaravel5.6で対応する](https://qiita.com/kobayashi-m42/items/c0a2609ae61a72dcc60f)


自作のmiddlewareを作成して、全てのrouteで発動させる

```php

<?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        ->header('Access-Control-Allow-Headers', 'Content-Type');
    }
}
```

#やってみたけど、うまくいかなかったこと
・nuxt側でproxyという機能を使ったcorsの設定
[Vue.jsとAPIサーバとのaxiosでCORSに引っかかった時のProxyを使った回避方法](https://qiita.com/Ryoma0413/items/c41d10d2e6e2a420c3cf)

[【Nuxt.js】データベースにCORSで接続できない？ならば @nuxtjs/proxy を使いなさい【手順】](https://blog.proglearn.com/2020/05/26/%E3%80%90nuxt-js%E3%80%91%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%ABcors%E3%81%A7%E6%8E%A5%E7%B6%9A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%EF%BC%9F%E3%81%AA%E3%82%89%E3%81%B0-nuxtjs/)


## 原因解明
baseURL、browserBaseURLの設定が必要だった模様。
参考：
[【解決済】Docker上のNuxtでaxiosのCORSエラーにハマりまくった話](https://from-age35.com/1985.html)
[baseurl](https://axios.nuxtjs.org/options/#baseurl)
[browserbaseurl](https://axios.nuxtjs.org/options/#browserbaseurl)

#corsの勉強になった参考文献
[CORSについて理解してLaravel5.6で対応する](https://qiita.com/kobayashi-m42/items/c0a2609ae61a72dcc60f)
[CORSまとめ](https://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34)
[【Rails6】Gem rack-corsを導入してCORS設定を行う(オリジン・CORSとは何か)](https://blog.cloud-acct.com/posts/u-rails-rackcors/)
[CORS を分かってないから動くコード書いて理解する](https://qiita.com/mochizukikotaro/items/6b72ad595db8a6b5514f)
[Preflight request (プリフライトリクエスト)](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)
ffmpeg で動画を 100 分割して 1 画面 100 分割表示する

## 対象読者
以下のように、動画を 100 分割して 1 画面 100 分割表示させたい方を対象としています。
![output-palette.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693216/f97e424f-3de4-df9b-9257-23afdfbd183d.gif)

## やり方

```shell:10x10.sh
## USAGE: sh 10x10.sh input.mp4
ffmpeg -i "$1" -filter_complex '[0:a]asplit=100'`seq -s '' -f '[a%02g]' 0 99`';[0:v]scale=192:-1,split=100'`seq -s '' -f '[v%02g]' 0 99`';'`ffprobe "$1" -hide_banner -show_entries format=duration | perl -ne 'next if not m{^duration=(.*)$}; printf q([v%1$02d]trim=%2$f:%3$f,setpts=PTS-STARTPTS[v%1$02d];[a%1$02d]atrim=%2$f:%3$f,asetpts=PTS-STARTPTS[a%1$02d];), $_, $1*$_/100, $1*($_+1)/100 for (00 .. 99);'``seq -s '' -f '[v%02g]' 0 99`'xstack=inputs=100:layout='"`perl -e 'for $y (0 .. $ARGV[1] - 1) { $h = ($y ? qq($h+h0) : 0); for $x (0 .. $ARGV[0] - 1) { $w = ($x ? qq($w+w0) : 0); push @o, qq(${w}_$h) } } END { print join q(|), @o }' 10 10`"':shortest=1[v];'`seq -s '' -f '[a%02g]' 0 99`'amix=inputs=100:duration=shortest,loudnorm[a]' -map '[v]' -map '[a]' -shortest output.mp4 -y
```

上記を保存して、`sh 10x10.sh input.mp4` と実行すると、`input.mp4` から `output.mp4` ができます。バージョン 4.3.1 の `ffmpeg` `ffprobe` と `perl` `seq` を使っています。`perl` や `seq` は filter 文を生成しているだけです。

### 処理の流れ

```shell
ffmpeg
    -i 'input.mp4'
    -filter_complex '
        [0:a]asplit=100[a00](中略)[a99];
        [0:v]scale=192:-1,split=100[v00](中略)[v99];
        [v00]trim=0.000000:18.099510,setpts=PTS-STARTPTS[v00];[a00]atrim=0.000000:18.099510,asetpts=PTS-STARTPTS[a00];
        (中略)
        [v99]trim=1791.851490:1809.951000,setpts=PTS-STARTPTS[v99];[a99]atrim=1791.851490:1809.951000,asetpts=PTS-STARTPTS[a99];
        [v00](中略)[v99]xstack=inputs=100:layout=0_0|0+w0_0|(中略)|0+w0+w0+w0+w0+w0+w0+w0+w0+w0_0+h0+h0+h0+h0+h0+h0+h0+h0+h0:shortest=1[v];
        [a00](中略)[a99]amix=inputs=100:duration=shortest,loudnorm[a]
    '
    -map '[v]'
    -map '[a]'
    -shortest
    output.mp4
    -y
```

### video `[v]` の処理

- [scale](https://ffmpeg.org/ffmpeg-filters.html#scale): 出力は横 1920px 想定なので、ここで 192px にしています。
- [split](https://ffmpeg.org/ffmpeg-filters.html#split_002c-asplit): ここで 100 個になります。
- 各入力毎の処理: `ffprobe` から取得した duration で、それぞれの video input をオリジナルの 1/100 の長さにしています。
  - [trim](https://ffmpeg.org/ffmpeg-filters.html#trim)
  - [setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts)
- [xstack](https://ffmpeg.org/ffmpeg-filters.html#xstack): 100 個を左上から順に並べます。全入力同じ大きさなので、位置計算には w0 と h0 しか使ってません。

### audio `[a]` の処理

- [asplit](https://ffmpeg.org/ffmpeg-filters.html#split_002c-asplit): ここで 100 個になります。
- 各入力毎の処理: `ffprobe` から取得した duration で、それぞれの audio input をオリジナルの 1/100 の長さにしています。
  - [atrim](https://ffmpeg.org/ffmpeg-filters.html#atrim)
  - [asetpts](https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts)
- [amix](https://ffmpeg.org/ffmpeg-filters.html#amix): 100 個の音声をミックスします。
- [loudnorm](https://ffmpeg.org/ffmpeg-filters.html#loudnorm): そのままだと音声が大分小さくなるので、ノーマライズします。

## 参考文献
- [解像度が一致しなくても映像を並べられる xstack | ニコラボ](
https://nico-lab.net/xstack_with_ffmpeg/)
- [trim フィルタの使い方 - ニコニコ動画研究所](https://looooooooop.blog.fc2.com/blog-entry-1154.html)
- [複数の音声を混ぜる amix | ニコラボ](https://nico-lab.net/amix_with_ffmpeg/)
コードレビューを依頼するときの心構え

## はじめに

コードレビューを依頼するとき、どんな気持ちでお願いしていますか？
自分が始めたての頃は、「チェックしてもらえてありがたいなあ」くらいの考えでした。

コードレビュー依頼とは、いわば**責任の共有依頼**です。
つまり、本質はそれほどカジュアルなものではありません。（依頼しやすい関係性は別として）

コードレビューを通したレビュアーには、品質の保証をしたという責任が伴います。
通したコードが不利益を生んだ場合には、レビュアーも責任を負わなければなりません。

そのリスクを負ってもらうことに対し、レビュー依頼者（reviewee, 以下レビューイと呼びます）」が果たすべき義務は、**レビュアーが最小限のコストで効果的**にレビューできるように最大限努力することです。

その努力の具体的な方法を、以下に書いていきます。

## 効果的/効率的なレビューをしてもらうために

### 👨‍💻 開発で気をつけること

レビューに必要なコストは、開発時点で半分以上決まると言っても過言ではありません。
具体的には以下の４点です。

#### 1. 読みやすいコードを書こう

読みやすいコードを書くことは、コード品質を高め、結果的にレビューコストを下げることができます。

意図の伝わりやすい実装、命名を心がけ、読みやすいコードにしましょう。
より詳しい読みやすいコードの書き方については、リーダブルコードなどの書籍や他の方の記事をご参照ください。

#### 2. Linter, Formatterを利用しよう

コード規約、フォーマットに関しての指摘・修正は基本的に人間のやることではありません。

`pre-commit hook`やVS Codeの`codeActionsOnSave`などを利用し、自動的に実行されるようにしましょう。

#### 2. コミットを分けよう

コミットを細かく分けることで、小さい粒度でレビューできるようになります。

レビューにおいてのみでなく「変更の経緯を追いやすい」「ロールバックしやすい」などのメリットがあります。

#### 3. プルリクエストが大きくならないようにしよう

差分ファイル数や変更行数があまりに多いと、レビューがちょっと億劫になりますよね。

仕様設計・工数見積もりの段階で差分が膨らみそうだと思ったら、まずは親ブランチを作り、そのブランチへのプルリクエストを小さく作るようにしましょう。
そうすることでレビュー機会を分割することができます。

#### 4. セルフチェックをしよう

レビューでの指摘を減らす為に、あらかじめ自分で確認することで手戻りを防ぎましょう。基本的には以下のようなことです。

- 仕様を満たせているか
- 読みづらくなっている部分はないか
- 動かしてみて不具合はないか

ただし、個人的な経験では**セルフチェックでは自分を正当化するバイアスがかかりやすい**為、客観性を意識的に強めるようにしましょう。

### 🛠 合同レビュー

レビューを依頼する相手にとって、あまり知らないシステム、大規模な変更のレビューなどは非常に読解コストが大きいです。

そのようなケースでは、合同でレビューする場を設けましょう。
仕様や実装について説明を行い、コミュニケーションをとりつつレビューを進めていきます。

### 🏷  プルリクエスト

#### 概要を書こう

満たすべき要件を共有しましょう。
具体的にはIssue、チケットへの関連付けです。

**「システム要件を満たしているか」は、レビューしてもらうべき重要な要素の一つ**、大前提になります。

##### システム仕様

システム要件を実現するために、どのように実装したかを記述しましょう。

書き方は様々あると思いますが、コアになる部分と、追加した/関連するテストを書くようにしています。（カバレッジ部分から注意して見るべきロジックの場所がわかる）

「**わかりにくいところをわかりやすくする**」ために書く、ということを念頭に置きましょう。

##### 画像や図

画面に変化がある場合などはスクリーンショットを添付するとより伝わりやすいです。

必要に応じて注釈を加えましょう。（Mac付属のプレビューで簡単にできます）

#### 🗣 コミュニケーション

レビューでコメントをもらったら、必ず返信(リアクション)するようにしましょう。
必要に応じて意見を述べ、修正し、再度確認を依頼しましょう。

このときビジネスのスピードとの塩梅で、対応するべきかどうか迷うこともあると思います。

基本的には**レビューイが仕様・実装・事業的優先度を最も把握できている** ので、責任を持って判断してください。
もちろん、必要に応じてチームと相談するようにしましょう。

## まとめ

一貫して大切なのは、相手がどうしてくれたら嬉しいのか考えること、**思いやる気持ち**です。

コードレビューは依頼する側、される側の双方の歩み寄りでより効果的・効率的に実施できます。
その実現のためには、逆の立場の視点を持つことが効果的です。

レビュアーの視点についても書いているので、ぜひ読んでみてください。

[>> コードレビューをするときの心構え](https://qiita.com/hinora/items/266fbfb62fd3d4c45edd)
[rails] NOFILEのマイグレーションファイルを削除






###事件内容

このようなファイルができてしまい、
rollbackができないため、マイグレーションファイルをdownさせることができない


```
up     20200926110535  ********** NO FILE **********

```


###事件が起こった経緯

おそらくマイグレーションのステータスがUPの状態で
マイグレーションファイルを削除してしまった。

私の場合はgitデスクトップでchangeを丸ごと削除したので、この事件が起きた模様。


###解決策

えっと、皆様が載せてくださっていた記事を何個か見させていただいた結果、無事解決いたしました。


まず、no faileに名前を付与するために
ターミナルでこのコマンドを実行してください:zap:
（マイグレーションIDはあなた様のnofileになっているIDに変えてください。
　　その後の名前はダミーですのでなんでも構いません。）

```
% touch db/migrate/20200926110535_fuwafuwa.rb
```

実行後↓

```20200926110535_fuwafuwa.rb
class Hoge < ActiveRecord::Migration[5.2]
  def change
  end
end

```

そうすれば、上記の名前マイグレーションファイルが
存在しているはずです。
#####バージョンはあなた様のrailsのバージョンを指定してください!!!!!:shamrock:

その後, rails db:migrate:statusで確認するとこのようになっていれば成功です。

```
up     20200926110535  fuwafuwa
```   


あとは、先ほどのマイグレーションファイルを削除すれば無事解決！:corn:
Sense HAT で落ちモノゲームを作った

子供用に、Raspberry Piでゲームを作ってみました。Sense HAT練習も兼ねて。
[クラックス](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%A9%E3%83%83%E3%82%AF%E3%82%B9)の上半分、みたいなゲームです。

本当にただ「作った」ことを見せたかっただけの記事です。。。

![IMG_5732.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238815/ba703d4e-4afe-0532-2e14-4a5982720cdf.jpeg)


```python
from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED
from time import sleep
from random import randint
from copy import copy

# Sense HAT 初期化
sense = SenseHat()
sense.clear()

red = (255, 0, 0)
blue = (0, 0, 255)
yellow=(255,255,0)
purple=(128,0,128)
green=(0,255,0)
indigg=(75,0,130)
orange=(255,128,0)
black=(0,0,0)

# 向きの固定
sense.set_rotation(0)

# パラメータ設定
fall_interval = 3
fall_speed = 0.5
fall_color = orange
fall_num = 8

# 落下物を生成し、配列に格納
blocks = list()
for i in range(0,fall_num):
    blocks.append((randint(0,7), 0-i*fall_interval))

bar_init = (3, 6)
bar_color = blue
sense.set_pixel(bar_init[0], bar_init[1], bar_color)
bar = copy(bar_init)

# ジョイスティックを左に倒したときの処理（受けブロックを左に進める）
def moveleft(event):
    global bar
    if event.action != ACTION_PRESSED:
        return
    sense.set_pixel(bar[0], bar[1], black)
    bar_moved_x = bar[0] - 1
    if bar_moved_x < 0:
        bar_moved_x = 0
    elif bar_moved_x > 7:
        bar_moved_x = 7
    bar = (bar_moved_x, bar[1])
    sense.set_pixel(bar[0], bar[1], bar_color)

# ジョイスティックを右に倒したときの処理（受けブロックを右に進める）
def moveright(event):
    global bar
    if event.action != ACTION_PRESSED:
        return
    sense.set_pixel(bar[0], bar[1], black)
    bar_moved_x = bar[0] + 1
    if bar_moved_x < 0:
        bar_moved_x = 0
    elif bar_moved_x > 7:
        bar_moved_x = 7
    bar = (bar_moved_x, bar[1])
    sense.set_pixel(bar[0], bar[1], bar_color)

# ジョイスティックのイベントハンドラに関数を設定
sense.stick.direction_left = moveleft
sense.stick.direction_right = moveright

# ゲーム開始
# 都度、落下物配列の各ブロックを一つずつ下に移動する。
# 落下物が一番下にたどり着いた（失敗）か、受けブロックが受け止めたか（セーフ）を判定。
# 全てのブロックが受け止められたら、成功。
blocks_tmp = copy(blocks)
failed = False
while blocks_tmp:
    tmp = list()
    for blk in blocks_tmp:
        blk_moved = (blk[0], blk[1] + 1)
        if blk_moved[1] > 7:
            failed = True
            break
            #sense.set_pixel(blk[0], blk[1], black)
            #continue
        if blk_moved == bar:
            sense.set_pixel(blk[0], blk[1], black)
            continue
        if blk[1] >= 0 and blk[1] < 8:
            sense.set_pixel(blk[0], blk[1], black)
        if blk_moved[1] >= 0 and blk_moved[1] < 8:
            sense.set_pixel(blk_moved[0], blk_moved[1], fall_color)
        blk = blk_moved
        tmp.append(blk_moved)
    print(tmp)
    blocks_tmp = copy(tmp)
    sleep(fall_speed)

# 結果表示
if not failed:
    sense.show_letter("O")
else:
    sense.show_letter("X")

sleep(3)
sense.clear()

del bar
del sense
```

では！
Linux mint 20 (19) - WQHD/4Kディスプレイの設定

環境 : Linux mint 20, Lenovo thinkpad WQHD


単純にUser interface scaleをDouble(Hi-DPI)にして、Fractional scalingをいじる、もしくは`xrandr --output eDP-1 --scale 1.5x1.5`にするのではティアリングが起きるし、かといって/etc/env...に垂直同期の設定を追加するとひどく映像が乱れる。でも次の方法を使うとうまく行った。

Linux mint 19や20以外のディストロ（Ubuntuとか）でもwqhd/4kディスプレイ使ってて、ティアリングが起こったりする場合は試す価値がありそうです。ただしそもそもHi-DPIに対応していないディストロとかだとうまく行きません。次で確認してください。https://wiki.archlinux.jp/index.php/HiDPI

WQHDで個人的に見やすいと感じる3200x1800で設定しますが見にくければ次のサイトを見て色々試してください。https://pacoup.com/2011/06/12/list-of-true-169-resolutions/

## 0

ディスプレイ名は`xrandr`で確認してください。

```
...
VGA1 connected 1024x768+1024+0 (normal left inverted right x axis y axis) 338mm x 270mm
...
```

次のような`~ connected ~`の一文を探してください。この場合VGA1がディスプレイ名です

## 1

まず、`$ cvt 3200 1800`でモードライン(Modeline)を生成する。

```
> # 3200x1800 59.96 Hz (CVT 5.76M9) hsync: 111.82 kHz; pclk: 492.00 MHz
> Modeline ★"3200x1800_60.00"  492.00  3200 3456 3800 4400  1800 1803 1808 1865 -hsync +vsync★
```

こういうのが出力されます、★の中をコピーする。

## 2

次に、`sudo xrandr --newmode "3200x1800_60.00"  492.00  3200 3456 3800 4400  1800 1803 1808 1865 -hsync +vsync`でモードを作成する。`--newmode`の後ろが先程のをペーストしたところです。

## 3

次に、 `sudo xrandr --addmode ディスプレイ名 "3200x1800_60.00"`でディスプレイにモードを追加する。



## 4

どちらかうまく行く方を選ぶ。

###### 4-1

Menu>Display>Resolutionで新しく追加された、`3200x1800`（`3200x1800_60.00`の場合もあり）を選択する。

###### 4-2

`sudo xrandr --output ディスプレイ名 --mode "3200x1800_60.00"`を実行する。



## 5

最後に、

###### 4-1の場合

~/.profileに

```
xrandr --newmode "3200x1800_60.00"  492.00  3200 3456 3800 4400  1800 1803 1808 1865 -hsync +vsync
xrandr --addmode ディスプレイ名 "3200x1800_60.00"
```

を追加する。

###### 4-2の場合

~/.profileに

```
xrandr --newmode "3200x1800_60.00"  492.00  3200 3456 3800 4400  1800 1803 1808 1865 -hsync +vsync
xrandr --addmode ディスプレイ名 "3200x1800_60.00"
xrandr --output ディスプレイ名 --mode "3200x1800_60.00"
```

を追加する。



#### 6 備考

私の環境（4-1でうまく行った）では、menu>Displayで選択してるので、.profileに`xrandr --output ディスプレイ名 --mode "3200x1800_60.00" `を記述する必要はないし(4-1の場合は)、なんなら`xrandr --output ディスプレイ名 --mode "3200x1800_60.00" `をするとブラックアウトする。
Mac上にMacをVMとしてインストール。VirtualBox仮想マシンにCatalinaをインストールする際のコツ

　Macでの開発で、Macの仮想マシンを使いたいと思い立ったのですが、Catalinaの仮想マシンを作る記事は日本語でも英語でも少ないうえに、まとまってる記事であっても以下のような問題があって、あちこち調べることになりました。

- どの仮想マシンがよいのかわからない
- ライセンス違反でない根拠が弱い
- インストーラーのISOイメージの最適なマウント方法がわからない
- リソース設定がみんな言ってることばらばらで不安
- 実際やったらretinaディスプレイで小さすぎて困る

いろんな記事を徘徊し、個人的な着地点を決めたので、備忘録を兼ねてまとめます。

参考記事などは以下。同じように困った方の参考になりそうなページです。
https://kyokara.com/mac-on-mac/
https://www.geekrar.com/create-macos-catalina-iso-file/
https://braitom.hatenablog.com/entry/2014/12/03/102521
https://medium.com/@geekrar9/how-to-install-guest-tool-on-macos-catalina-on-virtualbox-6309525d75b0
https://qiita.com/hnakamur/items/fca6379213a3033cb29d
https://qiita.com/minnsou/items/54491c01ac95a245b010

# どの仮想マシンを使うべきか

　理由はわからないけど、日英ともに記事が多いのはVirtualBoxなので、VirtualBoxを採用しました。
　実際にやってみると、大きなトラブルもなく仮想マシンを実現できたので、特に理由がなければVirtualBoxでよいと思います。

# ライセンス違反でないことを確認したい

　ライセンス条項については、**１．App Storeから得たライセンスを、２．同じMac上の仮想マシンに使ってよく、３．商用業務でも問題ないこと**、の３つを確実にしたかったので、結局一番確実な英文のCatalinaライセンス規約を読んでみることにしました。

https://images.apple.com/legal/sla/docs/macOSCatalina.pdf

`2. B. (iii)` が該当箇所なので、必要個所を抜粋すると、

> `2. Permitted License Uses and Restrictions.`
--- A.は省略 ---
B. Mac App Store License. If you obtained a license for the Apple Software **from the Mac App Store** or
through an automatic download, then subject to the terms and conditions of this License and as
permitted by the Services and Content Usage Rules set forth in the Apple Media Services Terms and
Conditions (https://www.apple.com/legal/internet-services/itunes/) (“Usage Rules”), you are granted a
limited, non-transferable, non-exclusive license:
--- (i)と(ii)は省略 ---
(iii) to install, use and run up to two (2) additional copies or instances of the Apple Software
within **virtual operating system environments** on each **Mac Computer you own or control** that is
already running the Apple Software, **for purposes of: (a) software development**; (b) testing during
software development; (c) using macOS Server; or (d) personal, non-commercial use.


ということなので、１．App Storeから得たライセンスを、２．同じ(自分の)Mac上の仮想マシンに使ってよく、３．商用業務でも問題ないこと（個人利用は(d)なので、(a)(b)(c)は業務でもよいと判断）、の３つが確認できました。

# インストーラーのISOイメージの最適なマウント方法

　ISOをホストOSでマウントしてそのドライブをゲストOSに使わせる方法と、ISOを直接ゲストOSにマウントする方法があります。後者のほうが手順が少なく、動作的に問題もありません。
　最新のVirtualBoxでISOを直接ゲストOSにマウントする操作方法は、https://kyokara.com/mac-on-mac/ に詳しく掲載されています。

# リソース設定がみんな言ってることばらばらで不安

　個人的な経験上、実機で開発環境を作った場合に最も問題になるのがSSDの小さい機種でXCodeがアップデートできなくなる問題です。
　最近あるプロジェクトの開発環境を、中古Mac＋Catalina再インストールの空っぽ状態の上に構築しました。サーバー側はPHPのLaravelをDocker上で構築されていて、アプリ側はReact Nativeで構築されていて、Visual Studio Codeで編集するという、フツーな環境です。この時もXCodeのアップデートができなくて詰んだのですが、原因はSSDが128GBだったことで、SSD容量を上げたらすぐ解決しました。

　ディスク以外のリソースは、足りなくなったらすぐ調整するという方針でよいかと思います。

# retinaディスプレイで小さすぎる問題の解消

　VirtualBoxのディスプレイ設定で150%くらいに拡大すればいいのですが、そうすると表示内容がぼやけます。上記のうち2つくらいの記事に書いてあるように、3Dアクセラレータを切ると改善するのですが、なぜ3Dアクセラレータが関係するのか、結局わからず。
　ほかにクリップボードの共有など不便な点はいくつかありますが、そのうちのいくつかはVirtualBoxのGuest Additionsを導入すると解決するそうです。私の用途的にはこれは不要なので試していません。

以上、同じことをされようとしている方の参考になれば幸いです。
初心者が今はやりの技術を調べてみた

# 目的
今回、Node.jsを使ってQiitaAPIを使っていろいろやってみようということで、今、初心者向けには何が流行っているのかを調べてみました。

# 調査方法
QiitaAPIを使って、「初心者」という単語を含んでいる記事を検索しました。
プログラム実行時点（2020年9月27日11時30分時点）で投稿時間が新しいものから上位100件を対象としています。

# コード
```Javascript
// axiosモジュールを読み込む
const axios = require('axios');

// main()関数を定義する
async function main() {
    // QiitaAPIで「初心者」という単語で記事を検索する
    let response = await axios.get('https://qiita.com/api/v2/items?per_page=100&query=' + encodeURIComponent('初心者'));
    // 結果を出力する
    for (let i=0; i<response.data.length; i++) {
        console.log(response.data[i].tags[0].name);
    }
}

main();
```

# 結果
2020年9月27日11時30分時点の結果をExcelで集計しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/300647bd-1b91-b3d4-df9b-fc6a49d82710.png)

# 考察
やはり、初心者向けはPythonやJavaScriptの記事が多いことが分かりました。
次に多いのがPHPやRubyということで、いまだに根強い人気があるのかなという印象です。
※私が勉強したことあるJavaについては少なくなってきているという印象です。

# 今後
今回はExcelを使って分析しましたが、Python使って分析できるようになってみようと思います。
ABC177d memo

本日より記録開始。
現状履修言語
C
C++
Ruby(基礎文法のみ)
python(基礎文法のみ）

入門　python3 購入


C++にて深さ優先探索(DFS)の実装(ABC177-D)


using namespace std;

int maxfriends=0;
int cnt=0;

vector<bool> seen;

void dfs(vector<vector<int>> &F,int v){
    seen[v] = true;

    for(auto next:F[v])
    if(!seen[next]){
        dfs(F,next);
        cnt++;
    }
}

int main(){
    int N,M; 
    cin >> N >> M;  
    vector<vector<int>> fs(N) ;



    for(int i=0; i<M; i++){
        int a, b; cin >> a >> b;
        a--; b--;
        fs[a].push_back(b);
        fs[b].push_back(a);
    }

    seen.assign(N,false);
    for(int i=0; i<N; i++){
        if(!seen[i]){
            cnt = 1;
            dfs(fs,i);
            maxfriends = max(maxfriends,cnt);
        }
    }
    cout << maxfriends << endl;
}
【GAS】繰り返し処理で スプレッドシート呼び出し回数を節約する２つのメソッド

##概要
GASを、ちょっとしたお役立ちツールくらいとしてしか使っていないので実感することが少ないけど、スプレッドシートを呼び出す回数が少ないほど処理速度が上がるらしい。

同じ結果になるなら呼び出し回数を節約する書き方をしてみようと言う事で、`A列を読み込み、その2倍,3倍を計算し、それぞれB列,C列に書き込むスクリプト`を例に、スプレッドシートを呼び出す回数を減らす書き方を考える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708687/aacb1f51-f6a4-67d1-d5d3-d4a705d6fcb4.png)
こんな感じの実行結果になるやつ。

##まずは手計算するような順番で書く
取りあえず何のひねりも無しに書いて、スプレッドシートの呼び出し回数（sheetオブジェクトの実行回数）を数えてみる。

```javascript
function KUMONshiki() { 
   
  var sheet = SpreadsheetApp.getActiveSheet(); 
   
  //最終行をget 
  var lastRow = sheet.getLastRow(); 
   
  var input, double, triple; 
   
  for(i=1; i<=lastRow; i++){ 
     
    //セルを読み込み（for内１回目） 
    input = sheet.getRange(i, 1).getValue(); 
     
    //２倍を書き込み（for内２回目） 
    double = input * 2; 
    sheet.getRange(i, 2).setValue(double); 
     
    //３倍を書き込み（for内３回目） 
    triple = input * 3; 
    sheet.getRange(i, 3).setValue(triple); 
     
  } 

}
```
個人的にとても安心な見た目(*´・ω・)

スプレッドシートを呼び出した回数は、最終行getで１回、for文の（読み込み１回＋書き込み２回）×６回で ⇒ 計１９回

##節約メソッド①「getValues」
セルを１つずつ読み込むのではなく、範囲で読み込む事で呼び出し回数を節約する。

```javascript
function getValues() { 
   
  //シートのデータを一気にgetValues 
  var sheet = SpreadsheetApp.getActiveSheet(); 
  var data = sheet.getDataRange().getValues(); 
   
  //最終行をget 
  var lastRow = sheet.getLastRow(); 
   
  var input, double, triple; 
   
  for(i=1; i<=lastRow; i++){ 
     
    //getValuesから必要なデータを呼び出し 
    input = data[i-1][0]; 
     
    //２倍を書き込み（for内１回目） 
    double = input * 2; 
    sheet.getRange(i, 2).setValue(double); 
     
    //３倍を書き込み（for内２回目） 
    triple = input * 3; 
    sheet.getRange(i, 3).setValue(triple); 
     
  } 
   
}
```
getValues、最終行get、for文の書き込み２回×６回で ⇒ 計１３回

範囲で一気に読み込んでいるので、for文の中でA列を扱うのにスプレッドシートを呼び出さなくて良くなった^^)b

`(i, 1)`と`[i][1]`の示す要素が違う為、i の取扱に注意が必要。この辺が苦手(ToT)

##節約メソッド②「push」&「setValues」
表題を裏切り３つ目のメソッドが・・・表題は「方法」的な意味って事で^^;

読み込みをまとめたので、今度は書き込みをまとめようって事。pushメソッドを使い計算結果を１つの配列に格納、setValuesメソッドで一気に書き込む。

```javascript
function push() {  
   
  //シートのデータを一気にgetValues 
  var sheet = SpreadsheetApp.getActiveSheet(); 
  var data = sheet.getDataRange().getValues(); 
   
  //最終行をget 
  var lastRow = sheet.getLastRow(); 
   
  var input, double, triple; 
  var output = []; 
   
  for(i=0; i<lastRow; i++){ 
     
    //getValuesから必要なデータを呼び出し 
    input = data[i][0]; 
     
    double = input * 2; 
    triple = input * 3; 
     
    //予め作っておいた２次元配列へpush 
    output.push([double, triple]); 
         
  } 
   
  //計算結果を格納した２次元配列を一気にsetValues 
  sheet.getRange(1, 2, 6, 3).setValues(output); 
   
}
```
getValues、最終行get、 setValuesで ⇒ 計３回

`[i][1]`的な記述だけになったので、for文の式も修正。

１９回が３回まで減らせることを考えると、こういう書き方を癖にするべきなんだろうなと思う。

##更に省略
メソッドではなく、工夫でget.lastRowも省略する。

今回の計算は、getValuesした要素全てが対象だから、for_of文で対応可能。もしくは`= sheet.getLastRow();`を`= data.length;`としても代用可能。

乱暴だけど、for文の条件式の終わりを大きな数字にしておいて、if文を使って「空欄だったらbreak」させることでも省略できる。

最終行の取得を省略することで、最初１９回だったスプレッドシートの呼び出し回数が、２回まで省略できた∩(´∀｀)∩ﾜｧｲ♪

##検討
スクリプトの最初と最後に`Logger.log`を挟んで実行して、開始時間と終了時間を表示させたところ、１９回呼び出しのスクリプトは約1.7秒、２回呼び出しのスクリプトは約0.4秒で完了していた。

データ量が増えると、かなりの時間差が発生しそう・・・気を付けます(m｡_ _)/ ﾊﾝｾｲ

###おしまい
JavaScriptの基礎

### JavaScriptの基礎を復習しました。
まだまだHTMLとCSSを組み合わせて、カレンダーを作ることを目指しています。
### 学習したコード
```JavaScript
var firstName = 'myname';
var age = 32;
console.log(firstName + '' + ' is' + age);

var job, is front engineer;
job = 'driver';
is front engineer　= false;

console.log(firstNa me + 'is a ' + age + ' year old ' + job +'.Is I front engineer? ' + is front engineer);
// Variable mutation
age = 'thirty two';
job ='office worker';

alert(firstName + 'is a ' + age + ' year old ' + job +'.Is I front engineer? ' + is front engineer);
 var lastName = prompt('What is my last name?');
 console.log(firstName + ' ' +lastName);
```
alertのメッセージをクリックして、 promptにlastName（苗字）を入力できる。

### C#をJavaScriptに変換する。
```c#
var seireki=0;
        var heisei=0;
        for( seireki=1989; seireki<=2017; seireki++)
        {
            Console.log("西暦 " + seireki + "年は、");
            heisei = seireki - 1988;
            Console.log("平成 " + heisei + "年");
```

上のコードは、エラーが出るかもしれません。For, loopのコードを調べてみます。



### 今日の振り返り
JavaScriptの基礎固めして、カレンダー作りに必要なコードを覚える。
勉強日誌22日目

最近天気が良い日があまりないですが頑張りましょう
筋トレとウォーキングもようやく習慣化。
英語の勉強もほんとにゆっくりと上達。

正答率　82% (67)

/etc/profile
全ユーザーのデフォルトに設定されている環境変数の変更

~/.bashrc
自分用にコマンドのエイリアスを設定

alias
登録されているエイリアスの表示

set -o ignoreeof
Ctrl+D を押してしまった際のログアウト処理

正答率　84%　(82)

$#
シェルの特殊変数、コマンド実行時に指定された引数の数

正答率　95% (79)

.xsession-errors
X Windows Systemのエラーが出力されるファイル

正答率　77%　(69)

XDMCP
ネットワーク上にあるリモートホストにグラフィカルログインする際に使用されるプロトコル

/etc/X11/xdm/xdm-config
XDMの設定ファイル
クラス（class）、オブジェクト（object）、インスタンス（ instance）の違いをシンプルにまとめる

###1.はじめに
クラス、オブジェクト、インスタンスの違いについての理解があやふやなままであったので、私なりにまとめてみました。
（言語によって、多少意味が違ってくる場合もあります。本記事ではPHP,Javaを想定しております。）

###2.要約
最初にかなり簡単な要約を下記に示します。

```
オブジェクト・・・「対象となる物」。概念、抽象的なもの
クラス・・・オブジェクトの設計図。
インスタンス・・・クラス（設計図）を元に作成された（単一の）物
```
###3.詳細
さらに詳しくまとめてみます。

***オブジェクト(object)***
「object」という英単語を日本語訳すると「物」、「物体」、「目的」、「対象となる物」などと出てきますが、プログラミング用語としての「object」は最後の「対象となる物」が一番近しいと考えます。

例えば「人」や「車」などがあって、「人」は"性別"や"名前"などがあったり(ありさま、状態)、"走る"、"食べる"などの振る舞いがあります。「車」にも”車種”があったり、”ブレーキ”をする、”エンジンを起動する”などの振る舞いがあります。

これらを具的的に設計していくのがクラスの役割になります。

私はオブジェクトとオブジェクト指向を混ぜて考えていた節があるのですが、この二つは分けて考えた方が良いです。
オブジェクト指向はあくまでもプログラミングの技術手法の一つです。
詳しくは[オブジェクト指向でなぜつくるのか](https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%8F%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC2%E7%89%88-%E5%B9%B3%E6%BE%A4-%E7%AB%A0/dp/4822284654)に大変わかりやすく書かれているので是非手にとって読んでみてください。

***クラス（class）***
クラスはオブジェクトを具体的に使用するための設計図のような物です。

大抵のクラスにはfield,property,インスタンス変数などがあり、プログラミング内で使用する「ありさま、状態」を定義します。
「振る舞い」もクラス内で関数として定義され、オブジェクトを通して使用されます。メソッドと呼ばれたりします。

関数とメソッドの違いは[こちら](https://stackoverflow.com/questions/155609/whats-the-difference-between-a-method-and-a-function)のstackoverflow内の説明がわかりやすかったです。

***インスタンス(instance)***
インスタンスはclassで設計されたオブジェクトを作成（具象化）します。
例：
「人」クラスから、"Mr.Hoge", "Ms.Fuga"といった具体的で単一のモノを作成


###参考
[Class vs Object vs Instance](https://alfredjava.wordpress.com/2008/07/08/class-vs-object-vs-instance/)
[バグ対応]暫定対応コードを書いたらやっておきたいこと

プログラムのバグに遭遇した時、とりあえず回避するためのコードを書くことがあるかと思います。
今回は、上記のようないわゆる暫定対応コードを書いた場合にやっておきたいことについて書いてみました。


例えば、FunctionA.javaのdo()メソッド内で時々発生する原因不明のエラーに対し、暫定対応のため、「this.temp()」メソッドを追加したとしましょう。

```java:FunctionA.java
・・（これより上既存のコード）
this.temp();
・・（これより下既存のコード）
```
このままだと、後から見た人が何のことかわからなくなってしまうので、コメントを入れます。

## タスク管理ツールを使っている場合

BacklogやRedmineなどのタスク管理ツールを使っている場合はチケットを作成し、コメントにはチケット番号とタイトルのみ記載し、詳細はそちらに書くようにしましょう。
例えば、チケット番号が「hoge-123」、タイトルが「エラーの一時回避」の場合は以下の通り。

```java:FunctionA.java
・・（これより上既存のコード）
// hoge-123：機能Aのdoメソッドで発生するエラーへの暫定対応
this.temp();
・・（これより下既存のコード）
```

チケットには、

- 発生事象
- 対応内容
- 今後の課題

などをとりまとめ、後で見た人がわかるようにします。
例えば以下のような感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356958/0b4efb12-c227-faa4-798e-f9d49cfd62b9.png)

## タスク管理ツールを使っていない場合

プロジェクトによってはタスク管理ツールを使っていないケースもあるでしょう。
その場合の代替案についても考えてみました。

### 1. 暫定対応用のフォルダを作ってメモを残す
代替案その1。
以下のように暫定対応用のフォルダを作成し、ファイル名にタイトルを記載し、中に発生事象、対応内容、今後の課題を記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356958/2210d0a6-d8a5-6e6a-8c23-283be570b69b.png)


### 2. 設計書に目立つように記載する
代替案その2。
設計書に吹き出しを入れて、そこに対応内容を記載する、もしくは対象処理の箇所の色を変えて、近くにコメントを残す、でもよいでしょう。

## NGな例
### 1.コメントを書かない
せっかく暫定対応のコードを記述しても、コメントがないのはNGです。
後で見た人がこのコード何?となりえず、そのことで調査が発生し、思わぬ時間をとりかねないからです。

### 2. コメントが短すぎる or 長すぎる
コメントを書かない、よりはマシですが、、コメントが短すぎる or 長すぎるのもNG。

#### コメントが短すぎるパターン
```java:FunctionA.java
・・（これより上既存のコード）
// 機能Aのdoメソッドで発生するエラーへの暫定対応
this.temp();
・・（これより下既存のコード）
```
上記はこれまでの例のタイトルの部分だけ記載したケース。
わからなくもないですが、もっと具体的な内容がほしいところです。

#### コメントが長すぎるパターン
```java:FunctionA.java
・・（これより上既存のコード）
/* 機能Aのdoメソッドで発生するエラーへの暫定対応
 * 発生事象:機能Aで5%程度の確率でエラー画面に遷移する事象が発生
 * 対応内容:回避用のtemp()メソッドを作成＆使用
 * 今後の課題:直接の原因を突き止め、対処する
 */
this.temp();
・・（これより下既存のコード）
```
これは何かのドキュメントか?というレベル長さ。
コードの可読性もさまたげてしまいそうですね。


やはり、コメントを書いて詳細は別所に記載するのがよいでしょう。


## 一番大切なこと
ここまでで、暫定対応コードを書いた場合はコード内にコメントを入れ、詳細は別所に記載するのがベターとお伝えしてきました。
が、一番大切なことは<b>こういった対応を行った際にどう記録を残しておくかチーム内でルールを統一しておくこと</b>です。

ある人は詳細をチケットに記載し、ある人はどこかにメモを残し、、では後から対応する人が困ってしまいますよね。

バグ発生⇒暫定対応コードを書くことになったら、まずチーム内のルールを確認し、ない場合はどうするか話し合って決めておきましょう！

## 終わりに
バグ対応は急を要することも多く、かなりエネルギーを消耗しますが、後日のことも考えて対応したいところ。
【Laravel】Collectionのrejectメソッド

##はじめに
今回もLaravelのCollectionのメソッドについてまとめたいと思います。

##rejectメソッドで条件に合わないものを除外してデータ取得する

Collectionの中から条件に合わないものを除外してデータ取得することができます。

```php:
$collection = collect([
    ['id' => 1, 'name' => '山田', 'age' => 18],
    ['id' => 2, 'name' => '佐藤', 'age' => 38],
    ['id' => 3, 'name' => '小林', 'age' => 25],
    ['id' => 4, 'name' => '鈴木', 'age' => 34],
    ['id' => 5, 'name' => '田中', 'age' => 29],
]);

$filtered = $collection->reject(function($values, $key){

    return ($values['age'] < 30);

});
print_r($filtered->toArray());

```

実行結果は下記になります。

```
Array
(
    [1] => Array
        (
            [id] => 2
            [name] => 佐藤
            [age] => 38
        )

    [2] => Array
        (
            [id] => 4
            [name] => 鈴木
            [age] => 34
        )

)
```
※条件式がtrueになるものは除外さます。

##おわりに
いかがでしたでしょうか。
rejectメソッドで条件に当てはまるものを除外できるので試してみてください。
PHP Laravel 6 画像のアップロード

#前提条件
画像ファイルの保存先 = ```storage/app/public```
データベースには```ファイル名```のみを保存。
ファイル名には```ランダムな名前```が自動で割り当てられる。


#フォームの作成

##フォームタグの記述
formタグに ```enctype='multipart/form-data'``` を記述しないとエラーを吐きます。
これを記述することで複数類(jpeg、png等)のデータ形式を扱う事でできるようになります。

```create.blade.php
<form method="POST" action="{{ route('recommends.store') }}" enctype='multipart/form-data'>
@csrf

</form>

```

##コントローラーの設定
imgがない場合に```$path = $request->file('img')->store('public/img');```でエラーを吐くためif文で分岐させました。

```recommendMovies/app/Http/Controllers/RecommendMovieController.php
public function store(Request $request)
    {
      if ($request->img === null) {
        RecommendMovie::create([
          'name' => $request->name,
          'description' => $request->description,
          'impression' => $request->impression,
        ]);
      }else {
        $path = $request->file('img')->store('public/img');
        RecommendMovie::create([
          'name' => $request->name,
          'description' => $request->description,
          'impression' => $request->impression,
          'img' => basename($path)
        ]);
      }
      return redirect('/recommends')->with('message', '作成しました');
    }
```

#viewの設定
シンボリックリンクを使用します。

```ターミナル
php artisan storage:link
```

storage\imgが作成され、この中にアップロードした画像が保存されます。
![Screen Shot 2020-09-27 at 12.03.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/736153/1ced20e9-65fd-b4f8-2011-28a34731b45c.png)

以下の記述でブラウザに表示させることができます。

```recommendMovies/app/Http/Controllers/index.php
<img src="{{ asset('/storage/img/'.$recommend->img) }}">
```