OmniAICreator/Qiita-1.07M huggingface dataset:
初めてのRaspberry Pi Pico ㉜ CircuitpythonでMCP3304

　[マイクロチップのMCP3304](https://ww1.microchip.com/downloads/en/DeviceDoc/21697F.pdf)は13ビットA-Dコンバータです。最上位は符号ビットなので、-4096～+4095までの分解能がある12ビットADCです。インターフェースはSPIバスで、転送速度は最大2.1MHz（5V）です。動作電圧は5Vが推奨されていますが、3.3Vでも動きました。

###MCP3304のおもなスペック
- ビット数　13
- チャネル数　8（シングルエンド）、4（差動）
- 基準電圧　内蔵なし、端子あり
- 変換速度　100ksps（5V時）
- インターフェース　SPI（モード0,0および1,1）、クロック最大2.1MHz（5V時）
- 動作電圧　4.5(2.7)～5.5V
- ピン数　16ピンDIP

###接続
|MCP3304の端子|	Picoの端子(GPIO)	|名称|
|------------|:-------------:|:------|
|1 ch0|	-|	-|
|2 ch1|	-|	-|
|3 ch2|	-|	-|
|4 ch3|	-|	-|
|5 ch4|	-|	-|
|6 ch5|	-|	-|
|7 ch6|	-|	-|
|8 ch7|	-|	-|
|9 DGND|	GND|	GND|
|10 /CS|	GP8|	GP8|
|11 Din|	GP3|	MOSI SPI0 TX|
|12 Dout|	GP4|	MISO SPI0 RX|
|13 CLK|	GP2|	SPI0 SCK|
|14 AGND|	GND|	GND|
|15 Vref|	3V3|	3.3V|
|16 Vdd|	3V3|	3.3V|
　ch0-ch1差動入力には、電池駆動の簡易電源TL431の出力をつないでいます。約2.5Vです。

###プログラム
　コマンドを送るフォマットは次のとおりです。
　　``Startbit　チャネル指定4バイト``
　例えば、差動ch0-ch1であれば、
　　``0000``
です。最後のチャネル指定ビットD0がMCP3304へ送られるタイミングで、約1ビットおいて、NULLビットに引き続き、
　　``Sign D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0``
のA-D変換結果データが、MCP3304からPicoへ送られてきます。
　SPIは基本8ビット単位なので、LSBのD0から前にさかのぼって、8ビット単位で送るべきデータを整理します。差動ch0-ch1の場合です。
　　``x x x x 1 0 0 0``   ``0 x x x x x x x``    ``x x x x x x x x``
　SPIは、クロックを送り続けないとデータはやってきません。上記のxはダミーなので、０でも1でもかまいません。ただし、最初の4ビットのいずれかを'1'にすると、Startbitと解釈されるかもしれないので、'0'にします。'0'でもクロックは発生します。したがって、ここでは、ch0-ch1差動のデータは、次のようにしました。
　　``0x08``   ``0x00``   ``0xff``

　本プログラムは、差動入力だけを対象にしています。

|チャネル指定|	1バイト目	|2バイト目|3バイト目|
|------------|:-------------:|:------|:------|
|ch0 = IN+　ch1 = IN-|0b00001000|0b00000000|0xff|
|ch2 = IN+　ch3 = IN-|0b00001001|0b00000000|0xff|
|ch4 = IN+　ch5 = IN-|0b00001010|0b00000000|0xff|
|ch6 = IN+　ch7 = IN-|0b00001011|0b00000000|0xff|

　3バイト送ったので、読み出したデータは3バイトです。1バイト目はごみなので捨てます。2バイト目は上位桁``Sign D11 D10 D9 D8``が右詰めで入っています。3バイト目は、``D7 D6 D5 D4 D3 D2 D1 D0``です。
　Signビットを見て符号をつけます。
　12ビットのデータなので、Vrefの3.3Vをかけ、4096で割って電圧を求めます。Vrefは、できるだけ正確にテスタで測った値を記入しておきます。

```python
from board import *
import busio
import time
import digitalio

print('\n  start\n')

spi = busio.SPI(GP2, GP3, GP4)  # SPI0BUS clock MOSI MISO
while not spi.try_lock():
    pass
spi.configure(baudrate=1_000_000, phase=0, polarity=0)

cs = digitalio.DigitalInOut(GP8)
cs.direction = digitalio.Direction.OUTPUT
cs.value = 1

def readADC():
    result = bytearray(3)
    cs.value = 0
    spi.write_readinto(bytearray([0x08,0x00,0xff]), result)  # cho-ch1
    cs.value = 1
    temp = (result[1] & 0b00011111) << 8 | result[2]
    Volts = -(temp & 0b1000000000000) | (temp & 0b0111111111111)
    #print(result[0], result[1], result[2])
    #print(bin(Volts))
    return(Volts)

while 1:
    print(str(readADC()*3.3/4096) + 'V')
    time.sleep(3.14)
```
　ch0-ch1を読み取っているところです。
![mcp101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/265c448e-cab5-c6b4-93f2-b19784c9df14.png)
React-BootstrapのForm.File要素の表示をカスタマイズする

## 概要
React-Bootstrapにはファイルのアップロードを行う`Form.File`の要素があるのですが、デフォルトのままだと下記の画像のようなシンプルなインプットのレイアウトになります。
<img width="250" alt="スクリーンショット 2021-03-21 4.34.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/73c99c82-ee51-ae76-459b-f8d60b17ebbf.png" />
これを独自のインプットの表示にするやり方を、今回紹介します。

## どのようにしたいのか
下記のTwitterのイメージにあるような、アップロードした画像をクリックするとファイルのダイアログが表示されるように、今回実装してみます。
<img width="400" alt="スクリーンショットスクリーンショット 2021-03-20 16.43.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/4c23d41f-472c-8ff3-789c-87aa44c7ad33.png" />

## 対応方法
[こちら](https://react-bootstrap.github.io/components/forms/#form-file-props)のドキュメントにある通り、Form.Fileに`custom`を設定します。その上で、`FormFile.Input`要素を配置して、これを画像の表示箇所に被るようにCSSで位置を調整します。画像が変わったときに走る関数は、FormFile.Input側に設定します。

## 実装サンプル
画像が未設定の時は、FontAwesomeIconの人アイコンを表示します。

```js:sample.js
const [displayIconSrc, setDisplayIconSrc] = useState(undefined);

function onChangeIconImage(e) {
  if (e.target.files.length > 0) {
    setValue("iconImage", e.target.files);
    const imageFile = e.target.files[0];
    // FileReaderオブジェクトを使ってファイル読み込み
    var reader = new FileReader();
    // ファイル読み込みに成功したときの処理
    reader.onload = function () {
      setDisplayIconSrc(reader.result);
    };
    // ファイル読み込みを実行
    reader.readAsDataURL(imageFile);
  } else {
    setDisplayIconSrc(undefined);
  }
}

return(
  <Form.File id="iconImage" name="iconImage" type="file" custom>
    <FormFile.Input
      style={{ width: "70px", height: "70px" }}
      onChange={onChangeIconImage}
    />
    <div>
      {displayIconSrc ? (
        <img
          src={displayIconSrc}
          className="mt-2 mr-2 rounded-circle"
          style={{
            width: "70px",
            height: "70px",
            position: "relative",
            bottom: "75px",
          }}
        />
      ) : (
        <FontAwesomeIcon
          icon={faUser}
          className="fa-2x mt-2 mr-2"
          style={{
            width: "70px",
            height: "70px",
            position: "relative",
            bottom: "75px",
          }}
        />
      )}
    </div>
    <div
      style={{
        position: "relative",
        bottom: "50px",
        left: "170px",
      }}
    >
      アイコン画像を選択してください
    </div>
 </Form.File>
);
```

以下のような表示になります。画像をクリックするとファイル選択のダイアログが表示されます。
<img width="300" alt="スクリーンショット 2021-03-21 4.44.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/c0f16b86-587d-821a-6765-95e856722682.png" />
TWELITEを試す２_シリアル通信　その１

#TWELITEでUART通信
ここでやりたいのは次のようなこと。

- Arduinoからのシリアル通信をTWELITEを使って遠隔に飛ばし、パソコンのシリアルモニタに表示する。
    - Arduino -(電線)-> Twelite1 -(電波)-> Twelite2/TweLiteR2 -(USB)-> PC

これができると複数の計測機器の計測結果をArduinoとTweliteを使って一つのパソコンに集約することができる。配線を複雑にせずにデータを受け取る側のパソコンを１台に集約できるのは、それなりに大きなメリットになる場合があろう。

## 使ったもの
- Arduino UNO、１台
- TweLite Dip、１台
- TweLite MonoStick、１台
- TweLite Dipをセットするブレッドボード

## 配線
|TWELite DIP | Arduino UNO | コメント |
|:-----------|:------------|:------------|
| VCC       | 3.3V         | 
| GND        | GND      |
| 10       | GND        |M1をGNDすることで子機に設定する
| 17         | GND          |BPSをGNDすることで、TweLite Stageインタラクティブモードで設定した通信速度で通信するように設定する。
| 7(RX)         | 1 (TX)         |
| 6 (TX)        | 0 (RX)         |
ただし、TweLite Dip側の数字は、ボードに刻印されている数字で示している。

- TweLiteはピン番号の表現の仕方が複数あるのがわかりにくい。刻印10はピン番号3、17は20、7は3、6は10に対応する。
- おまけに、刻印の数字がピンとピンの中間に記されているので、対応するのが上のピンか下のピンかもわかりにくい。刻印数字の下のピンが正しい。
- Arduino UNOのUARTは5V、TWELiteのUARTは3.3Vなので、上記のように直接つなげるのは危険かもしれない。今回試した限りでは機器に異常は発生しなかったが、推奨されない接続方ではある。
- TweLite DIPの刻印10のピン（M1）は子機に設定しなくても動きそうに思うが、これをしないとうまく動かなかった。

## TWELite DIPおよびMONOSTICKへのAppの書き込みと設定

- TWELite DIPをTWELITE R2に装着しUSBケーブルでパソコンと接続する。
- TweLite Stage を立ち上げてTWELite DIPを認識させる。
- TweLite Stageで「アプリ書き換え＞TWELITE Apps ビルド＆書換＞App_UART」と進み、UARTアプリを書き込む。
- TweLite Stageで「インタラクティブモード」を選び、モード（m）を透過モード（TransparentなのでT）にする。
    - 設定を変更した後は、新しい設定を反映させるために保存（S）する必要がある。
- 同様の設定をMONOSTICKについてもおこなう。すなわち、
    - App_UARTの書き込み
    - モードの透過モード（T）への設定
- 念の為、インタラクティブモードでTWELite DIPとMONOSTICKについて、以下の設定が同じ値になっていることを確認しておく。
    - application ID（デフォルトでは0x67720103）
    - channels（デフォルトでは18）

## Arduinoの設定
Arduinoには、シリアルに何かを定期的に書き込むスケッチをアップしておく。例えば、

```cpp
int i;
void setup() {
  Serial.begin(38400);
  i=0;
}
void loop() {
   Serial.println(i);
   i++;
   delay(1000);
}
```

- 書き込むときにはArduinoの0と1のピンに接続されている電線は外しておく必要がある。
- Arduino UNOでシリアル通信するときは、普通は9600bpsだが、38400bpsでも大丈夫。ただし、Arduino IDEでシリアル通信を見るときにはシリアルモニタの速度を38400に設定する必要がある。

## MonoStickが受け取るシリアル通信のパソコンでの表示
Twelite Stageのターミナル（メニューからビューワ＞ターミナル）でモニタした。

- 本来は普通のシリアル通信ソフトでモニタリングしたいのだが、MacOS Big Surでは普通に端末を認識することができない。
- 受け取り側をMonoStickではなくTwelite Dip + Arduinoにしたら、おそらくシリアル通信ソフトで受信することができると思う。その場合は3.3V UARTを5Vに上げないといけないかもしれないが。

## 結果
- はじめは機器の通信速度を38400bpsにそろえて実験した。結構な頻度（10回に１回くらいの印象）で抜けが生じることが分かったが、通信できている。
- 機器の通信速度を9600bpsに揃えた場合も成功した。

##感想等
これでうまくいけば、比較的安価にデータ収集システムを構築することができる。通信の安定性にやや難があるのが気になるが...。
Blenderのレンダリングの比較

## eevee vs cycles

[Blender](https://www.blender.org/)でデフォルトのeeveeとcyclesでレンダリングを比較する。

結論：ものによってはかなりの差がある。

### eevee

![eevee.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/9d3099ed-8846-5713-7c40-e0b98f62dab0.jpeg)

### cycles

![cycles.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/cffa1c22-32a5-d89c-856a-c313285ee600.jpeg)

### メッシュのマテリアル

マテリアルは、[PBR Materials](https://3d-wolf.com/products/materials.html)で作成。

- 球：ガラス
- 立方体：鉄
- 円柱：プラスチック
Windowsユーザー必見！scoopを使ってコマンドからGit、Node、npm、PHPをダウンロードしてHomebrewを実現しよう！！

皆さんこんにちは！

今日はWinodwsでコマンドから色々ものをダウンロードして見ようかなと思います。

良く解説動画を見ると、Macで説明されている方が多くその度に``Homebrew``と言う言葉を耳にします。

残念ながらWindowsではこのHomebrewと言うものは存在しません（多分）。

ですが、Homebrewと同じような機能をもつものがWindowsにも搭載されています！

その名は**scoop**！！

これを使えば、コマンドからNodeやらGitやらをインストールすることができます。

他にもscoopを使えばバージョンの指定を行うことも可能なので、わざわざサイトからダウンロードするなんて作業にはもうさよならです。

scoopをインストールするには``PowerShell``での作業が**必須**となりますのでご注意を。

それでは早速scoopを使って色々やってみましょう！

#scoopのインストール#

もう一度言います。

**PowerShell**で行ってくださいね。

```
Set-ExecutionPolicy RemoteSigned -scope CurrentUser
// 実行ポリシーの変更について聞かれるので「Y」を選択
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
```

```
scoop bucket add extras
scoop bucket add versions
```

この２つは良く使うのでインストールしてください。

#Gitの導入#

```
scoop install git
```

これでGitをインストールすることができました！

```
git --version
```

バージョンが返ってくればOK！

環境変数のPATHも自動で通してくれるのでめちゃ便利！

ついでに``openssh``も取得

```
scoop install openssh
```

#Nodeのインストール#

お次はNodeをインストールし見ましょう！

```
scoop install nodejs
```

##バージョン指定##

バージョン指定したい場合は以下のように実行

```
scoop install nodejs8
```

ただし、``scoop bucket add versions``を行っていない場合は出来ないので注意。

```
node -v

npm -v
```

バージョンが返ってくればOK！

#PHPの導入#

ここからはおまけみたいな感じです。

```
scoop install php-nts php-nts-xdebug vcredist2017 composer
```

これでPHPとComposerを使える環境が整いました。

```
php -v

composer -v
```

バージョンが返ってくればOK！

```
'****.dll' ** is not compatible with this PHP build linked with ** in Unknown on line 0
```

このようなエラーが出る方は、下記の記事が参考になります。

・[「MSVCR140.dll/VCRUNTIME140.dllがないため、プログラムが開始できません」と表示された場合](https://www.javadrive.jp/php/install/index2.html)

コマンドで操作を行うってやっぱり夢ありますよね。

これでバージョン管理も楽になるので、是非活用してください！

以上、「Windowsユーザー必見！Homebrewみたいにscoopを使ってコマンドからGit、Node、npm、PHPをダウンロードしてみよう！！」でした！

Thank you for reading
AtCoder自分用まとめ009(ABC196C Doubled)

#概要
自分のために、AtCoderで身に付けた内容・コードをまとめておく。

#内容
https://atcoder.jp/contests/abc196/tasks/abc196_c

##C
編集中

##C++
```cpp
#include<iostream>
#include<string>
using namespace std;
int main() {
  long long N;
  cin >> N;

  for(long long i = 1; ; i++){
    if(stoll(to_string(i) + to_string(i)) > N){
      cout << i - 1 << endl;
      return 0;
    }
  }
}
```
##C++\<bits/stdc++.h\>
```cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
  long long N;
  cin >> N;

  for(long long i = 1; ; i++){
    if(stoll(to_string(i) + to_string(i)) > N){
      cout << i - 1 << endl;
      return 0;
    }
  }
}
```
##Python3
```python
N = int(input())
for i in range(1, 1000001):
    if int(str(i) * 2) > N:
        print(i - 1)
        exit()
```
##Haskell
編集中

##Racket
編集中

##Vim
編集中


#参考にさせていただいたページ
- https://atcoder.jp/contests/abc196/tasks/abc196_c
- https://atcoder.jp/contests/abc196/editorial/946

#感想
もう少し慣れたら書き直したい。。
rails - テストコード基礎（Rspec・FactoryBot）

# テストコードの実装手順
Rspec・FactoryBotを使った基礎的なテストコード実装についてアウトプットもかねて自分用にまとめます。(今回はuserモデルの単体テストコード)
***
まずは実装の流れになります。

1.Gemインストール
2.Rspecの設定
3.FactoryBotの設定
4.テストコード記述ファイル作成
5.テストコード記述
6.テスト実行
***
### 1.Gemインストール

```ruby:Gemfile
group :development, :test do
  gem 'rspec-rails', '~> 4.0.0' #バージョン指定
  gem 'factory_bot_rails'
end
```

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

### 2.Rspecの設定
Rspecのインストール、ディレクトリ・ファイルを作成する

```:ターミナル
rails g rspec:install
```

テストコードの結果をターミナル上に可視化する

```:.rspec
--require spec_helper
--format documentation #追加
```

### 3.FactoryBotの設定
specディレクトリ内にfactoriesディレクトリを作成後

```:spec/factories/users.rb

FactoryBot.define do
  factory :user do
    nickname              {'test'}
    email                 {'test@com'}
    password              {'111111'}
    password_confirmation {password}
  end
end
```

### 4.テストコード記述ファイル作成

```:ターミナル
rails g rspec:model user
```

### 5.テストコード記述

```ruby:spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
  before do
    @user = FactoryBot.build(:user) #インスタンス生成
  end

  describe 'ユーザー新規登録' do 
    it 'nicknameが空では登録できない' do
      @user.nickname = ''
      @user.valid?
      expect(@user.errors.full_messages).to include "Nickname can't be blank"
    end
  end
end
```

### 6.テスト実行

```:ターミナル
bundle exec rspec spec/models/user_spec.rb 
```

***
## おまけ
###エラーメッセージの日本語化
以下の手順でエラーメッセージを日本語にすることもできる。

1.Gemインストール

```:config/application.rb
module Pictweet
 class Application < Rails::Application
   # 日本語の言語設定
   config.i18n.default_locale = :ja #追加
 end
end
```

```:Gemfile
gem 'rails-i18n'
```

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

2.各種ファイルの作成、記述

- config/localesディレクトリにdevise.ja.ymlファイルを作成
- [devise-i18n](https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml)から記述をコピーして貼り付け

```:config/locales/devise.ja.yml
ja:
  activerecord:
    attributes:
      user:
        confirmation_sent_at: パスワード確認送信時刻
        confirmation_token: パスワード確認用トークン
        confirmed_at: パスワード確認時刻
        created_at: 作成日
        current_password: 現在のパスワード
        current_sign_in_at: 現在のログイン時刻
        current_sign_in_ip: 現在のログインIPアドレス
        email: Eメール
〜〜〜〜〜〜〜〜〜〜　以下略　〜〜〜〜〜〜〜〜〜〜〜〜〜〜
```


- config/localesディレクトリにja.ymlファイルを作成

```:config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
     tweet:
       text: テキスト
       image: 画像
``` 

これで日本語化は完了です、あとはテストコードのエラーメッセージ部分を書き換えればテストも通ります。
RubyをMacにインストールするときのエラー

#はじめに
Rubyの勉強がしたいと思い、MacbookAirにRubyをインストールしようとしたときの試行錯誤の備忘録です。
Macには標準でRubyがインストールされているのですが、Rubyの参考書を進めていくうちに権限の問題で追加したいライブラリを追加できない。
自身の手でMacにRubyをインストールすれば、権限問題は解消するそうです。

#rbenvのインストール
Rubyをインストールするまでの道のりはざっくり４段階あります。
1. Xcodeインストール
2. Homebrewインストール
3. rbenvインストール
4. Rubyインストール

1と2はなんとかできた。
しかし3でエラーが出始める。

## Permission denied @ dir_s_mkdir - /private/tmp/homebrew...
brew install rbenvを実行するとエラー出現。
なにこれ？と思いコピーしてGoogle検索するとprivate/tmpフォルダの権限不足でrootユーザしか書き込みできない。ls -lコマンドで確認すると確かにそうなっている。
[こちらのサイト](https://www.tutorialfor.com/questions-142714.htm)によると
sudo chown -R 'username'/private/tmp/
で解決できるとのこと。Thank you.

##Interrupted system call @ dir_initialize - /usr/local/Cellar/rbenv/1.1.2
つぎに出たエラー。グーグルで検索してもよくわからない。
とりあえずターミナルを再起動して再度brew install rbenvを実行するとエラーはなくrbenvのインストールに成功した。

## BUILD FAILED
rbenv install 3.0.0を実行するとエラーが出る。
Installing ruby-3.0.0...
ruby-build: using readline from homebrew
BUILD FAILED (macOS 11.0.1 using ruby-build 20210309)
[こちらのページ](https://teratail.com/questions/88982)によるとcurlとopensslが古いバージョンのため。らしいとのことなので対策する。
対策でやったこと。
・opensslとcurlがinstallされていなかったので再インストール
・opensslとcurlがanaconda3のPATHだったので.bash_profileからPATHを削除して/usr/bin/配下のopensslとcurlに通す。

#インストール成功
rbenv install 3.0.0を再度実行するもまたしてもBUILD FAILEDが出る。

ならばRubyのバージョンを変えてみたらどうか、と思いrbenv install 2.7.2を実行するとなんと成功。

Windowsばかり使ってきていたので今回PATHやシェルの勉強を予期せずできてよかった。Rubyがんばるぞー。
Gitでsubtreeを使用して複数のリポジトリを扱う

# 概要
複数のリポジトリをまとめて管理するリポジトリを作成する。
例えば、front, backの二つのリポジトリを、mainリポジトリで管理する。

```:ディレクトリ構成
main
├── front
└── back
```

# 準備
以下三つのリポジトリを用意する

- main
- front
- back

# やること (mainにfrontを追加)
## 1. mainディレクトリに移動
`$cd main`

## 2. frontをリモートに追加
`$git remote add -f front git@github.com:front.git`

## 3. frontをsubtreeに追加
`$git subtree add --prefix=front front main`

prefixでディレクトリを指定、frontのmainブランチを追加する。
勝手にコミットされる。

# やること (mainにbackを追加)
mainにfrontを追加と同様

# subtreeのリポジトリの更新を取り込む
`git subtree pull --prefix=front front main`

# 参考サイト
- [Gitのサブツリーのマージについて - GitHub Docs](https://docs.github.com/ja/github/using-git/about-git-subtree-merges)
- [gitで外部moduleを扱う方法(subtree) - Qiita](https://qiita.com/__mick/items/e027cc3941ac52743bd5)
- [Git Subtree 事始め - Qiita](https://qiita.com/mikakane/items/487ca8b3acddfa5fdb41)
Django モデル構築01

#【概要】
Djangoのアーキテクチャの一つM(モデル)の基礎知識と構築の記事です。

【具体的な内容】
1 モデルの役割
2 DB(データベース)について
3 実際のModels.pyのコード例

#【1 モデルの役割】
モデルはWebAPPにおけるDB(データベース)の役割を与えられています。
Djangoの全体の中でModelがどのように関わるかを以下に記載します。

・全体の流れ 
ブラウザからのリクエスト → Webサーバー → ミドルウェア → URLディスパッチャ → **View** → URLディスパッチャ → ミドルウェア → Webサーバー

簡単にまとめると、ブラウザの操作がviewへ届き操作のフィードバックがブラウザに反映されます。この中でモデルはユーザの操作によってDB内部のデータを作成・更新・削除などを行ったり必要な時にviewへデータを渡す役割を担っています。


Viwe ← → **Model**


####・Django Object-Relational-mapper
DjangoはDjango ORMapperと呼ばれるマッパー機能を提供しており、「DBにおけるテーブルとカラム定義」と「モデルにおけるクラス属性の定義」を対応させています。
これにより、SQL文を使わずにSQLコマンドを使用したり、DBの種類における違いを吸収してくれます。

#【2 DB(データベース)について】
・DBの構造
最上位の単位はデータベース
その下に複数のテーブル
テーブルの中にデータの項目と各データが格納されています。

・Djangoの中でDBやテーブルは。
Djangoプロジェクトの中にModelはDjangoのアプリケーションの数だけ存在します。
Model(models.py)の中にはclass化されたテーブルを用意し

自分はDjangoを学び始めていた時はDBについてあまり知らず経験もない状態で、その状態で開発を進めると後でモデルの構造がスパゲティ状態になることがありました。保守性と拡張性に問題が出るため、良いとされるDB構造を学ぶことを推奨します。　


#【3 Models.pyのコード例】
学校の生徒の管理用のアプリケーションを実装する場合を想定します。
以下、生徒のデータを管理するためにStudentテーブルを作成したい場合の例です。
※idのAutoFieldはデータ作成時に自動的にDjangoから生成されるIDの値です。

```python:student/models.py
from django.db import models
    class Student(models.Model):
　  　  id = models.AutoField(primary_key=True)
　  　  name = models.CharField(max_length=256)
```
この状態でターミナルツールでマイグレーションを行うことで、プロジェクトのDBにStudentテーブルが追加されます。

```shell
python3 manage.py makemigrations
python3 manage.py migrate
```

部活テーブルを追加する場合はclassをmodels.pyに追加します。

```python:student/models.py
    class ClubTeam(models.Model):
　  　  id = models.AutoField(primary_key=True)
　  　  name = models.CharField(max_length=256)
```
生徒データに部活のデータを紐づけた管理をしたい場合はstudentクラスを以下のように編集します。

```python:models.py
from django.db import models
    class Student(models.Model):
　  　  id = models.AutoField(primary_key=True)
　  　  name = models.CharField(max_length=256)
　  　  club = models.ForeingKey(Clubteam, on_delete=models.CASCADE)
```
clubのForeingKey(...)は外部キーを取得したい場合の書き方です。

これ何が変わったのかというと、外部キーというものを使って部活テーブルのデータのidを生徒のclubカラムへ格納してます。
データ同士に関係性がある場合にDBで「一対一」「多対一」「多対多」のリレーションを定義したりします。
「DB リレーション」などで調べると色々出てきます。

ForeingKey(...)は多対一
OneToOneField(...)は一対一
ManyToManyField(...)は多対多の構造の時の書き方です。

on_delete=CASCADEは引っ張ってきた元データが削除された場合このデータも削除されるというオプションなのですが、ほかにどんなオプションがあるのか調べるとDBの構築の一助になるかと思います。

こうすることで、部活テーブルに変更があった場合でも生徒テーブルのデータも連動します。
例えば野球部が廃部した場合、部活テーブルのnameがbaseballの部活が削除されます。
生徒テーブルの元野球部員たちは部活テーブルのbaseballの削除に伴い、自動的にclubの中身が空白になります。

便利ですよね。
DBに明るくない方はモデル構築の前に基礎知識を調べてイメージを固めてください。
自分は、なぜ外部キーが必要なのか知らなかった時期にモデル構築をしたせいで後々大改修が必要になりました。
あるテーブルの特定の列のデータが削除されたら、他テーブルのデータを削除するみたいな処理を延々作ってました。

**超アホです。**
<font color="Beige">自分ならこんな人と一緒に仕事するの怖いです笑</font>

こんな風にならないためにDBの基礎知識は学習し、データ同士の関係性などは実装前にきっちり設定しましょう。
PythonでSAMLを実装

シングルサインオンの実装を理解するため、IDプロバイダの設定とサービスプロバイダをローカルで動作させるまでの手順をまとめました。

IDプロバイダにはAzureADを、サービスプロバイダにはhttps://github.com/onelogin/python3-saml というライブラリに含まれるpythonで書かれたflaskサーバーのサンプルを動作させます。

## 事前準備

- https://ngrok.com/ のインストール
- `ngrok http 8000` で起動し、発行された"https"のURLを以降{ngrok_url}として記載

## IDプロバイダ（AzureAD）の設定

- [Azureポータル](https://azure.microsoft.com/ja-jp/)を開く（サブスクリプションが作成済みである必要があると思う）
- エンタープライズアプリケーションを開く
- 「新しいアプリケーション」>「独自のアプリケーションの作成」をクリックし「	Integrate any other application you don't find in the gallery (Non-gallery)」を選択してアプリを作成
- 作成したアプリに移動し、「シングルサインオン」を開く。「SAML」を選択して下記を設定。
    - 識別子 (エンティティ ID): `{ngrok_url}/metadata/`
    - 応答 URL: `{ngrok_url}/?acs`
    - ログアウト URL: `{ngrok_url}/?sls`
- ユーザーとグループを開き、 「ユーザーまたはグループの追加」をクリックして、動作テストしたいユーザーを追加する

## サービスプロバイダの設定

- サンプルコードをクローン

```
git clone git@github.com:onelogin/python3-saml.git
```

- Azureポータル > エンタープライズアプリケーション > （作成したアプリ）> シングルサインオン に表示されている内容を参考に./demo-flask/saml/settings.jsonを設定する
    - sp.entityId: `{ngrok_url}/metadata/`
    - sp.assertionConsumerService.url: `{ngrok_url}/?acs`
    - sp.singleLogoutService.url: `{ngrok_url}/?sls`
    - idp.entityId: XXX（アプリ名）のセットアップ > Azure AD 識別子
    - idp.singleSignOnService.url: XXX（アプリ名）のセットアップ > ログイン URL
    - idp.singleLogoutService.url: XXX（アプリ名）のセットアップ > ログアウト URL
    - idp.x509cert: SAML 署名証明書 > 証明書 (Base64) をダウンロードした中身の文字列（改行やBEGIN CERTIFICATEなどの行は削除） 
- https://github.com/onelogin/python3-saml/blob/master/demo-flask/index.py#L26 あたりを下記のように書き換え

```
'https': 'on',
'http_host': request.host,
'script_name': request.path,
'get_data': request.args.copy(),
'lowercase_urlencoding': True,
'post_data': request.form.copy()
```
※ ngrokなどのproxyを経由していてもhttps振る舞うよう強制
※ AzureADのSAMLResponseは大文字/小文字の取り扱いが特殊なので、lowercaseに強制

- Mac上での実行に要求されるなライブラリのインストール（必要であれば）

```
# 参考 https://pypi.org/project/xmlsec/
brew install libxml2 libxmlsec1 pkg-config
```

- パッケージのインストール

```
python setup.py install
pip install -r demo-flask/requirements.txt
```

- サーバーの起動

```
cd demo-flask
python index.py
```

## 動作の確認

### ログイン

- `{ngrok_url}` にアクセスしログインする
- ユーザーの情報が取得できていることが確認できます

### ログアウト

- ログインボタンをクリック
- MSのログアウト画面にリダイレクトされ、続けてSP側に戻ってきて`Successfully logged out`と表示されることが確認できます

## 参考にしたリンク

- https://hisafi.hatenablog.com/entry/20200531/1590855668
- https://www.youtube.com/watch?v=SvppXbpv-5k
- https://docs.microsoft.com/en-us/archive/blogs/jpazureid/enterprise-applications-app-registrations
- https://github.com/onelogin/python3-saml/issues/179
【Rails】ransackで検索機能の実装

#前提
Deviseで認証機能実装済み（user）

**Userテーブル**（一部抜粋）
nickname:名前
introduction:紹介文
image_id:プロフィール画像（Refile）

#ransackをGemfileに追加

```Ruby:Gemfile
gem 'ransack'
```

忘れずにバンドルインストール

```
$ bundle install
```

#コントローラー

```Ruby:app/controllers/users_controller.rb
  def index
    @q = User.ransack(params[:q]) # 検索ワードをparams[:q]で受け取り
    @users = @q.result(distinct: true) # 該当した結果をデータ表示
  end
```

・distinct: true
重複を避ける


#ビュー 

検索窓

```erb:app/views/users/index.html.erb
<%= search_form_for @q do |f| %>
  <%= f.search_field :nickname_or_introduction_cont, placeholder: "Name or Word" %>
  <%= f.submit "Search" %>
<% end %>
```
・_cont
検索ワードを含むデータの取得・・・contains(含まれる)の略


表示(リンク)

```erb:app/views/users/index.html.erb
<% @users.each do |user| %>
  <%= link_to user_path(user) do %>
    <%= attachment_image_tag user, :image %>
    <%= user.nickname %>
  <% end %>
```
AtCoder自分用まとめ008(ABC196B Round Down)

#概要
自分のために、AtCoderで身に付けた内容・コードをまとめておく。

#内容
https://atcoder.jp/contests/abc196/tasks/abc196_b
>整数または小数 X が与えられるので、小数点以下を切り捨てて整数で出力してください。

```:入力形式
X
```

##C
```C
#include<stdio.h>
#include<string.h>
int main() {
  char x[300];
  scanf("%s", x);

  printf("%s\n", strtok(x, "."));
  return 0;
}
```
strtok <- string + tokenなのだと思う。

##C++
```cpp
#include<iostream>
using namespace std;
int main() {
  string x;
  cin>>x;

  for (char c: x) {
    if (c == '.'){
      break;
    }
    cout<<c;
  }
  cout<<endl;
}
```
##C++\<bits/stdc++.h\>
```cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
  string x;
  cin>>x;

  for (char c: x) {
    if (c == '.'){
      break;
    }
    cout<<c;
  }
  cout<<endl;
}
```
##Python3
```python
x = input()

print(x.split('.')[0])
```

##Haskell
編集中

##Racket
```racket
#lang racket
(define x (read-line (current-input-port) 'any))

(display (first (string-split x ".")))
(newline)
```

##Vim
編集中


#参考にさせていただいたページ
- https://atcoder.jp/contests/abc196/tasks/abc196_b
- https://stackoverflow.com/questions/8119949/best-way-to-do-input-with-racket

#感想
もう少し慣れたら書き直したい。。
Windows10で、ウインドウを最前面に設定／解除する方法

Pythonで、Windows10のアプリケーションを最前面に表示／解除させる方法です。

以下のパッケージが必要です。

```python
pip install pywin32
```

importするのはpywin32ではなく、win32guiとなります。

```python
import win32gui

# ウインドウのハンドルを取得する
hwnd = win32gui.FindWindow(None, title) # windowのハンドルを取得

#  最前面表示の設定
win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0,
                      0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
# 最前面表示の解除
win32gui.SetWindowPos(self.hwnd, win32con.HWND_NOTOPMOST, 0,
                      0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
```

titleにはウインドウタイトルを入れてることで、それをキーにウインドウハンドルが取得できます。


（参考）
https://office54.net/python/app/windows-foreground-active
https://blog.goo.ne.jp/masaki_goo_2006/e/6ddf4977ba01dd11d6be256c17cc2ccf
C#で特定の日時を過ぎたら開けなくする[WPF]

参照：
https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime.compare
<h2>コード</h2>

```C#
DateTime date1 = DateTime.Now;//現在時刻取得
DateTime date2 = new DateTime(2030, 1, 1, 0, 0, 0);//対象先の日付時刻設定(左から、年、月、日、時、分)
int result = DateTime.Compare(date1, date2);//比較

if (result < 0)
{
//現在時刻が対象先の日付時刻よりも早い場合の処理

}
else
{
//現在時刻が対象先の日付時刻よりも遅い場合の処理
    Close();//アプリケーション終了
}
```

<h2>注意点</h2>
PCの設定で日付を意図的に遅らせた場合は動作しない可能性がありますのでご注意ください。
<a href="https://qiita.com/aapython">aapython</a>はこのコードを使用したことによるいかなる責任を負いません。
SQLの練習

#カラムの追加
alter table テーブル名 add column 名前　型
# レコードの追加
insert into テーブル名()　values ();
# 要素の変更
update テーブル名　set 要素="" where id = "変更する箇所";
＊whereがないと全変更になっちゃって面倒なことになる。
#雑感
sqlの学習は楽しい。
データを比べていると、何かしらの気付きがある。
PowerShellでファイル名に作成日時を追加する

　作成日時順にファイルを整理したいときにファイル名の頭に作成日時を追加するスクリプトです。

　PowerShellのスクリプトは基本的にISEかPowerShellの画面を開いて実行します。
　バッチファイルからの起動方法についてはこちら。
　　→　[バッチファイルからPowerShellのスクリプトを起動する](https://qiita.com/harryyuni/items/c7095d0e472d50fdc35e)


```powershell:powershell
Set-Location "C:\Users\user\Pictures\My Cloud"
$movieFiles=Get-Childitem "*.MTS" -File
$movieFiles|foreach{
                    $newName=$_.LastWriteTime.ToString("yyyyMMdd-HHmmss")+$_.Name
                    Rename-Item $_.FullName -NewName $newName
                    }
```

まずはファイルの入っているフォルダに移動します。

```powershell:フォルダ指定
Set-Location "C:\Users\user\Pictures\My Cloud"
```

つぎにファイルの拡張子を指定します。

```powershell:ファイルの拡張子を指定
$movieFiles=Get-Childitem "*.MTS" -File
```

拡張子が表示されていないときは、エクスプローラーの「表示」タブで「ファイル名拡張子」のチェックをします。
![ファイル名拡張子.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622636/8932d332-4675-a749-45c5-0be6d47e247e.png)

```powershell:新しい名前
$newName=$_.LastWriteTime.ToString("yyyyMMdd-HHmmss")+$_.Name
```
　$_.LastWriteTimeはそのままだと日付型なので、ファイル名にするとエラーが出ますから、ToStringやformatで文字列型に変換します。
 日付のみをファイル名にすると、同じ作成日のファイルがあるとエラーになるので、+$_.Nameと元々のファイル名を後ろにつけることでエラー回避しています。拡張子も加えられます。

　yyyyMMdd-HHmmssをyyyymmdd-HHmmssと記載しないよう気をつけてください。
　Windows系の言語は基本的に大文字小文字を区別しないので私含めて意識しない人が多いと思いますが、mmは分、MMは月なので、MMを小文字にすると年"分"日となってしまいます。
　ちなみに、HHをhhとしても２４時間表記が１２時間表記になるだけなので影響は少ないです。
GitHub Actions内でdocker-compose execコマンド実行したときに"the input device is not a TTY"エラーが出たときの解決法

# はじめに
githubactionでdocker-compose exec コマンドを普通に利用すると

```
the input device is not a TTY
```
のようなエラーが発生してしまう。

今回はその解決方法を示す。

# 解決方法
docker-composeコマンドに`-T` オプションをつける！

例）

```
$ docker-compose exec -T [docker-compose service] [コマンド]
```

githubaction内で記述すると、こんな感じです！

```yml:githubactionファイル
name: githubaction sample

 # 省略

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Git checkout current branch #作業ブランチにchekout
      uses: actions/checkout@v2 
      with:
        ref: ${{ github.ref }}
    - name: docker compose exec command sample
      run:  docker-compose up -d &&
            docker-compose exec -T [docker-compose service] [コマンド]
```

以上です！
みなさんの問題解決につながればと思います。
AppSyncのパプラインリゾルバーを使ってみる

## パイプラインリゾルバーとは
- フィールドに対して複数のリゾルバーを利用したパイプライン状の処理を行うことができる機能
- リゾルバーの処理は関数として定義し、クエリ実行時にDynamodbデータソースとした処理を実行（関数１） → 実行結果の値を用いて異なるデータソースを利用して（例えばlambda等）の処理を行う（関数２）→ 処理結果をレスポンスとして返す、といったことが可能

ドキュメント：https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/pipeline-resolvers.html

> AWS AppSync は GraphQL フィールドに対してリゾルバーを実行します。場合によっては、アプリケーションは 1 つの GraphQL フィールドを解決するために複数のオペレーションを実行する必要があります。パイプラインリゾルバーを使用すると、開発者はオペレーション (関数と呼ばれる) を構成して順番に実行できます。


## パイプラインリゾルバーの構成
- Before マッピングテンプレート → 関数（複数設定可能）→ After マッピングテンプレート という順番で処理が行われる
- Apache Velocity Template Language (VTL) ユーティリティの利用ができ、\$ctx.stash のようにパイプラインリゾルバー内で共通で利用できるMapオブジェクトオブジェクトが利用できたり、パイプラインで実行された前のオペレーション結果を取得できる $ctx.prev.result 等が利用可能

### Before マッピングテンプレート
- 関数を実行する前の処理を行うことが可能

### 関数
- リゾルバーの設定と同じように、データソースの選択、リクエストマッピングテンプレート、レスポンスマッピングテンプレートを設定する
- パイプレインリゾルバーでは、複数の関数の定義が可能

### After マッピングテンプレート
- 最後の関数の出力から、最終きなレスポンスを返すための処理を記述する

## パイプラインリゾルバーを作ってみる

- 新規にAppSyncのアプリケーションを作成し、パイプラインリゾルバーを作ってみる。関数の利用の確認がしたかったため、関数で指定するデータソースは「None」を設定して動作確認をしてみた

### スキーマ定義の作成

```Graphql
type Query {
	result(before: String, function: String, after: String): Result
}

type Result {
	before: String
	function: String
	after: String
}

schema {
	query: Query
}
```

### リゾルバの設定
- クエリのリゾルバの設定画面を開き、「パイプラインリゾルバーに変換します」をクリックし、パイプラインリゾルバーの作成画面を開き、パイプラインリゾルバーの設定を行っていく


### Before マッピングテンプレート
- ここでは$ctx.stash.putを利用して、パイプラインリゾルバーで共通で利用できるMapに対し、関数で利用するための値を追加しておく

```
$util.qr($ctx.stash.put("before", "before"))
{}
```

### 関数の作成・追加
- サイドメニューの関数または、パイプラインリゾルバーの画面から、関数の作成を行う

### データソース
- Noneを選択

### リクエストテンプレートマッピング
- payloadを定義することで、レスポンステンプレートマッピングの処理時の $context.result に値が格納される。ここではfunctionという値を追加している

```
{
    "payload": {
        "function": $util.toJson("function")
    }
}
```

### レスポンステンプレートマッピング
- Beforeマッピングテンプレートにで $ctx.stash.before に入れた値を関数の実行結果に追加している

```
$util.qr($ctx.result.put("before", $ctx.stash.before))
$util.toJson($ctx.result)
```

### After マッピングテンプレート
- 前の処理（ここでは関数を指している）の処理結果が格納されている $ctx.prev.result に対して、afterという値を追加している

```
$util.qr($ctx.prev.result.put("after", "after"))
$util.toJson($ctx.prev.result)
```

## クエリの実行
- AWSコンソール上からクエリの実行を行なってみる

```graphql
query MyQuery {
  result {
    before
    function
    after
  }
}
```

- レスポンス
    - パイプラインリゾルバー、VTLユーティリティを使用して入れた値をレスポンスとして取得することができた

```json
{
  "data": {
    "result": {
      "before": "before",
      "function": "function",
      "after": "after"
    }
  }
}
```


## あとがき
- Functionは複数設定することが可能。パイプラインドライバーの動作を確認を行いやすくするために、データソースを「None」に設定したが、関数ごとに異なるデータソースを指定することもできるし、lambda関数等も指定することができるので、クエリ実行時にデータソースから取得したデータを加工してレスポンスとすることも可能
- 今回はクエリに対して設定を行なったが、ミューテーション（登録、更新、削除）に対しても使用することができるため、複数データソースへの処理や、lambda関数を利用してのデータの加工等も可能なので、サーバレスで様々な処理が可能そう

- パイプラインリゾルバー利用のための詳細なチュートリアルも用意されているのでやってみると良さそう
https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/tutorial-pipeline-resolvers.html




## 参考
- https://takumon.com/aws-appsync-pipeline-resolver-with-multiple-dynamodb-tables
- https://dev.classmethod.jp/articles/appsync-updates-11-21/
- https://fintan.jp/?p=4801
- https://thinkami.hatenablog.com/entry/2019/07/03/232547
ServiceNowにデータをインポート／エクスポートする方法

ServiceNowには次の方法でデータを読ませることができる。
要件に合わせてより適切な方法を選択する。

1. Easy Import　簡単だけど手動の操作が必要
1. File import set（手動）
1. Web service import set　（システム連携で利用）
1. Robust import set （複雑だけど一つの読込みから複数のテーブルを更新することが可能）　https://docs.servicenow.com/bundle/paris-platform-administration/page/administer/import-sets/concept/robust-import-set-transformers.html
1. Flow DesignerでRESTステップで読込み
1. Flow DesignerでData Stream
1. Table API
1. Scripted REST API
1. REST Message API
1. 添付ファイル（メール受信）、そこらかテーブルに変換
1. ファイルをGETして添付に書込み、そこらかテーブルに変換
1. MIDサーバを介してFile import set

以上
【Rails】 dependent: :destroy とは

#どんな機能なの？
結論から言うと、dependent: :destroyを使いことによって
**親モデルのレコードを削除する際に、それに紐づく子モデルのレコードも同時に削除されます。**
#具体的な使い方
dependent: :destroyはモデルのアソシエーションで使います。
例えば下記のようにユーザーとマイクロポストのアソシエーションを定義します。

```ruby:user.rb
has_many :mictroposts
```
これだけではユーザーが退会した時、そのユーザーのマイクロポストは残ってしまいます。
そのような場合に下記のようにdependent: :destroyを追加します。

```ruby:user.rb
has_many :mictroposts, dependent: :destroy
```
こうすることでユーザー退会時には、そのユーザーのマイクロポストも同時に削除されます。

#最後に
この機能は他に、いいね機能（いいねした投稿、された投稿が削除された場合、LikeModelのレコードも削除する。）やフォロー機能（フォローしたユーザー、されたユーザーが削除された場合、RelationshipModelのレコードも削除する。）など、アソシエーションをいじる場面でよく出てくるので必ず覚えておきたいですね！

また基本、応用関係なくなるほどと思ったことについて日記感覚で投稿していきます！
ありがとうございました！
AtCoder自分用まとめ007(ABC196A Difference Max

#概要
自分のために、AtCoderで身に付けた内容・コードをまとめておく。

#内容
https://atcoder.jp/contests/abc196/tasks/abc196_a
>整数 a,b,c,d が与えられます。
>a≤x≤b, c≤y≤d となるように整数 x,y を選ぶとき、 x−y の最大値を求めてください。

```:入力形式
a b
c d
```

##C
```C
#include<stdio.h>
int main() {
  int a,b,c,d;
  scanf("%d%d%d%d", &a,&b,&c,&d);

  printf("%d\n", (((b>a)?b:a)-((d>c)?c:d)));
  return 0;
}
```
##C++
```cpp
#include<iostream>
using namespace std;
int main() {
  int a,b,c,d;
  cin>>a>>b>>c>>d;

  cout<<max(a, b)-min(c, d)<<endl;
}
```
##C++\<bits/stdc++.h\>
```cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
  int a,b,c,d;
  cin>>a>>b>>c>>d;

  cout<<max(a, b)-min(c, d)<<endl;
}
```
##Python3
```python
a, b = map(int, input().split())
c, d = map(int, input().split())

print(max(a, b)-min(c, d))
```
##Haskell
編集中

##Racket
```racket
#lang racket
(define a (read))
(define b (read))
(define c (read))
(define d (read))
(display (- (max a b) (min c d)))
(newline)
```

##Vim
編集中


#参考にさせていただいたページ
- https://atcoder.jp/contests/abc196/tasks/abc196_a


#感想
もう少し慣れたら書き直したい。。
【Vue3】外部サイトからの遷移でクエリパラメータを受け取る（Vue Router4）

## 概要
- Vue3.0系（Vue Router4）で実装するにあたり、他ページから遷移してきた際に、クエリパラーメータを取得する方法

## 注意点
- 今回は簡潔に書くためにRouter周りもmain.tsに書いているが他に分割した方が望ましい
- セキュリティの観点からは最悪なソースですw　あくまで説明用のため

## サンプルコード
下記はmain.tsを想定しています.

```
import { createApp } from 'vue'
import { createRouter } from 'vue-router'
import Login from './components/templates/LoginTemplate.vue'
import App from './App.vue'

const router = createRouter({
  routes: [
    { path: '/', component: App },
    { path: '/login', component: Login },
  ]
})

router.beforeEach((to, from, next) => {
  // toからqueryを取得できます
  const auth = to.query.auth
  if (!auth) {
    next({ path: '/login', query: { redirect: to.fullPath } })
  }
})

const app = createApp(App)
app.use(router)
app.use(Store)
app.mount('#app')
```

## 解説
まずVue Router4では`createRouter`を使ってルーターインスタンスを生成します.

```
const router = createRouter({
  routes: [
    { path: '/', component: App },
    { path: '/login', component: Login },
  ]
})
```

`beforeEach`はそれぞれの画面に遷移する前に行う処理を記述できます.
下記の処理は、もしクエリパラメータとして`auth`がなければログイン画面にリダイレクトさせるというものです.
詳しい説明は省きますが`to`、`from`はいずれも[`RouteLocationNormalized`](https://next.router.vuejs.org/api/index.html#routelocationnormalized)というオブジェクトです. そのオブジェクトのメンバーの１つとして`query`があるので、そこから取得をします.

```
router.beforeEach((to, from, next) => {
  // toからqueryを取得できます
  const auth = to.query.auth
  if (!auth) {
    next({ path: '/login', query: { redirect: to.fullPath } })
  }
})
```

## 参考
- API Reference: https://next.router.vuejs.org/api/index.html

## あとがき
Vue3.0系はまだまだ参考になる記事が少ないですね。
Vueエンジニアの方々一緒に頑張りましょう〜
【blender2.92】コンポジティングで霧の表現【compositing】

# 下記動画のとおりに、コンポジティングで霧の表現をしてみました。(blender2.92使用)
Con Koumisさんの動画　「Blender 2.9, Mist, color and texture.」
[動画URLはコチラ](https://www.youtube.com/watch?v=pjGIbdKSf4o&t=137s)

## コンポジティングのノードはこんな感じ(基本的には動画をトレース)
![コンポジティング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/f9afc16f-8f93-5d5c-63dc-1bb7e7bb4458.png)

## 霧の位置関係的な比較画像
### 奥にある
![rendering0321_a01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/c459b9e6-0be9-927b-3f12-44026eef8736.png)
### 手前にある
![rendering0321_a02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/3e5488fa-6513-77d0-bdc0-3689bdc7162f.png)
【mailgun】独自ドメインを利用した独自メールアドレスを作成する方法 

Djangoを使ったwebアプリを作っているのですが、ユーザー登録時に仮登録からのメールリンクで本登録するものを実装しようと思いました。

その過程で独自ドメインのメールアドレスを作成する方法に苦戦したのでまとめました。

独自ドメインを使ってDjangoからメール送信する方法については後日まとめようと思います。

## 実現したいこと
- mailgunを使い独自ドメインのメールアドレスを作成する

## 前提条件
- 独自ドメインの取得が完了している
- レンタルサーバーの構築が完了している
- 独自ドメインとレンタルサーバーの紐付けが完了している

## 作業環境
- OS
    - CentOS7
- webサーバー
    - Nginx
- 言語
    - Python
- フレームワーク
    - Django

## 参考サイト

- [Mailgunを使ってDjangoのアプリからメールを送信する](https://developer.yukimonkey.com/article/20200320/)

手順は以下の通りです。

## 手順
1. mailgunにアカウント登録
2. サブドメイン設定
    1. レンタルサーバーにサブドメイン作成
    2. mailgunでサブドメイン登録
    3. レンタルサーバーにレコード登録
    4. mailgunでレコード確認
3. メールアドレスの作成
4. メール受信は有料

### 1. mailgunにアカウント登録
mailgunというサービスに登録していきます。
新規登録は[こちら](https://signup.mailgun.com/new/signup)から。
クレジットカードを登録することになりますが、最初の3ヶ月間、5000通までは無料なので安心してください。
3ヶ月後は有料になりますので、忘れないようにカレンダーにメモしておきましょう。

### 2. サブドメイン設定
次にメールアドレス用にサブドメインを設定していきます。
このサブドメインはメールアドレスの＠以下になります。
（例）my_mail@mail.mydomain.comというメールアドレスがあるとすると
mail.myadomain.comが今から設定するサブドメインになります。
ドメイン自体はすでに取得しているのでmail.を設定していくことになります。

#### 1. レンタルサーバーにサブドメイン作成
私が使っているさくらのVPSでは[こちら](https://secure.sakura.ad.jp/menu/dns/)から作成することができます。
ゾーン設定→エントリの追加と変更に作成したいサブドメイン名を記入(mail)→種別を別名(CNAME)に変更新規登録

#### 2. mailgunでサブドメイン登録
次にmailgunにサブドメインを登録していきます。
https://app.mailgun.com/app/sending/domains/new

mail.mydomain.comを入力してボタンをクリック
登録完了です。
左側のDomain SettingsをクリックしてDNS recordsをクリックします。
TXTレコードが確認できればOKです。
TXTレコードのEnter this valueをコピーしておきます。

#### 3. レンタルサーバーにレコード登録
レンタルサーバーに戻ります。
[こちら](https://secure.sakura.ad.jp/menu/dns/)から先ほどのサブドメインにレコードを登録していきます。

先ほど登録したサブドメインをエントリ名に記入します。
種別はTXTを選択
値にコピーしたものを貼り付けます。
TXTレコードは2つあるので2回行ってください。

#### 4. mailgunでレコード確認
レンタルサーバーにレコード登録を行ったらmailgunで接続確認を行います。
確認は簡単で、先ほどのDNS recordsの右上にあるVerify DNS Settingsボタンをクリックするだけです。
TXTレコードにチェックマークが付くと接続が完了していることになります。

登録したレコードが反映されるまで時間がかかりますので、チェックマークがつかなくても焦らないようにしましょう。
反映までに24~48時間ほどかかるようです。

### 3. メールアドレスの作成
mailgunでTXTレコードにチェックマークがついたら、次はSMTP credentialsをクリックします。
DNS recordsの右にあります。
右上のAdd new SMTP userをクリックしてメールアドレスを登録します。

これで独自ドメインを利用した独自メールアドレスの作成が完了です。

### 4. メール受信は有料
最後に補足としてmailgunは無料プランだとメールの送信はできるものの受信をすることができません。
webアプリに組み込む時は有料プランへのアップグレードが必要です。

## 参考サイト
- [Mailgunを使ってDjangoのアプリからメールを送信する](https://developer.yukimonkey.com/article/20200320/)

## 質問などがあればコメントをお願いします。
RubyonRailsで画像を投稿する機能を実装したいときに行うことまとめ

RubyonRailsで画像を投稿できるようにするための事前準備まとめ。
画面上にFormを表示させたりする部分は一旦除外。別途書くかも。

brew install imagemagick　でImageMagickをインストールする
※Homebrewのインストール方法はターミナルから下記を実行する。
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

※ImageMagickとはコマンドで画像生成、サイズ変更、拡張子の変更などが可能になるソフトウェア。
　GemではないのでGemfileに追記してbundle installを行うのではなく、Homebrewでインストールする。

Gemfileの一番下に下記2行を追記してbundle installを実行する。
gem 'mini_magick'
gem 'image_processing', '~> 1.2'

※MiniMagickとはImageMagickの機能をRubyonRailsで使えるようにするGem。ただしサイズ変更はできない。
※ImageProcessingとは画像のサイズ変更をRubyonRailで可能にするGemのこと。

ターミナルで　rails active_storage:install　→　rails db:migrate　の順に実行し
ActiveStorageを使えるようにする。
※ActiveStorageとはRailsでファイルアップロードの実装を簡単にするGem。画像のアップロードを簡単にする
　メソッドや画像を保存するテーブルを簡単に作成できる。

画像を保存したいモデルに has_one_attached :image　を記載する。
例）ツイッターのようなアプリでtweetモデルがある場合、app/model/tweet.rbに記載する。

画像を保存したいコントローラのストロングパラメータのpermitに:imageを追加する。
例）ツイッターのようなアプリでtweetコントローラがある場合、tweet_controller.rbに書く。

★いったんここまで2021/3/21
Dockerとdocker-compose



# はじめに
<!-- 発端や概要を記載 -->
Dockerについて学習したので記録として簡単に残します。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [Dockerとは？](#Chapter1)
1. [docker-composeとは？](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# Dockerとは？
Dockerとはコンテナ型の仮想環境を実行するためのプラットフォームとなっている。

VirtualBoxとの比較
![スクリーンショット 2021-03-21 17.08.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/97f123ff-548f-887d-c619-345785db6aee.png)


・ゲストOSを立ち上げない
・入出力をエミュレートしない


Dockerのメリット

・CPUのリソースを抑えられる
・バージョンを管理しやすい
・サーバーをいつでもリセットできる


Dockerの注意点
・土台となるOS以外だと動かない
・複数のディストリビューションを起動させることができない






<a id="#Chapter2"></a>
# docker-composeとは？
・Dockerのコンテナを複数同時に操るための便利なツール
・ymlファイルを利用してDockerに指示を出す
・簡単なコマンドで複数のコンテナを操作することが可能


<a id="#reference"></a>
# 参考文献
- [さくらのナレッジ　Docker入門（第一回）～Dockerとは何か、何が良いのか～
](https://knowledge.sakura.ad.jp/13265/)
- [さくらのナレッジ　Docker入門（第六回）〜Docker Compose〜
](https://knowledge.sakura.ad.jp/16862/)
VirtualBoxで仮想マシンを起動する際にKernel driver not installed (rc=-1908)と表示された場合（2021.3.21）

#背景
Linux標準教科書[^1]の学習を始めるにあたり、VirtualBoxで立てた仮想マシン上にCentOSをインストールすることにしましたが、仮想マシンを起動する際にエラーが発生したので対処方法を備忘録として残しておきます。
[^1]: [Linux標準教科書](https://linuc.org/textbooks/linux/)

#前提
* Macbook pro：macOS Big Sur バージョン11.2.1
* VirtualBox：バージョン6.1.18

#事象
ひと通り仮想マシン設定を終え、いざ起動しようとすると以下のようなエラーが。
「仮想マシン"[仮想マシン名]"のセッションを開けませんでした。」
「Kernel driver not installed (rc=-1908)　...以下略」
<img width="600" alt="スクリーンショット 2021-03-01 0.26.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226970/e8dd628e-9e66-028f-2313-db909e78bab8.png">
<img width="600" alt="スクリーンショット 2021-03-01 0.27.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226970/345d1477-8a9b-627d-d795-c78c1a8eea41.png">

#原因と対応方法
どうやらうちの賢いMacbookちゃんが得体の知れないアプリケーションの実行をブロックしてくれていたみたいでした。
「これは大丈夫なアプリケーションだから実行していいんだよ」というのを教えてあげるために、[システム環境設定]-[セキュリティとプライバシー]からアプリケーションの実行を許可しておく必要があります。
<img width="600" alt="スクリーンショット_2021-03-01_0_32_45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226970/909c040d-198c-101a-caf0-03fd3d596509.png">
<img width="600" alt="スクリーンショット_2021-03-01_0_32_37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226970/883009c3-5255-1ad8-5514-a1ae27239547.png">
上記の対応を行なった結果、エラーが発生していた仮想マシンを問題なく起動させることができました。

#補足
１．
[セキュリティとプライバシー]の画面に「許可」ボタンが表示されるのは、VirtualBoxのインストール後30分間のみのようです。
その場合は、一度VirtualBoxをアンインストールし、再度インストールすると「許可」ボタンが出てくると思います。

２．
今回発生したものと同一のエラーが、別の原因によって発生することもあるようです。
上記の対応方法で解決しない場合は別の原因が考えられます。
別の対応方法について解説しているページもありましたので、参考にしてください。
　・[VirtualBoxで「kernel driver not installed」エラーが出てOSが起動できない際の対処方法](https://kugenuma-3c-design.jp/mac%E9%96%A2%E9%80%A3/2421/)
　・[VirtualBoxでKernel driver not installed (rc=-1908)とエラーが出たとき](https://qiita.com/Buuuchi408/items/021d211d44207bc1f5d1)
　・[Virtualbox起動時にKernel driver not installed (rc=-1908)になったら](https://haiju.hatenablog.com/entry/2017/05/23/073723)
Firebase Cloud Functions × TypeScript

## Firebase CLI インストール
```
$ npm install -g firebase-tools
```

## Firebase ログイン
```
$ firebase login
```

## Firebase Cloud Functions
```
$ firebase init functions
```

## ESLintパッケージ インストール
```
$ npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier eslint-config-prettier eslint-plugin-prettier
```

## .eslintrc.json
```:.eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
    "prettier/@typescript-eslint"
  ],
  "plugins": [
    "@typescript-eslint"
  ],
  "env": { "node": true, "es6": true },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "sourceType": "module",
    "project": "./tsconfig.json"
  },
  "rules": {
  }
}
```

## Linter 実行
```
$ npm run lint:fix
$ npm run lint
```

## onUpdate関数
```index.ts
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";

/**
cloudFirestore 設定
*/
admin.initializeApp(functions.config().firebase);
const f = functions.region("us-central1");

/**
onUpdate関数 設定
*/
export const onUpdate =
  f.firestore.document("test/test1")
      .onUpdate(async (change, context) => {
        const data = change.after.data();
        const sample = data.sample;

        const ansRef = sample.replace(/\r?\n/g, "");

        return change.after.ref.set({
          sample: ansRef,
        }, {merge: true});
      });
```

## デプロイ
```
$ npm run deploy
```

## 参考文献
 - [【Flutter】(はじめて)Cloud Functions for Firebaseを使ってFirestoreのデータを定期的に更新してみた](https://qiita.com/yusuke_vp/items/39f5f15bbca32998a127)
 - [Cloud Functions を TypeScript で書く](https://qiita.com/star__hoshi/items/7dcf5970d28a7ff239fb)
 - [脱TSLintして、ESLint TypeScript Plugin に移行する](https://qiita.com/suzuki_sh/items/fe9b60c4f9e1dbc5d903)
 - [Cloud functions + typescriptでファイル分割を行う方法（あとレスポンスの改善とか）](https://qiita.com/gaku3601/items/4c887f30804ce8c83cbe)
 - [CloudFunctionsをきれいに整理したい。](https://qiita.com/1amageek/items/b93f8e4d99e3b6f423aa)
 - [改行をすべて削除する](https://javascript.step-learn.com/contents/J058-rn-delete.html)
 - [Cloud Firestore トリガー](https://firebase.google.com/docs/functions/firestore-events?hl=ja)
/dev/loopに容量が圧迫されてrails testができない問題...

cloud9のterminalでrails testを実行しようとしたら何と12ものエラーが...

備忘録として、またその他どなたかのお役に立てればと思い、記事を書いていきます。

キャプチャを失念しており、ほとんど文章での説明になりわかりにくいかと思いますが、ご容赦のほどお願いいたします。
では、書いていきます！

【1.状況】
AWSでrails testの実行時に12ものエラーが発生し、以下のメッセージが登場。
⇒　Error:「No spacd left on device」
　 
【2.状況分析】
→ 上記1.について色々調べていくと、どうにも容量不足のようです。

　　容量不足とは、主に以下2つのいずれかを指します。
　　①　ディスク容量の不足
　　②　「inode」の容量不足

　　ここで、「inode」とは要するに、ファイル情報(誰が、いつetc...などのプロパティ的な
　　情報)を管理するためのデータであるとのこと。

 　　  従って、この2つの内、どちらが原因であるのかを見極めることが必要です。
　　
　　それぞれ、以下に示すコマンドをterminalで実行すれば、容量が確認できます。
　
　　・　①の場合　
　　　 2-1) $ df　
　　
　　・　②の場合
　　　 2-2) $ df -i
　　
　　その結果、私の場合、②のパターンであることが分かりました。

　　 内容を見ていくと、以下5つのディレクトリが使用率100%と判明。。。
 　　　   ・/dev/xvda1
　　　・/dev/loop1
　　　・/dev/loop2
　　　・/dev/loop3
　　　・/dev/loop4

　　と分かれば、これらディレクトリを消去すればよいことになります。

【3.対策】
　
　　ターミナルで以下コマンドを実行すれば、ディレクトリを消去できます。

　　$ sudo rm -d ディレクトリ名
　　
　　今回の場合、/dev以下の階層を消去すれば良いので、
　　3-1) $ sudo rm -d /dev
  　　 を実行。　※ rmはremove、dは(おそらく)ディレクトリの略

　　これで、完了…と思いきや/devに格納されている全部のファイルに
　　以下のエラー発生。
   　　 Error:Operation not Permitted

  　　この事象について調べていくと、どうにも上記2.の/devディレクトリに
   　　ファイルを実行する権限が与えられていないことが原因であるとのこと。

　　そこで、/devディレクトリにファイルの実行権限を与える操作を行います。

　　そのためのコマンドを以下示します。
　　$ sudo chmod モード ファイル名(ディレクトリ名)

　　ここでいう、モードとは3桁の数字abcであるとのこと。

   　　　a:「所有者」の権限
   　　　b:「所有グループ」の権限
   　　　c:「その他」

  　　 ここで、abcの各桁には以下数字の合計値が入ります。
　　
　　モード(数字)   　　モード(アルファベット)  　　　権限
　　　  4             　　　　　　　　　  r         　　　　　　　　　読み取り
    　　　   2            　　　　　　　　　   w　　　   　　　　　 書き込み
      　　　 1              　　　　　　　　　 x       　　　　　　　　　   実行

　　つまり、実行だけが必要なら1、読み取りと実行が必要なら4+1=5、
　　何も必要なければ、0が入ります。

　　今回は、「所有者」と「その他」に全機能を付与したかったので、707としました。

　　従って、以下3-2)のコマンドをターミナルで実行しました。
　　3-2) $ sudo chmod 707 /dev

　　そして、再び3-1）を実行した後に2-1)を実行し、
　　フォルダ内を確認します。

　　以下の画像のように/devが消去され、容量が開放されたと思われます。
　　![スクリーンショット 2021-03-21 16.54.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040076/07b2ebf1-dfcd-ece4-a7bb-b2ba3ca13d25.png)

　　確認のため、rails testを実行します。
　　![スクリーンショット 2021-03-21 16.54.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040076/8303daf7-969d-91ee-de43-50dd1bf0d80c.png)

　　エラーがなくなり、晴れて問題が解消されました。

以上となります、イメージがつきにくかったかもしれませんが、ご参考になりますと幸いです。
それでは、また！

参照先
https://qiita.com/shisama/items/5f4c4fa768642aad9e06
https://mem-archive.com/2019/07/28/post-1976/
https://itojisan.xyz/trouble/15772/#2_inode
https://www.souichi.club/aws/out-of-disk-space/
shellでmakeのようにターゲットを指定して実行する

# 背景
makeがインストールされていない環境でmakeのようにターゲットを指定して処理を実行したいことがある。shellで引数にターゲットを指定して特定の処理のみを実行したり、複数のターゲットを連続で実行できるようにする。

# 環境
- Ubuntu 18.04.5
- dashまたはbash

# 実装
shell scriptの名前を `build.sh` とする。

```
$ cat build.sh
#!/bin/sh

top_dir="$( cd "$( dirname "$0" )" >/dev/null 2>&1 && pwd )"
cd $top_dir

help()
{
  echo "usage : $0 [target]..."
        echo "   all   : execute all target"
        echo "   build : build"
        echo "   test  : test"
        echo "   clean : clean"
        echo ""
        echo "   help  : show this message"
}

all()
{
  build
}

build()
{
        echo build
}

test()
{
  echo test
}

clean()
{
  echo clean
}

if [ "$#" = "0" ]; then
  help
fi

for target in "$@" ; do
  LANG=C type $target | grep function > /dev/null 2>&1
  res=$?
  if [ "x$res" = "x0" ]; then
    $target
  else
    echo "$target is not a shell function"
    exit $res
  fi
done
```

# 解説
## ディレクトリの移動
shell scriptが配置されているディレクトリに移動する。

```
#!/bin/sh

top_dir="$( cd "$( dirname "$0" )" >/dev/null 2>&1 && pwd )"
cd $top_dir
```

## 関数の実装
処理単位をshellの関数とする。

```
help()
{
  echo "usage : $0 [target]..."
        echo "   all   : execute all target"
        echo "   build : build"
        echo "   test  : test"
        echo "   clean : clean"
        echo ""
        echo "   help  : show this message"
}

all()
{
  build
}

build()
{
        echo build
}

test()
{
  echo test
}

clean()
{
  echo clean
}
```

## ヘルプ
引数が無いときはヘルプを表示する。

```
if [ "$#" = "0" ]; then
  help
fi
```

## ターゲットの呼び出し
for文で引数のターゲット毎に関数の有無をチェックする。
typeコマンドでコマンドがbuiltinコマンドなのか、shell関数なのかを判別する。
grepが文字列 "function" を検出したときは そのターゲットが関数と判断し、その関数を呼び出す。

```
for target in "$@" ; do
  LANG=C type $target | grep function > /dev/null 2>&1
  res=$?
  if [ "x$res" = "x0" ]; then
    $target
  else
    echo "$target is not a shell function"
    exit $res
  fi
done
```

## 使用例
### 引数なし
ヘルプメッセージが表示される。

```
$ sh build.sh
usage : build.sh [target]...
   all   : execute all target
   build : build
   test  : test
   clean : clean

   help  : show this message
```

### Build
```
$ sh build.sh build
build

$ sh build.sh clean
clean

$ sh build.sh test
test
```

### 連続実行
複数のターゲットを順に実行する。

```
$ sh build.sh all clean test
build
clean
test
```

### エラー
不正なターゲットの場合は停止する。

```
$ sh build.sh all hoge test
build
hoge is not a shell function
```
Gatsbyで作成したページを転送する


Gatsby で作成したページをリダイレクトしたい場合、ホスティング先で設定が必要であったが、 Gatsby のプラグインを設定することで対応することも可能です。

プラグインの設定方法などをまとめました。

## プラグインの追加

（2021/3/21 時点）今回追加する `gatsby-redirect-from` は内部で `gatsby-plugin-meta-redirect` に依存しているため 2 つパッケージの追加が必要となります。

### Yarn を利用している場合

```zsh
npm i gatsby-redirect-from gatsby-plugin-meta-redirect
```

### Npm を利用している場合

```zsh
npm i gatsby-redirect-from gatsby-plugin-meta-redirect
```

## プラグインの設定

先程追加した、プラグインの設定を以下ファイルに追記します。

```js:gatsby-config.js
plugins: [
  'gatsby-redirect-from',
  'gatsby-plugin-meta-redirect',
]
```

### `MarkdownRemark` ではなく `Mdx` を利用している場合

query option に `allMdx` を渡して下さい

```js:gatsby-config.js
plugins: [
  {
    resolve: 'gatsby-redirect-from',
    options: {
      query: 'allMdx'
    }
  },
  'gatsby-plugin-meta-redirect',
]
```

## Markdown ファイルに転送設定を追求

今回は、 `old-sample-markdown.md` と言うファイルを `old-sample-markdown.md` に変更した場合の例を記載します。

Markdown の先頭に `redirect_from` の記述を追加します。

```md:sample-markdown.md
---
title: Sample Markdown
redirect_from:
  - /old-sample-markdown/
---
```

設定を追加し、再度 build など実施すると旧 URL にアクセスした際に、新 URL にリダイレクトされるようになりました。

## その他補足

もし、 Netlify を利用しており、このプラグインを利用ぜず転送設定を行いたい場合は以下ドキュメントを参照してください。

https://docs.netlify.com/routing/redirects/

今回記載する内容は、同一サイト内のパス変更だけの対応です。異なるドメインへのリダイレクト等は各ホスティングサービスが提供するリダイレクト設定を使用して下さい。

## 使用した plugin や ドキュメント

https://github.com/kremalicious/gatsby-redirect-from

https://kremalicious.com/gatsby-redirect-from