OmniAICreator/Qiita-1.07M huggingface dataset:
Mysqlに接続できない時のTips

### エラー内容
Railsの開発中に突然mysqlにアクセスを阻まれる。。orz
`Mysql2::Error: Can't connect to local MySQL `
よく見るエラーですね。解消しましょう。

```
#入力コマンド
// mysqlの停止
$ sudo service mysql stop

// セーフモードでmysqlの起動
$ sudo mysqld_safe --skip-grant-tables &
[1] 17586

2019-05-21T07:14:21.943446Z mysqld_safe Logging to syslog.
2019-05-21T07:14:21.948065Z mysqld_safe Logging to '/var/log/mysql/error.log'.
2019-05-21T07:14:21.951694Z mysqld_safe Directory '/var/run/mysqld' for UNIX socket file don't exists.

[1]+  Exit 1                  sudo mysqld_safe --skip-grant-tables

```

`'/var/run/mysqld' for UNIX socket file don't exists.`
どうやら「ソケットファイルがないよ」と言ったエラーが起きているらしい。

作ろう！

### 解決コマンド
```
$ sudo mkdir /var/run/mysqld
$ sudo chown mysql:mysql /var/run/mysqld
```

接続の確認ができる。
※ときどき、時間が解決する時があって困る。(時間が経つと、mysqlに接続できる)

参考：
[MySQLサーバにログインできないとき](https://qiita.com/ferretdayo/items/98b615abf5ade60dac77)
[stackoverflow](https://stackoverflow.com/questions/42153059/mysqld-safe-directory-var-run-mysqld-for-unix-socket-file-dont-exists)


#### もしかすると...(他に考えられること)
```:エラー画面
Can't connect to MySQL server on DBサーバー~~~~~
```
- DB側でセキュリティグループの設定をしていてIP制限しているかも！
- セキュリティグループで解放しているwifiに接続し直せばOK
コントローラからViewに値を渡す

#ビューの作成
ビューはアプリケーションとして動作するHTMLにより構成されており、コントローラ/アプリケーションロジックをプレゼンテーションロジックから分離します。ビューは```resources/views```ディレクトリに保存する。

```php:resources/view/greeting.blade.php

<html>
  <body>
     <h1>Hello,{{$name}}</h1>
  </body>
</html>
```
このビューを```resources/views/greeting.blade.php```として保存しているので以下のようにグローバル```view```ヘルパ関数を使用し結果を返す。

```php
Route::get(`/`,function(){
  Return view (`greeting`,[`name` => `James]);
});
```

```view```ヘルパに渡している最初の引数は```resources/views```ディレクトリ中のビューファイル名に対応している。

二つ目の引数はビューで使用するデータの配列。上記の例ではビューに```name```変数を渡しそれをBlade記法を使用しているビューの中に表示される。

#ビューにデータを渡す

簡単にデータを配列でビューに渡せる。

```php
return view(`greetings`,[`name` => `Victoria`]);
```

この方法で情報を渡す場合その情報はキー/値ペアの配列。ビューの中で各値へは対抗するキーへアクセスできる。例えば```<?php echo $key; ?>のように表示可能。全データを```view```ヘルパ関数に渡す代わりに``with```メソッドでビューに渡すデータを個別に追加することもできる。

```php
return view(`greeting`)->with(`name`,`Victoria`);
```
#参照
https://readouble.com/laravel/5.7/ja/views.html
Desktop : OpenCV Merge Two Image

<h5>Goal</h5>
Test OpenCV to merge two images.

```OpenCV_MergeTwoImage.java
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.imgcodecs.Imgcodecs;

public class OpenCV_MergeTwoImage {

    public static void main( String[] args )
    {
        try{
            System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
            Mat source = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\ncku.jpg",Imgcodecs.CV_LOAD_IMAGE_COLOR);
            Mat source1 = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\jelly_studio_logo.jpg",Imgcodecs.CV_LOAD_IMAGE_COLOR);
            Mat destination=source.clone();

            //Imgproc.resize
            Rect roi=new Rect(50,50,90,62);
            Mat destinationROI = source.submat( roi );
            source1.copyTo( destinationROI , source1);

            Imgcodecs.imwrite("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\merge2.jpg", source);
        }catch (Exception e) {
            System.out.println("error: " + e.getMessage());
        }
    }
}
```
<h5>Result</h5>
![merge2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276243/de1bce91-dfa2-5b84-350f-1ac13b9a0af1.jpeg)
【解決】You must use Bundler 2 or greater with this lockfile.

`You must use Bundler 2 or greater with this lockfile.`が出た場合の対策。`You must use Bundler 2 or greater with this lockfile.`が出る原因は`bundle install`されているgemとそれを管理するbundlerのバージョンが違うことで起こっているみたい

## 解決策

以降でやりたいことは、 **「bunderとインストールするgemのバージョンを合わせるということ」**

Gemfile.lockを削除

```terminal
$ rm Gemfile.lock
```

アプリ本体にインストールされているgemも念の為削除

```terminal
$ rm -rf vendor/bundle
```

バージョン`2`以上のbundlerをインストール

```terminal
$ gem install bundler -v '2.2.17'
```

```terminal
$ bundle install
```

## bundlerを旧バージョンに合わせる方法

```terminal
$ gem install bundler -v 2.2.17
$ rm -rf Gemfile.lock
$ bundle _2.2.17_ install
```

以上です！
https://stackoverflow.com/questions/53231667/bundler-you-must-use-bundler-2-or-greater-with-this-lockfile/67632652#67632652
https://qiita.com/tanakaworld/items/e15ff9dbdd4b628378c2
https://matoyomi.hatenablog.com/entry/20200106/1578254682
https://qiita.com/yoshijbbsk1121/items/87250501b32c6433943e
https://stackoverflow.com/questions/53231667/bundler-you-must-use-bundler-2-or-greater-with-this-lockfile/57125886
DynamoDB の get-item と delete-item

こちらで作成したテーブルに対しての操作の話です。
[DynamoDB に boto3 で接続 （ハッシュキー、レンジキーを使う）](https://qiita.com/ekzemplaro/items/82b2013bd753ea981173)

get-item で次のようなエラーが出ました。

```text
$ aws dynamodb get-item --table-name tbl_iot --endpoint-url http://localhost:8000 --key '{ "id_device": {"S": "ras003" }  }'

An error occurred (ValidationException) when calling the GetItem operation: The number of conditions on the keys is invalid
```

delete-item でも次のようなエラーが出ます。

```text
$ aws dynamodb delete-item --table-name tbl_iot --endpoint-url http://localhost:8000 --key '{"id_device": {"S": "ras0003"}}'

An error occurred (ValidationException) when calling the DeleteItem operation: The number of conditions on the keys is invalid
```

ハッシュキー、レンジキーを使っているテーブルに対して、get-item, delete-item で ハッシュキー　と レンジキーを 指定しなかったので発生したエラーです。

次のスクリプトならば、エラーは出ません。

```bash:go_get.sh
ARGS="--table-name tbl_iot --endpoint-url http://localhost:8000"
#
aws dynamodb get-item $ARGS \
	--key '{"id_device": {"S": "ras0003"},"timestamp": { "S": "20180122082100" }}'
```

```bash:go_delete.sh
ARGS="--table-name tbl_iot --endpoint-url http://localhost:8000"
#
aws dynamodb delete-item $ARGS \
	 --key '{"id_device": {"S": "ras0003"},"timestamp": { "S": "20180122082200" }}'
```
Trailhead「フォームを使用したデータの入力」に出てくる難しいコントローラ

まとめ：`aura:id`が`expenseform`の`<lightning:input>`タグをすべて検証して、1件でも不正な入力があったらエラーメッセージを表示します。

```
({
    clickCreate: function(component, event, helper) {
        var validExpense = component.find('expenseform').reduce(function (validSoFar, inputCmp) {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validExpense){
            // Create the new expense
            var newExpense = component.get("v.newExpense");
            console.log("Create expense: " + JSON.stringify(newExpense));
            helper.createExpense(component, newExpense);
        }
    }
})
```

チャレンジでもなんでもない中盤に出てくるコントローラですが、前半(if分の手前)がぱっと見で理解できず手が止まったので詳しく記録します。
海外にも同じ悩みを持った方がそこそこいた模様([リンク](https://salesforce.stackexchange.com/questions/184525/help-me-to-undestand-this-lightning-helper-methods-reduce-showhelpmessageifin/184535))。

## reduceメソッド
Qiitaの[評価されている記事](https://qiita.com/chihiro/items/1047e40514a778c08baa)によると、
>隣り合う2つの配列要素に対して左から右へ同時に関数を適用し、単一の値にする。というメソッドです。
>例えば、「配列の中身を一つずつ足していって合計を求める」ということができます。
>構文：array.reduce(callback [, initialValue])

* array： `component.find('expenseform')`
* previous：一つ前の要素またはinitialValue。今回は`validSoFar`にこの値が入っている。
* current：現在処理されている要素。今回は`inputCmp`にこの値が入っている。
* index：現在処理されている要素のインデックス。
* initialValue：省略可能の第二引数の値。今回は'true'が入っている。

`component.find('expenseform')`は`aura:id`が`expenseform`の`<lightning:input>`タグへの参照を配列で取得できます。今回はすべての`<lightning:input>`タグにidが設定されています。


## showHelpMessageIfInvalid()
[公式の文書](https://developer.salesforce.com/docs/component-library/bundle/lightning:input/specification)のSpecificationを見てみましょう。メソッドが5つあります。
`<lightning:input>`が標準で有するメソッドにこれが記述されています。フォームコントロールが無効な状態にある場合にヘルプメッセージを表示します。

## inputCmp.get('v.validity').valid
コンポーネントに含まれている「validity」属性を取得し、さらにこれに含まれる「valid」プロパティを取得しています。公式によれば、このプロパティはBoolean型です。入力値に問題がないときのもTrueになります。
>valid: True if none of the preceding properties are true.

## return validSoFar && inputCmp.get('v.validity').valid;
returnする値は、数値ではなくBooleanです。リンク元では、previousとcurrentの加算値を返していました。
今回は、`validSoFar` (previous)と`inputCmp.get('v.validity').valid`(current)が共にTrueのときにTrueを返し、currentがfalseのとき(入力値に不正があったとき)にfalseを返します。
これを繰り返すということはつまり、ひとつでも不正な入力を検知したら後のループすべてがfalseになるということです。
reduceメソッドは**合計を求めるのではなく、falseが1度でも存在したかどうか**確認するために用いていたのです。
showHelpMessageIfInvalid()は、これを通しさえすれば赤文字エラーメッセージが表示されるということです。
UiPathでセレクターに変数を使う

セレクターに変数を使う方法を紹介します。
今回は↓のようなエキサイトニュースで「芸能カテゴリ」をクリックするという簡単な処理で考えてみます。
![excite_picture.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/c51846e7-3a8f-b281-3978-0fff42ec739a.png)
### 1. 芸能カテゴリのセレクタを変数に代入して実行する。
まず、クリックアクションで芸能カテゴリのセレクタを拾ってきます。
![芸能カテゴリクリック.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/dd2503c2-d4fc-ba39-0511-6ef437f34b96.png)
すると、だいたい↓のようなセレクタになっていると思います。
![芸能カテゴリ_セレクタ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/aeae0107-c828-f2aa-c8ed-ce64c035e362.png)
次に、セレクタを変数に代入してみます。
![セレクタ代入.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/6c724a67-5958-0061-9676-481e457c2df0.png)
 ↑画像のような感じですね。
右辺の詳細は↓です。○を付けた"芸能"を変数に置いていきます。
![セレクタ右辺.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/4f68d759-c85c-afd8-be51-2e29dd9d8fe7.png)
とりあえず、これでまず実行してみるとよいと思います。しっかりクリックされれば第一段階はＯＫです^^
### 2. "芸能"を変数に格納する。
![芸能代入.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/47244b11-d3f1-443d-d3a2-43afc1e01643.png)
こんな感じで'芸能'を文字列型で変数にします。（シングルクオートはセレクタ指定に使う際の仕様です）
次にselector変数に実際のセレクタを代入していきます。
![セレクタ代入.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/b89d0bf9-6c53-8d19-81f0-b55405846ae5.png)
 ↑こんな感じですね。右辺は↓です。![セレクタ代入右辺.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/90aa7aaf-bd25-cc5e-2ea4-7a7724f4285c.png)
これで完了です！
このselector変数をクリックアクションのセレクターに指定してください。

- セレクタ
![芸能セレクタ代入後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253801/7d21cb58-0835-dc1e-bfb7-73be011520f9.png)
データサイエンティストになるための(一変数)複素解析入門-第二回-

#コーシー・リーマンの関係式
##定義
前回の話は正則性についてお話ししました.
今回はコーシー・リーマン関係式からお話しします.
まずは,定義を書くと,
$f(z)=u(x,y)+iv(x,y)$     (3)
に対して,
$\frac{\partial u}{\partial x}=\frac{\partial v}{\partial y}$,$\frac{\partial u}{\partial y}=-\frac{\partial v}{\partial x}$              (4) 
のような式をコーシー・リーマンの関係式という.     
ただし,ここで$u,v$は$z=x+iy$の実部と虚部を構成する実数から構成される.
##性質
コーシー・リーマン関係式が成立し,かつ,$f(z)=u+iv$が全微分可能であることは$f(z)$が正則であるための必要十分条件である.
必要性と十分性の証明は様々な教科書やネット上の記事に譲るとして,ここではこれぐらいで次の章に移る.
#複素積分
##複素積分の定義
複素積分の定義は複素平面上の二点$(a,b)$に関して,
$\int_a^bf(z)dz$という線積分で与えられる.
もちろん,$a,b$をひっくり返せば$-$が全体に付くのは初等解析の場合と一緒である.
##一つの疑問
さて,察しのいい読者ならここで気づくと思われるが,
$(a,b)$の間で線積分を行うとき,その途中経路はどうなっているのだろうか.
今までやってきた積分というのは直線上の軸の上で積分を行うので,区間を二つ定めれば積分区間は自ずと決まった.しかし,複素積分は複素「平面上」,すなわち,二次元平面において二点間を定めて積分を行う,
ならその途中経路(積分を行う区間のこと.今回の場合,$a$と$b$を結ぶ線)は無数にあるではないか!?
そして,無数に経路があるなら,答えも無数にあるではないか!?
積分を行うと無数に答えがある?
このおかしな事実,もちろん誤りがあるのですが,どこが誤っているのか.
次回まで考えてみてください.

次回は今回の解答とコーシーの積分公式からはじめます.
スキルシート

#コントローラー
##アクションを適切に追加できる
コントローラはユーザーからのリクエストを受け取り、モデルやビューなどと連携し結果をユーザーに返す役割をする部分です。

Webページの具体的な処理はコントローラを使って行うのが基本です。コントローラはMVCアーキテクチャの基本となるもの。

ルーティングはアクセスしたアドレスを元に処理を割り振るための機能。

ルーティングはWebページを作って表示させるためのものではない。

具体的に実行すべき処理は別に用意されていてそれを特定アドレスに割り振って呼び出すためのもの。

呼び出される「具体的に実行すべき処理」を実装するために用意されているのが「コントローラ」。

MVCは「Model-view-Controller」の略。

これはアプリケーションの処理をMVCの3つの要素の組み合わせとして構築していく考え。

Model
データ処理全般を担当。具体的にはデータベースアクセスに関する処理全般を扱う。

View
画面表示を担当。表示に使うテンプレートなどがこれに相当。

Controller
全体の制御を担当。必要に応じてModelを使ってデータを取得したり、Viewを利用して画面表示を作成。

ModelやViewは特定の機能に特化。これに対してControllerは処理全般の制御を担当し、プログラムの本体部分。



Laravelの開発はまずControllerを作るところから始まる。

　Webアプリケーションにアクセスするとコントローラが処理を行う。必要に応じてビューやモデルを利用し画面表示やデータベースのデータなどを受け取っていく。


#参照
https://www.javadrive.jp/rails/controller/
https://qiita.com/shg3/items/8561a650d12bd13249b2
Desktop : OpenCV Mosaic

<h5>Goal</h5>
Make a mosaic image with OpenCV.

``` OpenCV_Mosaic.java
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;

public class OpenCV_Mosaic {

    public static void main(String[] args){
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        Mat im  = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\clean.jpg");

        Imgproc.resize(im,im,new Size(),0.1,0.1,Imgproc.INTER_NEAREST);
        Imgproc.resize(im,im,new Size(),10.0,10.0,Imgproc.INTER_NEAREST);
        Imgcodecs.imwrite("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\clean_mosaic.jpg", im);
    }
}
```
<h5>Result</h5>
![clean_mosaic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276243/f7e27ac2-93a6-a691-b802-abb337220c64.jpeg)
プログラムとの対話を自動化する expect の簡単なプログラム例

# やりたいこと

会社で自動化したい処理がいくつかあり、その中に対話形式のプログラムがあるため expect を利用することに。
初めて expect を使うため、下記の記事を参考にして簡単なプログラムを作ってみましたのでメモ。

「とりあえず動かしてみたい！」という方には参考になるかもしれません。


### 参考記事

[Linuxの対話がめんどくさい?そんな時こそ自動化だ！-expect編-](https://qiita.com/ine1127/items/cd6bc91174635016db9b)

# インストール

以下の方法で expect コマンドをインストールします。
ちなみに OS は CentOS 7.6 で実行しています。

```
$ sudo yum install expect
```

# 簡単な対話プログラムを自作

expect のテストとして使えそうな簡単な対話プログラムがなかったので自作しました（シェルのお勉強を兼ねて）。

```self-introduction.sh

#!/bin/bash

GetInfo() {
        item=$1
        read -p "${item}: " val
        echo ${val} # 受け取った値を標準出力することで値を渡す
}

SelfIntroduction() {
        name=`GetInfo name` # 関数の結果を変数に代入する場合、関数名をバッククオートで囲む
        age=`GetInfo age`
        echo "Hello! I'm ${name}, ${age} years old."
}

SelfIntroduction
```

実行すると対話形式で `name` と `age` を聞かれ、入力が終わると `Hello! I'm [名前], [年齢] years old.` と出力されるだけの簡単なプログラムです。

### 実行した結果

```
$ sh self-introduction.sh
name: Katsuo
age: 11
Hello! I'm Katsuo, 11 years old.
```

# expect を使ってみる

上記のプログラムを対話せずに実行するため expect を使ってみます。

名前と年齢の値は引数として渡します。

expect には書き方が２パターンあるようで、１つはコマンドとして書く方法、もう１つはプログラム言語っぽく書く方法です。

両方のパターンを試してみましたが、可読性などを考えると後者がおすすめです（ネットを調べるとなぜか前者で書かれていることが多い）。

今回は後者のプログラム言語っぽく書く方法でやってみます。

## プログラム言語っぽく書いてみる

以下が完成版です。
これでプログラムと対話することなく、名前と年齢を引数として渡すことで実行することができます。

```self-introduction.exp
#!/usr/bin/expect

set name [lindex $argv 0]
set age  [lindex $argv 1]

spawn ./self-introduction.sh

expect {
        "name" {
                send "${name}\n"
                exp_continue
        }
        "age" {
                send "${age}\n"
                exp_continue
        }
        "\\\$" {
                exit 0
        }
}

exit 0
```

### 実行してみる

以下の１行目を実行するだけで、止まることなく最後まで処理が実行されます。

```
$ expect self-introduction.exp Katsuo 11
name: Katsuo
age: 11
Hello! I'm Katsuo, 11 years old.
```

### 簡単に解説

```
#!/usr/bin/expect
```

いわゆるシバンです。
「これから expect でプログラム書きますよ！」というお知らせです。

```
set name [lindex $argv 0]
set age  [lindex $argv 1]
```

引数として受け取った値を変数に入れてます。

```
spawn ./self-introduction.sh
```

`spawn` で指定した対話プログラムが自動化の対象となります。
今回は同じディレクトリ内にある `self-introduction.sh` を対象としています。

```
expect {
    ...処理...
}
```

`expect { }` の中に自動化するための具体的な処理を書いていきます。

```
"name" {
        send "${name}\n"
        exp_continue
}
"age" {
        send "${age}\n"
        exp_continue
}
"\\\$" {
        exit 0
}
```

`name` でパターンマッチしたら、変数 `${name}` を入力してリターンします。
同様に、`age` でパターンマッチしたら、変数 `${age}` を入力してリターンします。

`exp_continue` を入力しておくことで `expect { }` ブロックから抜け出さずに処理を続けることができます。

`\\\$` の部分は、プロンプトの入力待ち状態になったら `expect { }` ブロックから抜け出すための処理です。
プロンプトは環境によって異なるため、`#` や `%` などに編集が必要な場合があります。
（コマンドプロンプトを起動して、入力待ちのときに表示される記号のことです。）

また、詳しい理由は分かりませんが `\` ３つ必要です。
内部でどのような処理が行われているか不明ですが、エスケープが２回必要みたいです。

以上！
#django で SQL的にテキスト型のフィールドを作成する指定 ( models.textfield() )

本文の通り。

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1950








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Desktop : OpenCV Concat

<h5>Gaol</h5>
Test OpenCV concat.

```OpenCV_Concat.java
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import java.util.ArrayList;
import java.util.List;

public class OpenCV_Concat {

    public static void main(String[] args){
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat im = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\ncku.jpg");
        List<Mat> matList=new ArrayList<Mat>();
        Mat hdst=new Mat();
        Mat vdst=new Mat();
        //3¦¸
        matList.add(im);
        matList.add(im);
        matList.add(im);
        Core.hconcat(matList, hdst);
        Core.vconcat(matList, vdst);

        Imgcodecs.imwrite("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\hconcat_ncku.jpg",hdst);
        Imgcodecs.imwrite("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\vconcat_ncku.jpg",vdst);
    }
}
```
<h5>Result</h5>
![vconcat_ncku.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276243/50399cbe-3fab-7766-2c87-9c91b708d64d.jpeg)

![hconcat_ncku.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276243/9ddf5c68-6e6d-108b-b557-a6322e84d7b2.jpeg)
Djangoでのプロジェクト作成からHTMLの読み込みまで～

##概要
Djangoでプロジェクト作成とHTMLの呼び出しまでの参考

- メモ程度のクオリティ
- env等の仮想環境は使用していないので他に参照しているサイトが有れば違うかも
- Djangoはインストールされている前提です


##環境
- Windows 10
- python 3.7
- Django 2.2

##プロジェクトの作成
まずはプロジェクトを作成しないと始まらないわけです。
とりあえず手っ取り早いのはコマンドプロンプト

プロジェクト作成場所まで移動

```:プロジェクト~アプリケーション作成
cd ***/***/*****
django-admin startproject mySite
cd mySite
python manage.py startapp myapp
```
上記コマンド実行で作成されるファイル構成

```:ファイル構成
myapp/
    migrations/
    __init__.py
    admin.py
　　apps.py
    models.py
    tests.py
    views.py
mysite/
    __pycache__/
    __init__.py
    settings.py
    urls.py
    wsgi.py
manage.py

```
実行後はmysite/にDB用の「db.sqlite3」が増えるが気にしなくておｋ

```:ローカルで実行
python manage.py runserver
```

[127.0.0.1:8000/](http://127.0.0.1:8000/)にアクセスしてこの画面が表示されればおｋ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247370/5de6fbba-0db0-2fe4-4b6a-99845e2b68fc.png)

実は「python manage.py startapp myapp」はなくてもおｋ


##HTMLの引用
適当なHTMLの準備する仮にindex.html
manage.pyと同じ階層にフォルダ(htmlPaga)作成して保存

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>index</title>
</head> 
<body>
    <h1>Sample</h1>
</body>
```

プロジェクトの編集箇所は3つ
/mysite/settings.py
/mysite/urls.py
/mysite/views.py ←新規作成

###settings.py

TEMPLATES['DIRS']にos.path.join(BASE_DIR, 'htmlPaga')の追記

```python:settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'htmlPaga')],　#←追記
        'APP_DIRS': True,
        'OPTIONS': {
                'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

```
###urls.py
 
urlpatternsに追記
上から順にやっていくとまだviews.pyを作成してないのでエラーが出る

ここではリクエストされたurlに対しての関数を実行させるために記載する
第1引数を空文字
第2引数は実行関数

```python:urls.py
from django.contrib import admin
from django.urls import path
from . import views #←追記

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index_template) #←追記
]
```

###views.py

/mySite/に「views.py」新規作成
今回は必要最低限のみ記載

```python:views.py
from django.shortcuts import render
from django.http.response import HttpResponse

def index_template(request):
    return render(request, 'index.html')
```

```:実行
python manage.py runserver
```

[127.0.0.1:8000/](http://127.0.0.1:8000/)にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247370/08601f4b-5fd3-c82f-1c7c-1368479597e6.png)
コマンドプロンプトからPowershellスクリプトを起動する

batファイルからPowershellを管理者権限で外部スクリプトを呼び出したいということで備忘録として残します。
すでにPowershellをRestricted以外の動作モードの場合は他のページのやり方でうまくいくのですが、一度もPowershellを起動した環境がない場合の苦肉の策になります。

### 環境
Windows10 バージョン1803 (17134.765)


### 以下のコマンドをDOSプロンプトやバッチの中で実行する

一度もPowershellを起動していないPC等で、ダルクリックでPowershellスクリプトを実行したいときに有用かと思います。

```

powershell -NoProfile -ExecutionPolicy RemoteSigned -Command "Start-Process powershell.exe -ArgumentList \"-ExecutionPolicy RemoteSigned\",\"hello.ps1\" -Verb runas"

```

-ArgumentListの書き方はいろいろあるようだが、string型の配列らしい。
実行するスクリプトへはパスを通すかフルパスで指定が必要です


### 参考

* [Start-Process](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-5.1)
* [カレントディレクトリーで起動し引数もつけられるsudo.batを作った](https://qiita.com/morihayasion/items/c5b923ec5d29c0267bc6)
* [About powershell.exe](https://docs.microsoft.com/ja-jp/powershell/module/Microsoft.PowerShell.Core/About/about_PowerShell_exe?view=powershell-5.1)
"Row size too large. The maximum row size for the used table type" って何？ #SQL

- メッセージの通り (行ではなく) 列定義の合計サイズが大きすぎる。
- エンコードやバイトの扱いによって `varchar(255)` この合計がそのままサイズに反映されるわけではないはず

>Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs'




# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1949








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
python3.6以上ならformatよりf-stringsが便利

python3で文字列に何かを追加するときは`format`を使っていたけれど、`f-string`のほうが簡潔かつ可読性高く、しかも１０倍は処理が速くて良いです。知ったきっかけはこの[記事](https://datawhatnow.com/things-you-are-probably-not-using-in-python-3-but-should/)。ほかにも便利な機能紹介が盛りだくさんでおすすめです。

# 使い方
`format`と`f-strings`の使い方を並べます。
`f-strings`は`f'文字列{挿入}'`と単純明快。

```py:
import emoji


oracle = emoji.emojize(':eyes:')
dragon = emoji.emojize(':dragon:')

proverb = '{}{}を欠く'.format(dragon, oracle)
f_proverb = f'{dragon}{oracle}を欠く'

# 🐉👀を欠く
```
# 速度比較
colaboratoryの%timeitマジックで調べたところ、１０倍の差をつけて`f-strings`が高速でした。

```py:speed_test
%timeit proverb = '{}{}を欠く'.format(dragon, oracle)
%timeit f_proverb = f'{dragon}{oracle}を欠く'

# 1000000 loops, best of 3: 329 ns per loop
# 10000000 loops, best of 3: 27.7 ns per loop
```
APIってなに？APIを公開するってなに？自社開発のAPIは他社に公開してなくね？

 
とあるEC通販の会社のフロントエンドエンジニアをやってます、新卒2年目です。

もうタイトルのまんま！
だから調べて記事にまとめてみたって感じ。

私と同じ疑問を持ってる人いるんじゃないかな？
いてもいなくてもどっちでもいいんだけどさ。

間違ってること書いてたらご指摘を頂きたいですね。

# まずはAPIでググってみた

APIってなんぞや、ググったろ。

[データの時間 今さら聞けないIT用語：やたらと耳にするけど「API」って何？](https://data.wingarc.com/what-is-api-16084)
>「API」とは、「Application Programming Interface」の頭文字です。
>大雑把に言うと「アプリケーションをプログラミングするためのインターフェース」という意味。
>インターフェイスとは、コンピュータ用語でいうと、「何か」と「何か」をつなぐもの

アプリケーションとプログラミングをつなぐものなんだね〜
どういうことだよ、笑

[【初心者入門編】APIとは？知ってワクワク Web APIの使い方](https://www.internetacademy.jp/it/programming/javascript/how-to-use-web-api.html)
>「ソフトウェアの機能を共有する仕組み」のこと
>よく使う機能がAPIとして用意されていれば、わざわざ一からプログラムを組む必要はありません。

ほんほん...
仕組みねぇ〜〜
さっきよりかはわかりやすいぞ。

>APIとはソフトウェアやアプリケーションなどの一部を外部に向けて公開することにより、第三者が開発したソフトウェアと機能を共有できるようにしてくれるものです。

え？外部に向けて公開しないとAPIにならないの？

そんなことないっしょ、だって自社用に作ったAPIって他社に公開してなくね？
ほかもググったろ！

>API（Application Programming Interface）とは、プログラムから特定の機能を利用できるように公開しているインターフェイスのことで、ソフトウェアの機能や情報を共有するための仕組みです。

公開しないとAPIじゃないんですか！！！
どういうこっちゃ！！

もう少し詳しく記事を読んでみよう...！

###寄り道、ちょっとだけ補足
- アプリケーションとは
**OS上にインストールして利用するソフトウェア全般のこと**を指してるらしい。
スマホのアプリもアプリケーションだよって感じ。

- ソフトウェアとは
意味合い的にはアプリケーションとほぼ同じらしい。
ソフトウェアの中にアプリケーションがいるイメージ。
[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/diff233software.html)

#APIでいう「公開」は外部（他社）に公開って意味ではないらしい

じゃあAPIの「公開」ってどゆこと？って話になると思うんですけども、
下記のように記載されてましたと。

>ソフトウェアにAPIという外部とやりとりする窓口を作り、外部アプリとコミュニケーションや連携ができる状態にする。

うーん...
わかるようなわからんような...

##自分なりにまとめてみた

通常のソフトウェアの機能にはAPIの窓口は存在しないんだよね、きっと。
窓口が存在しないソフトウェアの機能は**ただのソフトウェア機能**ですと。

ここにAPIの窓口を設置することで、**ただのソフトウェアの機能からAPIに進化**。
と同時に、窓口を設置したわけだから**「APIを公開しました」**ってことになるんだよね。

APIを公開したことによって、外部アプリケーションと「こんにちは」（連携）ができるわけだ。
「こんにちは」できるようになるというか、
公開した窓口から**「こんにちは、ほら働けよ」**って強制的に働かされてるイメージで良いのかね。

##例えば
#####他社でいうと...
yahoo天気っていうソフトウェア（アプリケーション）がありますと。
このソフトウェアは「お天気情報を表示する機能（API）」をみんなに公開（APIの公開：窓口作成）してるよ。
自分のページにyahooのお天気情報を追加したかったらこのAPIを使ってね。

#####自社でいうと...
Aソフトウェア（アプリケーション）とBソフトウェア（アプリケーション）があります。
どっちもお天気情報を表示させたいな。
とりあえずAで「お天気を表示させる機能を」作成したよ。
このAで作った「お天気表示機能」をBソフトウェアでも使ったろ！
「お天気表示機能」を公開（APIの公開：窓口作成）して「お天気表示機能API」の完成！
これでBでも「お天気表示機能」が使えるね〜〜。

って具合かな？笑
わかりづらくなっちゃったかも...。

##まとめ
- API
**API = 共有できるソフトウェア（アプリケーション）の機能のこと**
手順さえ間違わなければ、誰が使っても同じ動作をしますよ。

- APIを公開
ソフトウェアの機能に外部と連携できる窓口を作成
→ 窓口を作成した時点でそのソフトウェアはAPIになる
**外部に公開するという意味ではない！**
ここでいう外部は**別のソフトウェア（アプリケーション）**ってことなんですね。
Ace.jsに予測変換を追加する

##実行環境
・Electron
・[Ace.js](https://ace.c9.io/)

Ace.jsはHTML上で動作するエディターを追加するものです
ちょっと独特な感じだけど

Electronじゃない場合は読み込みディレクトリを修正してください。(多分)

[スぺニットはこちら](https://qiita.com/metalgearsolid3love/items/5b593afc097acc1b7261)

```javascript
const editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/javascript");
editor.$blockScrolling = Infinity;
editor.setAutoScrollEditorIntoView(true);
editor.setOptions({
	enableBasicAutocompletion: true,
	enableSnippets: true,
	enableLiveAutocompletion: true
});
// const beautify = ace.require("ace/ext/beautify"); // get reference to extension
// beautify.beautify(editor.session);
const langTools = ace.require("ace/ext/language_tools");
const words = [
	{"word":"hello"},
	{"word":"word"}
];
const rhymeCompleter = {
	getCompletions: function(editor, session, pos, prefix, callback) {
		callback(null, words.map(function(ea)	{
			return {name: ea.word, value: ea.word, meta: "データ名"}
		}));
	}
}
langTools.addCompleter(rhymeCompleter);
```

重要な場所はここだけ

```javascript
const langTools = ace.require("ace/ext/language_tools");
const words = [
	{"word":"hello"},
	{"word":"word"}
];
const rhymeCompleter = {
	getCompletions: function(editor, session, pos, prefix, callback) {
		callback(null, words.map(function(ea)	{
			return {name: ea.word, value: ea.word, meta: "データ名"}
		}));
	}
}
langTools.addCompleter(rhymeCompleter);
```


これでAce上で

![スクリーンショット (305).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264677/759d816e-7490-8c1e-2d20-3b17d9207d3d.png)


と予測変換追加されました。

GITの質問場で英語で書かれた記事を探しまくってやっと見つけた
英語読めない人にとっては地獄
blueqatで量子ゲート その6

#概要

blueqatで量子ゲートやってみた。
乗算器作ってみた。

#2bit乗算器


![mul.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/d888ffc2-2554-3942-99e4-d98a3bbf1854.jpeg)

#サンプルコード

```
c0 = Circuit(17).h[0 : 2].h[2 : 4]
c0 = c0.ccx[0, 2, 4]
c0 = c0.ccx[1, 2, 5]
c0 = c0.ccx[1, 3, 11]
c0 = c0.ccx[0, 3, 6]
c0 = c0.cx[5, 10].cx[6, 10].ccx[5, 6, 7]
c0 = c0.cx[4, 9].cx[7, 9].ccx[4, 7, 8]
c0 = c0.m[:].run(shots = 100)
for cnt in c0:
	print("{} * {} = {}".format(int(cnt[0 : 2], 2), int(cnt[2 : 4], 2), int(cnt[8 : 12], 2)))
```

#結果

```
3 * 2 = 6
0 * 0 = 0
0 * 2 = 0
2 * 3 = 6
2 * 1 = 2
1 * 0 = 0
3 * 0 = 0
1 * 3 = 3
3 * 3 = 9
0 * 3 = 0
3 * 1 = 3
1 * 2 = 2
0 * 1 = 0
1 * 1 = 1
2 * 2 = 4
2 * 0 = 0
```


以上。
Paperclip　～私的メモ～

#動機
プロジェクトでコードの改修をするにあたりPaperclipの仕様を
理解する必要が出てきたため。

#Paperclipとは
・Railsに入っているActiveRecord用のライブラリ
・ファイルアップロード用のgem

#has_attached_fileメソッド

```
has_attached_file( name, options = {} )
```

・基本的にはアップロードしたファイルの保存先をオプションで指定するもの

#指定できるオプション
①サイズ指定

```
:styles => { medium: "300x300>", thumb: "100x100>" }
```	
②保存先URL

```
:url  => "/assets/photo/:id/:style/:basename.:extension"
```	
③サーバ上の画像保存先パス

```
:path => "#{Rails.root}/public/assets/photo/:id/:style/:basename.:extension" 
```

#所感
初めての記事になりますがこれを機にアウトプットを続けて行きたいと思います。
新しい発見があった際は適宜追記予定。
Cognitive Services の東日本エンドポイントへの接続で、対応している TLS バージョンについてハマった件。

#早々に結論
Cognitive Services への接続には TLS 1.2 を使いましょう！

#ハマったところ
下記ドキュメントの通りで、東日本リージョンの Cognitive Services のエンドポイントなど、比較的新しく展開されたリージョンでは、TLS 1.0 / TLS 1.1 が無効化されています。

[Cognitive Services への接続には TLS 1.2 をご利用ください](https://social.msdn.microsoft.com/Forums/ja-JP/ecab7e31-dddb-48bf-8a8f-7a9f347ae1b5/cognitive-services-124081239825509321541239512399-tls-12?forum=cognitivesupportteamja)

かたや、.NET Framework 4.5 あたりの HttpClient ではデフォルトで TLS 1.2 は使わないようになってるっぽい感じで、それに気づかずハマり…。
[Default SecurityProtocol in .NET 4.5](https://stackoverflow.com/questions/28286086/default-
securityprotocol-in-net-4-5)

#どんな感じでハマったか
```
var client = new HttpClient();
//中略
var response = await client.PostAsync(<URL>, <Content>);
```
みたいな感じで .NET Framework の HttpClient クラスを使って接続しに行ってみたわけですよ。
※なんで SDK 使わないのかというツッコミはあるかもしれませんがw
そしたら例外が…。

`System.Net.WebException: 接続が切断されました: 送信時に、予期しないエラーが発生しました。 `

Fiddler でトレース取ってみたら、どうも TLS のハンドシェイクで失敗しているっぽかったので、調べたら出てまいりました…。
どうやらこれで TLS 1.2 を使うように設定しないといけないらしい。
[ServicePointManager.SecurityProtocol Property](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.servicepointmanager.securityprotocol?view=netframework-4.8)

というわけでコードをこんな感じに変更。

```
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
var client = new HttpClient();
//中略
var response = await client.PostAsync(<URL>, <Content>);
```

これでうまくつながるようになりました！

#改めて教訓
- Cognitive Services への接続には TLS 1.2 を使いましょう！
- というか、そもそも SDK が用意されているなら、回り道せずできるだけそっち使いましょうw
- HttpClient クラスの挙動には要注意！
- 上手くいかなかったら Fiddler でデバッグ！

それではまた！

#参考ドキュメント
[.NET Framework で TLS1.1 および 1.2 を有効化する方法 -まとめ-](https://blogs.technet.microsoft.com/jpieblog/2018/10/11/net-framework-tls11-12-2/)
[Cognitive Services への接続には TLS 1.2 をご利用ください](https://social.msdn.microsoft.com/Forums/ja-JP/ecab7e31-dddb-48bf-8a8f-7a9f347ae1b5/cognitive-services-124081239825509321541239512399-tls-12?forum=cognitivesupportteamja)
[.NET Framework でのトランスポート層セキュリティ (TLS) のベスト プラクティス](https://docs.microsoft.com/ja-jp/dotnet/framework/network-programming/tls)
[ServicePointManager.SecurityProtocol Property](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.servicepointmanager.securityprotocol?view=netframework-4.8)
EC-CUBE4でfaviconを変更する(4.0.2〜)

EC-CUBE4でfaviconを変更する方法です。
4.0.2から、faviconが管理画面の操作のみで変更できるようになりました。

[最新版「EC-CUBE 4.0.2」をリリース。複数の不具合修正とデザインカスタマイズに役立つ機能を追加。（2019/02/27）](https://www.ec-cube.net/news/detail.php?news_id=324)

## ファイル管理でアップロード

ファイル管理から特定のディレクトリにアップロードすることで、faviconが変更できます。

コンテンツ管理＞ファイル管理で、assets＞img＞commonとたどり、favicon.icoをアップロードしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72858/33fe85b6-2781-5b7b-2f5c-d54b16c23715.png)

以上の操作で、faviconが更新を更新することができます。

4.0.2以前の変更方法はこちら
https://qiita.com/ryo-endo/items/e413ddbb9ca627029bcf
html要素にfont-size: 62.5%;を指定したのに1.6emが16pxにならなかった話

二度目の投稿です。
今回は失敗からなるほど！！！！！が生まれたので
反省含めて載せます
結論から言えば、何もおかしくないし当たり前でした

# 一箇所だけだしなんでやと思いました

こちらコードです

```
(base.scss)

html {
  font-size: 62.5%;
}

(header.scss)

  h1 {
    font-size: 3.6rem;
    margin: 1.6em 0 1.6em 12em;

    @include mq() {
      font-size: 2.4rem;
      margin-left: 1.6em;
    }
  }
```
他の部分は思った通りになるんです、、、

# 検証ツールで実際何pxになっているのかみてみます

**57.6px**

どうしてええええええええええw

emのコンパイル後の値ってfont-size × emの値だから
emのコンパイル後の値 ÷ emの値で何倍かわかるのでは？

57.6 ÷ 1.6 = 36

36…あ、font-size!?となりました
あれでも62.5%で指定したのになぜ、、、、、

# emとremの知識がごちゃ混ぜになってました

[調べてたどり着いた神記事です](https://qiita.com/masarufuruya/items/bb40d7e39f56e6c25f0d)

> **rem**
  文書のルート要素、つまりhtml要素のfont-sizeを基準にする

**remはroot要素**

> **em**
  親要素のfont-sizeを基準に大きさを計算する

**emは親要素**

# つまり馬鹿だった

当たり前だった、h1ではfont-sizeを上書きしているから
font-size 36pxを基準にemも計算される
36 × 1.6 = 57.6
何もおかしくなかった
私が書いたコードを忠実に再現してくれただけだった

# そして学んだfont-sizeを親要素に指定してたらemが思う通りにならないってことは、、、

> よく検証ツールとかでみてて疑問だったことがある
なんでいちいちテキスト系divタグとかで囲ってんの？？？
しかも空だし、わからない、、、

これの謎が今回馬鹿をしたことでわかりました
親要素に左右されるので、親要素に当たるところにfont-sizeのrem指定があると良くない
だからdivタグで空の親要素を作ってたのか！！！！！
text系でmarginやpadding取らないようにしようと感じました


すごい初歩的な話ですが間違えて、馬鹿したことで理解が深まりました
これからも頑張ります！
ここまで読んでくれて、ありがとうございます
それでは、また！
.DS_storeのファイルが出現してしまう

ファイルの書き換えや移動の度に.DS_dtoreのファイルが出現する。
そのため、以下のコマンドを打って、削除を行う。

find / -name ".DS_Store" -delete

<img width="810" alt="スクリーンショット 2019-05-21 14.32.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386223/2d644190-7947-9c26-ff21-01fae1c5ab2d.png">

削除はできたものの、ファイルが依然と出現する。

そのため、.gitgnore　に、以下を追記
<img width="583" alt="スクリーンショット 2019-05-21 14.34.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386223/414ffaf4-1bf8-f7a8-a89e-d4de71d49088.png">

ターミナルで、　git rm -r --cached .DS_Store　を実行

<img width="810" alt="スクリーンショット 2019-05-21 14.36.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386223/662aa40a-a271-aa35-8d91-0b1e9bcf29d7.png">

削除が完了した

<img width="608" alt="スクリーンショット 2019-05-21 14.36.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386223/01712905-7147-8270-0445-c4883953d33b.png">
devise+ActiveAdmin+CancancanでAbilityクラスのuserがnilだった時に確認するところ

# 前提

先にdeviseでログイン回り構築済みの状態で、ActiveAdmin、cancancanの順に追加していった。
以下のサイトを参考に設定。

- [Deviseインストール済環境でActiveAdminの導入](https://qiita.com/cooltiger/items/205628642ed229e14ab9)
- [CanCanCanを使ってみる](https://qiita.com/naoki85/items/266c8d7ab469cc6ab1fe)
- [【Rails】ActiveAdmin＋CanCanCanで権限毎に色々したい](https://qiita.com/goosys/items/2e0d91061b131da686df)
- [[rails]ActiveAdminとCanCanCanを使って管理画面に権限機能をつける](https://blog.hello-world.jp.net/ruby/2074/)

環境は以下

- Ruby 2.5.3
- Rails 5.2.3
- activeadmin 2.0.0
- cancancan 3.0.1
- devise 4.6.2
-  rolify 5.2.0

# Abilityクラスのuserがnilだったら...

ためしたところ、権限が効いていなかった。
解決策としては、active_admin.rbのconfig.current_user_methodのコメントアウトを外すことだった。

```ruby:config/initialize/active_admin.rb(97行目あたり)
config.current_user_method = :current_user
```

# その他の補足

## 左上のタイトルを変えたりリンクをつけたりする
```ruby:config/initialize/active_admin.rb(7行目あたり)
  config.site_title = "マスタメンテナンス"
  config.site_title_link = "/admin"
```

## サインアウトでエラーとならないよう、deleteのメソッドを追加する。
```ruby:config/initialize/active_admin.rb(109行目あたり)
  config.logout_link_path = :destroy_user_session_path
  config.logout_link_method = :delete
```

## ユーザのActiveAdminサンプル
ロールにrolifyを使用している。ユーザテーブルのマスタメンテ画面にロール情報も追加したいときのサンプル
[stack overflow-Updating Roles in rolify using ActiveAdmin](https://stackoverflow.com/questions/20475257/updating-roles-in-rolify-using-activeadmin)より

```ruby:app/admin/users.rb
ActiveAdmin.register User do
  permit_params :email, :password, :password_confirmation, :confirmed_at, role_ids: []

  form do |f|
    f.inputs "User Details" do
      f.input :email
      f.input :password
      f.input :password_confirmation
      f.input :confirmed_at
      f.input :roles, as: :check_boxes
    end
    f.actions
  end

  # Allow form to be submitted without a password
  controller do
    def update
      if params[:user][:password].blank?
        params[:user].delete "password"
        params[:user].delete "password_confirmation"
      end

      super
    end
  end
end
```
Delphi 10.3 を使用してAWS S3からファイルを取得する

## やりたいこと
AWS S3からDelphi10.3を使用して
ファイルの取得を行う

## 環境
Windows 10
Delphi 10.3

## 実装
Formへ
AmazonconnectionInfoを張り付ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143249/fc0f981d-4139-6a0f-1c40-5f805456bc90.png)

AmazonconnectionInfo1の
プロパティ
AccountKey
AccountName
にAWSにて発行した値を挿入する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143249/0d00c32c-f06e-60e8-862e-af78d106f603.png)

対象のコード

```pascal
const
  BUCKET_NAME = 'your-bucket-name';
function TForm1.getUsersData(selectDir: TSelectDirOpt; userId : String):boolean;
var
  s3 : TAmazonStorageService;
  stream : TStringStream;
  objFolder : string;
  LFileName : String;
begin
  s3 := TAmazonStorageService.Create(AmazonConnectionInfo1);
  stream := TStringStream.Create;
  objFolder := 'your-folder/';
  LFileName := objFolder + your-file-name + '.json';
  if s3.GetObject(BUCKET_NAME, LFileName, stream) then
  begin
    stream.SaveToFile('c:\' + LFileName)
  end else
  begin
    showmessage('Download failed(score landmark)');
  end;
end;
```

※LFileNameには取得したいファイル名を記述してください。


## 所要時間
5分でできた。

## 追記

シンプルに書くとこんな感じ
#### GetObject from S3

```pascal

procedure TForm1.btnDownloadClick(Sender: TObject);
var
  s3 :TAmazonStorageService;
  strstr : TStringStream;
begin
  s3 := TAmazonStorageService.Create(AmazonConnectionInfo1);
  strstr := TStringStream.Create;
  try
    if s3.GetObject(BUCKET_NAME, OBJ_NAME, strstr) then
      ShowMessage(strstr.DataString)
    else
      ShowMessage('Download failed');
  finally
    strstr.Free;
    s3.Free;
  end;
end;
```

#### uploadObject to S3

```pascal

procedure TForm1.btnUploadClick(Sender: TObject);
var
  s3 :TAmazonStorageService;
  strstr : TStringStream;
begin
  s3 := TAmazonStorageService.Create(AmazonConnectionInfo1);
  strstr := TStringStream.Create(edit1.Text);
  try
    if s3.UploadObject(BUCKET_NAME, OBJ_NAME, strstr.Bytes) then
      ShowMessage('OK')
    else
      ShowMessage('Upload failed');
  finally
    strstr.Free;
    s3.Free;
  end;
end;
```

※ edit1.textは任意で、好きな値を入れて
> /dev/null 2>&1; 順序が逆では駄目な理由

後輩に説明するのにググったけどあんまりいい説明がなかった。


## ポイント

この謎を解くための前知識。

- ``>`` は ``1>`` の省略形であるということ
- リダイレクトは左から順番に処理されるということ
- ``2>&1`` は「標準エラーの出力先を標準出力にする」<b>ではなく、</b><br>
「標準エラーの出力先を<font color="red">標準出力と同じ場所にする</font>」であるということ


## 図解

例文

```bash
$ (echo "hoge" ; ecoh "fuga")
hoge
-bash: ecoh: コマンドが見つかりません
```

- ``hoge`` が標準出力
- ``-bash: ecoh: コマンドが見つかりません`` が標準エラー

## 例1: ``> /dev/null 2>&1`` の場合

例文

```bash
$ (echo "hoge" ; ecoh "fuga") > /dev/null 2>&1
```

### STEP1. ``(echo "hoge" ; ecoh "fuga")`` まで

```bash
$ (echo "hoge" ; ecoh "fuga")
```

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259373/1d834a0c-a14a-2ff6-90f5-f39848363a67.png)

これは流石に分かるとおもうので説明は割愛。

### STEP2. ``(echo "hoge" ; ecoh "fuga") > /dev/null`` まで

```bash
$ (echo "hoge" ; ecoh "fuga") > /dev/null
```

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259373/c6bd434f-1664-6f95-f990-bdcc296f80a5.png)

冒頭に書いたとおり、``>`` は ``1>`` の省略形である。
つまり標準出力(1)の出力先を変えたことになる。

### STEP3. ``(echo "hoge" ; ecoh "fuga") > /dev/null 2>&1`` まで

```bash
$ (echo "hoge" ; ecoh "fuga") > /dev/null 2>&1
```

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259373/e6a1d03c-c732-31ab-943d-531c36c3d50c.png)

冒頭に書いたとおり、``2>&1`` は、標準エラー(2)の出力先を標準出力(1)と<b>同じ場所にする</br>である。

したがって、図のとおり出力先は ``/dev/null`` となる。


## 例2: ``2>&1 > /dev/null`` の場合

例文

```bash
$ (echo "hoge" ; ecoh "fuga") 2>&1 > /dev/null
```

### STEP1. ``(echo "hoge" ; ecoh "fuga")`` まで

```bash
$ (echo "hoge" ; ecoh "fuga")
```

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259373/1d834a0c-a14a-2ff6-90f5-f39848363a67.png)

例1.と同じ。説明は割愛。

### STEP2. ``(echo "hoge" ; ecoh "fuga") 2>&1 `` まで

```bash
$ (echo "hoge" ; ecoh "fuga") 2>&1
```

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259373/1128df64-2a9d-e043-572f-53d36791c9ed.png)

冒頭に書いたとおり、``2>&1`` は、標準エラー(2)の出力先を標準出力(1)と<b>同じ場所にする</br>である。

標準出力(1)、標準エラー(2)ともに出力先はもともと「コンソール画面」である。
ここで標準エラー(2)の出力先を標準出力(1)と同じ場所にするということは、出力先を「コンソール画面」にするということ。
<font color="red">つまり何も変っていない。</font>

### STEP3. ``(echo "hoge" ; ecoh "fuga") 2>&1 > /dev/null`` まで

```bash
$ (echo "hoge" ; ecoh "fuga") 2>&1 > /dev/null
```

![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259373/06f02b4d-8426-b37e-cd83-0239fa9f4964.png)

冒頭に書いたとおり、``>`` は ``1>`` の省略形である。
つまり標準出力(1)の出力先を変えたことになる。

このとき標準エラー(2)については出力先を変更していない。
よって上記図のとおり標準出力(1)のみが ``/dev/null`` に出力され、
標準エラー(2)についてはコンソール画面に出てしまう。

ということである。
【初心者】紙に書くというプログラミングの勉強法

プログラミングを始めてまだ一ヶ月ですが、私なりの勉強法の一部をご紹介します。
###プログラミングの勉強法
プログラミングを勉強し始める時、Progateを使う方は多いと思います。
Progateは初心者にも優しいサイトとして有名ですが、文系初心者には理解が難しい場面がいくつもありました。
例えば、PHPのオブジェクト指向の基礎のところです。
いきなり「クラス」「インスタンス」「プロパティ」「メソッド」などの聞き慣れない用語が多く出てくるのでここが最初のつまずくポイントでした。
Progateでは、それぞれを分けて優しく解説してくれます。
しかし、メソッドの勉強をした後にプロパティについて復習するとすっかり忘れてしまっているため、またプロパティについての学習を始めなければなりませんでした。
その行為を何回か繰り返した後に、このままでは勉強の効率が悪いと気づきました。
そこで私は、Progateで個別に解説している用語を、自分で紙に書いてまとめ直してみました。
こうすることで「クラス」「インスタンス」「プロパティ」「メソッド」が一目で分かり、復習の効率が上がりました。
コードをわざわざ手書きするのは馬鹿らしいかもしれませんが、必要な情報を簡単に好きな場所に付け足すことができます。
![IMG_2434.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402245/9e9597c3-6fc3-ccc7-f860-0ccb005847ca.jpeg)
M3AAWG 45th General Meeting 参加レポート

2019.2.18~21 サンフランシスコで開かれたM3AAWG 45th General Meetingに参加して来ました。NDAの範囲内でみなさまに共有します。技術の話はだいたいNDA違反になるので伏せておきます。

##### M3AAWGとは？

M3AAWGとは、MESSAGING, MALWARE AND MOBILE ANTI-ABUSE WORKING GROUPの略語です。公式ホームページでは以下のように説明されています。
ref. [About M3AAWG](https://www.m3aawg.org/about-m3aawg)

> The Messaging, Malware and Mobile Anti-Abuse Working Group (M3AAWG) is where the industry comes together to work against bots, malware, spam, viruses, DoS attacks and other online exploitation.

分かりやすく説明すると、M3AAWGはGoogleやMicrosoft、Facebook、Twitterなどメッセージングを扱っている大企業はもちろん、アメリカ政府など各国の政府・団体・学者が集まり、メッセージングのあらゆることについて議論してベストプラクティスを確立した後、RFCとして業界標準にまで発展させる超国際的ワーキンググループです。日本からも団体、ISP、ベンダー企業が毎年参加し活動していて、去年[JPAAWG](https://meetings.jpaawg.org/)という日本のワーキンググループも設立されました。


[写真: M3AAWG Night Outの様子]
![m3aawg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/bf631d72-c502-2a57-1a71-d28b07ab0c30.jpeg)


##### M3AAWGの特徴

1. フラットな立場で話し合う。
集まったメンバーにはRFCの著者、RFCを決める人たち、GoogleでGmailを開発したキーエンジニア、アメリカ政府でメールシステムを運用しているエンジニア、アメリカ議会でメッセージング政策を提案する議員などさまざまですが、**みんながフラットな立場、フラットな目線でメッセージングに関する技術や政策について話し合う場**です。

2. 業種を超えて一緒に対策を考える。
メッセージング分野は、閉じられた一つの組織・プラットホームの中で完結するものではなく、必ず外に相手が存在するものです。Phishingメールなど問題が起こったら一つの組織内では対応しきれないことが多いです。このような問題について利害は異なっても同じくメッセージングを扱っている人たちが一緒に対策を考え、ベストプラクティスを作り、RFCや政策政策まで発展させて行きます。(例: 2017年アメリカ政府が導入を義務付けたDMARCなど。)

3. オープンラウンドテーブル形式の議論
議論されるアジェンダは事前に集められ、アジェンダ毎にオープンラウンドテーブル形式で議論されます。どのアジェンダにいつ参加するかは自由ですが、議論の結論が気になるので最後は一つのアジェンダに集中するとこになります。このオープンラウンドテーブルがM3AAWGの白眉。私の場合ケンブリッジの教授とRFCの著者、LinkedINのエンジニア、チェコのISPのエンジニアと話をしました。

4. ファシリテータの重要性
もちろんベンダーとISP、政府団体、学者で立場も意見も異なります。オープンラウンドテーブルでは意見をまとめる役のファシリテーターが二人以上いて、白熱する場をまとめます。非英語圏の参加者のたどたどしい英語での意見も素晴らしくまとめてくれました。このようなファシリテーター役を務める人はカンファレンスが始まる前に事前研修を受けることも出来ます。

5. ベストプラクティス化からRFC化、政府の政策にまで持って行く。
重要なアジェンダでオープンラウンドテーブルでは結論が出てないものは次のM3AAWGに持ち越され、大規模で議論されます。ここでまとまったらM3AAWGのベストプラクティスとして発表され、IETFにも提案出来ます。IETFはこれをRFC化出来る団体です。

6. 小ワーキンググループの存在
メッセージングと言っても幅は広いのでM3AAWGには小ワーキンググループが存在します。。参加者は自分の興味で小ワーキンググループを選択して参加し、自分の持っているスキルで貢献する仕組みです。たとえばSNSのAbuse対策ワーキンググループやベストプラクティスの翻訳ワーキンググループなど。私の場合、初参加ということもあり今回は翻訳の小ワーキンググループに名前を記しました。(早速、翻訳の依頼が来ています。）

[写真: M3AAWGに参加した弊社メンバーの様子]
![m3aawg-qualitia.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/5dbf1374-2b44-2ae2-97eb-0e29c63c780a.png)

##### 個人的感想

1. メールセキュリティ業界で長く勤めて来ましたが、この分野でここまで大規模な世界的カンファレンスは今回が初めてでした。メッセージング系エンジニアは基本的に外にはあまり出ない存在なので、同じ分野エンジニアたちを多く会えて直接現場の話が聞けたことが嬉しかったです。

2. オープンラウンドテーブルで個人が出した一つの意見がみんなの共感と支持を得てベストプラクティスになり、ついにはRFCまで行くというプロセスを目の前でみて感動しました。世界のスタンダードに携われるということ、私の知識と技術、経験で社会に貢献出来るということに喜びと誇りを感じました。

3. サンフランシスコという場所が良かったです。シリコンバレーが近いこともあり、アメリカの有名IT企業のエンジニアが会場のどこにもウロウロしていたのでいつでも話が出来ました。英語という言語やサンフランシスコという地域だからこそ得られる情報の豊富さには羨ましさまで感じました。

4. おまけな話ですが、会場のホテルが豪華でスポンサー企業が協賛してくれるご飯とおやつがゴージャスでした。Night Outのイベントではレトロゲーム機がたくさん並ぶサンフランシスコのクラブを貸し切ってゲーム遊び放題だったのも楽しかったです。

[写真: M3AAWG Night Outでゲームに夢中な様子]
![m3aawg_kof99.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/57c0de7e-2cf9-158b-a0d8-92151d6d2449.jpeg)


次回は2019.6月ハンガリーのブダペストで開かれます。ヨロッパで開催されるとアメリカとはまた異なる参加者がたくさん集まるらしいので気になるところです。

以上。
【Ruby】カスタム例外を作成する簡単３ステップ



# 概要
Rubyでは以下の簡単なステップで独自の例外を作成する事ができます。

- [(1)カスタム例外のクラスを作成](#カスタム例外のクラスを作成)
- [(2)メッセージを付け加える](#メッセージを付け加える)
- [(3)独自のデータを例外に付け加える。](#独自のデータを例外に付け加える)
 

# カスタム例外のクラスを作成
例外のクラスは他のRubyのクラスと同じです。
`StandardError`を継承する独自の例外クラスを作成しましょう。
(Rubyの慣習に従って、独自の例外クラスの名前の最後に`Error`をつけます。)

```ruby
class MyError < StandardError
end
```

# メッセージを付け加える
全てのRubyの例外オブジェクトは `message`の属性を持っています。

以下のようにして独自の例外にデフォルトのメッセージを定義してみましょう。

```ruby
class MyError < StandardError
  def initialize(msg="My Message")
  super
  end
end

raise MyError #=> My Message
```

これは全ての例外に言える事ですが、以下のように表示するメッセージを明示する事もできます。

```ruby
raise MyError, "Custom Message" #=> Custom Message
```



# 独自のデータを例外に付け加える
他のRubyのクラスと同様に、独自のデータを例外に付け加える事ができます。

```ruby
class MyError < StandardError
  attr_reader :attr

  def initialize(msg="My default message", attr="My value")
    @attr = attr
    super(msg)
  end
end

begin
  raise MyError.new("my message", "My value")
rescue => e
  puts e.attr #=> My value
end
```

以上です。
簡単に独自の例外を作成する事ができました。

# 参照
- [Custom exceptions in Ruby - Honeybadger Developer Blog](https://www.honeybadger.io/blog/ruby-custom-exceptions/)
Firestoreのフィールドにタイムスタンプを入れたい

# Firestoreのフィールドにタイムスタンプを入れたい

この要望を満たすのに検索すると、DatePipeを使用するとかserverTimestamp()を取ってきてtoDate()するとかmomentをインポートして使うとかいろいろあるけど、これが一番簡単じゃないかなあ？と思った備忘録。



### 前提

次のようなドキュメントフィールドがあったとする。timestampに現在時刻を入れてデータを追加したい。

```typescript
import { AngularFirestore } from '@angular/fire/firestore';
import { Component, OnInit } from '@angular/core'; 

constructor(
	    private db: AngularFirestore
	) {}

this.data = {
    username: this.username,
    message: this.message,
    timestamp: <処理>
}
    
this.db
    .collection()
    .add(this.data)…データ追加処理…以下省略
}
```



### やり方

timestamp：の＜処理＞の部分に現在日時を指定するフォーマットにして入れるわけだが、次のやり方でオーケー。

<br>

- Inject, LOCALE_ID, formatDateをインポート（app.module.tsはいじる必要ない）。

- コンストラクタに以下のように@Injectして、現在日時をlet now変数に代入。

- timestampフィールドに**formatDate()関数**でフォーマット指定して直接入れ込む。


```typescript
import { AngularFirestore } from '@angular/fire/firestore';
import { Component, OnInit, Inject, LOCALE_ID } from '@angular/core'; 
import { formatDate } from '@angular/common';

constructor(
    private db: AngularFirestore
    @Inject(LOCALE_ID) private locale: string,
  ) {}

addData() {
	let now = new Date(); 
	this.data = {
   		username: this.username,
    	message: this.message,
    	timestamp: formatDate(now,"yyyy/MM/dd HH:mm", this.locale)
	}

this.db
    .collection()
    .add(this.data)…データ追加処理…以下省略
}
```


<br>



あ、ラク～と思った。


<br>


以上



参考：[formatDate](<https://angular.io/api/common/formatDate#formatdate>)
AWS CloudFormation Master Class を受けてみた③ 「 CloudFormation Designer でテンプレートの作成 」

##はじめに
引き続き、Udemy にて Stephane Maarek 氏 が提供している「 [AWS CloudFormation Master Class](https://www.udemy.com/aws-cloudformation-master-class/) 」コースについて紹介していきます。今回は、CLoudFormation Desinger の機能とその使い方についてです。

- これまでの記事
 - [AWS CloudFormation Master Class を受けてみた①] (https://qiita.com/Yoshiyuki03/items/ad21f72dbfb9c9eb32fa)
 - [AWS CloudFormation Master Class を受けてみた② 「 CFnを利用したS3環境の構築 」](https://qiita.com/Yoshiyuki03/items/3ad97bbb8b9d905fa9d9)


##Using CloudFormation Designer
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/57a65b79-33b6-b9f5-623e-07b0276ad358.png)
CloudFormation では、テンプレートをデザインすることができます。
それにより、テンプレートの内容を可視化しながら作成できます。


###テンプレートのデザイン①
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/41c6cb33-9eee-bee2-1624-2a7a9d102f4d.png)
CloudFormation のサービス画面から、左上の「テンプレートのデザイン」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/530d2442-f056-6221-f69b-a1e327e10cca.png)
テンプレートを作成したいサービスを、左の一覧から選択したら、あとは右側に持ってくるだけです。
ここでは、EC2 インスタンスを例に行っています。
これで、EC2 インスタンスのテンプレートは完了しました。


###テンプレートのデザイン②
次に、作成した EC2 インスタンスに対して固定 IP を設定してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/300c489e-e464-5594-d4ae-68eb7d333d73.png)
これで固定 IP の設定も完了です。

セキュリティグループの設定も、同じ様に行うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/2f739955-e488-85ff-af22-7035214a0144.png)

他にも、既存の YAML テンプレを貼り付けることで、YAML の内容を図で確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/49b80cdb-5a0e-37da-8b7e-688eb0b0a76c.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/8e5a118e-5eb8-77bb-6da6-5e0f9f17a3fc.png)
デザインしたテンプレートを使用する際は、左上のアイコンより「アップロード」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/152beec3-5909-4abc-0394-bb46ea1a30a8.png)
テンプレートの選択画面で、「 Amazon S3 テンプレート URL の指定 」に、アップロードしたテンプレートの URL が表示されていることを確認したら、「 次へ 」を押して作成すれば完了です。


###まとめ
CloudFormation のテンプレートをデプロイする方法は2通りあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/c01235c8-08c8-4305-aada-7c940f696cae.png)

- 手動でデプロイ
 - CloudFormation Designer でテンプレートを作成  
 - コンソールからパラメータを入力

- 自動でデプロイ
 - YAML ファイルでテンプレートを編集
 - AWS CLI を使用してテンプレートをデプロイ
 

##おわりに
CloudFormation Designer でのテンプレートの作成の紹介については以上です。
このサービスを利用することで、ユーザ自身でテンプレートを自由にデザインし、デプロイすることができます。
次回は、CloudFormation のparameter について紹介していきたいと思います。
私の構成

いろんな構成の考え方や予算をご紹介する前に、私の構成を紹介しておきます

MB MSI H370 Gaming Plus 12000円

CPU Intel i7 8700(Optane付属のやつ) 42000円

RAM G.Skill DDR4 8Gx2 4Gx2 計 24GB 10000円と6000円

GPU MSI RTX2060 GamingZ  52000円

SSD ADATA SU650 240GB  6000円

HDD Seagate Bulk HDD 1TB + Intel Optanememory 16GB  4500円(OptaneはCPU付属)

PSU Owltech FSP 750W Silver  7500円

Case Thermaltake H26  4750円

Cooler Deepcool GAMMAX L240  7000円

計  151750円　！

これは現在運用中の最新機です
バイトをだいぶ頑張りました
これまでに３台作りましたが、正直誕生日とかに親の脛をかじりまくってました
初心者の方には初期投資を大きく！と言いましたが、僕の場合少しだけ妥協してます笑
少しだけですよ？
給料をすべて注ぎ込みました！特にCPUとGPUにお金をかけましたね～
RTX2060はベンチサイトを見てみるとGTX1080と同等の性能という結果が出てたので決めてました
そして昔からやってるメーカーMSI縛り
では次回から予算に対しての構成の考え方について書いていきます！