OmniAICreator/Qiita-1.07M huggingface dataset:
中間テーブルを用いた処理(Rails)

## 中間テーブルとは
中間テーブルは多対多の関係を表現するためのテーブルのことです。
テーブル同士が複数のレコードと対応している際に、中間テーブルを用いなければ非常に冗長なテーブル設計となってしまいます。
これだけでは意味不明だと思うので、下記の実例もよければ参考にしてください。

## テーブル設計
今回はgroupsテーブルとusersテーブルを作成します。
グループには複数のユーザーが所属し、ユーザーは複数のグループに所属できる、という仕様にするためgroupsテーブルとusersテーブルは多対多の関係になります。
この関係を整理するために、ユーザーが所属するグループと、グループに所属しているユーザーを管理する中間テーブル(group_usersテーブル)を作成します。
![スクリーンショット 2021-04-19 1.45.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/a59ce959-6531-846e-24c0-87e13393eeb7.png)


## 中間テーブルを作らなかったら？
usersテーブルでユーザーが所属するグループを管理、もしくはgroupsテーブルでグループに所属しているユーザーを管理する事になります。
下記の例では、usersテーブルでユーザーが所属するグループを管理しています。
これではユーザーが新しいグループに参加するたびに、usersテーブルのカラムを増やす事になるため、テーブル設計時にカラム数を決めることができません。
![スクリーンショット 2021-04-19 1.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/9d3a556f-61dc-4317-b796-c25e041b7dde.png)

カラムを増やさないために以下のようなテーブル設計にすることもできますが、これではusersテーブルに同じユーザーが2人以上存在する事になってしまいます。
![スクリーンショット 2021-04-19 1.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/56d28cde-a58f-6126-9e2c-48cbd0bde949.png)

## 実装編
今回はRailsを用いて、グループにユーザーを追加する処理を実装してみます。


モデルの実装内容は以下の通り。
・Userモデル

```ruby
class User < ApplicationRecord
  has_many :group_users
  has_many :groups, through: :group_users
end
```
・Groupモデル

```ruby
class Group < ApplicationRecord
  has_many :group_users
  has_many :users, through: :group_users
end
```

・GroupUserモデル

```ruby
class GroupUser < ApplicationRecord
  belongs_to :user
  belongs_to :group
end
```

画面の動きとしては、以下のGif画像のように登録ボタンを押下したらgroupに登録される感じです。
![bf5d192c77ea650caec24faff33379c3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/ec38439a-29f0-9765-f725-d8a27245b929.gif)

コントローラー側ではadd_userというユーザー追加用のメソッドを定義しています。
このメソッドの4行目でリレーションを追加する事により、中間テーブルにグループとユーザーが追加されます。

```ruby
  def add_user
    @group = Group.find(params[:group_id])
    user = User.find(params[:user_id])
    @group.users << user
    redirect_to group_path, notice: "ユーザーを追加しました。"
  end
```
プログラミング学習に役立つサイト

- [HTMLクイックリファレンス](http://www.htmq.com/)
フロントエンド実装はとりあえずこのサイトに目を通しておけばOK。早見表なので詳細な内容ではなく、要素毎に内容が詰め込まれている。

- [Pikawaka - ピカ1わかりやすいプログラミング用語サイト](http://pikawaka.com)
Ruby on Railsの学習でかなりお世話になっているサイト。内容が豊富で、完璧主義(笑)な自分の知りたいことも結構記載されていて助かってる。

- [「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/index.html)
略して**わわわIT用語辞典！**。ゆる〜いキャラクター達がゆるゆるとIT用語を解説している。

- [IT用語辞典 e-Words](https://e-words.jp)
IT用語を検索して調べた事がある人なら必ず一度は目にしたことがあると思われるサイト。[わわわさん](https://wa3.i-3-i.info/index.html)に登録されてない用語はこちらで。

- [difff《ﾃﾞｭﾌﾌ》](https://difff.jp/)
テキストの差分を表示してくれるサイト。勿論プログラムのコードにも利用可能。[VSCode](https://code.visualstudio.com/)みたいに差分を確認できる機能がデフォルトで搭載されているテキストエディタなんかもあるけど、これを使えば、文字数、空白数、改行数、単語数などの比較ができる。

- [ブラウザメモ帳](http://www.drpartners.jp/tools/browser-memocho.htm)
名前の通り、ブラウザ上で使えるメモ帳。各ファイルの一部分だけを切り取って比較確認したいとき等に使える。タブエディタでベタベタ並べたファイルを確認するときみたいに、余計な部分の情報を見なくて済むので便利。このサイト1ページで10項目分の内容を一覧表示できる。

---
他にもあったら、どんどん追記すべし！！
VscodeとVisual studioの違いやできること・できないことなどをまとめてみました！！

下記リンクを参考にさせていただきました。
ありがとうございました。
https://qiita.com/lldev2/items/46d55f71bdc1af2e3b10


初めにーー開発環境の拠点としてのエディタ

「Visual Studio Code」を使う理由：
「開発環境の拠点としてのエディタ」を通して見ることで最近の開発環境の変化を俯瞰的に捉えられると考えたから。

VScodeが開発された背景は簡単に言うとHTML５などを中心にした「webアプリ」（もしくは「ハイブリットアプリ」）が栄えたのが大きな要因と考える。それを書きやすいコードエディタの需要が出てきたので、「VScode」が開発された可能性がある。
しかし、それだけでは何の意外性もないので、もう少し掘り下げてみましょう。なぜ、Microsoft（以下「MS」）には「Visual Studio」というIDEがすでにあるのに、「VSCode」を新たに開発したのでしょうか？

開発形態の比較

静的言語/動的言語
それを考えるには、「動的（型付け）言語」「静的（型付け）言語」の軸で考えると俯瞰的に把握しやすい。まず単純にざっくり言うと、webアプリは動的言語と相性がいい。実際、フロントエンド側スクリプトのデファクトスタンダートである「javascript」も動的言語。

バッグエンド側で広く普及しているいわゆる「p言語」、「perl」「php」「python」「Ruby」もみんな動的言語。もちろん「java」などの静的言語のサーバーもあるが、エンタープライズ向けが多く、P言語ほど、大衆的ではない。

なぜ、Webアプリでは動的言語が好まれるのか？
・「HTML」「CSS」「Javascript」「PHP」「MySQL」などと５言語も使い分けることで、型で分ける以前に言語単位での分業がされている。
・データベースからデータを取得して、それを処理、表示するだけでシンプルな「CRUDアプリ」なら、型で整理する必要性が薄い。
・動的型付け言語は実行速度の面で不利だが、データベースのアクセス速度が最大のボトルネックになりがちなので、開発速度が優先される。
・WebアプリはB版で数多く開発して、ヒットしたものの開発を継続する、という市場探索的な開発形態を取ることが多い。そこでウォーターフォール的（型）的な設計よりもアジャイル的な開発の方が相性が良い。

そして、IDEは静的型付けの型情報が必要なので、動的型付けには起動や動作が軽いエディタで十分、といった状況言語がが続いた。
ただしここで、それならなぜ、これもMSが開発した「typeScript」のような静的型付け言語が、AltJSとして登場したのか？
という疑問が起こる。
それにはこう考える。
・まず、クラウドの潮流もあり、デスクトップアプリをWebアプリに移行する流れがあった。
・すると、CRUDだけで完結せず、ネイティブアプリの複雑さを引き受ける必要が出てきた。
・だから、フロントエンドを型付けで整理する需要が増え、TypeScriptが登場した。

そして当然、そのTypeScriptを書くのに、Vscodeは適している。
IDEとエディタの中間的なVSCodeが必要とされる理由の大筋はこのような理解している。

なお、やはりMSが開発した「PowerShell」も、VSCodeで書きやすいです。このPowerShellには「GUI／CUI」という軸が絡みます。ようするに、サーバ運用にはCUIの方が都合が良く、需要があったわけです。


総合開発環境とエディター

・総合開発環境
Visual Studio
・動作：windows
・対象：マルチデバイス/クロス
プラットフォーム/クラウド

Visual Studio for Mac
・動作：Mac OS
・対象：モバイル/クラウド/Mac


・コードエディター
Vscode
・動作：Windows, mac Linux
・対象：対象を問わず（※）開発言語をするもの（数百の言語に対応）
・備考：OSS、無償
（※）コードの実行に必要なコンパイラやランタイム、webサーバーは別途必要


Visual Studio for Mac　の web　ツール
・ .Net Core/ASP.NET Coreによるサーバーサイド開発
・ HTML/CSS/JSON に以下の機能を提供
 - HTMLテンプレート
 - コードハイライト
 - スマートインデント
 - インテリセンス
 - スニペット

標準機能と拡張
強力な標準機能の他にwebフロントエンド開発に特化した拡張が提供

開発支援機能の分類

入力支援機能
ツール
デバッグ
【Linux】Linuxファイル・ディレクトリの基本操作・コマンドまとめ

エンジニア歴5年の人が基本的かつ個人的によく使うLinuxコマンド（macのターミナルでも使える）をまとめました。
覚えておきたいオプション等は個人の意見であり、他の方からしたらもしかすると、「これもあったほうがいい」「それは別に」という意見もあるかもしれません。
随時コメントいただければ更新していきます。

# 目次
- [ワイルドカード](#ワイルドカード)
- [lsコマンド = list](#lsコマンド--list)
- [cdコマンド = change directory](#cdコマンド--change-directory)
- [pwdコマンド = print working directory](#pwdコマンド--print-working-directory)
- [mkdirコマンド = make directory](#mkdirコマンド--make-directory)
- [touchコマンド = ??](#touchコマンド--)
- [rmコマンド = remove](#rmコマンド--remove)
- [catコマンド = concatenate](#catコマンド--concatenate)
- [lessコマンド](#lessコマンド)
- [cpコマンド = copy](#cpコマンド--copy)
- [mvコマンド = move](#mvコマンド--move)
- [findコマンド](#findコマンド)
- [grep コマンド = global regular expression print](#grep-コマンド--global-regular-expression-print)
- [| = パイプライン](#--パイプライン)

# ワイルドカード
ワイルドカードとは、Linuxのコマンドラインで複数のファイルやディレクトリを操作する際に利用する特殊記号

**`*`** と **`?`**

## `*`
**任意の文字列**

> .rb拡張子のファイルのみを一覧表示

```
ls *.rb
```


> .log ファイルのみを削除

```
rm *.log
```


> ファイル名の中にfileという文字列を含むファイルすべてを一覧表示

```
ls *file*
```

## `?`
**任意の１文字**

> 拡張子が2文字のファイル一覧を表示

```
ls *.??
```

# lsコマンド = list
**ファイルやディレクトリの一覧を表示**

### 覚えておきたいオプション
> ## -a 
> 全てのファイルを表示
> 
> ## -A 
> ./ ../を除く全てのファイル
> 
> ## -l
> ファイル・ディレクトリの詳細情報を表示
>
> ## -h
> ファイルサイズを見やすくする
>
> ## -R
> 再帰的にディレクトリの中身を表示


# cdコマンド = change directory
**指定したディレクトリに移動**

# pwdコマンド = print working directory
**現在位置を絶対パスで表示する**

# mkdirコマンド = make directory
**ディレクトリの作成**

### 覚えておきたいオプション
> ## -p
> 階層ごとディレクトリを作成することが可能

# touchコマンド = ??
**タイムスタンプの更新、指定したファイルが存在しない場合、ファイル生成する**

# rmコマンド = remove
ファイル・ディレクトリの削除

### 覚えておきたいオプション
> ## -f
> エラー表示せずに強制的に削除する
> 
> ## -i
> ファイル削除前確認
> 
> ## -r
> ディレクトリの削除


# catコマンド = concatenate
**ファイルを結合して中身を表示**

よく使う使い方
``` :terminal
cat fileA
```

こんなこともできる
fileAとfileBを結合してfileABに格納する

``` :terminal
cat fileA fileB > fileAB
```

ただし、catコマンドは大きいファイルは向いていない
その代わりにlessコマンドをよく使う


# lessコマンド
**テキストファイルを１画面ずつ表示する**

### 覚えておきたいオプション
> ## -N
> 行数を表示
> 
> ## -S
> 行を折り返さない（横スクロールできない）
> 
> ## +F
> リアルタイムで監視

### lessコマンドの操作方法
| key | 内容 |
| :---: | :--- |
| /文字列 | 下方向に向かって検索をかける |
| ?文字列 | 上方向に向かって検索をかける |
| n | 次の検索結果へ移動する |
| N | 前の検索結果へ移動する |
| q | lessコマンドを終了する  |


# cpコマンド = copy
**ファイル・ディレクトリのコピー**

### 覚えておきたいオプション
> ## -p
> ディレクトリを再帰的にコピーする
	

# mvコマンド = move
**ファイル・ディレクトリの移動する**

### 使用例
``` :terminal
mv ~/workspace/hogehog.rb ~/workspace/hogehoge.rb
```
上記のように、ファイル作成時にtypo等がった際に、ファイル名を変更することもできます。

# findコマンド
**ファイルやディレクトリを検索する**

### 使用例
``` :terminal
find src/ -type f -name “*list*"
```
上記の例はキーワードでファイルを検索した例

findコマンドはできることがたくさんあるぶん覚えるのも大変なので、都度検索して利用しています

# grep コマンド = global regular expression print
**指定した文字列を検索する**

### 使用例
``` :terminal
grep -r 'HogeHoge' app/
```
上記のように、ディレクトリを指定して、指定した文字列が含まれるファイルを検索します。
例えば、あのメソッドどこで定義されてるかなー？と調べるのに効果的です。 
（テキストエディタを使っている人はもしかするとそちらの機能を使うと思います。）

### 覚えておきたいオプション
> ## -r
> ディレクトリ 内のファイルを検索する
> 
> ## -i
> 大文字と小文字を区別せず検索する
> 
> ## -l
> 検索結果にファイル名のみ出力する
>
> ## -C
> 検索結果に一致した箇所から前後に指定した行数表示する


# `|` = パイプライン
**コマンドの標準出力を次のコマンドの標準入力へ渡す**

例えば、catコマンドとgrepコマンドを使うことで、ファイルないからある文字列を検索して、検索結果のみを出力することができます

``` :terminal
cat account.txt |grep ‘北野 渚’
```
rx6800(RDNA2) + Ubuntu で powerlimit するメモ

基本 Navi 以降の AMD GPU を powerlimit し Linux で動かすのはあきらめてください(そもそもドライバが RDNA2 サポートしていないか, まともにサポートしていない. また不都合も多い). 

それでも無理やり動かしたい人向けです.

ドライバは amdgpu-pro 20.50 を想定します.

## rocm-smi

powerlimit するには rocm-smi 使います.
ただ昔の rocm-smi はなくなって(昔の rocm-smi は RDNA2 でも一応うごくかもだがいろいろエラーがでてきちんと動いているのかあやしい), 新しい(?)のを使うのが推奨になっています.

https://github.com/RadeonOpenCompute/rocm_smi_lib/tree/master/python_smi_tools

こちらはビルドが必要です. cmake でビルドしておきましょう.

ただ, これでもやはり RDNA2 はいくつかエラー出たり, status 不明みたいなレポートが出ます. 一応 powerlimit や fan 速度などは設定できるようですが...
(よく fan 速度設定できない or 不明みたいな不都合がでる)

うまくいかないときは, dmesg などにエラー出ていないかチェックしましょう. 不都合でたら基本リブートしてなんとかやりくりします.
iframeでpdfを表示する際にツールバーを非表示にする方法

複雑な家庭の事情により、iframeでpdfを表示する際にツールバーを非表示にする必要があったためメモ。

### やりたいこと

ブラウザでPDFを開くときに表示される、ダウンロードボタンや印刷ボタンの表示領域を非表示にしたい。

![Group 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253912/ca19082b-089f-7321-2bab-8e0e752694bc.png)

PDF本体を表示する領域が狭くなってよろしくないとか、ダウンロードできないようにしたいとか、印刷させたくないとか、いろいろな理由でこいつを消したいと思うことがあると思います。



### やったこと

iframeでsourceを指定する際のurlに`#toolbar=0&navpanes=0`をつけるだけ

```
<iframe src="https://hogehoge.test/test.pdf#toolbar=0&navpanes=0'">
```
みたいな。

他の方法としてはiframeに"preview"というidをつけて、previewAreaというクラスを付与して、cssで非表示にするみたいなのもありらしいです。

```
<script>
mounted(){
    const preview = document.getElementById('preview')
    const item = preview.contentWindow.document.querySelector('#toolbar')
    item.classList.add('previewArea')
}
</script>

<style lang="scss" scoped>
.previewArea {
    #toolbar {
        display: none;
    }
}
</style>
```

あとはpdf.jsをつかってがんばったり色々あると思いますが、ライトにやるなら今回のやりかたでいいんじゃないかと。


### 参考文献

https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_open_parameters.pdf
JavaScript 学習メモ

4/16 　
#本日の学習内容

9時～　　ボタンごとに違うテキストが表示されるボタンの仕組みを理解した。

```html:test.html
<label>アイスクリームの味:
        <select class="ice-cream" name="ice-cream">
          <option value="">1つ選択してください …</option>
          <option value="chocolate">チョコレート</option>
          <option value="sardine">イワシ</option>
          <option value="vanilla">バニラ</option>
        </select>
      </label>
      
      <div class="result"></div>
```
```js:test.js


document.querySelector('.ice-cream').addEventListener('change', (event) => {
document.querySelector('.result').textContent= `You like ${event.target.value}`;

});
```
・ice-creamの値が変わったらイベントを起こす
・resultのテキストコンテントを'Youlike${event.target.value}'にする。
・html側で、表示したいvalueの値と、表示したいところにresultの値を設定しているところがポイント


10時～　この記事の執筆　学習サイト探索

11時～　ストップウォッチの作成
　　　　htmlはこんな感じ

```html:test.html
<div id="timer">00:00:000</div>
    <button id="start">start</button>
    <button id="stop">stop</button>
    <button id="reset">reset</button>
```
jsファイルに書く内容をまとめる

・Startを押した時間から今の時間をひいて、それを表示する
・ミリ単位なので、変数を使って分、秒単位に直す

眠たくなったので、ストップウォッチは中止

14時～書籍で学習

15時～　foreach map の学習
BitcoinJSでデジタル署名を作成する。

※勉強内容のアウトプットです。

## 電子署名とは
**電子文書上の署名全般**を言う。

買い物のお会計の時にタブレットにするサインも電子署名であり、
以下で述べる公開鍵暗号方式を用いたデジタル署名も電子署名の一種である。

## デジタル署名とは
**公開鍵暗号方式**を利用した電子署名である。
デジタル署名によって証明できることは以下のようなことである。

- 送信されたデータは確かに秘密鍵の持ち主から送信されたものである。
- 手元にある公開鍵は確かに送信者の秘密鍵に対応する公開鍵である。
- 送信データが改ざんされていない。

※注意点としては、以上のことだけでは**なりすましを完全には防げない**。デジタル署名の仕組みは別記事に起こそうと思います。

## BitcoinJSを使った署名データの作成

```javascript
// ライブラリ読み込み
const bitcoinjs = require('bitcoinjs-lib')
const crypto = require('crypto')

const data = '署名対象データ'

// 署名対象データをハッシュ化
const dataHash = crypto.createHash('sha256').update(data).digest()
console.log('Date Hash: ' + dataHash.toString('hex'))

// ECPair生成
const ECPair = bitcoinjs.ECPair.makeRandom({rng: crypto.randomBytes, compressed: false})

// 署名データ作成
const signature = ECPair.sign(dataHash)
console.log('Signature: ' + signature.toString('hex'))
```

署名対象データはそのままだとサイズが大きいことがあるので、**署名対象データは通常、事前にハッシュ化する**。
今回はSHA256を使用し、32バイトのメッセージダイジェストに対して署名した。
標準入力がファイルであるようにする


標準入力がファイルからのリダイレクトだと、statやmmapが効いて便利である。しかし、標準入力がパイプだとそういった機能は使えない。

ファイルでなかった場合はファイルに書き出してからexecすることで、標準入力がファイルであることを保証できると思った。
※ただし後始末の関係上開いているファイルを削除するのでWindowsではうまく動きません

```c:stdinasfile.c
#include "../compat.h"

#ifdef STANDALONE
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
unsigned char buf[BUFLEN];
#else
#include "../cielbox.h"
#endif

//#include <errno.h>

#ifdef STANDALONE
int main(const int argc, const char **argv){
	initstdio();
#else
int stdinasfile(const int argc, const char **argv){
#endif
	if(argc<2){
		fprintf(stderr,"cmd | stdinasfile program/interpreter...\n");
		fprintf(stderr,"in this way program can \"stat\" previous pipe.\n");
		return 0;
	}

	struct stat st;
	int status = fstat(0,&st);
	if(status || !S_ISREG(st.st_mode)){
		//fprintf(stderr,"running stdinasfile %d %d %x\n",status,errno,st.st_mode);
		char template[]="/tmp/stdinasfileXXXXXX";
		int fd = mkstemp(template);
		unlink(template);
		int len;
		for(;(len=fread(buf,1,BUFLEN,stdin))>0;){
			write(fd,buf,len);
		}
		lseek(fd,0,SEEK_SET);

		close(0);
		dup2(fd,0);
		close(fd);
	}

	const char *cmd=argv[1];
	char **args=(char**)malloc(sizeof(char*)*(argc));
	for(int i=1;i<argc;i++)args[i-1]=(char*)argv[i];
	args[argc-1]=NULL;
	execvp(cmd,args); //execvp is required; cmd might be interpreter name
	free(args);
	return 0;
}

```
Anaconda NavigatorでGluevizやOrange3がインストールできないとき

# きっかけ
Anaconda NavigatorのHome画面から、GluevizとOrangeの[install]ボタンを押したところ、何も起きなかったため、バージョンが古いせいかと思い、 Anaconda Navigator 1.10.0 にバージョンアップしてから、再挑戦してみました。が、しかしそれでもインストールできませんでした。
対象OSはWindows10です。

# 調べてみました
何が何でも、Anaconda Navigatorからインストールしなければ！という拘りを捨てたら簡単でした。
Googleで**conda install Glueviz**を検索してみました。
検索結果の上位をクリックしてみたら、Anaconda.orgのサブディレクトリに飛びまして、
Glueviz   --> https://anaconda.org/astropy/glueviz
Orange    --> https://anaconda.org/conda-forge/orange3
そして、そこにconda install コマンドが書いてあったので、試してみました。

# 実際にインストールしてみました

## Gluevizの場合

Anaconda Promptを管理者として実行して、次のコマンドを実行しました。

```
conda install -c astropy glueviz
```

全行のログは下記のとおりです。
**Proceed ([y]/n)?**　のところで、**y** をタイプしてエンターを押せば、インストールを開始して、**done** が表示されたら完了です。

```
(base) C:\WINDOWS\system32>conda install -c astropy glueviz
Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: C:\ProgramData\Anaconda3

  added / updated specs:
    - glueviz


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    glueviz-0.15.2             |                0          19 KB  astropy
    ------------------------------------------------------------
                                           Total:          19 KB

The following NEW packages will be INSTALLED:

  dill               pkgs/main/noarch::dill-0.3.3-pyhd3eb1b0_0
  fast-histogram     pkgs/main/win-64::fast-histogram-0.9-py37h080aedc_0
  glue-core          pkgs/main/win-64::glue-core-0.15.6-py37haa95532_0
  glue-vispy-viewers pkgs/main/noarch::glue-vispy-viewers-0.12.2-py_0
  glueviz            astropy/win-64::glueviz-0.15.2-0
  mpl-scatter-densi~ pkgs/main/noarch::mpl-scatter-density-0.7-py_0
  plotly             pkgs/main/noarch::plotly-4.14.3-pyhd3eb1b0_0
  pyopengl           pkgs/main/win-64::pyopengl-3.1.1a1-py37haa95532_0
  retrying           pkgs/main/win-64::retrying-1.3.3-py37_2


Proceed ([y]/n)?

```

## Orange3の場合

上のGluevizとほぼ同様です。
Anaconda Promptで下記コマンドを実行してください。

```
conda install -c astropy glueviz
```

# あとがき

同じようなことで、お悩みの方にお役に立てばいいのですが。また、アドバイスがありましたら是非教えてください。
Raspberry Pi3で人だけを検出する監視カメラをつくる

監視カメラで人を検出する方法は画像処理による動体検知等様々あるが、
ディープラーニングを用いてみようと思い立った。
そのときのいくつかの、トラブルシューティングについての備忘録である。

####1. 使用するモデルについて
（１）Masked-RCNNを使用してみる

RaspberryPi3では重すぎてうまく動かなかった・・・
RaspberryPiのスワップ領域を広げたり、様々試みたがダメだった。

（２） MobileNet SSD v2を使用してみる

こちらのサイトを参照
[ラズパイ上で訓練済みモデルを使って物体検出をしてみた](https://ymgsapo.com/2019/04/05/raspi-opencv-dnn-obj-detection/)

MobileNetはエッジデバイスでも動かせるように軽量化されているため、RaspberryPiには最適かも。
[上記サイトで紹介されているリンク](https://github.com/rdeepc/ExploreOpencvDnn)から学習済みモデルをそのままダウンロードして使用してみると、RaspberryPiでもサクサクと動いた。

で、ここでは、このMobileNet SSD v2をベースに機能を拡張していく。

####2. サンプリング間隔と熱暴走
（１）サンプリング間隔

上記のモデルを使用して、以下のようなフローのプログラムを作成。

【カメラ画像取得】
　　　　&#x2193;
【AIによる物体識別】
　　　　&#x2193;
【「人間」と識別されるフレームが存在するか判定】
　　　　&#x2193;
【存在すればLINE通知を送信】

この一連のフローの実行に2~3秒程度かかった。
このフローをそのままループさせて実行。
すると、数分後には処理が停止し、RaspberryPiが固まってしまった。
熱暴走のようである。

```bash
vcgencmd measure_temp
```

上記コマンドで、CPU温度を確認すると、85℃くらいまで跳ね上がっている。
やはり、かなりCPUに負荷がかかっているようだ。

そこで、ループの間にsleep()を挟み、サンプリング間隔を長めにとってみた。
確かにサンプリング間隔が長いほどCPU温度の上昇率は抑えられたが、温度上昇が続くことは変わらなかった。
そして、時間の差こそはあれ、熱暴走することがわかった。

（２）RaspberryPi冷却

Amazonで、冷却ファン付のRaspberryPiケースを1000円程度で購入。
[Miuzei 最新Raspberry Pi 3B+ ケース](https://www.amazon.co.jp/gp/product/B07J4PTL79/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)

冷却ファンの威力は素晴らしかった。
上記の処理でsleep()を挟まなくても、CPU温度が47℃前後からほとんど変化しなくなった。
半日実行しつづけても全く問題なく、熱暴走から解放された。

（３）通知をリモートから停止する

人を検知時に無条件にLINE通知を送るようにしたが、留守中の家に家族が帰宅したときにLINE通知が送信され続けるので、通知送信をリモートから止められる仕組みが必要だった。

そこで、無料のSalesforce Developerエディションを活用。
カスタムオブジェクトを作成し、パラメータ名とパラメータ値を項目として作成する。
このカスタムオブジェクトに欲しいパラメータをデータとして登録する。

RaspberryPi側のプログラムでは、作成したカスタムオブジェクトから欲しいパラメータ値をSalesforceの REST API で取得し、値に応じてLINE通知をするかしないかを選択できるようにした。

これで、リモートからSalesforceのサイトにアクセスし、カスタムオブジェクトのレコードのパラメータ値を変更することで、LINE通知する／しないを切り替えられるようになった。
同じ仕組みで、他にもきめ細かい制御をリモートから行うことができるはず。
SourceGeneratorのデバッグ

# 概要

Visual Studio 2019 バージョン 16.10 preview 2の新機能で`SourceGenerator`のデバッガーサポートが追加されました。
デバッグに難があったので朗報ですね。

https://docs.microsoft.com/ja-jp/visualstudio/releases/2019/release-notes-preview#16.10.0.pre.2.0

# 方法

>ソース ジェネレーターのデバッガー サポートが追加されました。 まず、\[Project Properties Debug](プロジェクト プロパティのデバッグ) ページで、"Roslyn コンポーネント" デバッガー オプションを有効にする必要があります。 そして、適切なターゲット プロジェクトを選択する必要があります。 次に、ジェネレーター プロジェクトで F5 キーを押します。これにより、ターゲット プロジェクトをビルドする CSC.exe/VBC.exe が開始され、ジェネレーター コードをデバッグできるようになります。

プロジェクトのプロパティを開いてもデバッガーオプションには見当たりません。
そこで`SourceGenerator`のプロジェクトファイルを編集して`<IsRoslynComponent>true</IsRoslynComponent>`を加えます。

```xml
<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>library</OutputType>
		<TargetFramework>netstandard2.0</TargetFramework>
		<IsRoslynComponent>true</IsRoslynComponent>
	</PropertyGroup>
</Project>
```

改めてプロジェクトファイルのプロパティを開くと、デバッグページから無事に`Roslyn Component`が選択できるようになります。

![srcgen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135585/1552b884-eaaa-6e1c-d1ac-cdae4c679cfb.png)

あとはリリースノート通りにターゲットプロジェクトを指定するだけですね。
ターゲットプロジェクトからの`SourceGenerator`プロジェクトの参照に`<OutputItemType>Analyzer</OutputItemType>`がないと選択できないので注意しましょう。

#参考

‍https://github.com/dotnet/roslyn-sdk/pull/726
人工キー、自然キーのどちらを使うべき？

人工キーを使うべきか自然キーを使うべきか、昔から論争になっています。
私は、一度すべて自然キーで実装して苦労したことがあったので、人工キーを使ったほうが良いのかと思い、調べてみました。

# 人工キーと自然キー

人工キーは主キーのうち、システム側で自動的に与えられるものです。
基本的にユーザーからは見えません。サロゲートキーとも言います。
自然キーはその逆で、ユーザーが与える主キーです。その性質上、1つのカラムで自然キーになることは少なく、複合キーになることが多いです。

# 人工キーを使うメリット
一般的に、よく言われる人工キーのメリットは次のようなものがあります。

* テーブル間の依存関係を薄くできる
* 複合キーを排除でき、SQLが簡潔に書ける


## テーブル間の依存関係を薄くできる
依存関係については主キーの構造が変化したときを考えるとわかりやすいです。
人工キーを使った場合と自然キーを使った場合のER図を作りました。
![人工キー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420954/99ddc10b-243b-46c2-8f0c-212faf7ba3e2.png)

この図で、もしテストテーブルに中間/期末フラグを設けることになった場合のことを考えます。
赤字が追加箇所です。

![人工キー（キー追加）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420954/25cd9d0f-4aa0-b777-f8c4-2415c0c37841.png)

人工キーのみの場合は、変更はテストテーブルだけで済みますが、自然キーのみの場合は成績テーブルにも影響が発生していることがわかります。
このように、人工キーを使った場合はテーブル構造の変化が、ほかのテーブルに影響を与えにくくなり、後々の変更に強くなります。

## 複合キーを排除でき、SQLが簡潔に書ける
自然キーでは、どうしても単一のカラムが主キーになることが少なく、複合キーになることが多いです。
そのため外部キーも複数のカラムを書くことになり、SQL文が煩雑になりがちです。
次に先ほどのER図の成績テーブルから1行取り出すSQLを書いてみます。

~~~ SQL
-- 人工キーを使った場合
SELECT * FROM 成績
WHERE 学生ID = 000
AND テストID = 000;

-- 自然キーのみ使った場合
SELECT * FROM `成績`
WHERE `学籍番号` = 000
AND 科目 = '数学'
AND 年度 = 2021
AND 期 = '前期';
~~~
複合キーが混じると、条件式がだいぶ増えてしまいました。
単純に数行増えただけに見えますが、これが意外と馬鹿にならなかったりします。
条件を1行書き忘れるだけでも不具合になり、かつSELECT、INSERT、UPDATE・・・など、それぞれSQLを書く必要があるので割と見落としがちになります。
さらにテーブル構造に変更があった場合、前述のとおり自然キーでは影響範囲が大きくそこでまた不具合が発生しうるので、テストの工数まで考慮するとなかなか馬鹿にできない違いになってきます。

# 自然キーのメリット
自然キーを使うメリットは以下のようなものがあげられます。

* 結合せずに他テーブルのデータを参照できる
* 業務に無関係なカラムが増えない

## 結合せずに他テーブルのデータを参照できる
先ほどのER図を見てみると、自然キーのみで設計した場合は、成績テーブルにテストの科目、年度、期のデータが含まれています。
人工キーではいったん成績テーブルとテストテーブルを結合しなければ、これらのカラムは参照できません。

## 業務に無関係なカラムが増えない
人工キーは本来業務に利用しないデータであるので、ある意味冗長なデータといえます。
ER図の学生テーブルは、学生IDは、イコール学籍番号を表しているといえます。
ですので、人工キーでは学生IDが主キーで重複できないカラムなので、学籍番号に対しても同様にUNIQUE制約をつける必要があります。
また、テストテーブルでは科目、年度、期がテストIDという1カラムにまとまってしまっているので、変更の影響範囲が見極めにくくなる、ということもあります。

なお自然キーでは無関係なカラムがないため容量が少なくて済む、というメリットも言われたりしていますが、これはあまり気にしなくてよいかと思います。
自然キーは複合キーになりがちで、外部キーがその分増えるため、結局はあまり変わらないはずですので。

# 結局どっちをつかったらいいのか
私は大体以下の指針で検討します。
こんな意見もあるよって方はコメントいただけると嬉しいですー。

* 候補キーが複合キーでなく、かつ（ほぼ）不変ならそれを自然キーとして使う（ER図の学生テーブル）
* 候補キーが複合キーで、かつほかのテーブルから参照されている場合、依存関係を薄くして変更に強くするため人工キーを使う（ER図のテストテーブル）
* 候補キーが複合キーで、かつほかのテーブルから参照されていない場合、複合キーを使用する（ER図の成績テーブル）
Macでgitコマンドが使えなかった場合の解決法

Macのターミナルで"git --version"と打ったら、以下のエラーが出てしまった。

"xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun"


![92E3FAFF-F256-4073-BD53-DEA440BA4412_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1345377/841a12f5-5615-d89d-ad2a-82d8d5a6b90e.jpeg)

調べて見ると、"xcode-select --install"とターミナルに入力して、Command Line Tool Pacageをインストールすることで、解決できるらしい。

さっそくやってみた。
インストール完了後に、試しに"git"と入力したら、ちゃんとusageを表示してくれた。

![26596DD6-88A2-46A5-83FF-4834389F6E9A_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1345377/7b3e55f4-bf74-4047-66c1-152c5de916ec.jpeg)

これでひとまず、問題は解決した。
[KPI]　fuelphpで共有todoリスト作成

#TodoList一覧
カテゴリー毎にtodoリストを作成できる

![スクリーンショット 2021-04-19 0.03.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/0c383a72-7b5e-7082-323f-1944cf5561a4.png)

#各カテゴリーのtodoリスト一覧
カテゴリーに対応したtodoリストを作成できる

![スクリーンショット 2021-04-19 0.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/f718e75e-456e-570a-cc52-41b71a286abb.png)

#todoリストの招待画面
新規登録時にuser_code、todoリスト作成時にtodo_codeが作成される。
招待したいuser_code、todo_codeを入力して送信し、相手が承認すれば共有することができる

![スクリーンショット 2021-04-19 0.04.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/f5e93f75-8f98-8333-9c5c-bcd99546de9a.png)

#招待承認画面
この画面で招待を承認するか拒否するか決める
![スクリーンショット 2021-04-19 0.17.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/4353632f-7742-bfba-0388-1a9394fc8262.png)

#サイドメニュー
![スクリーンショット 2021-04-19 0.04.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/a8a7cf5f-4b2e-636a-13f0-e82861c671ad.png)
競プロをPythonでやるときのメモ

# はじめに

AtcoderをPythonで戦って行く際、忘れまくるのでメモりまくります


## 標準入力

### ただ受け取るだけ


```python
入力：admin
s = input()
print(s)

admin 型[str]

入力：123
s = int(input())
print(s)

123 型[int]→文字列はエラーになる
```

### リストにする

```python
入力：admin
s = list(input())
print(s)

['a','d','m','i','n'] 型[list]
```

### mapを使う（一度に複数の変数を受け取る）

```py
入力：3 4 5
a, b, c = map(int, input().split())
print(a,b,c)

3 4 5 型[int]
```

### 改行されている値の取得

```py
入力
1
2
3
4

# if 行数がわかる場合
a = [int(input()) for i in range(4)]

# if 行数が不明の場合
import sys

a = []
for i in sys.stdin:
    a.append(int(i))

[1, 2, 3, 4]
```


## 標準出力

### 複数の変数を出力

```py
入力：[1, 2, 3, 4]
a = [1,2,3,4]
count = 1
print(a)
for i in a:
    print(count, i)
    print("{0}, {1}".format(count, i))
    count += 1

[1, 2, 3, 4]
(1, 1)
1, 1
(2, 2)
2, 2
(3, 3)
3, 3
(4, 4)
4, 4
```



## 文字列操作

### 逆順に出力

```py
入力：123
a = input()
print(a)
print(a[::-1])

123 型[str]
321 型[str]
```

## 繰り返し処理

### 引数を複数に

```py
a = [1,2,3]
b = ["a", "b", "c"]
for (i,j) in zip(a,b):
    print(i,j)

1 a 型[int str]
2 b 型[int str]
3 c 型[int str]
```

### 引数を複数に　その２

```py
a = [11,12,13,14,15]
b = ["a", "b", "c", "d", "e"]


for (i,j) in zip(range(len(a)),b):
    print(a[i], b[i])

11 a 型[int str]
12 b 型[int str]
13 c 型[int str]
14 d 型[int str]
15 e 型[int str]

```
AppExchange の基礎 ⇒ AppExchange の使用開始

１．AppExchange とは何ですか?
２．AppExchange のコレクションの説明として適切なのは、次のうちどれですか?
３．AppExchange のソリューションの説明として適切なのは、次のうちどれですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/865a7cf5-f5a0-13f8-97c1-ae188130f77a.png)
Java初学生が簡単な基礎から学び始めるまで

##自己紹介
こんにちは。私は現在運用保守のエンジニアとして働こうとしている22歳都内在住エンジニア（）です。
自分のための備忘録として簡単なjavaの基礎をまとめていこうと思います。少しでもかつての私のような入門者たちに役に立てば幸いです。

##対象者
この記事の対象となる人はJavaで何ができるかなどの情報ではなく、主に出力方法や、配列や変数などの宣言の方法のまとめを知りたいというよう方向けになります。

##文字及び数字の出力
```java
//文字の場合
System.out.println("テスト");

//数字の場合
System.out.println(1);
```
基本的にSystem.out.printというものはコンソール上に出力結果を出すものになります。数字の場合は""がいらないと覚えてます。

...端的すぎるのでもう少しわかりやすくしますね。

##もう少しわかりやすくすると

```java
public class Sample01 {
    public static void main(String[] args) {
        // データ型や宣言方法のまとめ
        int age = 22;
        String name = "テスト太郎";

        System.out.println(age);
        System.out.println(name);
        
        System.out.pritln(11111);
        System.out.println("適当な数字");

```
これでいかがでしょうか。
変数の宣言方法もついでに書いてしまいましたが、なんとなく把握できそうですね!
int=数字
String=文字
という感じになり、変数ageやnameに指定しているデータ型の値を格納するといった感じですね。

いったんは初期的なところを記載させていただきましたが次回の記事からはもう少し処理的なところを書いていこうと思います。
備忘録といった感じで試験的にやっているものなので長続きするかわかりませんが、頑張ってみます！
Web開発の仮想化についてまとめてみた（図あり）

Dockerについてあまり理解していなかったので、
自分なりに簡単にまとめていきたいと思います。

今回はWebアプリ構築することを前提に書いていきます。


#Dockerとは
仮想環境を構築するためのツールです。

**"コンテナ"**と呼ばれる仮想環境を構築し、
そのコンテナを組み合わせて動かすことでWebアプリを動かすことができます。

**コンテナとは**
設定ファイルなどをひとまとめにしたもの。
例えば、
アプリ（laravel、Railsなど）、ミドルウエア（MySQL,Nginxなど） 、OS（CentOS,Ubuntuなど）など様々なコンテナを作ることができます。

Docker意外にも様々な仮想化ソフトが存在します。（図）
![スクリーンショット 2021-04-18 17.51.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/c3e4588a-b5ac-75a0-50e6-401b45af17e1.png)

コンテナを細かく見るとこんな感じです（図）
![ev091.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/8071a78c-7956-304b-de70-c85c38ef3e9a.jpeg)


####イメージ
Dockerコンテナを作るためのためのレシピみたいなものです。

####ベースイメージ
Docker Hubなどで提供されているベースになるイメージです。

####レイヤ
レイヤを重ねることでイメージを自分好みにカスタムできます。



#Dockerと仮想化ソフト(VirtualBox)の違いは？
仮想化ソフト(VirtualBox)
■メリット
・細かな設定ができる。
■デメリット
・ゲストOSを起動しなければならない。Dockerに比べてCPU、メモリを消費する。

Docker
■メリット
・イメージがあれば簡単に環境構築ができる。
・「作って壊す」がすぐでき、必ず同じ環境が作れる。
■デメリット
・同一のOSから複数のコンテナを作成するため、違うOSを使いたい場合は別のマシン必要。


#家を例にして比較（DockerとVirtualBox）
![スクリーンショット 2021-04-18 17.52.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/ca6bfd01-a6bb-3465-91f9-f95ee6ce7ce0.png)
![スクリーンショット 2021-04-18 17.52.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/a1a0b8f8-5e14-5378-2076-e87932a4ff94.png)
####①土地（ホストOS）
　家を立てるのに土地が必要。

####②家の外装（VirtualBox、Docker Engine）
　家の骨組み、外観を決める。

####③家の内装（Vagrant、Docker）
  　Vagrant：内観の設計、部屋を何するかを決める
　　　　　→細かく決めるが設計など時間がかかる。

  　Docker：部屋を何するかを決める
　　　　　→部屋をすぐに変更できるが家の細かなカスタムは不向き。
AWS CLI で最新の AMI 情報を取得する方法

何回やっても忘れるのでメモ。


## 結論

アーキテクチャーや名前などの検索条件は適宜調整する。

```yaml
## aws ec2 describe-images --owners amazon --filters "Name=architecture,Values=arm64" "Name=name,Values=amzn2-ami-hvm-*" --query "sort_by(Images, &CreationDate)[-1]" | yq eval -P
Architecture: arm64
CreationDate: "2021-03-26T22:38:04.000Z"
ImageId: ami-03888b30ba5826eed
ImageLocation: amazon/amzn2-ami-hvm-2.0.20210326.0-arm64-gp2
ImageType: machine
Public: true
OwnerId: "137112412989"
PlatformDetails: Linux/UNIX
UsageOperation: RunInstances
State: available
BlockDeviceMappings:
  - DeviceName: /dev/xvda
    Ebs:
      DeleteOnTermination: true
      SnapshotId: snap-0106c0756363a552d
      VolumeSize: 8
      VolumeType: gp2
      Encrypted: false
Description: Amazon Linux 2 LTS Arm64 AMI 2.0.20210326.0 arm64 HVM gp2
EnaSupport: true
Hypervisor: xen
ImageOwnerAlias: amazon
Name: amzn2-ami-hvm-2.0.20210326.0-arm64-gp2
RootDeviceName: /dev/xvda
RootDeviceType: ebs
SriovNetSupport: simple
VirtualizationType: hvm
```


## 参考文献

- [Find a Linux AMI - Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)
- [Query for the latest Amazon Linux AMI IDs using AWS Systems Manager Parameter Store | AWS Compute Blog](https://aws.amazon.com/blogs/compute/query-for-the-latest-amazon-linux-ami-ids-using-aws-systems-manager-parameter-store/)


どっとはらい。
条件分岐と演算子について


フリマアプリの商品詳細画面で

条件分岐１
-

解答１
-

###ログインかつ出品者
こちらには編集雨ボタンと削除ボタン表示

```ruby
<% if user_signed_in? && current_user.id == @item.user_id %>

<% end %>
```

devise導入で使用できるメソッド

|メソッド|用途|
|--|--|
|user_signed_in?|ユーザーがサインイン済かどうかを判定|
|current_user|サインインしているユーザー情報を取得|

@item.user_id　今ログインしている人のuser_idがitemテーブルにあれば出品者ということになる。

＊before_action :authenticate_user!	コントローラーに設定して、ログイン済ユーザーのみにアクセスを許可する.

別解
-
可読性を高めるために

```ruby
<% if user_signed_in? %>
  <% if current_user.id == @item.user_id %>
  
  <% end %>
<% end %>
```



条件分岐２
-

###ログインはしているが出品者ではない投稿者
購入ボタン表示

```ruby
<% elsif user_signed_in? && current_user.id != @item.user_id %>
```

別解2
-

```ruby
<% elsif user_signed_in? %>
  <% if current_user.id != @item.user_id %>
  
  <% end %>
<% end %>
```
windowを用いたcount distinct集計を行う

# 概要

count distinct集計にwindowを使うことはできないが、それに対する代替手段を備忘のためまとめる。


# やり方

`count(distinct X) over (order by Y)`したい時、

1. `row_number() over (partition by X order by Y) as rn`で変数群X毎にY順で出現順序をつける
1. `sum(sum(if(rn = 1, 1, 0))) over (order by y)` で初出の箇所のみで和を集計する

```sql:windowでcountdistinct
with
sample_data as (
    select
        *
    from unnest([
        struct(date '2019-01-01' as dt, 'user1' as user_id),
        (date '2019-01-02', 'user1'),
        (date '2019-01-02', 'user2'),
        (date '2019-01-03', 'user3'),
        (date '2019-01-04', 'user3'),
        (date '2019-01-05', 'user3'),
        (date '2019-01-02', 'user4'),
        (date '2019-01-04', 'user4'),
        (date '2019-01-04', 'user5')
    ])
)

select distinct
    dt,
    sum(case when rn = 1 then 1 else 0 end) over (order by dt) as accumulated_uu
from (
    select
        *,
        row_number() over (partition by user_id order by dt) as rn
    from sample_data
)
```

# 参考

- [sql - Distinct in Window Functions. BigQuery - Stack Overflow](https://stackoverflow.com/questions/48225898/distinct-in-window-functions-bigquery)
 - 別の例
three.jsで物体が衝突したことを検知する

# 概要

three.jsで物体が衝突したことを検知したくて色々ググって実践してみたんですが、どうもうまくいきませんでした。英語のサイトなども探してまわって最終的に以下で説明するようなコードで実現できたのですが、どうもすっきりしない…謎のあるコードになってしましました。とりあえず現時点でのコードを備忘録として載せます。

# 衝突検知のサンプル

二つの球体があり、一つの球体がもう一つの球体に衝突したら停止するという非常にシンプルな動作です。intersectsSphereを使って衝突を検知しています。動作自体は想定通りの動作です。

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

# 個人的に謎の箇所

私のthree.jsの知識が足りてないからだと思いますが、以下の点が謎でした。

```javascript
  sphere.geometry.computeBoundingSphere();
  // 球体（緑）用のBoundingSphere
  var sphereBBox = new THREE.Sphere(sphere.position, sphere.geometry.boundingSphere.radius);
```

衝突検知用のBoundingSphereを作成しているんですが、そもそも`computeBoundingSphere()`によって`sphere.geometry`にboundingSphereオブジェクトが生成されているんですよね。以下のような感じ。

```javascript
  sphere.geometry.computeBoundingSphere();
  // sphere.geometry.boundingSphereが生成される
  // 但し、このオブジェクトで衝突検知しようとしてもうまくいかない?

  // 球体（緑）用のBoundingSphere ← 結局これが必要になった
  var sphereBBox = new THREE.Sphere(sphere.position, sphere.geometry.boundingSphere.radius);
```
`sphere.geometry.boundingSphere`が生成されているのだからこれで衝突判定すればいいように思うんですがどうしてもうまくいかない。（厳密にはboundingSphereの位置をうまくセットできなかった。）結局、判定用にSphereを作成してradiusの値などをコピーすることでうまくいきました。

初歩的な何かを見逃しているような気もしますので、判明したら追記していきます。
textの書き換え

# text()
- 要素のテキストを設定、または設定されているテキストを取得できるメソッド
- text()で取得するテキストにはHTMLタグは含まれない
- 指定した要素が複数存在した場合は、1つのテキストとして連結されて取得する

# テキストの変更
セレクタで指定した要素の中身を変更したい場合は、.text()の中に直接値を入力する

```php	
$("要素").text("変更後の文字")
```

```php	
 <body>
    <div class="sample">このテキストを変更する</div>
    <script>
     $('.sample').text('変更しました！')
    </script>
  </body>
```
Virtual BoxのFailed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter' (VERR_INTNET_FLT_IF_NOT_FOUND). を解決する

#遭遇したエラー内容

下記構成の仮想マシンを起動しようとしたところ
Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter' (VERR_INTNET_FLT_IF_NOT_FOUND).
とのエラーで仮想マシンが起動できなかった
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/cba1bdce-d2d3-bef4-6ba6-a79095669dcc.png)


#解決に至るまでにやった手順

①「Alt+R」で「ファイル名を指定して実行」を開き、「control」と入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/e3649960-5ed7-fe9f-aaa0-63e883e51d7a.png)

②「ネットワークとインターネット」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/1924f7d6-c709-c2da-c6fb-3ea1ed655ba8.png)

③「ネットワークと共有センター」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/c40b26ca-27ea-4027-cd1b-0b9d0c4827de.png)

④「アダプターの設定の変更」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/b45b696a-6671-fb64-177b-22adc0dbfcaf.png)

⑤環境によって変わると思うが、「イーサネット2」を右クリック→「無効にする」を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/78148d35-7efb-f6f5-0d4d-6c26b64fcb83.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/e243ce61-43af-eb80-ff5b-92a9193984a7.png)

⑥再度「イーサネット2」を右クリック→「有効にする」を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704575/5706f4db-4e13-4f38-9c9c-61551292068c.png)

これで解決しました

## 参考
この方のブログがよくまとまっていて参考になったので、私の手順で解決しなかった方はこちらを読んでみて欲しい
https://qiita.com/miyase256/items/e56d413c6aa2b4eb257c
Android Studio のインストールとAVD作成

Android エミュレータを利用するために Android Studio をインストールし
仮想端末(AVD)を作成する手順です
※わかりにくい記述などありましたら、ご指摘いただけるとありがたいです



## Android Studio のダウンロードとインストール

[JetBrains Toolbox](https://www.jetbrains.com/ja-jp/toolbox-app/)を使用してインストール・アップデートすることもできます

個別にダウンロードしてインストールする場合は
https://developer.android.com/studio?hl=ja からダウンロードします

#### macOSの場合
ダウンロードしたdmgをマウントして`Android Studio.app`を`/Applications`にドロップ

#### Windowsの場合
![AndroidStudioSetup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/21ef69ba-8674-b041-48b1-ee11d6119fb9.png)
`Android Virtual Device`を選択し、ウィザードに沿ってインストールする





## Android SDK のインストール

Android Studio を初回起動時にセットアップが始まるので画面指示どおりに進めてください





## Android Virtual Device (AVD)作成

![avd1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/8d70b6ab-bf85-a73f-8332-4cff194e3590.png)
Android Studio を起動し、起動時の画面の`Configure`から`AVD Manager`起動

![avd2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/a7c8ca93-2470-4b33-1b58-2bed4f399b7a.png)
Android Virtual Device Manager で `Create Virtual Device` を選択

![avd3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/b48d9d47-8fab-d75a-967f-7f2e2d3f1058.png)
適当な端末定義を選択 (画像ではPixel 2)

![avd4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/6611e1a6-4bb3-9b90-9eeb-e75f2dbbf255.png)
OSイメージを選択 (ダウンロードしていなければ先にDownloadボタンでインストール)

![avd5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/bf301c6e-6f73-e0c8-2f94-0ffc382ac86b.png)
AVD Name を決めて完了
※コマンドラインで操作する場合にこの名前で指定することになります
データウェアハウスとデータベースの違い

#プログラミング勉強日記
2021年4月18日
AWSの勉強をしているときに"データウェアハウス"という言葉を見かけて調べてみたらデータベースとの違いがいまいちわからなかったので、備忘録として残す。

#データウェアハウスとは
　データウェアハウスを直訳すると、"データの倉庫"という意味になる。人によって定義範囲は異なるが、一般的には時系列で整理された大量の等号された業務データやその管理システムのことをいう。
　Googleで調べてみると以下のように出てきた。

> データウェアハウス（Data Ware House）とは、組織の意思決定を支援するために使用される大規模なビジネスデータを指します
(参考：https://www.talend.com/jp/resources/what-is-data-warehouse/)

　


#データベースとは
　データを複数集めて、使いやすいように整理した情報の塊のことをいう。コンピュータで管理するデータをデータベースということが多いが、神で管理している電話帳などもデータベースである。

#データウェアハウスとデータベースの違い

##1. 分析のしやすさ
　一番違うとされているのが、分析のしやすさであり、データウェアハウスは分析に最適化されている。一般的にはシステムが異なればデータの保存状態も違うので、あるシステムから別のシステムにデータを転送するときには大きな負荷がかかる。しかし、データウェアハウスではデータを保存するときに時系列で整理するのでスムーズに分析できる。

##2. データ容量の大きさ
　データウェアハウスとデータベースでは、蓄積できるデータ量の大きさの違いもある。データベースでは容量を超えてデータが多い場合は、サマリデータの形で蓄積しないといけなくなる。そのため、データベースでは分析が難しくなることがある。データウェアハウスではストレージ容量が多いことが特徴としてある。また、データウェアハウスではデータ分析目的に応じて整理することができる。


#参考文献
[データウェアハウス](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%8F%E3%82%A6%E3%82%B9)
[そもそもデータベースとは？基礎から分かるデータベース入門](https://proengineer.internous.co.jp/content/columnfeature/6411)
[DWH（データウェアハウス）とデータベースの違いとは？](https://it-trend.jp/dwh/article/explain)
[データウェアハウスとデータベースとの違いは？導入のポイントを解説](https://www.dsk-cloud.com/blog/difference-data-ware-house-and-deta-base)
[データウェアハウスと単なるデータベースの違い](https://www.teradata-jp.com/post/2018/07/05/%E3%83%87%E3%83%BC%E3%82%BF%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%8F%E3%82%A6%E3%82%B9%E3%81%A8%E5%8D%98%E3%81%AA%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E9%81%95%E3%81%84)
RxJS_Observableについて

RxJSのObservableについて解説します。間違った解釈がありましたらご指摘ください。

まずは簡単に用語の説明からしていきます。

###リアクティブプログラミングとは

データを受け取るたびに関連したプログラムが反応して、処理を行うようにするプログラミングの考え方です。
SPAには不可欠な要素ですね。

###データストリームとは

リアクティブプログラミングでは、随時発生するデータを処理することができる。
この随時データが生成されて、その都度流れてくるデータの流れをデータストリームという。


#RxJSについて

ObservableはDOM操作に使われます。

##Observable
データを生成し、observerメソッドを呼び出して、データをobserverに通知する

##observer
Observableからのデータを受信する

##next 、 error 、complete
Observerは、Observableをsubscribe(購読)し、受け取ったデータを処理する。
next 、 error 、complete の処理をする

####next
Observableがデータを生成する度にObservableによって呼び出される。
Observableによって生成されたデータを引数に取る。

####error
エラーが発生したことを通知する。
これが呼び出されると、 next や complete はそれ以上、呼び出されない。

####complete
完了したことを通知する。
エラーがなかった場合、最後のnextメソッドが呼び出された後に、Observableによって呼び出される。

##subscribe
Observableから流れてくるデータをObserverがsubscribeで受け取り、受け取ったデータに関して、必要な処理を行う。

##コード例

最初に`Observable`はnew演算子で作成します。Observableの特徴の一つとして、値を複数まとめて扱えることにあります。

色々な記事でonserverという単語がありよく分からなかったのですが``Observable``の参照を見てみるとsubscribeメソッドの引数にobserverと記述されていたので、observerはメソッドかなんかだと思ってましたがsubscribeメソッドの変数名のことを指していると思います。
この当たりは間違っているかもしれません。。。

```typescript
subscribe(observer?: PartialObserver<T>): Subscription;
```

``Observable``の引数にはsubscribe関数を記述します。
下記コードからnext comlete errorはObservableのメソッドであるということがわかります。

subscribeメソッドは通知の受信を止めるためにunsubscribe()メソッドがあるSubscriptionオブジェクトを返します。

コードの結果は以下のようになります。

```
開始
0
1
2
3
4
5
終了
```

上記の順番を見てわかるようにObservableはsubscribeメソッドが走ったタイミングでデータ
が流れていることがわかります。したがって、作成したObservableの値はsubscribe()メソッドで受け取ることができます。

```typescript
import { Observable } from "rxjs";

//new演算子でObservableのオブジェクト生成
// observerはただの引数名
let observable = new Observable(function subscribe(observer) {
    try {
        // Ovservableのメソッドを実行
        observer.next(0);
        observer.next(1);
        observer.next(2);
        observer.next(3);
        observer.next(4);
        observer.next(5);
        // 正常に完了したことを通知
        observer.complete();
    }
    catch (err) {
        // エラー通知
        observer1.error(err);
    }
});
// 最初に呼び出されます
console.log('開始');

// Subscribe関数は、Observerを受け取って、Observerの中にある関数(next,error,complete)を実行します。
// subscribe()のカッコないにはobserver.next()が行う処理を記述
observable.subscribe(val => console.log(val));
console.log('終了');

参考
https://qiita.com/Sekky0905/items/93bd4804a2003ed0aa8d
https://qiita.com/agajo/items/7942743a0130f7a0f30b
https://fumiononaka.com/Business/html5/FN1802005.html
￥エンマークをつけて３桁区切りで表す


①変数で価格の数値を取得

|変数|表示|
|--|--|
|=@item.price|9768|

|メソッド|表示|
|--|--|
|number_to_currency(数値 [, オプション])||
|= number_to_currency(@item.price）|9,768.00|
*コンマがつくが、小数点まで表示される

②小数点以下を消す

|メソッド|表示|
|--|--|
|number_to_currency(数値 [, strip_insignificant_zeros: true])||
|= number_to_currency(@item.price, strip_insignificant_zeros: true)|9,768|

③通貨マークを表示させる

|メソッド|表示|
|--|--|
|number_to_currency(数値 [, strip_insignificant_zeros: true])||
|= number_to_currency(@item.price, unit: "￥", strip_insignificant_zeros: true)|¥9,768|

参考:@Sotq_17さん　感謝です。


>https://qiita.com/Sotq_17/items/1e45ff848d8ebab221e5
repository does not contain an application file to import

#ServiceNowでフォークされたリポジトリからアプリケーションをインポートしようとすると・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287651/59b06a36-0bb1-888f-ae24-3baee8c79381.png)

#Branchの記述が誤っている可能性。Githubでブランチをよく確認してほしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287651/466366b2-a5ee-74ef-bd8c-cbcac65b8cc0.png)

#解決
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287651/f2cf916d-4c67-0252-5133-a3122f89d8f4.png)

#最後に
New to ServiceNowというServiceNowのラーニングを進めている中、このエラーを解消するのに一日かかってしまった。。。おかげで勉強にならず涙。

今後もServiceNow学習の為、記事にできることは記事にしたいと思います。
【Python】すべてのシートのアクティブセルと表示倍率を整える。

pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、アクティブセルの設定と表示倍率に関してです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

納品書だったり、見積だったり、発注書だったり
一つの企業様に様々な書類を纏めて送る場合もあると思います
作成中は倍率を変更していたりするので
発送する前に体裁を整える場合も多いと思います。

今回はサンプルと言う名前のブックにある全てのシートを
決められたセル（今回はアクティブセルをA1）、
元の倍率(今回は１００％)に整えるコードを記述してみます。

# 最終的なコード

```python
from openpyxl import load_workbook

wb = load_workbook('サンプル.xlsx')

cell_no = 'A1'
zoom_scale = 100

# 全シートを取得して１シートずつ設定
for ws in wb.worksheets:
    sv = ws.sheet_view
    # アクティブセルを'A1'に設定
    sv.selection[0].activeCell = cell_no
    sv.selection[0].sqref = cell_no
    sv.selection[0].activeCellId = None
    # 表示倍率を100％に設定
    sv.zoomScale = zoom_scale
    sv.zoomScaleNormal = zoom_scale

wb.save('サンプル_修正.xlsx')
```

アクティブセルに関しては
activeCell属性を設定すると同時に、sqref属性と、activeCellIdを
表示倍率に関しても
zoomScale属性を設定すると同時に、zoomScaleNormal属性を
それぞれ設定しておいた方が良いようです。
ブック内の情報整合性を保つために必要な様なのですが、
「なぜか」にたどり着けず、もやもやしている状態です。

今は、セットで変更するものと覚えておいて、理由が理解出来たら追記したいと思います。
Gatsby.jsを一週間勉強して分かったこと

皆さんReactのフレームワークGatsby.jsをご存じでしょうか？

恐らくReactのフレームワークと言ったらNext.jsが代表かと思われます。

そこで今回は、Gatsby.jsを一週間勉強してGatsby.js良いところ悪いところ**完全な主観**でまとめてみたいと思います。

もう一回言います。

主観でまとめます。

悪魔で僕個人の意見なので、鵜呑みにはしないようお願いします。

こんな感じなんだと思って頂ければ十分です。

それでは早速良いところをまとめていきます。

#良いところ#

##ルーティングの設定が不要##

まず、１つ目はルーティングについてです。

Reactでルーティングを行う時って結構面倒ですよね。

必要なパッケージをインストールしたり、あとは``push``メソッドとかを``store``で管理したり色々と慣れるまでは面倒。

Gatsby.jsではそれが不要です！

Gatsby.jsはデフォルトで``src\pages``というフォルダがあります。

ここがルーティングそのものになります。

どういうことか。

例えば、``http://localhost:8000/contact/input``というパスは``src/pages/contact/input.js``を参照するということです！

要するにルーティングを行う場合は、``src/pages``配下にあるファイル・フォルダそのものがルーティングになっているわけです！

わざわざ設定しなくても勝手にやってくれる！

僕にとってはこれが一番良い点でした。

##ページ遷移##

ページ遷移を行う場合もGatsbyではデフォルトで用意されています。

わざわざ``react-router``や``react-router-dom``をインストールする必要がありません。

以下に例を挙げておきます。

```jsx
import React from "react"
import { Link } from "gatsby"

const Example = (props) => {
  return (
    <>
      <Link to="/contact/input">お問い合わせフォーム</Link>
    </>
  )
}

export default Example
```

メソッドとしてページ遷移を行う際も``navigate()``というメソッドがもともと用意されています。

これは``push``メソッドと同じ動きをします。

```jsx
import React from "react"
import { navigate } from 'gatsby-link'

const Example = (props) => {
  return (
    <>
      <Button variant="outlined" onClick={() => navigate('/contact/input')}>
        お問い合わせフォーム
      </Button>
    </>
  )
}

export default Example
```

こんな感じでルーティングに関しての機能がデフォルトで用意されているのが最高でした。

#悪い点#

##ヘッダーやフッターコンポーネントはページごとにレンダリング##

ReactやVueでヘッダーやフッターなどのコンポーネントを使用する際、メインとなるファイルに``<Header />``などを記述すことで各ファイルにこれらを書かなくて済むという仕組みですが、Gatsbyではこれができません。

なぜかは知りません。

もしかしたら出来るかもしれないです。

なので、マイページ使うヘッダーやフッターは``layout.js``にまとめてそれを毎回呼び出すというのが定石らしいです。

Layoutの使い方は公式のドキュメントに詳しく書いてあるのでリンクを貼っておきますね。

[https://www.gatsbyjs.com/docs/how-to/routing/layout-components/](https://www.gatsbyjs.com/docs/how-to/routing/layout-components/)

SPAならこの問題を解決してほしいと願っております。

#まとめ#

結論、良い点は

1. ルーティングの設定が不要
2. ページ遷移の機能がデフォルトで備わっている

で、悪い点は

1. 毎回使うコンポーネントは毎回レンダリングを行わなければいけない

です！

まだ１週間しか勉強していないので、もっと良い点、悪い点があると思います。

学習を進めていくにあたってまた記事として書いていこうかなと思います。

引き続き勉強頑張ります。

Thank you for reading
コードを消す会

weblio辞書開発チームでは定期的に「コードを消す会」を実施しています。
時間をかけず開発コストを下げるのにとてもいい取り組みだと考えています。

### コードを消す会ルール
#### 事前準備
- 日頃の開発中に消せるコードを探す。消せるような気がするというレベルでOK。本当に消して問題ないかは会当日に調査する。
- 消せそうなコードを見つけたら、リポジトリに「コードを消す会」ラベルを付けてissueを作成する。

#### 当日
- 会の時間は4時間～1日。
- 新しくコードを追加することはしないが軽微な修正（変数名の変更、変数からリテラルへの変更、JavaDocコメントや一部アノテーションの追加等）はOK。
- 時間内に行うのは実際にコードを消してプルリクを作成すること。レビューは含めない。
- 実は使われているコードだった等、調査の結果消す事が出来ないと分かった場合その旨をissueに記載しcloseする。

### 良い点
- 不要コードが減ることで、開発時にコードの見通しが良くなる。
- コードを消すだけなので、リファクタリングと異なり取り組みやすい。
- コードへの理解が深まる。

### 悪い点？
- 不要コードがあまりないプロダクトでは実施する意味がない。
(そもそも不要コードがない状態が理想ですが、歴史が古い&大規模なプロダクトでは難しい・・・)

### 実績
- 単語ごとに処理を分けるために読み込んでいたが、実は処理を分ける必要がなかったため読み込みが不要になったcsvファイル(70万行以上)の削除
- スマホサイトに関するCSSのPCサイトでの読み込み処理の削除
- 呼び出されていないAPIの削除(結果、サーバが1つ不要になりそう)等

まだまだ削除できそうなコードに関するissueが作成されているため、
(スマホサイトでのみ読み込めばいいファイルや、リニューアル前のページに関する処理など)
これからもコードを消す会を実施していきたいと考えています。

### おわりに
コードを消す会の翌日に会の振り返りも実施しています。
辞書開発チームでは振り返りにも力をいれているので、そちらについてもまた記事をかけたら良いなと思います。

GRASグループ株式会社では開発メンバーを募集中です。
3月に社名がウェブリオ株式会社からGRASグループ株式会社に変わりました。
https://gras-group.co.jp/careers/
Linuxでもlatexindentを使いたい

LaTeXのフォーマッタであるlatexindentですが，Linuxのインストール方法だけ何故か全然情報がありません．ですがインストール方法はどこよりも一番簡単でした．

# 結論
Ubuntuの場合は以下

```sh
$ sudo apt install texlive-extra-utils
```

これで入ります．VSCodeの`Ctrl + Shift + I` のフォーマットも難なく動くようになります．

# 参考文献
ここに他のディストリビューションのインストールコマンドも載ってます．大体同じようなパッケージ名でした．(というかcommand-not-found.comとかいう便利なサイトあったんですね...)

https://command-not-found.com/latexindent
[即席]Railsの複数画像投稿に枚数制限をつけたい！

# はじめに
本日、ポートフォリオ作成中に、「あ、複数画像投稿の枚数の制限をかけたいな〜」と思い調べたのですが、あまり「これだ！」と思える記事に出会えなかったので、私なりに簡単に楽に実装できる方法を考えてみたのでここでアウトプットします。もしかしすると、かなり脆弱性のある実装かもしれませんが、そこは個々のご判断でお願いいたします。

# 結論
結論からいうと、添付したファイル数が基準を超えたときに、アラートを出して投稿（更新）ボタンを非活性化してしまうということです。

以下に具体的なコードを貼っておきます.
実言うと、これはプレビュー機能実装で使ったコードなんですけどね、、、


```preview.js
document.addEventListener('DOMContentLoaded', function(){
  const ImageList = document.getElementById('practice-views');
  const submit=document.getElementById("submit"); //更新ボタンの取得
//ファイル選択をしたときに以下を発火
  document.getElementById('practice_image').addEventListener('change', (e)=>{　
    while(ImageList.lastChild){
      ImageList.removeChild(ImageList.lastChild);//ここは気にしなくてOKです
    }
   });
  document.getElementById('practice_image').addEventListener('change', (e)=>{
    const files = e.target.files;
　　//以下で枚数制限をかけています。
    if(files.length>4){
      alert("投稿できる画像数は4枚までです");
      submit.setAttribute("disabled",true);　//非活性にする！！！！
      return false;
    }else{
      submit.setAttribute("disabled",false);//活性にする！！！！
    }
    Array.from(files).forEach(file => {
      const blob = window.URL.createObjectURL(file);
      const imageElement = document.createElement('div');
      imageElement.setAttribute('class','preview_image' );  

       // 表示する画像を生成
       const blobImage = document.createElement('img');
       blobImage.setAttribute('src', blob);
       imageElement.appendChild(blobImage);
       ImageList.appendChild(imageElement);
    });
  });
});

```

とりあえず、ここに着目してくださればわかるかと思います。

```preview.js
document.getElementById('practice_image').addEventListener('change', (e)=>{
    const files = e.target.files;
　　//以下で枚数制限をかけています。
    if(files.length>4){
      alert("投稿できる画像数は4枚までです");
      submit.setAttribute("disabled",true);　//非活性にする！！！！
      return false;
    }else{
      submit.setAttribute("disabled",false);//活性にする！！！！
    }
```

イベントオブジェクトの中から、添付したファイルの情報をとってきてfilesに格納しています。そして、そのfiles.lengthで格納されているデータの数を見ているわけです。たったこれだけです！！！
ちなみにeturn false;にしているのは、画像枚数が制限つを超えた場合は後の処理をさせたくないからです。

# おわりに
以上で、画像枚数の制限をかけることができました。
手軽に簡単に実装したい方は、この方法を是非検討してみてくださいね！
【初心者】PHP abstract 抽象クラス

## はじめに
オブジェクト指向プログラミングを学習している中で、abstract宣言について学んだため備忘録。


## 抽象クラス(abstract)
* 抽象クラスはクラスではあるが、直接インスタンスを生成することができない。
* クラスの継承をして使われる。=>開発のルールを作ることができる
* 抽象クラスの中でabstract宣言されたメソッドは、継承された子クラス内で必ずそのメソッドを使わなければならない。
* クラスで使うときは普通の継承のように`extends`を使う。
* アクセス修飾子は、`public`と`protected`のみ使用可能。


コードを書いてみる。

```categoryAbstract.php
abstract class CategoryAbstract 
{
    public function echoAnimal() {
        echo '動物です';
    }
    abstract function echoPlant();
}

// CategoryAbstractを継承
class Category extends CategoryAbstract
{ 
    public function echoAnimal() {
        echo '動物です';
    }
    public function echoPlant() {
        echo '植物です';
    }
}

$category = new Category();
$category->echoAnimal();    //動物です
$category->echoPlant();     //植物です
$categoryAbstract = new CategoryAbstract();
$categoryAbstract->echoAnimal();    //抽象クラスはインスタンス化できないためエラー
```

## 書き方の基本ルール
### ①抽象クラスのabstractと宣言されているちゅうsyメソッド内に処理を書くことはできない。
下記のように親クラスである`abstract宣言`された抽象メソッド内に処理を書くとエラーとなる。

```.php
abstract class CategoryAbstract {

    public function echoAnimal() {   
        echo '動物です';               //一般的な関数の宣言のため問題なし
    }

    abstract function echoPlant() {
        echo '植物です';               //抽象メソッドに処理を書いているためエラー
}

```
### ②抽象クラスを継承した子クラスでは、親クラスでabstract宣言されたメソッドは必ず使われなければならない。
下記のように子クラスのメソッドをコメントアウトするとエラーとなる。

```.php
class Category extends CategoryAbstract{

    public function echoAnimal() {
        echo '動物です';
    }
  //public function echoPlant() {
  //    echo '植物です';          //親クラスでabstract宣言されているため、子クラスで書かれていないとエラー
  //}
}

```