OmniAICreator/Qiita-1.07M huggingface dataset:
SSRとは何かメリデメとフローを学んだまとめ(SPAと比較)


## SSR(サーバーサイドレンダリング)とは
元々ブラウザ上でしか動かなかったJavaScriptをサーバー内部で実行して、HTMLを生成することを指します。
もう少し言うと、リクエストがあった時にJavaScriptをダウンロードしてクライアントでレンダリングするのではなく、初回のリクエストはサーバー側でレンダリングして返すと言うこと。

## SSRはなぜ必要とされているのか
SSRが必要とされる一番の理由はSEO対策だと思っています。
ReactやVueなどのSPAサイトを構築するとGoogleクローラーがJavaScriptを解釈しない可能性があり評価してくれないことが考えられます。
その対策としてJavaScriptをサーバー側で実行してHTMLを生成して返してくれるSSRが必要とされている。（この辺りはメリットで話します）
しかしGoogleクローラーも進化を遂げて現在ではSPAサイトでも認識され評価してくれています。
ただこの懸念はGoogleを信じるしかないので、リプレイス等でSPAに変える際絶対にSEOに影響がないという保証はどこにもないのでSSRが必要なのではないでしょうか。

## SSRのメリットは何か

### 初回レンダリングが早い
SSRではサーバー側のNode.jsでJavaScriptを実行してた結果HTMLを生成してクライアントに返してくれるため早い。
Webアプリにバンドルされる機能の大半は初期表示に必要がないため、初期表示をしてから読み込めばよい
SPAなどはリクエストしてレスポンスを受けてからJSをブラウザで実行するため待ち時間が発生する。

### SEOに強い
SSRはサーバーでJavaScriptを実行しHTMLを生成してクラアント側に返すため正しく評価されると言えます。
一方SPAの課題として２つのSEO問題がSSRはそれらを解決できます。

・非同期コンテンツを待ってくれない
　Googleは同期的JavaScriptアプリケーションのインデックスを作成するためAjax等でコンテンツを取得する場合にクローラーが待ってくれない可能性があると言われている。そのためSEOが重要なページは非同期コンテンツを取得する場合SSRが必要。

・レンダリングエンジンが古い場合HTMLを認識してくれない
　クローラーがJavaScriptを解釈しない場合何もない状態を受け取ります。
　レンダリングエンジンが古いと正しく動かず正しいHTMLを認識してくれないということはありえますが、Googleから最新のChromeに常に対応していくことが発表されているのであまり問題にはならないと思う。


## SSRのデメリットは何か

### サーバー側の負荷が高い
サーバー側でレンダリングするということはサーバーのCPU負荷が増えるということ。
トラフィックが多いことが見込まれる場合はキャッシュ対応をしっかりと行う必要がある

### Node.jsを実行できる環境が必要になる
SPAとは異なりJavaScriptを実行するためNode.jsが実行できる環境を準備しないといけない。

## SPAとSSRの流れ

### SPA

![spa.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/6541cf90-27c2-d4d7-4f06-ab9490fe9696.jpeg)


#### SPAが生まれた理由
SPAがそもそも生まれた理由はページ遷移のたびにリクエストをすると動的処理が行われるからサーバーの負荷が高くなって遅いんじゃないか？だったらページ遷移ごとのリクエストやめちゃおうぜって言うことです。

#### SPAの流れ
ページ遷移やコンテンツの切り替えはサーバーで行なっていたものをブラウザ側の仕事にすることでサイトの高速化を図りました。
そのためSPAはWebサーバーへのリクエストは1度きりです。
そしてページ固有のコンテンツだけを変更させます。
例えばフッターとヘッダーはどのページも共通だった場合、それ以外のコンテンツだけを変更させます。
Reactのような仮装DOMの場合、変更のあった差分だけをDOMに反映させるためページの変更ごとに全てのDOMを作り直す必要がありません。

ただしSPAは最初の表示が遅いです。
一番最初の表示は必要のないrouterやstoreなどのjsも含まれて送られるためJavaScriptのダウンロードと実行に時間がかかります。
またOGPの設定もできません。
先ほどお話ししたようにページのコンテンツをDOM操作で変更しているだけなのでページごとのOGP設定ができないです。
JavaScriptで<meta>タグを変更してもいいですが動的な変更が読み取れない場合もあるためそうゆう場合はSSRを使う方がいいでしょう。

### SSR

![ssr.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/afd1cf7e-4956-9210-9e44-f7d4405f5dfc.jpeg)


#### SSRが生まれた理由
SSRが生まれた理由は冒頭でお話しした理由です。
もう１つの理由があるとするならばSPAの初期表示が遅い部分を補うことです。

#### SSRの流れ
SSRの流れはほとんどSPAと変わらず差分だけを非同期リクエストします。
大きな違いは、レスポンスでレンダリング済みのHTMLを渡します。レンダリングまでブラウザが行なっていましたがSSRではレンダリングまではサーバーで行いpaintingはブラウザで行うと言う点です。
レンダリング済みのHTMLとはJavaScriptで変更したDOM操作なども反映されたファイルです。
そのためSPAでできないOGP設定もサーバー側でHTMLを作成する静的ページなのでできます。

デメリットは紹介しているので割愛します。

# 最後に
今回学んだことをまとめ見ました。
SSRとSPAってなんだ？となっていましたが明確に必要な理由やメリット・デメリットが理解できました。
色々と勘違いしている部分もあり情報不足だったなと実感しています・・・
今後はSSGについても学んでいきたいなと思います。
EC2のキーペアを紛失した時の簡単な対処法

EC2のキーペアを無くしてしまった時、既存のインスタンスに別のキーペアを登録できます。
新しいインスタンスを作成する必要はありません。

例としてlinux/MacOSの場合の手順を示します。

## 新しいキーペアを作成する

新しいキーペアの作成は必須ではありません。
既存の別のキーペアを使用する場合はスキップしてください。

* AWSマネジメントコンソールにアクセス
* `EC2` > `ネットワーク&セキュリティ` > `キーペア` へ移動
* 「キーペアを作成」をクリック
![スクリーンショット 2020-10-12 15.38.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252165/57dbd778-36a7-e37f-5e5c-a14dd9585681.png)
* キーペア名を入力して「キーペアを作成」をクリック
![スクリーンショット 2020-10-12 15.38.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252165/59b67bdc-5b0d-b989-303a-b37120294ff5.png)
* pemファイルがダウンロードされる
* pemファイルを適当なディレクトリに移動し、適切な権限を設定する

  ```
  $ mv xxxxx.pem ~/.ssh/
  $ chmod 400 ~/.ssh/xxxxx.pem
  ```

#### Windowsの場合
* [キーペアの作成またはインポート](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/ec2-key-pairs.html#prepare-key-pair)

## 公開キーを作成する

* `$ ssh-keygen -y -f ~/.ssh/xxxxx.pem`
* 出力された公開キーを「ssh-rsa 」も含めて全てコピーしておく

```
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClKsfkNkuSevGj3eYhCe53pcjqP3maAhDFcvBS7O6V
hz2ItxCih+PnDSUaw+WNQn/mZphTk/a/gU8jEzoOWbkM4yxyb/wB96xbiFveSFJuOp/d6RJhJOI0iBXr
lsLnBItntckiJ7FbtxJMXLvvwJryDUilBMTjYtwB+QhYXUMOzce5Pjz5/i8SeJtjnV3iAoG/cQk+0FzZ
qaeJAAHco+CY/5WrUBkrHmFJr6HcXkvJdWPkYQS3xqC0+FmUZofz221CBt5IMucxXPkX4rWi+z7wB3Rb
BQoQzd8v7yeb7OzlPnWOyN0qFU0XA246RA8QFYiCNYwI3f05p6KLxEXAMPLE
```

#### Windowsの場合

* [キーペアのパブリックキーを取得する](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/ec2-key-pairs.html#retrieving-the-public-key-windows)

## EC2インスタンスのユーザーデータを変更する

* EC2インスタンスを停止
* `アクション` > `インスタンスの設定` > `Edit user data` をクリック
![スクリーンショット 2020-10-12 15.56.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252165/a89698dc-fa3c-262b-a36a-3e149d282d44.png)
* すでに定義されたユーザーデータがある場合は、一旦どこかへ退避しておく
* ユーザーデータに下記のスクリプトを貼り付ける

```
Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0

--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
cloud_final_modules:
- [users-groups, once]
users:
  - name: username
    ssh-authorized-keys: 
    - PublicKeypair
```
* **users.name** と **PublicKeypair** を修正して「保存」をクリック
  * users.name ... ec2-user など
  * PublicKeypair ... 先ほど作成した公開キー
![スクリーンショット 2020-10-12 15.59.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252165/46899ed7-9150-a60c-aa10-05aaee698243.png)

* インスタンスを起動
* 起動後、ダウンロードしたpemファイルを使用してssh接続出来ることを確認する
    * `ssh -i ~/.ssh/xxxxx.pem ec2-user@xxx.xxx.xxx.xxx`
* インスタンスを停止
* 先ほど貼り付けたスクリプトを公開キーを含め全て削除する
    * 退避したユーザーデータがある場合は貼り付ける
* 「保存」をクリック
* インスタンスを起動する

## 参考

[最初の起動後に SSH キーペアを紛失した場合、Amazon EC2 インスタンスに接続するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/user-data-replace-key-pair-ec2/)
yps並走備忘録　Task4 WordPress環境構築

更新を大分サボってたので大分時間が経ってしまいましたが、Task 4の備忘録を思い出しつつ書いてみます。
ypsはLaravelでの開発がメインですが、今回はちょっと寄り道的なタスクでWordPressの構築を行います。

#事前準備
wgetがインストールされていない場合はインストールしましょう
`sudo yum install wget -y`

#WordPressのセットアップ
※記事執筆時（2020/10/12）の最新版は5.5

**tmpディレクトリに最新版のWPをダウンロードして解凍**
1. `cd /tmp` [^1] 
2. `wget https://ja.wordpress.org/latest-ja.zip`
3. `unzip ./latest-ja.zip`

**ディレクトリを移動**
4. `mv wordpress '任意のディレクトリ名'`　※任意の名前に変更（なるべく一般的な名前は避ける）
5. `mv '任意のディレクトリ名' /var/www/html/`

**MySQLにWP用のデータベースを作成**
6. `mysql -u root -p`　でMySQLにログイン

**以下MySQL Cliでの操作**
7. `create database '任意のDB名';` ※データベース名はなるべく複雑なものの方がベター
8. `grant all on ypswpdb.* to '任意のuser名'@localhost identified by '任意のパスワード';`　データベースの権限を委譲しています
※ここで設定したユーザー名とパスワードを忘れてしまうと後々面倒なのでどこかにメモるなりしておく
9.設定し終わったら　`exit;`

**WP設定ファイルの更新**
`cd /var/www/html/yps-wp/`
`cp -p wp-config-sample.php wp-config.php`

まずは下記を変更します。

```
define( 'DB_NAME', ' #7で設定したDB名' );
define( 'DB_USER', '#8で設定したuser名' );
define( 'DB_PASSWORD', '#8で設定したパスワード' );
```

続いて下記を更新します。

更新時にはコメントにあるようにhttps://api.wordpress.org/secret-key/1.1/salt/ にアクセスすると自動でシークレットキーを生成してくれるので便利です（アクセスする度に新しいキーが生成されます）。

```
define( 'AUTH_KEY',         'put your unique phrase here' );
define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
define( 'NONCE_KEY',        'put your unique phrase here' );
define( 'AUTH_SALT',        'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
define( 'NONCE_SALT',       'put your unique phrase here' );
```

最後に下記を更新します

```
$table_prefix = '任意の文字列_';
```
`:wq`で保存したら一先ずWPの設定は完了

**ファイルとディレクトリのオーナー権限を変更**
`cd /var/www/html`
`sudo chown -R centos:nginx /var/www/html/wwpp/`
`sudo find /var/www/html/wwpp/ -type f -exec chmod 664 {} \;`
`sudo find /var/www/html/wwpp/ -type d -exec chmod 775 {} \;`

**次にnginxの設定を変更してLaravelからWPへルートディレクトリを変更します**
`sudo vi /etc/nginx/conf.d/default.conf`

編集内容は以下の通り

```
root /var/www/html/yps/public;
#↓に変更
root   /var/www/html/wwpp;

#追記
location /wp-config.php {
  deny all;
}
```

`:wq`で設定を保存したらphp-fpmとnginxを再起動します
`sudo systemctl restart php-fpm && sudo systemctl restart nginx`

※WPとLaravelを同時に動かしたい場合は下記のリンクを参照
>参考：[LaravelとWordPressの共存](https://cloudpack.media/10634)

**ドメインネーム（設定してない場合はインスタンスのpublic IP）でブラウザからアクセス**
WPのインストール画面が出ていれば成功です。
ただし、このままだとテーマやプラグインのインストールができないので少し設定をいじります。

`cd wp-content/plugins/`
`wget https://downloads.wordpress.org/plugin/ssh-sftp-updater-support.0.8.2.zip`
`unzip ./ssh-sftp-updater-support.0.8.2.zip` 
`rm http://ssh-sftp-updater-support.0.8.2.zip` 
`sudo chown -R centos:nginx ./ssh-sftp-updater-support/`

正常にプラグインがインストールされていればテーマをインストールできるようになっているはずです。
念のため下記の参考リンクを使ってできる範囲でのセキュリティ対策もしておきましょう

>参考リンク：[簡単にできるWordPressのセキュリティ対策x12](https://baigie.me/officialblog/2020/01/28/wordpress-security/)

以上でWPの構築は終了です。

[^1]: /tmpは再起動時にディレクトリが消えるので、wgetでインストールするときなどに便利
AWS CDKで暗黙の依存関係が削除できないとき

# CDKでクロススタック参照するリソースを作成したとき

CDKで複数スタックを定義して、スタック間でリソースを共有したいケースはよくあると思います。
スタックAで定義したLambda関数をスタックBでも使いたい、とかそういう感じのやつです。

基本的にCDKは頭がいいので、渡したいリソースを適当に変数にでも入れて別のスタックに引き渡してやれば、明示的にアウトプットを定義してやらなくても勝手に依存関係を理解していい感じにしてくれますよね。

しかし、いざクロススタック参照していたリソースを削除しようとすると、CloudForamtionがこんな感じにエラーを出してきます。

```
Export StackA:ExportsOutputFnGetAttLambdaFnstacka07BAF5DArn93F62DF0 cannot be deleted as it is in use by StackB
```

# どうしてですか？

CDKは賢いので、StackAで作成したLambdaがStackBで使われなくなった事に気付いてアウトプットを削除します。
そして`cdk deploy`を走らせると、StackBはStackAに依存しているため、先にStackAのデプロイが走ります。

そう！！StackBより先に！！StackAを更新しようとするのである！！！

そうすると、LambdaがStackBで使われているためアウトプットの削除が出来ないのです。

# 解決方法

### 先にStackBだけ単体で更新する

まあ、当然といえば当然なのですが、StackBを先に単体で更新してからStackAを更新するとうまくいきます。

```
cdk deploy -e StackB
```

デプロイ時にオプション`-e`をつけると、指定したスタックのみ更新してくれます。

これでStackBからStackAのLambdaを参照しなくなり、依存関係がなくなったため、以降は前述のエラーなくStackA、StackB共にデプロイできるようになるはずです。


# めでたし！！！！！！！！！！

知らなかったの私だけかもしれないですけどね！！
なかなか`-e`オプションにたどり着けなかったので……。
ちゃんとドキュメントを読みましょうというお話でした。

ドキュメントを読もう：[AWS CDK Toolkit (cdk command)](https://docs.aws.amazon.com/cdk/latest/guide/cli.html)
Amazon Elastic Transcoder概要とLambdaからのJob実行

# Amazon Elastic Transcoder

映像・音声をユーザーが再生可能なフォーマットに変換するクラウドサービス

# 用語

- Pipeline
  動画を通してトランスコードを行うパイプライン
  Pipeline ID が割り当てられ、Lambda 等から使用する際に指定
  以下主な設定項目
  - 変換元/先の S3 バケット
  - 変換完了 SNS 通知

- Job
  Pipeline 内で実行するトランスコード処理
  Lambda 連携する場合は Lambda から生成、実行する
  以下主な設定項目
  - 変換元/先ファイル名
  - Preset
  - サムネイル生成等のオプション

- Preset
  トランスコード内容をまとめた設定
  Job にてトランスコード内容として指定
  AWS で用意されているものかカスタムで生成したものを使用
  Preset ID が割り当てられ、Lambda 等から使用する際に指定
  Preset一覧：https://docs.aws.amazon.com/ja_jp/elastictranscoder/latest/developerguide/system-presets.html

# アーキテクチャ例

![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/f53251c1-1901-8494-c3cc-382195708d38.png)
1. 動画が S3 にアップロードされたことをトリガに Lambda を実行
2. Lambda で Amazon Elastic Transcoder の Job を実行
3. Amazon Elastic Transcoder が S3 内の元動画からトランスコードしS3 に出力

# トランスコード時間

元動画の 50 ～ 100%程度

# 料金試算

## 無料枠

- SD: 20 分
- HD: 10 分

### 1 日 1 時間分の動画をトランスコードした場合

- SD(480p)の場合  
  (1 時間 ×30 日 ×60 分 - 20 分)×0.017USD = 30.26USD = 3177 円

- HD(720p)の場合  
  (1 時間 ×30 日 ×60 分 - 10 分)×0.034USD = 60.86USD = 6390 円

# Amazon Elastic Transcoder + Lambda 例

1. AWS マネジメントコンソールから Pipeline の作成
   Pipeline の名前、変換元/先の S3 バケット、サムネイルの出力先 S3 バケット等を指定
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/f6650ba6-c1a9-8ea6-91ea-72b514f7c033.png)

2. Job は Lambda から生成するため不要、Preset は用意されたものを使用するため不要
3. S3 を以下構成で用意
- 入力用:
    - bucket : elastic-transcoder-dev-input
    - key : input/
- 出力用:
   - bucket : elastic-transcoder-dev-output
   - key : output/

4. Lambdaトリガ設定
    - トリガとするサービス：S3  
    - バケット：elastic-transcoder-dev-input
    - イベントタイプ：すべてのオブジェクト生成イベント
    - プレフィックス：input/
    - サフィックス：.webm

5. Lambdaロール設定
  Elastic TranscoderにJobをSubmitできるポリシー「AmazonElasticTranscoder_JobsSubmitter」を追加します

6. Lambda実装  
  以下サンプル

```javascript
let aws = require('aws-sdk');
let s3 = new aws.S3({apiVersion: '2006-03-01'});
let ets = new aws.ElasticTranscoder({apiVersion: '2012-09-25', region: 'ap-northeast-1'});

exports.handler = function(event, context) {
  
  let pipelineId = 'xxxxxxxxxxxxx-xxxxx';
  let presetId = '1351620000001-000030';

  let bucket = event.Records[0].s3.bucket.name;
  let key = event.Records[0].s3.object.key;
  let fileName = (key.split('/')[1]).split('.')[0];
  
  ets.createJob({
    PipelineId: pipelineId,
    OutputKeyPrefix: 'output/',
    Input: {
      Key: key,
      FrameRate: 'auto',
      Resolution: 'auto',
      AspectRatio: 'auto',
      Interlaced: 'auto',
      Container: 'auto',
    },
    Output: {
      Key: fileName + '.mp4',
      ThumbnailPattern: fileName + '-thumbs-{count}',
      PresetId: presetId,
      Rotate: 'auto'
    }
  }, 
  function(error, data) {
   if(error) {
       console.log(error);
       context.done('error',error);
   } else {
       console.log('Job submitted');
       context.done(null,'')
   }
  });
}
```
`ets.createJob`：Jobを生成しています
`PipelineId`、`presetId`：AWSマネジメントコンソールで確認して指定
`OutputKeyPrefix`：出力先フォルダ
出力されるファイルは、`OutputKeyPrefix`＋`Output['key']`になります


## 参考記事

- https://qiita.com/con_mame/items/b58a5e017e7c9ab2356b
- https://qiita.com/hayashier/items/5407134e95beb3927f25
【自分用】JSPファイルとサーブレットクラスを使用したブラウザ表示

<h3>初めてJSPとサーブレットクラスの連結がうまくいったので記録。</h3>


【参考リンク】
・Html プルダウンメニューの表示について
(https://murashun.jp/blog/20200128-66.html)
・Html 複数行のテキスト入力フォーム作成
(http://www.htmq.com/html/textarea.shtml)



<h3>【JSPファイル】</h3>

```java

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>お問い合わせフォーム</title>
</head>
<body>


<%--formを挿入する準備 --%>
<form action="/example/P157_s" method="post">

<%--お名前入力タブ --%>
	名前<input type="text" name="name"><br>

<%--お問合せの種類選択タブ --%>
	<select name="qtype">
      <option value="company">会社について</option>
      <option value="product">製品について</option>
      <option value="support">アフターサポートについて</option>
      </select>

<%--お問い合わせ内容入力タブ --%>
      <p>お問い合わせ内容を入力してください</p>
      <textarea name="body" rows="4" cols="40">
      </textarea><br>

      <%--送信ボタン --%>
	<input type="submit" value="送信">

</form>
</body>
</html>

```

<h3>【サーブレットクラス】</h3>


```java

package p157_s;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/P157_s")
public class P157_s extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");

		String name=request.getParameter("name");
		String slags=request.getParameter("qtype");
		String comment=request.getParameter("body");

		//javaコード
		String errorM="";
		if(name==null||name.length()==0) {errorM+="氏名が入力されていません";}
		if(slags==null||slags.length()==0) {errorM+="お問合せの種類が選択されていません";}
		else if(slags.equals("company")){slags="会社について";}
		else if(slags.equals("product")){slags="商品について";}
		else if(slags.equals("support")){slags="アフターサポートについて";}
		if(comment==null||comment.length()==0) {errorM+="お問い合わせ内容が入力されていません";}

		String msg=("氏名["+name+"]様 お問合せの種類["+slags+"] お問合せ内容["+comment+"]");
		if(errorM.length()!=0) {msg=errorM;}

	response.setContentType("text/html; charset=UTF-8");
		PrintWriter out=response.getWriter();

		out.println("<html>");
		out.println("<head>");
		out.println("<title>お問い合わせフォーム</title>");
		out.println("</head>");

		out.println("<meta.charSet=\"UTF-8\">");
		out.println("<body>");
		out.println("<p>"+msg+"</p>");
		out.println("</body>");
		out.println("</html>");
	}
}

```
==とequals

コード作成時にちょっとしたミスを繰り返してしまうので
戒め的に備忘録として記事にします。

String型の変数のif文での確認で下記のミス

```
<✕>
if(name == "minato"){
・・・処理
}

<〇>
if(name.equals("minato")){
・・・処理
}
```
Moyaを使ってmultipart/form-dataでimageのPOST

今更ながら若干ハマった為、メモ

```
var task: Task {
        switch self {
              
        case .hoge(let files)：
        //filesは[Data]

            let fileMFDataArray: [MultipartFormData] = files.enumerated().map({ (index, data) in
                MultipartFormData(provider: .data(data),
                                  name: "file", //こっちがKey
                                  fileName: "\(Int(Date().timeIntervalSince1970))\(index)",　//UnixTime + index番号 のファイル名を生成
                                  mimeType: "multipart/form-data")
            })
            return .uploadMultipart(fileMFDataArray)
    
        }
    }
```

あとは忘れずにheaderを["Content-Type": "multipart/form-data"]にすれば完了！
railsでformをdisableして送信すると値が送信されてない場合の解消法

jsで一部formの値をdisableにしていたところ、値が送られていおらずその対処を行いました。

調べてみたところ`disable` 属性はPOSTされないらしく、これを回避してPOSTするためには`readonly` 属性が利用できるとこのことで追加してみました

```
<input placeholder="名" type="text" name="company" readonly="readonly">
```

### 参考記事
[フォームでdisabled属性を指定すると送信されない](https://shanabrian.com/web/html-css-js-technics/set-disabled-form-not-send.php)
Nuxt.ts - axiosのheadersに常にtokenを付与する方法


JWTのトークンをリクエストの度に付与するのが面倒で、この実装で実現できたのでメモ


```plugins/axios.ts
import { Context } from '@nuxt/types';
import Cookies from 'js-cookie';

export default function ({ $axios }: Context) {
  $axios.onRequest((config) => {
    const token = Cookies.get('authToken');
    if (token) {
      config.headers.common['Authorization'] = 'Bearer ' + token;
    }
    return config;
  });
}
```

```nuxt.config.js
export default {
  // ...
  plugins: ['@/plugins/axios'],
  // ...
}
```
未経験から3回の自社・受託開発会社のインターンをした話

こんにちは

プログラミングの勉強を始めて4ヶ月目、1年と1ヶ月目にインターンをし、
現在2年目にして3回目のインターンをしているそっしーといいます。

相当技術力があったんだろうといわれると、面白いことにそうではありません。
自分が実務経験を得られた理由は何だったのか、これからエンジニアを目指す方に
共有できたらと思いこの記事を書きました。

##目的と手段の話
目的をまず設定し、それを達成するための手段を実行していくことが大切です。
太平洋を横断するとなった時、勢いでそのまま泳ぐバカはいません。
太平洋を横断するために船を探します。
それと同じように、現実でもまず目的を把握し、それに適した手段を取っていく必要があります。
抽象的な話ですが、意識するのとしないのでは多少なりとも差が出ているでしょう。

##まず自分の軸を固める
哲学的な話になってしまいますが、自分の軸を固めることはとても大切です。
軸があることで信頼されやすく、また会話を明確に進めることができるからです。
なぜエンジニアになりたいのか、なぜ頑張るのか、といった勉強以前の意識を
ガッチリと固めました。
あなたが人事だとしたら、曖昧な回答をする人よりも軸があって
明確な回答ができる人の方が採用したいと思いますよね。
要らなそうで、実はかなり役に立つ準備なのでまずはここからやってもらいたいです。

##アウトプットは保存しておく
自分が都度作った作品は、必ず保存しておきましょう。
未経験の人が実力を示すには、アウトプットした作品が一番有効です。
そのためにも、ある程度凝った物を作る癖と、それを保存する癖は大切です。

##SNSを活用
プログラミングの勉強と一緒に、Twitterでエンジニアアカウントを作りました。
SNSの力は偉大で、今ではSNSマーケティングという言葉が当たり前になっています。
始めた目的は発信力を少しでも得られたらというものからでしたが、
このTwitterが自分のキャリアの後押しになることは当時の自分も想像できませんでした。

鬼のようにがむしゃらに頑張っているキャラでTwitterを動かし、いいねを稼ぎ、
コツコツとフォロワーを稼いでいきました。
フォロー対象は経営者か人事、デザイナー、エンジニアのみで、
フォロワーの8割はエンジニアだと思います。
自分からフォローしていくのは最初の100~200人のみで、エンジニアに絞り、
なるべくいいねをしてもらえそうなツイートをすることで拡散され、
毎日数人ずつ増えていきました。

勉強(Progate)を始めて4ヶ月目、Twitterで見かけた企業主催の勉強会に参加した時でした。
そこにいた駆け出し起業家さんと仲良くなり、「うちに来る？いくらがいい？」
といってもらったのです。
当時、自分の相場もわからないアホだったので(Hello Worldをいろんな言語で出力していた)
「(朝から晩まで勉強しているし、)30万円くらいですかね。」
と返答。
そしたらまさかの承諾で、Progate歴4ヶ月で一月30万円という大金を手にすることになりました。
資金振りが良くなく2ヶ月で終わったのですが、
その時お金を貯金に回してバイトを辞め、時間の全てをプログラミングの勉強に費やしました。
**時間最優先**の考え方はとても今に活きたと思います。
この話は再現性がとても低いので、ここで終わりにします。

2回目のインターンは、Twitter採用でした。
当時の自分は精神的にどん底で、「なぜこんなに勉強しているのにお金にならないんだ」と
今にも挫折しそうでした。自己肯定感のかけらもなかったのを今でも覚えています。

そんな時、友達にいわれた一言が自分のキャリアスタートの引き金になりました。
「技術力があることと、稼げることは別物だよ」
そこでようやく気付きました。
「自分を売り込まなければならない」と。

##技術力があることと稼ぐことは違う
これは自分が最も勘違いしていたことの１つでした。
「一生懸命頑張っていれば、いつか報われる。だからひたすら頑張っていれば良い。」
この考え方が、自己肯定感を下げる大きな原因になっていました。

友達に技術力と稼ぐことは違うんだと言われてから、
自分を売り込むことを意識しました。
まずは募集サイトから応募して面接をしてみました。
結果は落選です。当時はまだ授業があり、参加できて週1~2だったので当然だと思います。
それでも最後にプライドを捨てて、
自分で作ったLPをTwitterで公開し、
「0から全て自分でやりました。なんでもするのでアルバイトでもなんでも
　雇っていただける企業様がいたらお願いします」
と呟きました。
物乞いのような気分です。自己肯定感がどん底で、自暴自棄になっていたので、
クソくらえという勢いでツイートしたのです。

結果、そのツイートは拡散され、2回目のインターン先の社長から
声がかかったのです。
「Swift、やってみる？」
「できるかわからないけれど、やってみたいです。」
初めて自分を売り込んで成果が出た瞬間でした。

この時、Swift歴は1週間もありません。HTMLやCSS、お遊び程度のRailsスキルでした。
その後採用理由を聞いたところ、「**信頼できると思ったから**」だそうです。
一度目のインターンも、二度目のインターンも、面白いことに
自分のその時点の技術力の評価ではなく、**伸び代への投資**だったり、**人間性**だったのです。
この2回目のインターンでの業務経験が、今のインターンに受かるのに最も活きてきます。


##企業のニーズに合わせる

3回目のインターンは、真っ向勝負でした。
面接で受かるには、自分の売り込み方がかなり大切です。
ただ「自分はこういう人間だ！」と主張してもダメです。

企業方針に賛同したら、真っ先に募集要項を確認しましょう。
・どんなスキルが歓迎されるのか
・どういうスタイルの人材を求めているのか
企業ニーズをしっかりと把握する必要があります。

自分が受けた会社では、
・UIUX重視
・Firestoreの使用経験
・RealmSwiftの使用経験
・関数型プログラミングでの開発経験
・スピード開発
・ライブラリを使った開発
・テストコード
などだった気がします。
幸い、今まで溜めていたポートフォリオのUIのおかげで0次を通過し、
1次に進みました。
そこで「WebAPIを使ったアプリを2週間ほどで作ってきて欲しい」と課題が出されました。

会社のHPから、UIUXとスピードを重視していることがわかっているため、
新型コロナウイルスの感染状況が確認できるアプリを3日で作り、提出しました。
その後のフィードバック後の修正も数日で終わらせ、スピード感とやる気を自分の中の最大限で
アピールした結果、なんとか最終面接を合格しました。

一見、現時点での自分を売り込むだけで良いと思われがちですが、
企業側のニーズも加味しなければなりません。
その時点でそのニーズを満たしていなくても、面接の前準備やら
面接中に寄せていくことはできるかと思います。

##おわりに
人それぞれ思うことはあると思いますが、
個人的には「数打ちゃ当たる」よりも「一球入魂」派です。
面談って意外とつかれますからね..。
Lambda_備忘録


備忘録用


(notice_unhealthy_to_slack)

```
import boto3
import json
import logging
import os

from base64 import b64decode
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError


# The Slack channel to send a message to stored in the slackChannel environment variable
SLACK_CHANNEL = os.environ['slackChannel']
HOOK_URL = os.environ['hook_URL']

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def handler(event, context):
    logger.info("Event: " + str(event))
    message = json.loads(event['Records'][0]['Sns']['Message'])
    logger.info("Message: " + str(message))

    alarm_name = message['AlarmName']
    #old_state = message['OldStateValue']
    new_state = message['NewStateValue']
    #reason = message['NewStateReason']

    slack_message = {
        'channel': SLACK_CHANNEL,
        # 'text': "<@UL0TNE657> 【ENV: dev/stg】 %s // state is now %s" % (alarm_name, new_state)
        'text': "<@UL0TNE657> 【ENV: dev/stg】 %s // state is now %s" % (alarm_name, new_state)
    }

    req = Request(HOOK_URL, json.dumps(slack_message).encode('utf-8'))
    try:
        response = urlopen(req)
        response.read()
        logger.info("Message posted to %s", slack_message['channel'])
    except HTTPError as e:
        logger.error("Request failed: %d %s", e.code, e.reason)
    except URLError as e:
        logger.error("Server connection failed: %s", e.reason)
モギモギ 2nd 解説

## [A. キャンディーと2人の子供 / Fighting over Candies](https://atcoder.jp/contests/abc047/tasks/abc047_a)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  vector<int> a(3);
  cin >> a.at(0) >> a.at(1) >> a.at(2);
  
  // 小さい順に並び替え
  sort(a.begin(), a.end());

  // 小さい2つと一番大きいものを比較して同じ値なら2人で分けることが可能。
  if(a.at(0) + a.at(1) == a.at(2)) {
    cout << "Yes" << endl;
  } else {
    cout << "No" << endl;
  }
}
```

## [A. Infinite Coins](https://atcoder.jp/contests/abc088/tasks/abc088_a)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, a;
  cin >> n >> a;

  // 500円玉で可能な限り払うと残りの払うべき金額は n を 500 で割ったあまりになる。
  // そのあまりがA円以下であれば所持しているお金でちょうど払い切ることが可能
  if(n % 500 <= a) {
    cout << "Yes" << endl;
  } else {
    cout << "No" << endl;
  }
}
```

## [B. Long Long Ago](https://atcoder.jp/contests/tkppc4-1/tasks/tkppc4_1_b)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, k;
  cin >> n >> k;
  vector<int> a(n);
  for(int i = 0; i < n; i++) cin >> a.at(i);

  // ansは結婚最有力候補の人の番号
  // ansAgoは結婚最有力候補の人のアゴの長さ
  int ans = -1;
  int ansAgo = 0;
  for(int i = 0; i < n; i++) {
    // 現状の結婚最有力候補の人とり顎が長く、
    // 王様よりも短い人がいればその人を最有力候補にする。
    // (番号とアゴの長さの更新)
    if(ansAgo < a.at(i) && a.at(i) < k) {
      ans = i + 1;
      ansAgo = a.at(i);
    }
  }

  cout << ans << endl;
}
```

## [A. Frog 1](https://atcoder.jp/contests/dp/tasks/dp_a)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  cin >> n;
  vector<int> h(n);
  for(int i = 0; i < n; i++) cin >> h.at(i);

  // 各地点までの最短経路の値を格納していく配列
  // (ゼロ値で初期化されるのでdpの各要素の中身は0)
  vector<long long> dp(n);

  for(int i = 1; i < n; i++) {
    // i == 1 のときは1つ前の地点との距離の差の絶対値を格納
    // それ以外では、『1つ前までの最短距離(dp)と1つ前の地点との距離の差の絶対値の和』と
    // 『2つ前までの最短距離(dp)と2つ前の地点との距離の差の絶対値の和』から小さい方を格納
    // dp.at(i) : i地点にたどり着くまでの最短経路
    // abs(dp.at(i) - dp.at(j)) : i地点からj地点までにいくまでのコスト
    if(i == 1) {
        dp.at(i) = abs(h.at(i) - h.at(i-1));
    } else {
        dp.at(i) = min(dp.at(i-1) + abs(h.at(i) - h.at(i-1)), dp.at(i-2) + abs(h.at(i) - h.at(i-2)));
    }
  }

  cout << dp.at(n-1) << endl;
}
```

## [C. GeT AC](https://atcoder.jp/contests/abc122/tasks/abc122_c)

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, q;
  string s;
  cin >> n >> q >> s;

  // これは n 文字目までに "AC" が出現した回数を格納する配列
  vector<int> cusum(n);

  for(int i = 1; i < n; i++) {
    // ACが出たなら 直前までに出た回数に1を加算した後を格納
    // 出ないのであれば 直前までに出た回数をそのまま格納
    if(s.at(i-1) == 'A' && s.at(i) == 'C') {
      cusum.at(i) = cusum.at(i-1) + 1;
    } else {
      cusum.at(i) = cusum.at(i-1);
    }
  }

  for(int i = 0; i < q; i++) {
    int l, r;
    cin >> l >> r;
    // r文字目までに出た回数からl文字目までに出た回数をそのまま引く。
    cout << cusum.at(r-1) - cusum.at(l-1) << endl;
  }
}
```
Flutterでimportしたクラス名がコンフリクトした場合の対応

firebase_authを更新したところ、FirebaseUserがDeprecatedになりUserに変更されていました。
もともとアプリでUserクラスをモデルとして定義していたので、firebase_authとuserモデルをimportしていたファイルで以下のようなエラーが発生しました。

```
'User' is imported from both
'Userクラスを定義しているファイル1' and
'Userクラスを定義しているファイル2'.
```

以下のようにimport文に `as` を付与して、`UserModel.User` として参照することでコンパイルできるようになりました。

```
import 'package:プロジェクト名/model/User.dart' as UserModel;
```


参考
https://coflutter.com/dart-flutter-how-to-solve-naming-conflict-or-ambiguous-import/
iOS safariのinputイベント+focus()の謎挙動について

下のような文字を一文字を打つと自動で次の入力値に行くようなjqueryをかきました
※実際のものより色々省いたので下記で動くかは未確認



```
<html>
<input id="number1" type="number" name="number1" value="" >
<input id="number2" type="number" name="number2" value="" >
<input id="number3" type="number" name="number3" value="" >
<input id="number4" type="number" name="number4" value="">
</html> 

<script type="text/javascript">
            $(function(){
              $('input[type=number]').on('input', function(ev){

                var $me = $(this);
                var $list = $('input[type=number]');

                  $list.each(function(index){
                   
                    if ($(this).is($me)) {

                      $list.eq(index+1).focus();
  
                      ev.preventDefault();

                    }
                  });
                
                });
           });

</script>
```

PC系ブラウザでは問題なかったですがiPhoneのsafariでは下記のようなよくわからない現象がおきました

`number1に1と入力`
↓
`何故かnumber1とnumber2に1と入力されnumber3にフォーカスが移動`

あれこれ調べてみたものの解決策らしきものは見当たらず
**safariではinputイベントの発火のタイミングが早すぎて(遅すぎて?)focusの直後にも発火しているのでは?**
と思い下記のようにすることで一応想定した動きを得ることはできました

```
setTimeout( function(){
  $list.eq(index+1).focus();
} ,100)
```
お名前.comのドメイン&レンタルサーバにアクセスできなくなった時の対処方法

お名前.comのドメイン&レンタルサーバにアクセスできなくなった時の対処方法

お名前.comで設定してドメインとレンタルサーバ、暫く正常に表示されていたのですが、
一週間くらいして突然「申し訳ございません。このページに到達できません」「このサイトにアクセスできません」のエラーが表示されるようになりました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/56321da0-68dd-d18a-cd6b-a7a9d7dc69d2.png)

fpsで接続はできるし、ドメインも稼働中なのにdnsの設定がおかしくなったのかなと色々見直していました。

色々調べた結果、ドメインを作成した後メールアドレスの確認をする必要があったのですが、
普段使っているメールアドレスとは別のメールアドレスを使用していたため、気づかずはまってしまいました

メールアドレスの確認メールのurlを踏んで、20分程で解除され無事アクセスできるようになりました
解除されるまでは、dnsの反映と同じように最大72時間掛かるようです


同じようなエラーになった人の参考になれば幸いです。
PolarFire SoC Icicle Kit 開封の儀

PolarFire SoC Icicle Kit 開封の儀

- 購入
    - CrowdSuply
        - https://www.crowdsupply.com/microchip/polarfire-soc-icicle-kit
    - Microsemi
        - https://www.microsemi.com/existing-parts/parts/152514
- ドキュメント
    - 日本語ブローシャ
        - http://ww1.microchip.com/downloads/jp/DeviceDoc/00003292A_JP.pdf
    - ユーザーガイド
        - https://www.microsemi.com/document-portal/doc_download/1245042-ug0882-polarfire-soc-fpga-icicle-kit-user-guide
    - Quick Start Guide
        - https://www.microsemi.com/products/fpga-soc/polarfire-soc-icicle-quick-start-guide
    - Demo: Linux Quick Start
        - https://www.crowdsupply.com/microchip/polarfire-soc-icicle-kit#demo-linux-quick-start
- その他
    - PolarFire SoC Icicle Kit with Antmicro’s HDMI board
        - https://antmicro.com/blog/2020/07/polarfire-soc-with-antmicro-hdmi-board/
       
## U-Boot起動？

シリアルつないで電源いれるだけ？ ROMになんか入ってるっぽい。

- 12V電源 -> J29 (左側) に接続
- USB -> J11 （右側）に接続
- screen /dev/ttyUSB0 115200 でコンソール接続
- SW6 ON でパワーON,LEDが色々点灯、シリアルに（カラフル）起動ログが出る

![スクリーンショット 2020-10-12 15.11.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157475/f246f6a2-1511-1e90-7777-b05004042c40.png)

固まった？？？

つづく、、、
CentOSのrbenvのupdate



# イントロ

CentOSのrbenvが古そうだったのでupdate


# まずは

たんに，

    rbenv update

しても

```
> rbenv update
Updating rbenv
 |  fatal: unable to access 'https://github.com/sstephenson/rbenv.git/': SSL connect error
Updating rbenv-update
```

と怒られる．


# 解決策

そこで，

```bash
> cd ${rbenv root) #=> /usr/local/rbenv
> git remote add origin git@github.com:sstephenson/rbenv.git
> git pull origin master
```

とします．何，普通にgitの使い方．そうすると，pluginsに必要なcommand群がinstallされます．そうしておいて，

```bash
> rbenv update
Updating rbenv
 |  From github.com:sstephenson/rbenv
 |  * [new branch]      gh-pages   -> origin/gh-pages
 |  * [new branch]      user-gems  -> origin/user-gems
 |  * [new branch]      version-aliases -> origin/version-aliases
 |  * [new tag]         v1.1.0     -> v1.1.0
 |  * [new tag]         v1.1.1     -> v1.1.1
 |  * [new tag]         v1.1.2     -> v1.1.2
 |  There is no tracking information for the current branch.
 |  Please specify which branch you want to merge with.
 |  See git-pull(1) for details.
 |  
 |  git pull <remote> <branch>
 |  
 |  If you wish to set tracking information for this branch you can do so with:
 |  
 |  git branch --set-upstream-to=origin/<branch> master
 |  
Updating rbenv-update
```

と，無事updateできたらしい．

でも，最新版のrubyは2.7.0-preview2で，変わらずでした．

やれやれ．



------
 - **source** ~/Desktop/lecture_22f/multi_scale_22/semi_lattice_20f/rbenv_update_centos.org
Dartの非同期周り(async, await, then)

Dartの非同期周りの挙動や使用どころについてのメモ。

基本的にDart(Flutter)はシングルスレッドで実装して、どうしても重い処理はIsolateやComputeを使用して別スレッドで処理することになる。
ただ単純なシングルスレッドだとネットワークレスポンスを待ったりする間にUIが固まってしまうので、Dartではイベントループを使用して非同期処理を実現している。
非同期処理の方法がasync,await,then辺りであり、それぞれの使い所や挙動の違いをまとめた。

# async, await, thenの使い所
- async: 非同期メソッドを定義する場合に使用する
- await: 非同期メソッドの実行を待ってから以降の処理をしたい場合に使用する
- then: 非同期メソッドの実行結果のコールバックを受け取って処理したい場合に使用する
    - thenの外に記述された処理はコールバックを待たずに実行されていく
    
# 動作検証

## コード

```dart:test.dart
void main() async {
  print("001");
  returnTwo().then((value) {
    print(value);
  });
  print("003");
  var value = await returnFour();
  print(value);
  print("005");
}

Future<String> returnTwo() async {
  print("returnTwo");
  await Future.delayed(Duration(seconds: 2));
  return "002";
}

Future<String> returnFour() async {
  print("returnFour");
  await Future.delayed(Duration(seconds: 2));
  return "004";
}
```

## 実行結果

```shell
001
returnTwo
003
returnFour
002
004
005
```


## 解説


① 001: 普通に順番通り出力される
② returnTwo: returnTwo()がコールされてawaitされる前なので出力される 
③ 003: main()が進んでいき003が出力される
④ returnFour: returnFour()がコールされてawaitされる前なので出力される
⑤ 002: returnTwo()の待ちが終了して002が出力される
⑥ 004: returnFour()の待ちが終了して004が出力される
⑦ 005: mainが進んでいき005が出力される

## ポイント

② returnTwo()全体の実行が待たれるのではなくreturnTwo()内で待ちが発生する処理までは同期的に実行される
③ returnTwo()内部で待ちが発生するとmain()は進んでいく
⑦ main()はreturnFour()をawaitしているのでreturnFour()が完了するまで処理は進んでいかない


# 参考
https://medium.com/@jelenaaa.lecic/when-to-use-async-await-then-and-future-in-dart-5e00e64ab9b1
https://medium.com/@kawanojieee/dart-async-await-394846fb3d2c
https://medium.com/flutter-jp/isolate-a3f6eab488b5
【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた～その6～

# はじめに

みなさん、初めまして。
Djangoを用いた投票 (poll) アプリケーションの作成過程を備忘録として公開していこうと思います。
Qiita初心者ですので読みにくい部分もあると思いますがご了承ください。

シリーズ

- [【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた～その0～](https://qiita.com/oboerarenai_user/items/4ff87b2afbad8c16ad40)
- [【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた～その1～](https://qiita.com/oboerarenai_user/items/4357841493832cd6ca2a)
- [【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた～その2～](https://qiita.com/oboerarenai_user/items/4a36c2b11e7dee74b66b)
- [【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた～その3～](https://qiita.com/oboerarenai_user/items/db5ef43bcff25223a147)
- [【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた～その4～](https://qiita.com/oboerarenai_user/items/b942c865e38a46d112c6)

# 作業開始

今回はstaticファイルを操作していきます。staticファイルとはJavaScript、CSS、画像などのことです。

## アプリ の構造をカスタマイズする

SCCファイルを作成します。
まずはCSSファイルを格納するディレクトリを作成します。

Djangoのデフォルト仕様に則り「polls/static/polls/」ディレクトリを作成します。その配下にstyle.cssファイルを作成しましょう。

CSSを記述します。

```css:polls/static/polls/style.css

li a {
    color: red;
}
```

HTMLにCSSを読み込みます。
この時、{% static %}テンプレートタグを使用するのを忘れないでください。

```html:polls/templates/index.html

{% load static %}

<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">

```

サーバを起動しSCCが適用されていることを確認します。

```python

(poll-HcNSSqhc) C:\django\poll>python manage.py runserver
```

リンクが赤になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763383/df9703ec-20b7-1d85-14f1-f1a46165ff2d.png)

より自然な緑にしておきます。

```css:polls/static/polls/style.css

li a {
    color: green;
}
```

## 背景画像を追加する

画像フォルダを作成します。
画像もstaticファイルの一種ですので、「polls/static/polls/images」フォルダを作成し、配下にDjangoのロゴを配置します。

```css:polls/static/polls/style.css
body {
    background-image: url("images/django.png");
    background-size: 30%;
    background-repeat: no-repeat;
}
```

背景画像が表示されました。画像読み込みができたので、とりあえずOKとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763383/d384cecb-aab5-14e2-77b6-bbc37ca4f3d2.png)

本日はここまでにします。ありがとうございました。
既存のプロジェクトにprettierを使用する

### 最初に
自動コード整形に、prettier を使い始めてみたのですが、既存のコードに適応する方法が分からなかったので、調べてみました。

### 手順

1.  Install
2.   `.prettierignore` の作成
3.  prettierの実行

#### Install

最初にprettierをインストールします。

```
npm install -g  prettier
```

#### `.prettierignore` の作成

自動コード整形しないファイルを記載します。

```js:.prettierignore
node_modules/
```

#### prettierの実行

最後にprettierを実行します。

```
prettier --write "**/*.js"
```

### まとめ

プロジェクトの途中からでも、prettierを入れることが簡単なので、フォーマット揃えたいなと思った時は気軽に試してみてください。
DXライブラリで2Dピクセルシェーダーする

久しぶりに使おうとしたら大いにハマったので自分用メモ
※DirectX9記述
※ＤＸライブラリ Ver3.21 時点

#サンプルHLSL
画面全体にモザイクをかけるだけ
PS_INPUT、OUTPUTの記述を省略した最小限のソース

```
sampler sampler0 : register( s0 ) ;

float	mosLv;		//	モザイク強さ 0.0に近いほど荒い
float	alpha;		//	輝度：0.0～1.0

float4 main( float2 uv : TEXCOORD0 ) : COLOR0
{
	float	size1	= mosLv * 100;
	float2	uv1		= floor( uv * size1 + 0.5f ) / size1;	//	0.5fで中心揃えになる、端の部分が半分になるイメージ

	float4	texc	= tex2D( sampler0, uv1 );
	texc.a			= alpha;
		
	return texc;
}
```

DXライブラリについてくるツール（ShaderCompiler.exe）でコンパイルする
コマンドでPS2_0かPS3_0を指定

```
ShaderCompiler.exe /Tps_2_0 HLSLファイルのパス
```

拡張子.psoのシェーダーファイルが生成される。

#C++側

DxLib_Init()の前にDirectX9を使う宣言！
いつの間にかデフォルトでDX11を使うようになってたので注意
これをしないと何も描画されなくて延々と泣くことになる。

```
SetUseDirect3DVersion( DX_DIRECT3D_9EX );
```

シェーダーファイル読み込み
コンパイルで生成された、拡張子.psoのファイルを使用する。
※生のHLSLを読んでも何も起こらないので注意

```
int psHandle = LoadPixelShader( "Mosaic.pso" );
```

ポリゴンの頂点定義（インデックス式）
楽したいのでラムダ式記述。

```
std::array< VERTEX2DSHADER, 4 >	vertex;
std::array< unsigned short, 6 >	vertexIndex;

auto Settings = []( VERTEX2DSHADER &vtx, float x, float y, float u, float v )
{
	vtx.pos = VGet( x, y, 0.0f ) ;
	vtx.u   = u;
	vtx.v   = v;
	vtx.su  = u;
	vtx.sv  = v;
	vtx.rhw = 1.0f ;
	vtx.dif = GetColorU8( 255,255,255,255 ) ;
	vtx.spc = GetColorU8(   0,  0,  0,  0 ) ;
};

Settings( vertex[ 0 ], 100.0f,	100.0f,	0.0f, 0.0f );
Settings( vertex[ 1 ], 600.0f,	100.0f,	1.0f, 0.0f );
Settings( vertex[ 2 ], 100.0f,	600.0f,	0.0f, 1.0f );
Settings( vertex[ 3 ], 600.0f,	600.0f,	1.0f, 1.0f );

vertexIndex = { 0, 1, 2, 1, 2, 3 };
```

使用するテクスチャをセット
LoadGraphで読み込んだ画像やMakeScreenしたスクリーンなど

```
SetUseTextureToShader( 0, imgHandle ) ;
```

さっき読み込んだシェーダーファイルのハンドルをセット
HLSLで記述したパラメータもここで調整

```
SetUsePixelShader( psHandle );
SetPSConstSF( GetConstIndexToShader( "alpha", psHandle ), 1.0f );
SetPSConstSF( GetConstIndexToShader( "mosLv", psHandle ), 0.5f );
```

描画
アドレスモードはお好みで

```
SetTextureAddressMode( DX_TEXADDRESS_CLAMP );
DrawPolygonIndexed2DToShader( vertex.data(), 4, vertexIndex.data(), 2 );
```

#まとめ

これでもうハマらない。
DXライブラリのバージョンアップで仕様が変わりませんように・・・
AWSデプロイ後、画像が表記されない問題について

### 本番環境にアクセスしたらCSSがかかっていない。。。そんな時に解消した自分の解決法を備忘録に残します。画像の場所はapp/assets/imagesです

### 解決策1　CSSファイルの拡張子の後ろに.SCSSを付け足す
しかしこれでも解決しませんでした。人によってはこれだけいけたという人も聞きます。

### 解決策2　CSS.SCSSの表記を見直す
僕の場合、表記が
```background-image: url(/assets/画像名);
```
だったのを
```background-image: image-url("画像名");
```
に変更後

```
$ git pull origin master
```
で反映させる。しかしこれでも適用されず

### 解決策3　コンパイルし直す
https://qiita.com/yoheism42/items/dcf71691ca3e8dfc26c5
ここの記事を参考に


```
$ find app/assets/ -type f -exec touch {} \;
$ rake assets:clobber assets:precompile
$ RAILS_ENV=production rake assets:precompile
```
を試す。そうすると２行目のコマンドで

```
========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================
```
こんなエラー。これに対しては
```$ yarn upgrade
```
その後またさっきの3行のコマンドを初めから試す。そうすると今回は弾かれずにすんなりいった。

最後に

```
$ sudo systemctl start nginx
$ sudo systemctl reload nginx
```
の順に実行してエンジンエックス再起動

その後

```
$ ps aux | grep unicorn
$ kill 1376　　 ←unicorn masterの行の一番左端の数字
$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
```
### これでなんとか画像を表示させることに成功しました。
長かった・・・
シンボリックリンクの作成/削除方法

情けない話ですが、いつも忘れてしまうので自分の備忘録です:point_up:
自分は画像などを切り分けて、シンボリックリンクを使って表示させています。参考になれば幸いです。
間違っている点等ありましたらご指摘ください！！

## ☆やること
① .ssh/configの作成
② シンボリックリンクの作成

## ☆手順
ssh接続
↓
シンボリックリンク作成
↓
シンボリックリンク削除

## ☆ssh接続
### configの設定
SSHコマンドを入力するのが面倒なので、サーバごとに設定しています。
現場の先輩から教わって、タイムアウト設定を無しにしています。

```
$ cd ~/.ssh
$ vi config

Host *
ServerAliveInterval 30
ServerAliveCountMax 5
TCPKeepAlive yes

### Connect Setting Name ###
Host sample_w1
HostName 0.0.0.1
Port	 22
User	 hoge
IdentityFile	sample.pem
```

設定が終わったら、続きです。
サーバの<code>/var/sample_api/public</code>を対象にシンボリックリンクを作成します。

```
$ ssh sample_w1

[hoge@sample_w1 ~]$ ls /var/sample_api/public
fonts  img  index.html  js
[hoge@sample_w1 ~]$ cd プロジェクト
```

### シンボリックリンクの作成
```
[hoge@sample_w1 ~]$ ln -s /var/sample_api/public sample_api
[hoge@sample_w1 ~]$ ll
drwxrwsr-x 1 hoge   team  0 1月 1 13:54 .
drwxrwsr-x 1 hoge   team  0 1月 1 13:54 ..
lrwxrwxrwx 1 hoge   team  0 1月 1 13:55 sample_api -> /var/sample_api/public/
```

### シンボリックリンクの削除
```
[hoge@sample_w1 ~]$ unlink sample_api
[hoge@sample_w1 ~]$ ls -a
.			..
```
注意すべき点として、<code>rm</code>コマンドで実体を削除しないようにしてください...

## ☆参考文献
https://qiita.com/colorrabbit/items/2e99304bd92201261c60
https://www.atmarkit.co.jp/ait/articles/1605/30/news022.html
https://qiita.com/passol78/items/2ad123e39efeb1a5286b
Flutter自体のバージョンを切り替える方法

今はfvmを使用しています。

# 以下過去の記事
複数のFlutterアプリを開発しているとFlutter自体のバージョンを切り替えることもあります。
今のFlutterではバージョンの切り替えをスムーズにする方法がサポートされていないので、試行錯誤の結果以下の方法でバージョンを切り替えています。

## リポジトリのclone
depthやブランチは指定せずにcloneします。

```
git clone https://github.com/flutter/flutter.git
```

## stableチャンネルを参照する
上の方法でcloneするとmasterブランチ(チャンネル)を参照しているので以下のコマンドでstableに変更します

```
flutter channel stable
```

## 任意のバージョンに変更する
以下のgitコマンドでローカルリポジトリを任意のバージョンに変更します。この例では1.17.4に変更しています。

```
cd flutterリポジトリ
git checkout 1.17.4
```

以下のようにdetached HEADになったよと言われますが、 `git checkout stable` で stableブランチに戻れるので、特に気にしなくてよいです。

```
Updating files: 100% (3130/3130), done.
Note: switching to '1.17.4'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 1ad9baa8b9 Change iOS device discovery from polling to long-running observation (#59695)
```

## 最新にしたい
stableブランチ(チャンネル)に戻れば、clone時点の最新になります。
試していませんが、新しいバージョンがリリースされたときは `git pull` あたりで `stable` チャンネルの最新にできそうです。

```
cd flutterリポジトリ
git checkout stable
```

# 最後に
`flutter version` `flutter upgrade/downgrade` など使う方法も検索すると見つかりましたが、複数のバージョンを気軽にスイッチするには、この方法が私的にはベストでした。
Access2019単品購入方法

#はじめに

9/15にデータベースの学習を開始して、1ヶ月弱が経ちました。データベースの基本、SQL基礎、と学んできて、いよいよAccessに突入です。
昨年PCを購入した際に、
Microsoft(R) Office Home and Business 2019 ( Word / Excel / Outlook / PowerPoint ) ( 個人向け )
を付けました。が、こちらにはAccessは入っていません。
ということで、Access2019を単体で購入することにしました。

購入方法に種類が色々とあったので、どれを購入して良いかわかりません。
なので、この記事に整理しながら、購入方法を決めたいと思います。

#Access2019購入方法
以下の3通りのパッケージがあるようです。
それぞれの内容は下記の通り。
(この内容で合っているかは自信無しです…。自分が理解した通りにまとめてみました。）

公式価格は2020/10/12時点のもの。


【Access2019単品】（買い切り）
公式価格：¥16,284 (https://www.microsoft.com/ja-jp/microsoft-365/p/access/cfq7ttc0k7q8?activetab=pivot%3aoverviewtab)
買い切りの永続ライセンス。
Windows PC 2 台で利用可能。
購入後、自動バージョンアップはされない。ずっと2019のまま。バージョンアップしたいときには、またバージョンアップ版を買う必要がある。
一度購入すると、ダウンロードしたPCが壊れるまで使える。
PCを買い替える際は、同じライセンスを引き継ぐことはできない。また改めて買いなおす必要がある。


【Office Professional 2019】（買い切り）
公式価格：¥65,784 (https://www.microsoft.com/ja-jp/microsoft-365/p/office-professional-2019/cfq7ttc0k7c5?activetab=pivot%3aoverviewtab）
Word、Excel、PowerPoint、Outlook、Publisher、Accessが含まれる。
買い切りの永続ライセンス。
Windows PC 2 台で利用可能。
購入後、自動バージョンアップはされない。ずっと2019のまま。バージョンアップしたいときには、またバージョンアップ版を買う必要がある。
一度購入すると、ダウンロードしたPCが壊れるまで使える。
PCを買い替える際は、同じライセンスを引き継ぐことはできない。また改めて買いなおす必要がある。


【Microsoft 365 Personal】（月額or年額サブスク）
公式ページ年額：定価＝¥12,984/年。2020/10/12時点＝¥9,089(30%オフ)/年。
公式ページ月額：¥1,284 (https://www.microsoft.com/ja-jp/microsoft-365/p/microsoft-365-personal/cfq7ttc0k5bc?activetab=pivot%3aoverviewtab)
Word、Excel、PowerPoint、Outlook、Publisher、OneDrive、Accessが含まれる。
サブスクリプション。
Windows PC、Mac、iOS および Android に対応。同時に5台のデバイスで利用可能。
常に最新バージョンの Office アプリと 1 TB のクラウド ストレージ、高度なセキュリティが含まれている。

#単品の価格比較

単品のものを購入することにしました。
以下、2020/10/12時点の価格。全て税込み。

【公式ホームページ】
価格：¥16,284
（https://www.microsoft.com/ja-jp/microsoft-365/p/access/cfq7ttc0k7q8?activetab=pivot:overviewtab）
購入後、その場ですぐにダウンロードできる。

【Amazon】
-パッケージ版(カード)　Microsoft Access 2019(最新 永続版)|カード版|Windows10|PC2台
価格：¥14,791　（参考価格¥16,280の¥1,489(9%)オフ。148 Amazonポイント(1%)還元あり。）
（https://www.amazon.co.jp/Microsoft-Access-2019-%E3%82%AB%E3%83%BC%E3%83%89%E7%89%88-Windows10/dp/B07K2XFBZH　
購入後、オンラインコードが記載されたカードが送付される。

-オンラインコード　Microsoft Access 2019(最新 永続版)|オンラインコード版|Windows10|PC2台
価格：¥14,643（参考価格¥15,074の¥431(3%)オフ。Amazonポイント還元は無し。）
（https://www.amazon.co.jp/Microsoft-Access-2019-%E3%82%AB%E3%83%BC%E3%83%89%E7%89%88-Windows10/dp/B07LBWK416?th=1）
購入後、その場ですぐにダウンロードできる。

【その他のネットショップ】
「Access 購入方法」でググったら、¥12,800で購入可能なショップが出てきました。が、不安なので手は出さず。Amazonで購入しようと思います。

こんな解説記事がありました！
[【Access 2019】安く購入する方法・価格はいくら？ (PCの鎖)](https://pc-chain.com/access-sale/9495/)
やはりAmazonで購入しようと思います。

#おわりに
Amazonで、オンラインコード版 ¥14,643　を購入することにしました。
偶然にも明日、明後日はAmazonプライムデーです。
Accessも安くなるのか…？というケチケチ根性が顔を出してきたので、明日価格を見てから購入します。

→2020/10/13追記：Prime Dayセールで、¥13,179（¥14,643からさらに1割引）になっていました。購入しました。
CodeIgniter4でTwigを使う(Composer利用)

#CodeIgniter4でもtwigを使いたい
[前の記事](https://qiita.com/kohenji01/items/bcf4832af61e0e0c446f)ではCI4にSmartyを組み込みましたが、近頃はTwigをテンプレートエンジンに採用しているケースも多いのではないでしょうか？
本記事ではCI4にTwigを利用する方法の解説です。

#Twig for CodeIgniter4を導入する
CI4上でTwigを利用するには拙作、[CodeIgniter4 for Twig](https://github.com/kohenji01/CI4Twig)を使うと手っ取り早いです。
CI4との統合は最低限の実装にとどめているので動作は軽いと思います。

例は「[CodeIgniter4をインストール (Composer利用)](https://qiita.com/kohenji01/items/a36dbbbb19bb8808d104)」での導入を終えた流れでインストールをした場合です。

```bash:composerによるTwig&nbsp;for&nbsp;CodeIgniter4の導入
$ cd /home/ci4test
$ composer require sarah-systems/ci4twig
```

以下は、概ねREADME.mdからの抜粋です。

#使い方
デフォルトでは、Twig関連のパスは自体は次のような設定で動作するようになっています。

| 種類         | パス                        |
|:-------------|:----------------------------|
| テンプレート | app/Views                   |
| キャッシュ   | writable/twig/cache         |

`writable`が正しく書き込み可能な場合、キャッシュディレクトリは自動的に生成されます。
もしエラーが起きた場合は、これらのディレクトリを作って適切なパーミッションを与えることで動作します。

もしこのパスを変更したい場合は`.env`ファイルに次のパラメータをセットすることで、任意のパスに変更可能です。

```bash
CI4Twig.TemplateDir = /path/to/TemplateDir
CI4Twig.CacheDir = /path/to/CacheDir
```

これ以外にも`.env`では、TwigのDebugフラグのOn/Offとデフォルトの拡張子を設定できます。

```bash
CI4Twig.Debug = 1 または 0
CI4Twig.DefaultTemplateExtension = .html.twig
```

#view()
CI4のview関数をTwig用にCI4Twigというnamespaceで定義しています。

利用する際は`app`ディレクトリ直下の`Common.php`に次を追記してください。

```php
require_once ROOTPATH . "vendor/sarah-systems/ci4twig/src/Common.php";
```

使用法はCI4のview関数と同じですが、関数の利用時には名前空間を指定するか、事前にエイリアスを張ってください。

```php
\CI4Twig\view('template.html.twig');
```

または

```php
use function CI4Twig\view as view;
view('template.html.twig');
```

拡張子`.html.twig`（`CI4Twig.DefaultTemplateExtension`で設定されたものです。無指定の場合は`.html.twig`）は省略可能です。

```php
\CI4Twig\view('template');
```

view関数の第2パラメータはTwig変数`$CI`にアサインされます。

```php
$data = [ 'apple' , 'banana' , 'lemon' ];
\CI4Twig\view('template',$data);
```

Twigのtemplate上では

```twig
{{ CI.0 }} ← appleが表示されます。
```

第3引数の$optionsは無視されます。

#Service

CI4のServiceが利用可能です。

```php
use CI4Twig\Config\Services;

$time = date('Y-m-d H:i:s');
$twig = Services::twig();
$twig->Environment->addGlobal('time',$time);
$twig->Environment->display('template.html.twig');
```

次回はCI4のValidationの使い方について簡単に説明します。
JavascriptのFetchをネストして2回リクエストを投げる

#やりたいこと
大元は、配列から値を1つずつ回してXmlHttpRequestでPOSTを2回やろうと思ってたのですが、なかなかネスト後の値が検知できずにいたところで難しそうだったのでFetchを使ったところうまくネストして2回リクエストを送った値が取得できたのでメモします。化石の知識しかないので過不足は多分結構あります。

#コード例
これは例なのでPOSTする先やbody、headerは適宜変更してください。
1回目のリクエスト後にresponseをparseして、使いたい値を取り出してreturnで返すことで次のthenで使うことができます。
これをさらにretuenでfetchを投げることで次のthenで処理できるようにしているという流れになります。(or はJsonで返ってくることを想定したコードです)

```javascript:fetchNest.js
fetch('http://localhost:8922/services/AdministrationService', {
    method: 'POST',
    body: 'fname=aaaaa&uuid=31963958-31b2-487e-b185-c3559e6bb611&format=XLSX',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'text/xml'//or'application/json'
    },
}).then(function(response) {
    return response.text();//or response.json();
}).then(function(responseText) {
    var parser = new DOMParser();//or responseText.dataValue.reportId;
    var doc = parser.parseFromString(responseText, "text/xml");
    return doc.getElementsByTagName("dataValue")[1].textContent;
}).then(function(reportId) {
    return fetch('http://localhost:8922/services/ReportService', {
        method: 'POST',
        body: 'fname=aaaaa&uuid=31963958-31b2-487e-b185-c3559e6bb611&format=XLSX&reportId='+reportId,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'text/xml'
        },
    });
}).then(function(response) {
    return response.text();
}).then(function(responseText) {
    console.log(responseText);
}).catch(function(e) {
    // エラーが発生した場合の処理
    console.log(e);
});
```

#大変参考にさせて頂きました
[まだXMLHttpRequestを使ってるの？　fetchのすすめ](https://qiita.com/uhyo/items/91649e260165b35fecd7)
[Fetch の使用](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch)
なぜLinuxを使うのか

# はじめに
どうも、isso0424です。
この記事はLinux布教を推し進めたい変態による記事になっています。
興味のある方はどうぞ。

# Linuxって何?
まず「Linuxって言われてもわからん!!!」っていう人もいるかもしれないので軽く紹介しておきます。
Linuxはコンピュータの***OS***の一つです。
OSがまずわからんって人はWindowsとかMacOSとかと同じようなものだと思ってください。
そしてLinuxは基本的にMacOSと同じUNIX系のOSに分類されます。

# 利点紹介TIME
能書きはここまで。
**Linuxの利点**について紹介していきます。
## 1.軽い
はい、見出しのとおりです。
Windowsで、低スペックなPCを使っていると結構動作が重くなります。(筆者は一昨年までこの環境でした)
これは、バックグラウンドで余計なプロセスが大量に走ることに起因するものです。
***ここでLinuxを見てみましょう***
Linuxは最低限のプロセスで動くので基本軽いです。
**重いと言われているGnomeですらWindowsよりも軽いです。**

## 2.ソフトウェアのインストールが楽
ここではArchlinuxの例を示します。
もしGitをインストールするとすると、Windowsであれば

- 1.ダウンロードするためのページに移動
- 2.インストーラーをダウンロード
- 3.ダウンロードしたインストーラーを使ってインストール

の少なくとも3ステップが必要です。
しかし、ArchLinuxであれば、

```bash
$ sudo pacman -S git
```
これでインストールが終わります。
見ればわかるとおり、**1行でソフトウェアのインストールを済ませることができます。

## 3.ターミナルで生活できる
windowsでは、GUIが無いと生活ができません。
しかし、linuxではGUIが無くともコンソール上で生活ができます。
コンソール上でビルド、ファイル編集、
何が嬉しいかというと、充電が不安なときに仮想コンソールで作業したり、sshでリモートログインしてPCコンソール上で作業したりすることができます。

## その他にも...
- 様々なディストリビューションがある
- サーバーの運用時に勉強が楽になる
- 自分の好きなデスクトップ環境を使える
- 全部カスタマイズできる

など数多くのメリットがあります。

# まとめ
VMでも良いのでぜひLinuxを一回使ってみてください!!!
もしかしたらPC生活が変わるかもしれません!!!!

# おまけ
この記事の本質とはそれてしまうのですが、VMでのUbuntuの実行についての記事を貼っておきます
[Windows10上に仮想Ubuntu環境を構築（VMware Workstation Player）](https://qiita.com/iwa_gino/items/11aaffa9e49f2fc423d0)
[Windows10にVirtualBoxとUbuntuをインストール](https://qiita.com/pyon_kiti_jp/items/0be8ac17439abf418e48)
PostgreSQLでDBlinkを使用する方法

PostgreSQLでDBLinkを使用する時のメモです。
DBLinkを使用することでリモートのデータベースへ接続してSQLを発行することが出来る。

# dblinkを利用できるようにする

OracleDBのようにデフォルトだとDBlinkを使用できない。
extensionを導入する必要がある。

```
create extension dblink;
```

# DBlintk作成して接続

```
select dblink_connetct('DBLINK01','host=host2 port=5432 dbname=db2 user=xxx password=xxx');
select * from dblink('DBLINK01',
                     'select id, name from table') as t1(id text, name text) ;
```

# DBlinkのを作成しないで接続

```
select * from dblink('hostaddr=IPorHostname port=Port dbname=dbname user=connect_user password=Password',
                     'select id, name from table') as t1(id text, name text) ;
```
PyTorch を CUDA11 でビルドする

# 背景

* 最新の nvidia ドライバ(450 あたり)を使っている.
  * CUDA 11 になっている
* Pytorch の prebuilt 対応は 10.2 まで

いずれ CUDA11 対応(v1.7.0?)も出てくるでしょうが, それまでは自前でビルドして対応します.

https://discuss.pytorch.org/t/install-pytorch-with-cuda-11/89219

Linux(Ubuntu)を想定します.

## 手順

https://varhowto.com/install-pytorch-cuda-11-0/

にある通りでいけました. ありがとうございます.

もろもろ apt や (mini)conda で依存パッケージなどいれたのち, 最終的には普通に

```
$ python setup.py install
```

でいけます.