OmniAICreator/Qiita-1.07M huggingface dataset:
Javascript基礎知識＃3(if文)

##はじめに
この記事は私の脱コピペを目指すために書いている自分用のメモです。

※内容について、誤った知識やもっとわかりやすい表現等ございましたら、ご指摘いただけますと幸いです。

##目次
1. HTMLを書き換える
2. if文（条件分岐）とは
3. else とは
4. else if とは
5. if文を入れ子(ネスト)で使う

#1. HTMLを書き換える


index.html に書いたものをJSを使って書き換えてみる


```javascript:main.js
'use strict';
document.getElementById('id名').textContent = 書き換えたい文字列();
```

.getElementByIdでIdを取得して.textContentで書き換える。
例）以下

```html:index.html
<html>
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <div id="example">書き換え前</div> 

    <script>
      'use strict';
       document.getElementById('example').textContent = '書き換え後'();
    </script>
  </body>
</html>
```

```javascript:index.htmlの結果
書き換え後
```

#2. if文(条件分岐)とは
もし○○だったら実行、もし○○かつ○○だったら実行といった
ある条件が成り立つかどうかで動作を変えるのがif文

**「もし、〜であるなら〜しなさい」**



```javascript:mian.js
if(条件式1) {
  条件式1が true の時に実行する処理;
}
```

```javascript:mian.js
let x = 1;
if(x === 1) {
  console.log('YES');
}
```

```javascript:結果
YES
```
といった感じ。


#3. elseとは
if文にプラス「ではなかったら」の条件を付ける文

「もし、〜であるなら〜しなさい。**それ以外であれば〜しなさい**」

```javascript:mian.js
if(条件式1) {
  条件式1が true の時に実行する処理;
} else {
  すべての条件式が false の時に実行する処理;
}
```

```javascript:mian.js
let x = 1;
if(x === 4) {
  console.log('YES');
} else {
  console.log('NO');
}
```

```javascript:結果
NO
```

といった感じ。

#4. else ifとは

if文を使う時に、複数の条件で分岐させることができる文

「**もし、〜であるなら○○。～であるなら○○。**それ以外であれば〜しなさい」

```javascript:mian.js
if(条件式1) {
  条件式1が true の時に実行する処理;
} else if(条件式2) {
  条件式1 が false で条件式2が true の時に実行する処理;
} else {
  すべての条件式が false の時に実行する処理;
}

```

```javascript:mian.js
function exam(result) {
  if(result > 90) {
    console.log('合格');
  } else if(result > 80){
    console.log('修正');
  } else {
    console.log('不合格です');
  }
}
```

```javascript:結果
exam(92);
>> 合格

```

といった感じ。


#5. if文を入れ子(ネスト)で使う


if文のブロック(｛｝)の中に別のif文を記述することもできます。


```javascript:mian.js
if (条件式1) {
  条件式１が true の時に実行する処理;
  if(条件式2) {
    条件式2が true の時に実行する処理;
  } else {
    条件式2が false の時に実行する処理;
  }
} else {
  条件式1が false の時に実行する処理;
}
```

```javascript:mian.js
function exam(result) {
  if(result > 80) {
    if(result > 90) {
      console.log('合格');
    } else {
      console.log('修正');
    }
  } else {
    console.log('不合格');
  }
}
```

```javascript:結果
exam(78);
>> 不合格

```

といった感じ。
【JavaScriptメモ】map() メソッド、forEach()メソッドで配列のインデックスを取得したい場合は第二引数を指定する

# JavaScript の map() メソッド、forEach()メソッドにおいて対象配列のインデックスを取得したい場合は第二引数を指定する
こんにちは、ndj です。
`JavaScript` の `map()`メソッド、`forEach()`メソッドを使用する際に対象配列のインデックスを取得する方法を忘れていたので、メモです。

## 第二引数を指定すればOK
`map()` に渡す `callback`関数の第二引数を指定すればインデックスを取得することができます。
`forEach()` の場合も同様です。

```sample.js
arr = ['a', 'b', 'c'];

arrMap = arr.map((val, i) => `val: ${val}, index: ${i}`);
console.log(arrMap);
// result: [ 'val: a, index: 0', 'val: b, index: 1', 'val: c, index: 2' ]

arr.forEach((val, i) => console.log(`val: ${val}, index: ${i}`));
// result: val: a, index: 0
//         val: b, index: 1
//         val: c, index: 2
```
## 最後に
忘れないようにメモしておきます。
誤字脱字、アドバイスや記事の誤りなどありましたらコメントいただけますと幸いです。

## 参考
[MDN web docs: Array.prototype.map()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
[MDN web docs: Array.prototype.forEach()]()
Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)の解決まで。


#原因:
helokuのMysqlとデプロイ使用しているデータベースが紐付けられていなかったため。

#確認したこと
```
heroku info
```
実行後、データベースの環境変数を確認

```
CLEARDB_DATABASE_URL:     mysql://xxxxxxxxxxxx
CLEARDB_DATABASE_GREEN:   mysql://xxxxxxxxxxxx
LANG:                     en_US.UTF-8
RACK_ENV:                 production
RAILS_ENV:                production
RAILS_LOG_TO_STDOUT:      enabled
RAILS_SERVE_STATIC_FILES: enabled
SECRET_KEY_BASE:
```

あるはずのDATABASE_URL：がないし、mysql2でデータベース作ったはずなのに反映されてない・・・。

#結論：

これは、ターミナルで

```
heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}
```
の入力がなく、mysql2のデータベースに環境変数を格納できていなかったため。

#最後に：

環境変数を変更するため、herokuのHPのアプリのページへ遷移し、settingsをクリック。

画面中央のReveal Config Varsをクリック。Config Varsを編集して終了。


無事、

```
heroku run rake db:migrate
```
出来ました！
vim で C/C++ 系ファイルでインデントさせないようにする

## 背景

`set nocindent` でインデント無効にできるはずであるが,
vim 8.1 から?(e.g. Ubuntu 20.04, Git bash for Windows), 
`set nocindent` を `~/.vimrc` に記述しても C/C++ ファイルでインデントしたまになってしまう.
(`cindent` がなぜか有効になる)


## 解決方法

Ubuntu 20.04 + vim 8.1(標準で入っているもの) とします.

"set nocindent" doesn't work in ~/.vimrc [solved]
https://forums.gentoo.org/viewtopic-p-3551447.html?sid=048d6eb2117269b64d39104c49f0da25

とりあえず

```
autocmd BufEnter * set noautoindent nocindent  
```

を `~/.vimrc` に書けば解決します.

ただ, これだとすべてのファイルで有効になるので,

```
autocmd BufEnter *.cc set noautoindent nocindent
```

などとするとよいでしょう.

### その他: CMake の場合

`CMakeLists.txt` などの cmake ファイルも, 自動でインデントされてしまいます.

この場合は `indentexpr` が設定されていたからでした.


```
autocmd BufEnter *.cmake set noautoindent nocindent indentexpr=
```

などとして `indentexpr` を off(空文字を設定) にすれば解決します.



## 詳細

Vim の自動インデント機能について
https://machakann.hatenablog.com/entry/2015/08/15/132247

を参考に調べればどこで `cindent` が有効になっているかわかる...  かも?
Binance pool でイーサリアムをマイニングする

Binance で ETH マイニングプールのサービスが始まりました.

https://cointelegraph.com/news/binance-launches-ethereum-mining-pool-with-0-5-fees

手数料が少ないのが魅力です.

また, Pool saving で, マイニングしたコインを貸出することで, さらに金利を稼ぐことができます.
(たぶん. 2020/11/16 時点では ETH においては Pool saving はまだ未対応)

https://www.binance.com/en/support/announcement/3d97d8c444e64909a6d6991fa27de1c8

## 設定

ETH を設定してみましょう.

tutorial を見ればだいたいわかります.

注意すべきところとして, Mining account は, Binance 利用者の間でユニークである必要があります
(よく使う名前(e.g. `example`)だと(ほかのユーザーに)すでに取得されているエラーが出てしまう)

ここで設定したアカウント名が wallet 名となるので, ユニークである必要があるためです(binance のユーザ名が wallet 名ではない)

あとは普通に miner を設定すればマイニングできます!

## 問題点など

SSL 接続は対応していないようです(443 port があるが... 少なくも NBminer + `stratum+ssl` はダメだった).

マイニングされたコインは Binance の wallet に記録されます.
現在(2020/11) Binance は日本では登録されたサービスではないため, 日本居住者のアカウントですと今後 Binance(未登録業者)へのアクセスが規制されたりなどあると, マイニングしたコインをロストする可能性があります.

Pool だけを提供するモードもほしいですね(払い出し先の ETH アドレスを指定できる)

## TODO

Dual Saving と連携できるか調べる(Dual Saving 自体も, ETH についてはまだ未対応っぽい)

https://academy.binance.com/en/articles/a-quick-guide-to-binance-dual-savings


Dual Saving は, 簡単に言えばターゲット価格を上回るかどうかで貸出金利を BTC or BUSD(Binance USD stable coin)で受け取るサービス. 通常の預金運用に比べると, うまく行った場合得られる金利は高いっぽい. いずれにせよ金利は得られるので, 運用資産がマイナスになることは無いっぽい. マイニングしたコインを HODL するのがメインの人向け.

得られる金利の源泉は, 相手にはターゲット価格に到達するかどうかのオプション取引を提供してそれの手数料から, ですかね.
Railsにて検索機能を追加する。

#概要
アプリケーション内でデータを検索できる機能があると、ユーザーがデータを探す際便利である。検索機能はSNS等でもよくある機能なので、実際に検索機能を実装してみる。
userというテーブルがあるとした場合、userを検索する機能を実装する。

#1.ルーティングの設定
userを扱うUserModel、UsersControllerは作成されていることを前提とします。

```ruby:/config/routes.rb
# 省略
  resources :users do
    get "search", on: :collection
  end
```

searchアクションはリソースの集合を表すためon: :collectionを追加します。

#2.モデルにクラスメソッドsearchを追加

```ruby:/app/model/user.rb
class User < ApplicationRecord
  class << self
    def search(query)
      rel = order("id")
      if query.present?
        rel = rel.where("カラム名 LIKE ?, "%#{query}%")
      end
      rel
    end
  end
end
```

class << self〜endでクラスメソッドを定義できます。
ローカル変数relを定義し、検索ワードが空でなければSQLのLIKEを使用し、該当カラムから対象のレコードを絞り込みます。

#3.コントローラにsearchアクションを追加

```ruby:app/controllers/users_controller.rb
# 省略
def search
  @users = User.search(params[:q])
  render "index"
end
```

Userモデルで定義したクラスメソッドsearchをここで使用します。

#4.viewにフォームを記載

```:app/views/users/index.html.erb
# 省略
<%= form_tag :search_users, method: :get, class: "search" do %>
  <%= text_field_tag "q", params[:q] %>
  <%= submit_tag "検索" %>
<% end %>
```

form_tagは引数にパスを指定したフォームを作成します。デフォルトのmethodがPOSTであるため、getメソッドを指定しています。
text_field_tagでフォームを作り、検索ワード"q"は検索後もフォーム内に残しておくために第２引数にparams[:q]を指定しています。

#まとめ
以上で、検索機能を実装できます。
SQLを扱う箇所もありましたので、これを機会に勉強していきたいです。
【Tips】断続的にAzure SQL Databaseに接続できない場合の暫定対処方法について

#はじめに
Azure SQL Databaseへの接続が断続的に失敗するような現象は、**データセンター側の問題**(データベースが配置されたクラスタノードで問題が発生している など)、**サービスレベルに応じたデータベースのリソース制限**など、様々な要因によって発生する可能性があるかと思います。
サービスレベルに応じたデータベースのリソース制限が要因の場合、データベースのサービスレベル／価格レベルをあげる、データベースへの処理量を減らすなどの対処を実施することにより問題を解決できる可能性があります。
また、データセンター側の問題が疑われる場合は、**データベースの再構成(Reconfiguration：リコンフィグレーション)**を実施することにより、現象が解消できる可能性があります。
今回は、**手動でデータベースの再構成を実施する方法**について、紹介したいと思います。

#目次
[1. Azure SQL Database 手動によるデータベースの再構成 (Reconfiguration)](#1-azure-sql-database-手動によるデータベースの再構成-reconfiguration)
[2. SQL データベース - 設定：構成 から 価格レベル、サービスレベル (仮想コア数)を変更](#2-sql-データベース---設定構成-から-価格レベルサービスレベル-仮想コア数を変更)
[3. まとめ](#3-まとめ)
[4. 参考情報](#4-参考情報)

#1. Azure SQL Database 手動によるデータベースの再構成 (Reconfiguration) 
■ **Invoke-AzSqlDatabaseFailover (PowerShell) コマンドを実行**
「Invoke-AzSqlDatabaseFailover」 (PowerShell) コマンドを実行することにより、手動でデータベースの再構成(Reconfiguration) を実行することが可能です。 
![command1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752487/0641857e-c16b-ce86-c661-9332c1605439.png)
**【コマンド例】**
![command2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752487/9ba1e192-ed2b-21e1-07be-452b03f5a5f3.png)
※ Azure ポータル - Cloud Shell (PowerShell) から「**Invoke-AzSqlDatabaseFailover**」コマンドを実行することが可能です。
![command3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752487/30114835-f181-5c7c-dd09-ae7f235afb31.png)
**【補足】**
「**Invoke-AzSqlDatabaseFailover**」コマンドは、1回実行すると30分間は再実行できなくなります。

#2. SQL データベース - 設定：構成 から 価格レベル、サービスレベル (仮想コア数)を変更
SQL データベース - 設定：構成 から 価格レベル、サービスレベル (仮想コア数)を変更することで、 **Invoke-AzSqlDatabaseFailover (PowerShell)** コマンドを実行した場合と同様に、**データベースの再構成(Reconfiguration)** を行うことが可能です。
![command4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752487/b44ed12c-d099-9866-aacb-b31db0bbfb76.png)
※ 必要に応じて、価格レベル、サービスレベル (仮想コア数) を元の設定に戻す場合にも、データベースの再構成(Reconfiguration)が行われることになります。

#3. まとめ
今回は、Basic、Standard および General Purpose サービス レベルを想定した内容となりますが、Premium、Business Critical サービス レベルの場合でも同様に**「Invoke-AzSqlDatabaseFailover」**コマンドを実行することが可能です。なお、Premium、Business Critical サービス レベルでは、SQL Server Always On 可用性グループと同様のテクノロジーを使用しているため、本コマンドの**「-ReadableSecondary」**オプションを指定することで、フェールオーバーテストを手動で実行することが可能になるようなので、ゾーン冗長を構成した場合におけるアプリケーションの性能試験、再試行ロジックのテストを柔軟に実行することができるかと思います。

#4. 参考情報
・[Azure SQL Database と SQL Managed Instance の高可用性](https://docs.microsoft.com/ja-jp/azure/azure-sql/database/high-availability-sla#premium-and-business-critical-service-tier-availability)
・[Invoke-AzSqlDatabaseFailover](https://docs.microsoft.com/ja-jp/powershell/module/az.sql/invoke-azsqldatabasefailover?view=azps-5.0.0&viewFallbackFrom=azps-4.5.0)
・[アプリケーションの障害回復性のテスト](https://docs.microsoft.com/ja-jp/azure/azure-sql/database/high-availability-sla#testing-application-fault-resiliency)
(備忘録) discord.jsでシャーディング

[discord.js](https://discord.js.org/)のシャーディングの仕組みがイマイチ分かりにくかったので、自身の備忘録も兼ねてまとめたいと思う。
ちなみに、公式のガイドのほうの解説は[**こちら**](https://discordjs.guide/sharding/)にある。

# シャーディングの方法
discord.jsでは[**ShardingManager**](https://discord.js.org/#/docs/main/stable/class/ShardingManager)を用いてシャードを一元管理できる。

シャーディング用のソースコード上でShardingManagerのインスタンスを作成。
その際、BOT本体が記述されているソースコードファイルを指定することで、それを元に各シャードを初期化できる。
注意しなければならないのは、そのBOT本体が記述されているソースコード単体で実行しても動作するように設計しておかなければならないということだ。

公式ガイドではShardingManagerのインスタンスを作成する際にBOTのトークンを渡しているが、あらかじめ環境変数に`DISCORD_TOKEN`としてトークンを登録しておけば、自動的にトークンが渡されるようになっている。

# シャーディングの仕組み
discord.jsのShardingManagerでは各シャードを子プロセス（デフォルト）かワーカースレッドとして実行されるようになっている。
この際、BOT本体が記述されたソースコード側で特にシャードIDやシャード数に関する値を指定する必要が無いため、不思議に感じると思う。
これはShardingManagerのインスタンスが作成された際にNode.js側の環境変数（要するに`process.env`）に以下のような値が与えられているからだ。

```js
SHARDING_MANAGER  // シャーディングマネージャを使用していることを示す
SHARDS            // シャードID（何番目のシャードか）
SHARD_COUNT       // シャードの総数
DISCORD_TOKEN     // BOTのトークン（ShardingManagerで改めて指定すると上書きされる）
```

[**Client**](https://discord.js.org/#/docs/main/stable/class/Client)のインスタンスを作成する際、これらの環境変数が参照されるためBOT本体を記述しているソースコード側ではClientのオプションとしてシャーディング周りの値を指定する必要が無くなっている。
ただし、それ以外のオプション値（`partials`や`ws`など）は指定する必要があるので、注意が必要だ。

また、ShardingManagerのインスタンスを作成する際に、`totalShards`オプションを与えずとも、`spawn()`メソッドを実行した時点で`totalShards`プロパティの値が上書きされるため、例えば`shardCreate`イベント内で`totalShards`プロパティの値を参照したとしても、問題なく値を得られる。

# 参考リンク
[/discord.js/src/sharding/ShardingManager.js#L138](https://github.com/discordjs/discord.js/blob/766b91d306e93ef2e58bc52c9be5633b1092277a/src/sharding/ShardingManager.js#L138)
[/discord.js/src/sharding/Shard.js#L55](https://github.com/discordjs/discord.js/blob/766b91d306e93ef2e58bc52c9be5633b1092277a/src/sharding/Shard.js#L55)
[/discord.js/src/client/Client.js#L47](https://github.com/discordjs/discord.js/blob/766b91d306e93ef2e58bc52c9be5633b1092277a/src/client/Client.js#L47)

# あとがき
走り書きに近い備忘録ゆえに内容は推敲されていませんが、未来の自分を含め、参考になれば幸いです。
Dockerコンテナ内でgnome-terminalの実行を試みるもエラー（Failed to execute child process “dbus-launch” (No such file or directory)）

Dockerコンテナ内でgnome-terminalの実行を試みるも以下の通りエラー

```
# gnome-terminal -e "python3 test.py"
# Option “-e” is deprecated and might be removed in a later version of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to execute after it.
# Error constructing proxy for org.gnome.Terminal:/org/gnome/Terminal/Factory0: Failed to execute child process “dbus-launch” (No such file or directory)
```

dbus-x11をインストールして解決

```
sudo apt-get install -y dbus-x11
```

gnome-terminalがない場合は以下でインストール可能

```
sudo apt-get install -y gnome-terminal
```

# 参考
[simple interprocess messaging system (X11 deps)](https://launchpad.net/ubuntu/bionic/+package/dbus-x11)
Vue.jsでカスタムなページタイトルを設定する

#はじめに
ちょっとの間悩んでた表題の問題が他人のコード見てたらふと解決したので軽くまとめていきます。Vue.jsでページタイトルをデフォルトのアプリ名から変更する方法です。

#手順
まず、Vue.jsでページタイトルを規定してるコードはpublic/index.html内にあります。

```html:public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title> <!--ここですここ、ここ-->
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
```
しかし、ここは変数で指定してありますしあまりこのファイルを弄るのはよくないようです。なのでどこでこの変数を指定するのか書いていきます。
まず、rootフォルダにvue.config.jsというJavaScriptファイルを作ります。
そしてそこに次のように入力してください。

```javascript:vue.config.js
module.exports = {
    pages: {
        index: {
            entry: 'src/main.js', // ここは変えないで
            title: 'ページタイトル', // 好きな文字列をいれてください
        }
    }
}
```
そうしてビルドし直すと無事ページタイトルが変更されてると思います。

#最後に
サイト自体のタイトルの後にページのタイトルをいれる方法はそのうち実装しようと思うので成功したら追記します。
DigisparkでAnalogRead～GP2Y0A21YKを使う2～P5を使う

DigisparkでAnalogRead～GP2Y0A21YKを使う～の続きです。
https://qiita.com/usashirou/items/70ff2f869901fc159df6
##互換DigiparkのP5はリセットになっている
互換DigiparkのP5ピンはリセットに割り当てられているため、入力で使用するとリセットされてしまうのでP5ピンを使えるようにしましょう。
###Amazon で売ってる Digispark クローンの 5 ピンめを使えるようにしたメモ
https://qiita.com/illness072/items/3f5787c2ac4263283cbb
を参考に設定します。
まずは、ArduinoISPが使えるボードを用意します。
##必要なもの
・ArduinoUnoなどのIPSが使えるボード
・ジャンパワイヤー6本
#AVRdudeをインストールする
次に、PCのセッティングをします。
私は、Windows環境で行いました。
AVRdudeはWinAVRに入っているようです。
https://ja.osdn.net/projects/sfnet_winavr/releases/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/2922937b-df0f-6aad-4b7d-ef9ae91f0cfe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/a623f897-6d86-568a-e101-b568829adece.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/e10d128a-1f77-e5b9-5767-26b2c91dd29c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/fdf1e218-c938-4a75-66ad-08a22c403394.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/1401ed04-69cc-4544-2a0d-506ab175444e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d4eab2d9-4219-3e51-bbb5-85f1795f8350.png)
![20-7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/a8d5efe7-05da-ef2a-f9f5-65a40dd5d626.jpeg)
##動作確認
コマンドプロンプトでavrdudeと入力し以下の返答があればインストール完了です。
![21-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/bc3dc495-3aab-14da-e565-ff7bd65653e0.jpeg)
##設定
Arduinoと以下の通り接続します。(もちろん電源も）
Arduino⇒Digispark
D10⇒P5
D11⇒P0
D12⇒P1
D13⇒P2
次に、コマンドプロンプトを立ち上げます。
**私はCOM26につながっています。

```
C:\Users\user>avrdude -P COM26 -b 19200 -c avrisp -p attiny85 -n
C:\Users\user>avrdude -P COM26 -b 19200 -p attiny85 -c avrisp  -U hfuse:w:0x5F:m
```
コマンドプロンプトの様子
![22-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ade2a6d1-bfa2-ae7a-5279-e3adfc1de8b9.jpeg)

##2入力用プログラム
P2,P5のアナログ入力のプログラムを以下に示します。

```
#include <DigiUSB.h>

int adc1;
int adc2;
float dis1;
float dis2;

void setup()
{
  pinMode(2, INPUT);
  pinMode(5, INPUT);
  DigiUSB.begin();
}

void loop()
{
  adc1 = analogRead(1); //Read P2
  adc2 = analogRead(0); //Read P5
  dis1 = 6787.0/((float)adc1-3.0)-4.0;
  dis2 = 6787.0/((float)adc2-3.0)-4.0;

  DigiUSB.print("{\"Distance1\":");
  DigiUSB.print(dis1);
  DigiUSB.print("\"Distance2\":");
  DigiUSB.print(dis2);
  DigiUSB.println("}");
  DigiUSB.delay(1000);
}
```
問題なく、動作しました。
![23-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/66b1fa0b-b36f-4059-74d2-c38ecdaf07b9.jpeg)
DigisparkでAnalogRead～GP2Y0A21YKを使う～

前回に引き続きDigisparkを使います。
DigiSparkの良さは、8ピンでUSBが搭載されており、AnalogReadやI2Cが使える点です。
##AnalogReadのメリット
RaspberryPiやJetsonにはDigitalWriteやDigitalReadはありますが
AnalogReadがありません。
AnalogReadは温度センサーや、電力測定、測距モジュール等に使われていますが使用できないのです。
DigiSparkを使う事でこの欠点を補う事ができます。
##複数のマイコンを使う
なお、Raspberry piの記事の多くはADC用ICを使うようです。
これは、別マイコンにプログラムを書くよりも、Raspberry piでコントロールする方が良いとの考えだと思います。
逆に複数のマイコンに個別にプログラムすることで、Raspberry pi等の処理を簡単にすることができます。

##GP2Y0A21YKを使う
今回は、シャープの測距モジュールGP2Y0A21YKを使用します。
###引用プログラム
<B>DigisparkとLM61で温度を測る</B>を引用します。
https://atotto.hatenadiary.jp/entry/digispark_lm61_usb
GP2Y0A21YKの計算式は<B>測距モジュール(GP2Y0A21)を使ってみた</B>を引用しました。
http://taroooyan.hatenablog.com/entry/2015/08/16/000000

```
#include <DigiUSB.h>

void setup()
{
  pinMode(2, INPUT); // P2 = anolog input 1
  pinMode(1, OUTPUT);
  DigiUSB.begin();
}

void loop()
{
  digitalWrite(1, HIGH);

  int step;
  float dis;
  step = analogRead(1);
  dis = 6787.0/((float)step-3.0)-4.0;
  DigiUSB.print("{\"Distance\":");
  DigiUSB.print(dis);
  DigiUSB.println("}");
    
  digitalWrite(1, LOW);
  DigiUSB.delay(1000);
}
```
ファームウェアを書き込むと、デバイスマネージャーからはDigiUSBと認識されます。
![10-2-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3a230db4-8ad9-332e-4875-4a73a47048bc.jpeg)
##配線
GP2Y0A21YKの赤線を5V、黒線をGND、黄線をP2に接続します。
![DSC_0554 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/81d6b625-715d-f050-ecd0-40bb2717fc56.jpeg)
##動作確認
DigiSparkの出力は、PCではmonitorというソフトウェアなどで見ることができます。
https://github.com/digistump/DigisparkExamplePrograms
![10-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/658fda9b-0b1e-2095-a7f0-1e8dd0159921.jpeg)
以上で、DigiSparkを使ってアナログリードをすることが可能になりました。
後は、RaspberryPiやPCでソフトウェアを作ることで、近接センサーの値を使用する事ができます。
##GP2Y0A21YKの性能が悪い
さて、ここで大失敗がおきました。
それは、GP2Y0A21YKの性能が想定以上に低かったのです。
購入が中国だったせいか、10～25㎝のレンジでしか使用できず、実使用で使えるレベルではないために、使うか悩んでしまっていたりします・・・

次は、GP2Y0A21YKを2個使えるようにします。
DigisparkでAnalogRead～GP2Y0A21YKを使う2～P5を使う
https://qiita.com/usashirou/items/e023d536719bcd883448
BookShelfアノテーションで複数取得する方法で迷ったのでアウトプットする。

#はじめに
BookShelfを使ったデータの取り込みで、データベースの依存関係が複数ある場合の
クエリ取得方法で迷ったので、やった内容をアウトプットする。
その為、説明等は適当な部分多い。

作成していたアプリは、ルーム毎にユーザとメッセージを保存する。
メッセージ交換用アプリ


#Bookshelfとは
Node.jsとかで使えるデータベースに対して、データを取得できる便利な道具です。

##アノテーションについて
DBのテーブル同士を関連づけて取得できるものになります。

~~~
 var Room = Bookshelf.Model.extend({
   tableName: 'rooms',
   hasTimestamps: true,
   messages: function() {
     return this.hasMany(Message);
  }
 });
~~~

アノテーションに当たる部分

*  hasMany    : 一対多（Roomテーブルの1行に紐づくMessageテーブルの行は多数あるって意味）
*  belongsTo　:　一対一(MessageとUserテーブルで紐づくデータは1行に対して1行のみ)

~~~
//Roomテーブルを取得する際に紐ずいているMessageテーブルのデータを取得する。

   messages: function() {
     return this.hasMany(Message);
  }
~~~



##DBの構成

* こんなかんじ
<a href="https://gyazo.com/cb4fdbd76214a7720f2ac7673070c2ad"><img src="https://i.gyazo.com/cb4fdbd76214a7720f2ac7673070c2ad.png" alt="Image from Gyazo" width="581"/></a>

##階層アノテーション取得方法


* それぞれのテーブル定義

~~~
var Bookshelf = require('bookshelf')(knex);

var User = Bookshelf.Model.extend({
  tableName: 'users'
});

var Room = Bookshelf.Model.extend({
  tableName: 'rooms',
  hasTimestamps: true,
  messages: function() {
    return this.hasMany(Message);
  }
});

var Message = Bookshelf.Model.extend({
  tableName: 'messages',
  hasTimestamps: true,
  user: function() {
    return this.belongsTo(User);
  }
});
~~~

結局のところ、一対多のデータから、さらに一対一のデータを取り出すには、fetchでwithRelatedで
'message.user'のように、Roomテーブルでアソシエーションとして指定したmessageからさらにMessageでアソシエーションした
userを指定するとデータとして取得できる。



~~~
/**
*     RoomテーブルからroomIdを紐づけてMessageテーブルのデータを取得
*                    Messageテーブルからい1対1関係のデータを取得する。
**/

                  new Room().query({where:{id : roomId}})
                          .fetch({withRelated:['messages','messages.user']})
                          .then((messageRoom) => {
                            
                            res.render('chat',{
                              roomName: messageRoom.attributes.room_name,
                              roomId : messageRoom.attributes.id,
                              userName: login.name,
                              userId: login.id,
                              message: messageRoom.relations.messages.models
                            });
                            
                            
                            var messageTests = messageRoom.relations.messages.models;
                            
                            for(var val of messageTests){
                              
                              console.log(val.attributes.message);
                            }
                            
                          });
~~~

また、一対多の時にデータを取得する場合は、
room.relations.messages.modelsというようにいったんmodelsを指定してから
attributes.[カラム名]といった形でデータを取得する。
一対一の場合には、messages.relations.user.attributes.[カラム名]という形にすればいい。

初めてQiita書いたので、間違っている事もあると思われますが、ご了承ください。
M5Stackで簡易的にビープ音を鳴らす

# はじめに

M5Stackでちょっとした開発をするときに動作確認やアラーム(警告音)として「ビー」とか「ブー」とかいったビープを鳴らしたい場合がある。

しかし、M5Stackの作法を知らないと大音量になったり、ビープ音が止まらないというワナにはまる。
自分も実際そのワナにはまり、ネットを検索すれば多くの人が同じワナにはまり、そしていろいろな説明や実装方法を記載している。

ちゃんとした実装をするには正しく動きを理解する時間や手間をかける必要があるが、時間がない場合やとりあえずビープ音を鳴らしたい場合に使える方法を記載する。

# 環境
Windows PC：Windows 10 Pro 64bit (1909)
Arduino IDE：V1.8.13
M5Stackプラットフォーム：バージョン 1.0.6
M5Stackライブラリ：バージョン 0.3.1

# 1. setup()内で簡易的にビープ音を鳴らす

```cpp:BeepSample_M5Stack_setup.ino
#include <M5Stack.h>

void setup() {

  M5.begin();
  M5.Power.begin();

  M5.Speaker.begin();       // 呼ぶとノイズ(ポップ音)が出る時がある 
  M5.Speaker.setVolume(1);  // 0は無音、1が最小、8が初期値(結構大きい)
  M5.Speaker.beep();        // ビープ開始
  delay(100);               // 100ms待つ(beep()のデフォルト)
  M5.Speaker.mute();        //　ビープ停止

}

void loop(){
          :
    （ループ処理）
          :
}
```

ポイントは`M5.Speaker.beep()`があくまでビープを**開始するだけ**で、ビープを**終了させるには別途処理**(`M5.Speaker.mute()`、等)**が必要**というところ。

# 2. loop()内で簡易的にビープ音を鳴らす

```cpp:BeepSample_M5Stack_loop.ino

#include <M5Stack.h>

void setup() {

  M5.begin();
  M5.Power.begin();

  M5.Speaker.begin();       // ノイズ(ポップ音)が出る時がある
  M5.Speaker.setVolume(1);  // 0は無音、1が最小、8が初期値(結構大きい)
}

void loop(){
          :
     （ループ内処理）
          :
  M5.Speaker.beep();        // ビープ開始
  delay(100);               // 100ms待つ(beep()のデフォルト)
  M5.Speaker.mute();        //　ビープ停止
          :
　   （ループ内処理）
          :
  delay(1000);              // 1秒間待つ（1秒+α毎にビープ音が鳴る）
}
```
`loop()`内の場合は`setup()`内とちょっと違い、`M5.Speaker.mute()`の代わりに`M5.update()`が実行されていればタイミング次第でビープは停止する。(`M5.update()`が内部で`M5.Speaker.update()`を実行し、さらに`M5.Speaker.update()`が内部で`M5.Speaker.mute()`を実行する)

ただし、ビープの鳴らす時間（デフォルト100ms）より前に`M5.Update()`が実行されてしまえば`M5.Update()`は無効になり、`M5.Update()`が実行されるまで処理に時間がかかる場合その間ビープ音は止まらないので注意。


# 最後に（注意事項含む）

細かい内部の動きの説明や正しい実装は他の多くの方がいろいろな説明をしているのでそちらを参照して欲しい。

なお、M5Stackでビープのテストを行う場合は大音量で音が止まらない状況になる可能性があるので以下の点に注意。

+ バッテリーは外しておく（可能であれば）
+ スケッチを書き込んでM5Stackのリセットがかかった瞬間に大音量の音が鳴り続ける場合があるので、すぐにUSBケーブルを抜ける準備をしておく。バッテリーが付いている状態だと、USBケーブルを抜いて電源ボタンを２度押しして電源も落とす必要がある。
+ 上記を反射的に行える心の準備をしておく
pythonで、定義された辞書に指定したキーが存在するかを調べた際のメモ

以下の通りすればよい

```python:test.py
mydict = {
      "item1":"aaa",
      "item2": {
        "item21": "ddd",
      }
}

if "item1" in mydict:
    print("item1 exist!")
else:
    print("item1 not exist!")

if "item2" in mydict:
    print("item2 exist!")

    teststring = "item2"
    testmatrix = mydict[teststring]
    if "item21" in testmatrix:
        print("item21 exist!")
    else:
        print("item21 not exist!")

    if "item22" in testmatrix:
        print("item22 exist!")
    else:
        print("item22 not exist!")

else:
    print("item2 not exist!")

if "item3" in mydict:
    print("item3 exist!")
else:
    print("item3 not exist!")
```

実行

```
$ python3 test.py
item1 exist!
item2 exist!
item21 exist!
item22 not exist!
item3 not exist!
```

# 参考
[辞書に指定したキーの要素が含まれているか確認する](https://www.javadrive.jp/python/dictionary/index7.html)
GCPのPCA (Professional Cloud Architect)に合格しました。


#はじめに
前回、[ACEを取得](https://qiita.com/Takao_/items/e09dde47461757e7ef7d)したのですが、自分的に理解が曖昧な部分が多かったので、理解を深めるためにPCA(Professional Cloud Architect)を受験し、なんとか合格できたので学習の流れをまとめておきます。
#使用した教材
ACEを取得してそのまま継続して学習したので、そこで使用した教材は割愛します。
まずは[試験ガイド](https://cloud.google.com/certification/cloud-architect?hl=ja)の確認は必須です。ACEとは違って、３つのケーススタディ( Mountkirk Games / TerramEarth / Dress4win )をもとにして出題される問題があるので、知らずに受験すると少し焦るかもです。
私が受験した際も１３問がケーススタディからの出題でした。

### ケーススタディ
以下のアーキテクチャ解説動画を確認することで、ある程度事前に内容を把握できます。
英語の動画となりますが、私は英語が苦手なので、全て翻訳して確認しました。
##### ◆Dress4win
・[GCP Professional Cloud Architect "Dress4win" Case Study Cheat Sheet - Part 1 (Solution Concept)
](https://www.youtube.com/watch?v=TtBWCDhEabY)
・[Dress4Win Sample Solution
](https://ja.coursera.org/lecture/preparing-cloud-professional-cloud-architect-exam/dress4win-sample-solution-KXrnv)

##### ◆Mountkirk Games
・[GCP Professional Cloud Architect "Mountkrik Games" Case Study Cheat Sheet - Part 1
](https://www.youtube.com/watch?v=65g7AbjC4EA)
・[Mountkirk Games Sample Solution
](https://www.coursera.org/lecture/preparing-cloud-professional-cloud-architect-exam/mountkirk-games-sample-solution-ZUaYI)

##### ◆TerramEarth
・[GCP Professional Cloud Architect "TerramEarth" Case Study Cheat Sheet - Part 1
](https://www.youtube.com/watch?v=87T13gyjSJ4)
・[TerramEarth Sample Solution
](https://ja.coursera.org/lecture/preparing-cloud-professional-cloud-architect-exam/terramearth-sample-solution-SR1ak)

###Udemy
こちらも英語教材なので、Google翻訳で対応しました。若干翻訳に違和感を感じる部分もありますが、慣れればあまり気になりません。
・[Google Certified Professional Cloud Architect Practice Tests](https://www.udemy.com/course/gcp-pca-practice-tests-latest/)


###WHIZLABS
本試験のレベルに近い内容だった感じがします。ちなみにこちらも英語教材です。日本語教材も探しましたが見つけられませんでした。
・[Google Cloud Certified Professional Cloud Architect
のPractice Tests](https://www.whizlabs.com/google-cloud-certified-professional-cloud-architect/)

###模擬試験
無料で何度も受験できますし、説付きなのでこちらは繰り返し理解できるまでやりました。
・[Professional Cloud Architect 模擬試験](https://cloud.google.com/certification/practice-exam/cloud-architect?hl=ja)

###公式ドキュメント
全てには目を通していませんでしたが、前述の問題を説いた際に理解があやふやな場合の確認用で目を通しました。
・[GoogleCloudドキュメント](https://cloud.google.com/docs?hl=ja)

##おわりに
ACEの受験後で基礎知識が頭に残っていたことも幸いし、仕事の合間の時間でコツコツやって1ヶ月程度で合格できました。
ちなみにプロフェッショナルの試験は合格特典として、ステッカーと、以下からどれか一つグッズをもらえるそうです。
![GCPグッズ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438093/d98ab1c7-cb3c-9043-3d68-ae9307f5f297.png)

![スクリーンショット 2020-11-15 0.25.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438093/d214b01a-e068-f18c-c15d-b29368c4819f.png)
オンプレDBサーバ(MySQL)のデータをRDSに移行する方法

# What's this?
サーバのAWS移設で、DBのデータをRDSに持っていった際の備忘です。
気をつけるべきポイントは以下の通りです。

- RDSではrootを使用できない
- 多くの場合直接RDSに接続でいないため、対向サーバ（今回の場合EC2）を経由させる必要がある


# 注意
取得したダンプファイルはmy_databases_yyyyMMdd.sqlで表しています。
Mysqlは5.7系です

# 手順
### ①オンプレの方のフルダンプを取得する
```
> mysqldump --password=■■■ --skip-add-drop-table --single-transaction --databases 【ダンプ取得対象のDB】 > my_databases_yyyyMMdd.sql
```
新規の（まっさらな）RDSに反映させる前提なので`--skip-add-drop-table`をつけてDROP TABLEステートメントを省略しています。
またデータの整合性を保つために`--single-transaction`を付与しております。


### ②sqlデータを置き替える
RDSではrootは取れないので、代わりにadminに修正します。

```
> sed -i -e 's/DEFINER=`root`@`localhost`/DEFINER=`admin`@`%`/g' my_databases_yyyyMMdd.sql
```
### ③sqlデータをzip化する
```
> zip -e --password=【パスワード】 my_databases_yyyyMMdd.zip my_databases_yyyyMMdd.sql
```

### ④zipデータをローカルに取得する
WinSCPなりなんだりでよしなに取得してください

### ⑤データをEC2サーバに上げる
今回の場合、ローカルからS3にアップし、EC2からS3にアップしたファイルを引き上げてます

```
> aws s3 cp s3://tmp/my_databases_yyyyMMdd.zip .
```

### ⑥zipデータを解凍する
```
# unzip -P 【パスワード】 my_databases_yyyyMMdd.zip
```

### ⑦RDSにデータを突っ込む
```
# mysql -h 【RDSエンドポイント】 -u admin -p < my_databases_yyyyMMdd.sql
```
Teradataに対するODBC接続

#DSN（DataSourceName）の解決

TeradataのODBCドライバはDNSからCOP(Communication Processor)エントリを探して接続します。

1. DNSから「データベース名+cop1」エントリを探索
2. 見つかった場合は「cop2」「cop3」・・・と順に探索
3. 見つかったエントリの中からランダムに選択して接続
4. 次の接続は数字を増やして順に接続（ラウンドロビン）

なお、ODBC DSNに複数のデータベース名があり、最初の名前にCOPが定義されていない場合は、すべての名前はCOPサフィックスなしで解決されます。定義されているCOPの数を検出する試みは行なわれません。

###設定例

```
# COP entries for dmdev
153.64.209.91 dmdev dmdevcop1
153.64.209.92 dmdev dmdevcop2

# COP entries for dmtest
153.64.106.78 dmtest dmtestcop1
153.64.106.79 dmtest dmtestcop2
```

#参考
[ODBC Driver for Teradataユーザー・ガイド](https://docsplayer.net/61695007-Odbc-driver-for-teradata-user-guide.html)
[Resolving a Data Source Name • ODBC Driver for Teradata® User Guide • リーダー • Teradataドキュメント](https://docs.teradata.com/reader/pk_W2JQRhJlg28QI7p0n8Q/OtwtnsApvmMRDdYP3lfc4A)
金融のテナーを期間順にソートする方法

金融業界では、ReutersやBloombergなどのデータベンダーからデータを取得することが多い。

ベンダーから取得した生データは数値部分が先頭に配置されているため、時系列の順にソートされない。

```生データのソート.txx
110M,10Y,11M,11Y,12M,12Y,13Y,14Y,15M,15Y,16Y,17Y,18M,18Y,19Y,1D,1M,1W,1Y,20Y,21Y,22Y,23Y,24Y,25Y,26Y,27Y,28Y,29Y,2D,2M,2W,2Y,30Y,31Y,32Y,33Y,34Y,35Y,36Y,37Y,38Y,39Y,3D,3M,3W,3Y,40Y,4M,4Y,5D,5M,5Y,6M,6Y,7D,7M,7Y,8M,8Y,9M,9Y,O/N,T/N
```

この生データのソート順を期間順に変更するための手順を示す。

```tenor.txt
O/N,T/N,1D,2D,3D,5D,7D,1W,2W,3W,1M,2M,3M,4M,5M,6M,7M,8M,9M,10M,11M,12M,1Y,15M,2Y,18M,3Y,4Y,5Y,6Y,7Y,8Y,9Y,10Y,11Y,12Y,13Y,14Y,15Y,16Y,17Y,18Y,19Y,20Y,21Y,22Y,23Y,24Y,25Y,26Y,27Y,28Y,29Y,30Y,31Y,32Y,33Y,34Y,35Y,36Y,37Y,38Y,39Y,40Y

```

#1 Excel > File > Option > Advanced > Edit Custom Lists
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274248/413033d5-c4e5-8b8c-d40f-90d49333a057.png)

#2
Add >  上記のtxt内の文字列を貼り付け > OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274248/eeb2a1a9-af40-510c-1e62-9842b8a26030.png)

これでExcelが自動でユーザー定義のソート順を判断し、並び替えてくれる。
EC2 Instance Connectはパブリック IPアドレスを優先する？

# やってみていること
EC2が3つあります。
1. 踏み台サーバとして起動。パブリックIPあり。
2. Webサーバとして起動。パブリックIPあり。
3. Webサーバとして起動。パブリックIPなし。

なんで、3.はパブリックIPなしかと言うと、元々ELB経由で接続する予定なので、パブリックIPアドレスは不要なのですが、2.のときにうっかり付けて起動してしまった、というわけです。しかも、後からは外せない:frowning2:

今のところはプロト環境として構築中なので、本番のときは付けないで起動せねば！と心に固く誓うだけじゃなく、しっかりメモしたところです。

# EC2 Instance Connectってのがあるらしいじゃない！？
保守作業に当たってのアクセス制限とか操作記録とか、どうしようかといろいろ考え中にEC2 Instance Connectというのがあるのを知って試してみています。

## 環境構築
元々、踏み台サーバからsshでアクセスできるようにしてあったので、そこは割愛します。
実は、踏み台サーバへのログインもどうしようかと、まだ考え中で。。。AWSコンソール使う？余計なもの見せたくないしなぁ。。。もし機会があれば投稿しようと思います。

少なくとも、踏み台サーバからEC2インスタンスへはEC2 Instance Connectでログインするようにしようかと思ったわけです。ログに残るし（未確認:sweat_smile:）、IAMで制御できるし（まだよく分かってない:tired_face:）というのが狙いです。

1. IAMユーザー（実際にやったのはユーザーが属するグループ）にEC2InstanceConnectポリシーを追加。
2. 踏み台サーバにログインして、`pip install ec2instanceconnectcli`を実行。とドキュメントには書いてあったけど、その前に`sudo easy_install pip`しないとpipが使えない。。。
3. IAMユーザーのアクセスキーを作る。それを以下のように設定（AWSのドキュメントにあるサンプルなのでご安心を）。リージョンも設定しておくと接続のときに指定しなくていいので楽（かも）。

```
$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json
```

## いよいよ接続！
`mssh 2.のWebサーバのインスタンスID`としたところ、だんまり。。。しばらくしてタイムアウト:confounded:
一方で`mssh 3.のWebサーバのインスタンスID`としたところ、無事接続。
タイムアウトのメッセージを見ると、パブリックIPアドレスに対してコネクションタイムアウト、とのこと。そりゃWebサーバに外からsshつながるようにポート開けてないし。msshはIPアドレス指定できなから、インスタンス起動した時点で詰んでたってこと！？

# まだ旅の途中

保守作業などでログインするときに人別にIDを付与して、操作記録を残すのは原則だと思うのです。AWSでのベストプラクティスを探す旅路の途中です。ガンダーラはあるのか。。。:thinking:
【Java】ConcurrentModificationExceptionとは何か

#プログラミング勉強日記
2020年11月15日
Javaでコードを書きテストを使用してあっているか確かめていたところ、`java.util.ConcurrentModificationException`という例外が発生したのでConcurrentModificationExceptionとは何なのか、どうすればいいのかまとめる。

#ConcurrentModificationExceptionとは
　[ ConcurrentModificationExceptionのJavadoc](https://docs.oracle.com/javase/jp/7/api/java/util/ConcurrentModificationException.html)には以下のように書いてある。

> この例外は、オブジェクトの並行変更を検出したメソッドによって、そのような変更が許可されていない場合にスローされます。

　基本的には、<b>繰り返しているものが変更されたときに早めに失敗して例外を投げるフェイルファーストするために使用される</b>。つまり、繰り返し処理を終了する前に例外が発生している。

　for-each文はIteratorを使用しているが、あまり冗長ではないが、テストでIteratorを使用するようにいリファクタリングした場合は`remove()`などの追加のメソッドにアクセスできる。removeメソッドがConcurrentModificationExceptionを引き起こさないため、繰り返しの処理中に呼び出しても大丈夫である。

　自分のコードの場合はArrayListの扱い方に問題があった。ArrayListとIteratorは内部で「変更された回数」を保持している。ArrayListのiterator()メソッドで生成されるIteratorはforで回す際に使うnext()メソッドなどを起動した際に，変更された回数にずれがないかチェックしていて、ずれがあったためConcurrentModificationExceptionの例外が発生していた。
　[JavadocのArrayList](https://docs.oracle.com/javase/jp/7/api/java/util/ArrayList.html)に以下の記述があった。

> このクラスの iterator および listIterator メソッドによって返されるイテレータは、フェイルファストです。イテレータの作成後に、イテレータ自体の remove または add メソッド以外の方法でリストが構造的に変更されると、イテレータは ConcurrentModificationException をスローします。このように、並行して変更が行われると、イテレータは、将来の予測できない時点において予測できない動作が発生する危険を回避するために、ただちにかつ手際よく例外をスローします。
通常、非同期の並行変更がある場合、確かな保証を行うことは不可能なので、イテレータのフェイルファストの動作を保証することはできません。フェイルファストイテレータは最善努力原則に基づき、ConcurrentModificationException をスローします。したがって、正確を期すためにこの例外に依存するプログラムを書くことは誤りです。「イテレータのフェイルファストの動作はバグを検出するためにのみ使用すべきです」。

#参考文献
[クラス ConcurrentModificationException](https://docs.oracle.com/javase/jp/7/api/java/util/ConcurrentModificationException.html)
[JavaでConcurrentModificationExceptionを回避](https://www.codeflow.site/ja/article/java-concurrentmodificationexception)
安全な数字(ruby編)

#[問題]安全な数字(ruby編)
#問題
4 桁のパスワードを考える上で法則性のある数字を避けようと考えています。
4 桁の数字で構成されたパスワードの文字列 s が入力されるので同じ数字が 2 つ以上存在すれば「NG」、そうでない場合は「OK」と出力してください。
#入力される値
入力は以下のフォーマットで与えられます。

s

・1 行目に 4 桁の数字で構成されたパスワードの文字列 s が与えられます。
・入力は合計で 1 行となり、入力値最終行の末尾に改行が 1 つ入ります。
#期待する出力
4 桁の数字で構成されたパスワードの文字列 s が入力されるので同じ数字が 2 つ以上存在すれば「NG」、そうでない場合は「OK」と出力してください。
#入力例1
2020
#出力例1
NG
#入力例2
1234
#出力例2
OK
#私の答え
```java:
a = gets.chomp.chars
if (a.count - a.uniq.count) > 0
    puts "NG"
else
    puts "OK"
end
```
###1行目のcharsメソッドで例１で例えると["2" "0" "2" "0"]のように1文字づつ分割している
###2行目でa.countの返り値4からa.uniq.countの返り値2を引いた数が0より大きければ"NG"を出力するというもの。
#uniqメソッド
配列の要素の中で重複している要素を削除して削除後の配列として返すメソッド
#countメソッド
* 文字列の特定の文字の出現回数を数えるための機能(「こんばんは」という文字に「ん」は2回みたいに数える機能)
* 配列の要素の数を数えるための機能

#以上！
macOS で pandas をインポートしようとしたら No module named '_bz2' というエラーが出る

# 環境
- macOS Big Sur バージョン 11.0.1
- pyenv で python をインストール

# 問題
python で何気なく pandas をインポートしようとしたところ、

```python
import pandas as pd
```

次のようなエラーが発生しました。

```
Traceback (most recent call last):
...(中略)
ImportError: No module named '_bz2'
```

# 原因
pyenv で python をインストールする際に、コンパイラが bzip2 というパッケージを認識していなかったために、python の bz2 ライブラリがインストールされず不完全な状態になっていると予想できます。  

なので、pyenv でインストールした時に次のような warning が表示されていたことでしょう。

```
$ pyenv install 3.9.0

...(中略)
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
```

# 解決方法
コンパイラに bzip2 ライブラリを認識させた状態で、 pyenv を使って python を再インストールします。

### 1. bzip2 パッケージをインストール
```
$ brew install bzip2
```

インストールの途中で、おそらく次のようなメッセージが出てくると思います。これが非常に重要です。

```

For compilers to find bzip2 you may need to set:
  export LDFLAGS="-L/usr/local/opt/bzip2/lib"
  export CPPFLAGS="-I/usr/local/opt/bzip2/include"
```

### 2. LDFLAGS と CPPFLAGS を設定
brew でインストールしただけでは、 pyenv で python をビルドする際に bzip2 パッケージをコンパイラは認識してくれません。  
コンパイラに認識させるためには、先ほど出てきたメッセージの通り、`LDFLAGS` と `CPPFLAGS` を設定する必要があります。  
そのために、.zprofile または .bash_profile の中に次の文を付け加えます。

```
export LDFLAGS="-L/usr/local/opt/bzip2/lib"
export CPPFLAGS="-I/usr/local/opt/bzip2/include"
```

前に別の `LDFLAGS` と `CPPFLAGS` を設定していた場合、これらの FLAG はスペースでつなげることで複数指定することができるので、次のようにしても良いでしょう。

```
export LDFLAGS="$LDFLAGS -L/usr/local/opt/bzip2/lib"
export CPPFLAGS="$CPPFLAGS -I/usr/local/opt/bzip2/include"
```

### 3. python を再インストール
pyenv でお好みのバージョンをインストールします。

```
$ pyenv install <version>
```

おそらく先ほどの warning は消えていたと思います。

その後は、いつもの pyenv によるインストール手順に従い、メインで使う python のバージョンを指定し、シェルをリロードします。

```
$ pyenv global <先ほどインストールしたバージョン>
$ exec $SHELL -l
```

おそらく pandas を読み込めるようになっているはずです。


# (参考) Linux の場合
以下の記事が参考になります。
[scikit-learn で No module named '_bz2' というエラーがでる問題](https://qiita.com/kizashi1122/items/2a0abcbfab99fecf16c6)


# 感想
Linux で同じエラーに対処する方法はたくさん見つかったのですが、macOS でのエラー対処法は見つからなかったので、自力で解決するしかなく大変でした。
C#でbase64エンコードしてBearerTokenを作成する

# 背景
TwitterAPIのaccessTokenを取得するためのBearerTokenをC#で作成する必要があり、
調べたときの備忘録です。

# コード
以下の流れで作成していきます。
1. API keyとAPI secret keyを用意する
2. API keyとAPI secret keyをコロンでつなぐ
3. byteの配列に変換する
4. base64に変換する

```csharp
using System;

// API keyとAPI secret keyを用意する
string apiKey = "abcdefg";
string apiSecretKey = "kdsajfkllpwjioajfjdsa;fdksajf";

// API keyとAPI secret keyをコロンでつなぐ
string strBearerTokenCredentials = apiKey + ":" + apiSecretKey;

// byteの配列に変換する
byte[] byteBearerTokenCredentials = Encoding.ASCII.GetBytes(strBearerTokenCredentials);
Console.WriteLine(Encoding.ASCII.GetString(byteBearerTokenCredentials));

// stringのbase64に変換する
string strBearerTokenCredentialsBase64 = Convert.ToBase64String(byteBearerTokenCredentials);
Console.WriteLine(strBearerTokenCredentialsBase64);
```

# 結果
```bash
// base64エンコードする前
abcdefg:kdsajfkllpwjioajfjdsa;fdksajf

// base64エンコードした後
YWJjZGVmZzprZHNhamZrbGxwd2ppb2FqZmpkc2E7ZmRrc2FqZg==
```

上記の流れで作成していきましたが、無駄な処理であったり、もっと良い作り方がある場合はご教示いただけると幸いです。
FFMpegを使って動画ファイルをMediaStudioへライブ配信してみる。【備忘録】

# FFMpegでRTMP配信
Twitter社の[Media Studio](https://studio.twitter.com/library)を触る機会があり、勉強しようと思ったけど[AWS Elemental Live](
https://aws.amazon.com/jp/elemental-live/)のような上等な配信設備なんて持ってない。
そこで`FFMpeg`を使って、LIVE配信環境を作成することにした。きちんと設定してないとMedia Studio側で「`the media could not be played.`」と表示されて躓いてしまったので備忘録を貼っておく。

## Media Studioにお勧めされたエンコーダー設定
[ソース設定](https://help.twitter.com/ja/using-twitter/how-to-use-live-producer)を行うと以下のエンコーダーの推奨設定が表示された。（2020/11現在）
ただ、Twitter社の設定ページをみると推奨ビットレートが2500kだったりしたので、適宜合わせる形にした。

|エンコーダー設定|おすすめ|
|---|---|
|オーディオコーデック|AAC|	
|音声サンプリングレート|44,100|	
|オーディオビットレート|128,000|	
|音声チャンネル|2|
|動画コーデック|H.264/AVC|
|動画ビットレート|9,000,000|	
|動画フレームレート|30|	
|動画キーフレーム間隔（秒）|3|
|動画の幅|1920|
|動画の高さ|1080|

## FFMpeg コマンド
試行錯誤した結果、以下の設定でテスト動画`hogehoge.mp4`を配信することができた。
最初、音声の設定を適切に設定していなくて配信できなかった。
実際に使うときは、もっと調整の余地はあると思います。

``` bash
ffmpeg -re -i 'hogehoge.mp4' -vcodec libx264 -r 30 -b:v 2500k -ar 44100 -ab 128k -ac 2 -acodec aac -strict experimental -f flv rtmp://{RTMP URL}/{RTMPストリームキー}
```
## 参考
- [FFMpeg Stream Guide](https://trac.ffmpeg.org/wiki/StreamingGuide)
Railsでちょっとしたアイコンを使いたい

#はじめに
　ちょっとお洒落にデザインしたかったので、アイコンを使ってみた。
##Font Awesome
　無料で使えるアイコンがたくさん揃っている。Railsでも使う事ができる。

##使えるまでの準備

###1. Gemを記述

```ruby:Gemfile
gem 'font-awesome-rails'
```
ファイルの一番下に追記する。

###2. インストール
　ターミナルで、

```bash
bundle install
```

###3. ビューファイルで使えるように読み込ませる

```ruby:app/views/layouts/application.html.erb
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.9.0/css/all.css">

```
`<head>タグ`の中に記述する。

##使い方
[公式サイト](https://fontawesome.com/v4.7.0/icons/)から使いたいアイコンを選び、

```ruby
<i class="fa fa-アイコン名"></i>
```

ヘルパーメソッドでも使うことができる。
Laravel-引数ありコントローラーで、引数がない場合の動作も許可するAPIを作る

例えば投稿機能postコントローラーがあり、特定のuser_idの引数に渡す。
このページにアクセスした時に、
引数としてユーザーID（テーブル上では 'user_id'）があれば、そのユーザーIDのpostだけをAPIとして表示し、
引数がなければ全postをAPIで表示したいときなんかの動き。


### route側の設定
api.php

```php
Route::get('postlist/{id?}','PostController@postlist');
```
こんな感じで引数に「?」を入れると、引数ありでもなしでもいけるよって言うルーティングを許可します。


### コントローラー側の設定
idのある場合とない場合の動作もコントローラーに記述が必要です。

PostController.php

```php
public function postlist($id = null)
    {   
        if($id == null){
            //user_idが入ってない場合は全ポストを取得
            $posts = Post::All();
        }else{
            //user_idが入っている場合は全ポストを取得
            $posts = Post::where('user_id', $id)->get();
        }
        return $posts;
    }
```

ユーザーIDが入っていない場合、user_idにかかわらず、全ユーザーのpostを返してくれる。
![スクリーンショット 2020-11-14 23.31.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287983/c5c2670f-3411-719d-a0f3-8cc004979f2d.png)





ユーザーIDが入っている場合、そのユーザーIDの情報だけをAPIで返してくれる。
![スクリーンショット 2020-11-14 23.29.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287983/71ce6872-d4d5-9ee3-9ba5-e5c088948cb6.png)
[Mac]写真アプリでネットワークドライブに写真を読み込めなくなった

# 症状
ネットワークドライブ（NAS）上に Mac の「写真」アプリのライブラリファイルを置いているのですが、いつからか iPhone の写真を読み込めなくなってしまいました。
具体的には、写真を読み込むと直後にライブラリの「読み込み」が開くが、いつまで待っても何も追加されない。

# 試したこと
- [ライブラリの修復](https://support.apple.com/ja-jp/HT204967) では復旧せず。
- ローカルドライブにライブラリがある場合は、正常に読み込みができる。
- 「イメージキャプチャ」でも、ネットワークドライブに読み込もうとすると同様に失敗する。「写真」アプリとは違い、エラーダイアログが出る。

# 解決方法

Apple サポートコミュニティで解決方法を見つけました。
[Image Capture cannot import to network (bug?)](https://discussions.apple.com/thread/250776961)

1. 「セキュリティとプライバシー」を開き、「プライバシー」タブから「フルディスクアクセス」を選ぶ。左下の鍵ボタンでロックを解除しておく。
2. Finder で `Command+Shift+G` を入力し、`/System/Library/Image Capture/Devices` を開く。 
3. `PTPCamera.app` を 「セキュリティとプライバシー」 の右側のリストにドラッグ
![セキュリティとプライバシー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/ef28ba85-62d0-85e2-3059-4f7ec235cf15.png)

これで無事に読み込めるようになりました！

# 検証環境
macOS Catalina 10.15.7 / MacBook Pro 2016
iPhone XS
(NAS) Buffalo LS510D
Node-RED の Pi-Keyboard フローで文字を取りこぼす問題

#### 追記 (2020/11/17)
本修正は本家に取り込まれました。
Raspberry Piでご利用の方は下記コマンドを入力することで問題解決されるはずです。

```shell
$ cd $HOME/.node-red
$ npm update node-red-node-pi-gpio
$ node-red-restart
```


# Node-RED の Pi-Keyboard フローで文字を取りこぼす問題

某SNSで

`Pi-Keyboardを利用した際に文字を取りこぼすことがある。`

という質問がありました。

**問題は解決しないと気が済まないタチなので調査してみました。**

## Pi-Keyboardの仕組み

Pi-Keyboardというのは、**[こちら](https://github.com/node-red/node-red-nodes)** で管理されているノードでして、
USB接続されたキーボード入力を検出するためのものです。

**ざっくりな仕組みとしては下記のようなイメージです**

##### 1. nrgpio.py

/dev/input/by-path/配下に存在するキーボードの入力を監視して入力があれば内容を標準出力する。

##### 2. 36-rpi-gpio.js
  
 1.の出力を拾ってPi-Keyboardの次のノードにメッセージを送る。

## 原因

  問題はバースト的にキー入力イベントが発生した場合に起こります。

### 例えばabが同時に入力された場合

1.からは `"a,0\n"` `"b,0\n"` の2行分の文字列が出力されます。
2.は入力は1行である前提の実装で、キー入力間隔が長い場合は問題ありません。
しかしバースト的なキー入力で発生した場合、2行目以降のデータ `"b,0\n"` は捨てられてしまう。
.....という問題でした。

## 修正

**RaspberryPi4では、下記にファイルがありますので公式修正されるまでは、直接書き換えてください。**
`$HOME/.node-red/node_modules/node-red-node-pi-gpio/36-rpi-gpio.js`

下記のように入力は複数行あるという前提のソースに書き換えます。

```diff:36-rpi-gpio.js
    function PiKeyboardNode(n) {
        RED.nodes.createNode(this,n);
        var node = this;

        if (allOK === true) {
            node.child = spawn(gpioCommand+".py", ["kbd","0"]);
            node.status({fill:"green",shape:"dot",text:"rpi-gpio.status.ok"});

            node.child.stdout.on('data', function (data) {
-                var b = data.toString().trim().split(",");
-                var act = "up";
-                if (b[1] === "1") { act = "down"; }
-                if (b[1] === "2") { act = "repeat"; }
-                node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
+                var d = data.toString().trim().split("\n");
+                for (var i = 0; i < d.length; i++) {
+                    if (d[i] !== '') {
+                        var b = d[i].trim().split(",");
+                        var act = "up";
+                        if (b[1] === "1") { act = "down"; }
+                        if (b[1] === "2") { act = "repeat"; }
+                        node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
+                    }
                }
              }
            });
```

## おまけ

改善確認のため `raw` というパラメータを追加すると状況がよく分かります。

```javascript
          node.send({ topic:"pi/key", payload:Number(b[0]), action:act, raw:`${data}` });
```

## ということで...

問題解決って、気持ちがいいですね。

※よく見るとGPIOInNodeでも同じ問題の対策実装が入っていますね

## 追記) プルリク作ってみた

あえてGPIOInNodeの実装に合わせて修正しプルリクを作ってみた。
https://github.com/node-red/node-red-nodes/pull/717

## 追記2) マージされました。

https://github.com/node-red/node-red-nodes/commit/906a48fa61c87ee02a009aad2db34789615b37d3

特にコメントも頂けず、、、1時間後にマージされました 😂
と思っていたら、しばらくたってコメント頂けた 😃
めでたしめでたし。
SpringBootでAOP

# Dependencies Version
| Library | Version |
|:-:|:-:|
| org.springframework.boot:spring-boot-starter-aop  | 2.4.0 |

# 実装例
```aop.java
package com.example.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MethodStartEndAspect {

    private static final Logger logger = LoggerFactory.getLogger(MethodStartEndAspect.class);

    @Before("execution(* com.example..*(..))")
    public void start(JoinPoint joinPoint) {
        logger.info("START {}#{}", joinPoint.getSignature().getDeclaringType().getName(), joinPoint.getSignature().getName());
    }

    @After("execution(* com.example..*(..))")
    public void end(JoinPoint joinPoint) {
        logger.info("END {}#{}", joinPoint.getSignature().getDeclaringType().getName(), joinPoint.getSignature().getName());
    }

}
```

# `@EnableAspectJAutoProxy`は不要。
Spring Bootに内包されているので。
横並びのときに高さがずれる問題の解決方法【inline-block】

要素を横並びにするときに、今だと`display:flex`が主流かなと思います。
でも、他にも要素を横並びにする方法はあって、その1つに`inline-block`を使って横並びにする方法があります。

でも、inline-blockを使って横並びにすると1つぶつかる問題があって、それが高さがずれる問題です。
こちらみてみてください！

![a41535e1fa625c41e0d5998b6afd93bd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592040/7673513e-47c7-7def-3ffd-cce0992ef4c9.png)

このように、高さがずれてしまうんですよね。
これの原因が`inline-block`の`vertical-align`の初期値が`base-line`だからです。

http://www.htmq.com/style/vertical-align.shtml

なので、高さを調節するためには、`vertical-align: top;`を指定すると高さがそろってくれます。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="css,result" data-user="okalog" data-slug-hash="yLJZKNN" 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="inline-block">
  <span>See the Pen <a href="https://codepen.io/okalog/pen/yLJZKNN">
  inline-block</a> by TakahiroOkada (<a href="https://codepen.io/okalog">@okalog</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
HTMLからHamlに変更する方法

# Hamlに変更

Gemfileの1番したに

```  

gem "haml-rails", "~> 2.0"
```

を書く。
terminalで`bundle install`をする
これでHamlを使うことができる。


#全てのファイルをHamlに変更
terminalで

```
rails haml:erb2haml
```
を行うと既存ファイル全てがhamlに変更することができる。
その際に`（y/n）`を聞かれるので全部`y`で答えて全て変更完了。
【JavaScript / jQuery】Googleドライブに保存した画像をHTMLで表示させる

####はじめに

初めての投稿です。自分の復習も兼ねて、Qiitaに記事投稿していこうと思います。
至らない点があったらスミマセン。
今回JavaScriptでご紹介していますが、変数にGoogleドライブのURLを格納できる言語でしたらどの言語でも問題ありません。
というより、imgタグに直接記述するだけならHTMLのみで完結します。

<h4>内容</h4>
JavaScript,jQueryを利用してGoogleドライブの画像をHTMLに引っ張ってくるという趣旨の記事になります。

趣味でよくiPadを使ってイラストを描くのですが、描いた絵を自分の開設しているWebページへ表示させる時にPCに送ってサーバに送って・・・という作業が面倒だったので、iPadから直接Googleドライブに画像を置いて、そこからプログラムで引っ張ってくればいいじゃないかと思ったのが始まりです。

Googleドライブに画像を保存している前提で執筆していきます。



<h4>Googleドライブに保存した画像の設定を変更する</h4>
コンテンツを右クリックし、「リンクを取得」を選択します。
![スクリーンショット 2020-11-13 6.20.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/859704/686fd569-ea88-974d-88a6-03b06bb37d4a.png)

権限を「制限付き」から、「リンクを知っている全員」に変更します。

![スクリーンショット 2020-11-13 6.25.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/859704/c35f2659-2b20-f8ff-ba05-b61f3bb062ca.png)

この時、リンクのURLは下記のようになっています。
`https://drive.google.com/file/d/画像ごとに異なるID/view?usp=sharing`

この[画像ごとに異なるID]をJavaScriptに記述し、HTMLで表示させようという流れになります。

またこちらのリンクへ実際に移動してみると分かるのですが、閲覧者側では違うURLとして表示されます。
このように、ファイルを確認するページ別にURLが異なるのですが、HTMLの``<img>``を利用して画像を表示させる場合は下記のURLを利用します。

``http://drive.google.com/uc?export=view&id=画像ごとに異なるID``


<h4>画像のIDを変数に格納する</h4>
変数に画像のIDを格納していきます。ファイルIDは「XXXX」と表記しています。
今回はjQueryのbefore要素も利用しています。

```html:index.html
<!-- <head>等、一部省略 -->
<body>
    <div class="container">
      <h4>画像を表示</h4>
      <div id="driveImg"></div>
    </div>
 <!-- jQueryでbefore要素を利用。今回の場合、containerとdriveImgの間に画像が挿入される -->
</body>
```


```javascript:script.js
const URL = "http://drive.google.com/uc?export=view&id=";
const item = "XXXX";
//XXXX : Googleドライブの共有リンクのURLから確認したファイルのID

const driveURL = URL + item;
//driveURL = "http://drive.google.com/uc?export=view&id=XXXX";　となった

$('#driveImg').before('<img src="' + driveURL + '">');
/*
<div id="driveImg"></div>の後ろに、
<img src="http://drive.google.com/uc?export=view&id=XXXX">が挿入される。
*/

```

####結果

![スクリーンショット 2020-11-14 22.46.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/859704/5c040487-dc2a-dafb-d843-d37d9f8bf7b7.png)

画像が表示されました。
なお2020年11月現在、ファイルのIDの文字数は33文字で統一されています。

内容は以上となります。
自分はいろんな画像のIDを配列に格納したので、その名残でJavaScriptとしてのファイルもご紹介したのですが、imgタグのみでも実装できるので初学者の方でも比較的簡単に実現できる内容だと思います。

実際やってみると分かるのですが、重いファイルをこれで表示させるとなかなか時間がかかります。
趣味で描いているイラストのサイズは2500*3000px程度であることが多いのですが、このくらい大きな画像になってしまうと読み込みに失敗してしまうことがたまにあります。

軽いファイルにならこの方法は十分使えるかもしれませんね。
良ければ応用してみてください。

閲覧ありがとうございました！

#####追記
編集リクエストを頂いたので一部修正しました。
こんな機能もあるんですね・・・ありがとうございます。