OmniAICreator/Qiita-1.07M huggingface dataset:
c++のvector,array,配列での最大値・最小値取得法まとめ

最近c++を勉強し始めて、最小値・最大値の取得方法につまづいたので備忘録として残します。
vector型、array型および配列の3種類を調べました。
また、調べた関数は```min_element```関数,```max_element```関数および```minmax_element```関数です。この３つの関数はc++の標準ライブラリに用意されています。

## 結論
最小値・最大値を別々に知りたい場合

```cpp
// xはvector or array or 配列
int min = *min_element(begin(x), end(x));
int max = *max_element(begin(x), end(x));
```

最小値・最大値両方得たい場合

```cpp
// vector　の場合(vecはvector型配列)
pair<vector<int>::iterator, vector<int>::iterator> minmax;
minmax = minmax_element(begin(vec), end(vec));
// xが　array or 配列　の場合
pair<int*, int*> minmax;
minmax = minmax_element(begin(x), end(x));
```

## テスト
{10,30,20,50,40}という数字列を使って動作テストをしました。
### vector型の場合
minmax_element関数を使うときに```pair```クラスに格納されるのはイテレータであることに注意が必要です。

```cpp
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    vector<int> vec;
    vec = {10,30,20,50,40};

    // 最小・最大値
    int min = *min_element(begin(vec), end(vec));
    int max = *max_element(begin(vec), end(vec));
    cout << min << " , " << max << endl;

    // minmax関数 (イテレータがpairに格納されたものが返される)
    pair<vector<int>::iterator, vector<int>::iterator> minmax;
    minmax = minmax_element(begin(vec), end(vec));
    // pairの最初の要素が最小値のイテレータ, ２番目の要素がmaxのイテレータ
    cout << *minmax.first << " , " << *minmax.second << endl;
    return 0;
}
```
```
#出力結果
10 , 50
10 , 50
```

### array型の場合

```cpp
#include<iostream>
#include<algorithm>
#include<array>
using namespace std;
int main(){
    array<int, 5> arr;
    arr = {10,30,20,50,40};

    //　最大・最小を別々に取得したい場合
    int min = *min_element(begin(arr), end(arr));
    int max = *max_element(begin(arr), end(arr));
    cout << min << " , " << max << endl;

    // minmax関数 (最小・最大値のポインタがpairに格納される)
    pair<int*, int*> minmax;
    minmax = minmax_element(begin(arr), end(arr));
    //値を取り出す際は*演算子を使う
    cout << *minmax.first << " , " << *minmax.second << endl;
    return 0;
}
```
```
#出力結果
10 , 50
10 , 50
```
### 配列の場合
```cpp
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int x[5] = {10,30,20,50,40};; //要素数5の配列を定義

    //　最大・最小を別々に取得したい場合
    int min = *min_element(begin(x), end(x));
    int max = *max_element(begin(x), end(x));
    cout << min << " , " << max << endl;

    // minmax関数, 最小値と最大値のポインタを返すので、int*と定義
    pair<int*, int*> minmax;
    minmax = minmax_element(begin(x), end(x));
    //値を取り出す際は*演算子を使う
    cout << *minmax.first << " , " << *minmax.second << endl;
    return 0;
}
```
```
#出力結果
10 , 50
10 , 50
```

## 備考
<https://cpprefjp.github.io/reference/algorithm/minmax.html>
<https://qiita.com/shirakawa4756/items/f4cc65c6b2b412b10c0c>

不備などがありましたら、教えていただけると幸いです。

## 追記(2021/8/6)

@myoukaku　さんに以下のような```auto```を使った書き方を教えていただきました。ありがとうございます。

~~例えば、vector型を使うとき、２行を一行にすることができます。~~
例えば、vector型を使う時の記述を簡単にできます。

```cpp
//autoを使う前
pair<vector<int>::iterator, vector<int>::iterator> minmax;
minmax = minmax_element(begin(vec), end(vec));

//autoを使った場合
auto minmax = minmax_element(begin(vex), end(vec));
```
また、この書き方であればvector型だけでなく、array型や配列でも同じ書き方で済みます。
[GAS] URLからドライブのアイテムを取得するコード(リソースキー対応)

Google Driveのアップデートで、各アイテムのURLに「リソースキー」が付与されることとなりました。

https://support.google.com/a/answer/10685032?hl=ja

これに伴って、DriveAppにもAPIが追加されました。

https://developers.google.com/apps-script/reference/drive/drive-app

- DriveApp.getFolderByIdAndResourceKey(id, resourceKey)
- DriveApp.getFileByIdAndResourceKey(id, resourceKey)

現時点でのDriveAppには残念ながらURLからフォルダやファイルを取得するAPIが用意されていません。
そこで本記事では、URLからフォルダやファイルを取得するコードを紹介します。

# コード

URLのパターンとしては以下の4パターンあります。（ファイルについてはファイルの種別によって先頭のURLが変わります）

- https://drive.google.com/drive/folders/{フォルダID}
- https://drive.google.com/drive/folders/{フォルダID}?resourcekey={リソースキー}
- https://drive.google.com/file/d/{ファイルID}/view?usp=sharing
- https://drive.google.com/file/d/{ファイルID}/view?usp=sharing&resourcekey={リソースキー}

今回はこの4パターンに対応したコードです。以下の2つの関数を作成しました。URLを渡せばフォルダやファイルのオブジェクトが返ってきます。

- URLからフォルダを取得するgetFolderByUrl関数
- URLからファイルを取得するgetFileByUrl関数

```javascript:コード.gs
function myFunction() {
  // URLからフォルダを取得
  const folderUrl = 'https://drive.google.com/drive/folders/xxxxxxxxxx?resourcekey=yyyyyyyyyyyy'
  const folder = getFolderByUrl(folderUrl)
  console.log(folder.getName())

  // URLからファイルを取得
  const fileUrl = 'https://drive.google.com/file/d/xxxxxxxxxx/view?usp=sharing&resourcekey=yyyyyyyyyyyy'
  const file = getFileByUrl(fileUrl)
  console.log(file.getName())
}
```

それぞれの関数は以下の通りです。

```javascript:関数.gs
// URLからフォルダを取得する
function getFolderByUrl(url) {
  const info = getIdAndResourcekeyByUrl(url, true)
  if (info['resourcekey']) {
    return DriveApp.getFolderByIdAndResourceKey(info['id'], info['resourcekey'])
  } else {
    return DriveApp.getFolderById(info['id'])
  }
}

// URLからファイルを取得する
function getFileByUrl(url) {
  const info = getIdAndResourcekeyByUrl(url, false)
  if (info['resourcekey']) {
    return DriveApp.getFileByIdAndResourceKey(info['id'], info['resourcekey'])
  } else {
    return DriveApp.getFileById(info['id'])
  }
}

// アイテム情報オブジェクトを取得する
function getIdAndResourcekeyByUrl(url, isFolder=true) {
  return {
    'id': getIdByUrl(url, isFolder),
    'resourcekey': getQueryParamsByUrl(url)['resourcekey']
  }
}

// URLからアイテムIDを取得する
function getIdByUrl(url, isFolder=true) {
  if (!url || url === '') {
    throw Error('無効なURL')
  }

  // スラッシュでURLを分割
  const splitedUrl = url.split('/')
  // idの前に来る特定の文字列
  let searchString = 'd'
  if (isFolder) {
    searchString = 'folders'
  }

  let id = ''
  for (let i=0; i<splitedUrl.length; i++) {
    // 特定の文字列に一致する場合はidを取得
    if (splitedUrl[i] === searchString && splitedUrl[i+1]) {
      id = splitedUrl[i+1]
      break
    }
  }

  // クエリパラメータは除去
  return id.split('?')[0]
}

// URLからクエリパラメータを取得
function getQueryParamsByUrl(url) {
  const params = {}

  if (url.split('?').length < 0) {
    // クエリパラメータがない
    return params
  }
  // クエリパラメータの文字列を取得
  const queryUrl = url.split('?')[1]
  if (queryUrl) {
    // パラメータ毎にキーと値を抽出
    const queryRawParams = queryUrl.split('&')
    queryRawParams.forEach(function(value, index) {
      const kv = value.split('=')
      params[kv[0]] = kv[1]
    })
    return params
  }
  // 全てのキーと値を持ったオブジェクトを返却
  return params
}

```
node.jsでsocket.ioを使い大きなデータを送信すると途切れる話

node.jsで音声データのやり取りをする処理を書いたのだが、大きなデータだと途切れる時がある。

なんか色々調べたら、これで解決できるらしい。

socket.ioを持ってくるときに

``` app.js
const io = require('socket.io')(http,
  {maxHttpBufferSize: 1e10}
);
```
バリバリドキュメントに書いてあるのだが、しばらく沼ったのでメモ

maxHttpBufferSize　は指数記法で書くらしい


https://socket.io/docs/v3/server-initialization/#:~:text=upgrade%20is%20cancelled.-,maxHttpBufferSize,-Default%20value%3A%201e6
Grove IoT スターターキット for SORACOM の使い方

「Grove IoT スターターキット for SORACOM」の最初の使い方として、基盤についている LED を点灯させてみました。

```text:led_test/led_test.ino
// ---------------------------------------------------------------
/*
	led_test.ino

					Aug/04/2021
*/
// ---------------------------------------------------------------
 
#include <WioLTEforArduino.h>

WioLTE Wio;

void setup() {
	delay(1000);

	SerialUSB.println("");
	SerialUSB.println("*** START ***");  
	SerialUSB.println("### I/O Initialize.");
	Wio.Init();
	delay(1000);
	SerialUSB.println("### Setup completed.");
	SerialUSB.println("");
}

// ---------------------------------------------------------------
void loop() {
	led_delay_proc(0,0,1,1000,"blue");
	led_delay_proc(0,1,0,1000,"lime");
	led_delay_proc(1,0,0,1000,"red"); 
	led_delay_proc(1,1,0,1000,"yellow");    
	led_delay_proc(0,1,1,1000,"cyan");
	led_delay_proc(0,0,0,2000,"black"); 
	SerialUSB.println("");
}

// ---------------------------------------------------------------
void led_delay_proc(int rr,int gg,int bb,int msec,String mesg){
	Wio.LedSetRGB(rr, gg, bb);
	SerialUSB.println("*** "+ mesg + " ***");
	delay(msec);
}

// ---------------------------------------------------------------
```

Arduino IDE の様子
![arduino_ide_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/76003a65-9e3f-714f-0a12-e52e6f740c1f.png)

マイコンボードに書き込んで、実行させます。
LED が点灯し、シリアルモニタに次の表示が出ます。
![wiolte_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/bd135299-2594-2d28-4b19-7aa5162bb4f0.png)

実行時の様子
![wiolte_aa.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/0376f552-9f23-ab09-bf41-5dd60f7c0506.jpeg)
AWS Amplifyを使ってReactアプリをデプロイ

# はじめに

React アプリを作成してローカルの開発サーバで動きを確認できたので、デプロイしていく。AWS EC2 インスタンスにサーバ構築をしてデプロイしようと調べていたところ、AWS Amplify という便利なサービスを見つけたので、[AWS で React アプリケーションを構築する](https://aws.amazon.com/jp/getting-started/hands-on/build-react-app-amplify-graphql/)を参考に試してみる。
なお、React アプリはすでに作成して GitHub レポジトリにプッシュ済みを前提としている。

# 1. React アプリをデプロイしてホストする

AWS マネジメントコンソールにログインして、AWS Amplify コンソールへ遷移。公式では [Deploy] の下の [GET STARTED] を選択と書かれているが、現在の画面にはないので [Deliver] の下の [Get started] を選択。

![amplify_getstarted.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/220b234b-3525-02f3-62a6-e92a09b60024.png)

自身が使用している Git レポジトリプロバイダを選択する。今回の場合は、GitHub を選択。GitHub で認証する。

![amplify_host.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/4a63212d-dc61-52a0-e690-e4fe32d0eff9.png)

認証完了後に、レポジトリとブランチを指定する。

![amplify_authentication.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/431af100-77fb-dc23-5667-91764e5689b9.png)

ビルド設定 amplify.yml が出てくるので、デフォルトのままと進める。

```yaml:amplify.yml
version: 1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install # yarn install から修正
    build:
      commands:
        - yarn run build # yarn run build から修正
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
```

ビルド設定をデフォルトのまま進めて、最終的な詳細を確認して[保存してデプロイ]を選択。しばらく待つとビルドおよびデプロイ完了となる。

![amplify_build.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/b2ba0fb2-3d72-17db-db53-eb793c49ef04.png)

# おわりに

驚くほど簡単にデプロイができた。これをベースに Amplify CLI での扱いなどを理解していきたい。
How to import SSL certificate on MacBook?

It migt be common if you encounter an issue when you try to access internet sites. The reason is that specific SSL certificates are not imported on your laptop. This note is a quick tutorial how you can import SSL certificate on your MacBook.

<img src="https://i.imgur.com/yZZVFLM.png" width=70%>

Click "Not Secure" on your Chrome URL bar and select the root certificate. Drag the certificate and drop it somewhere you like.
<img src="https://i.imgur.com/NA111Um.jpg" width=70%>

Double click the certificate. Select "System" and hit "Add", and it will import the certificate to Keycahin.
<img src="https://i.imgur.com/5YEZNch.jpg" width=70%>

Double click the certificate which has been imported.
<img src="https://i.imgur.com/Czihbd5.jpg" width=70%>

Hit "Trust" and select "Always Trust", and close Keychain. You will be asked to input your MacBook's password - try to do.
<img src="https://i.imgur.com/X8HoQs2.jpg" width=70%>

Try to visit the site you would like to access - it might be working if the import has been done successfully!
p5.playをやる記事#04_画像を適用する

[前回の記事](https://qiita.com/sdkfz181tiger/items/033e84190df1955492c5) | [次回の記事](https://qiita.com/sdkfz181tiger/items/bfd4e59491379fd57fd9)

p5.playの使い方を解説しております。
[第1回の記事](https://qiita.com/sdkfz181tiger/items/c424b0777f7d7fe2203a)はこちらにありますのでご参照ください。

## 画像を適用する

スプライトに画像を適用します。(これがやりたかったんですよね!!)
下に簡単な画像を用意してみましたので、こちらをお使いください。
"右クリック -> ダウンロード -> 保存"で出来ると思います。

![t_tanu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/ed83b976-f64a-c0c0-7027-efb60586596b.png)

勿論、自分で画像を作る事もできます。
お勧めのオンラインエディタがありますのでご紹介しますね。
(最近は何から何までブラウザがあれば出来てしまうのです!!)

[Piskel](https://www.piskelapp.com/)

Piskelはとても便利なオンラインツールです。
挑戦したい方は、この動画を参考にしてくださると幸いです。(宣伝です!!)

<iframe width="560" height="315" src="https://www.youtube.com/embed/BC3ZTrrUzyU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## 画像ファイルをスケッチにアップロードする

先ほどの画像(タヌキの画像です)を、スケッチにアップロードしましょう。
スケッチの右側にあるメニューボタンをクリックします。

![ss_small_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/4808978e-e200-d581-27b6-4707b3aaa17c.png)

次に、"Files"をクリックし、"Drag files here or select"のエリアに画像ファイルをドラッグ&ドロップします。
アップロードが完了するとファイル名が表示されます。(t_tanu.pngという感じです)
このファイル名を使ってロードしますので覚えておきましょう。

![ss_small_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/27ea5b48-2403-5ecf-7d75-1c7d268a975d.png)

## 画像ファイルをロードする

ここからはプログラムのお話になります。
p5.playで画像や音声ファイルを使用するには、事前にロードする必要があります。
今回は画像ファイルですので、loadImage関数を使います。
引数には、先ほどアップロードした画像ファイルの名前を記述します。(確認しておきましょう)
この関数を記述する場所はpreload関数の中になります。

```JavaScript
loadImage(ファイル名);
```

最後に、addImage関数を使って画像データを適用します。

```JavaScript
スプライト.addImage(画像データ);
```

あらかじめ変数"img"を用意し、ここに画像データを格納します。
全体としては下記の様になります。

```JavaScript
let img;// 1, 画像データを格納する変数

function preload(){
   img = loadImage("t_tanu.png");// 2, 画像をロードする
}

function setup(){
   createCanvas(windowWidth, windowHeight);
   frameRate(32);
   noSmooth();
   let spr = createSprite(width/2, height/2);
   spr.addImage(img);// 3, 画像データを適用する
}

function draw(){
   background(0);
   drawSprites();
}
```

うまく動いていれば、スプライトに画像が適用されている事がわかります。
(テンションが上がりますね!!)

![ss_mid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/3bf53fee-4cd7-128e-4d98-e8bddbf9e394.png)

次回はアニメーションについてのお話になります。

[前回の記事](https://qiita.com/sdkfz181tiger/items/033e84190df1955492c5) | [次回の記事](https://qiita.com/sdkfz181tiger/items/bfd4e59491379fd57fd9)

## おまけ動画(こちらもよろしくお願いします)

<iframe width="560" height="315" src="https://www.youtube.com/embed/bHtS5tgRmFY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
プロミスマスターメモ

# プロミスの基本的な書き方

```js
const prA = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('prA')
      resolve()
    }, 1000)
  })
}
const prB = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('prB')
      resolve()
    }, 1000)
  })
}
const prC = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('prC')
      resolve()
    }, 1000)
  })
}

Promise.resolve()
  .then(prA)
  .then(prC)
  .then(prB)
```

# for文を交えた書き方
```js
const prA = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('prA')
      resolve()
    }, 1000)
  })
}
const prB = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('prB')
      resolve()
    }, 1000)
  })
}

const promises = []

const prX = (num) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(num)
      resolve()
    }, 1000)
  })
}

for (let i = 0; i < 3; i++) {
  promises.push(prX(i))
}

Promise.all(promises)
  .then(prA)
  .then(prB)
```
統計検定2級　2019年11月　問12

## 問題
・[統計検定2級　2019年11月　問12](https://www.toukei-kentei.jp/wp-content/uploads/201911grade2.pdf)

## 問12

### Ⅰ

$$E[\hat{\mu_{1}}] = E[\frac{1}{2}(X_{1}+X_{2})]$$

$$=\frac{1}{2}E[X_{1}]+E[X_{2}]$$

$$=\frac{1}{2}(\mu + \mu)$$

$$=\mu$$

よって、不偏推定量であるので、正しい。

### Ⅱ

$$V[\hat{\mu_{1}}] = V[\frac{1}{2}(X_{1}+X_{2})]$$

$$=\frac{1}{4}V[X_{1}]+V[X_{2}]$$

$$=\frac{1}{4}(\sigma^{2} + \sigma^{2})$$

$$=\frac{1}{2}\sigma^{2}$$

ここで、今回使用するチェビシェフの不等式を導出する。（[参照](https://www.youtube.com/watch?v=d-ugoDdXWrU)）

マルコフの不等式より

$$P(X \geq C) = \frac{E[X]}{C}$$

$X = (Y-\mu)^{2}$、$C=\epsilon^{2}$とすると

$$P((Y-\mu)^{2} \geq \epsilon^{2}) \leq \frac{E[(Y-\mu)^{2}]}{\epsilon^{2}}$$

よって

$$\begin{align}
P(|Y-\mu| \geq \epsilon) \leq \frac{\sigma^{2}}{\epsilon^{2}}\tag{1}
\end{align}$$

全確率の和は $1$ なので

$$1 - P(|Y-\mu| \geq \epsilon) = P(|Y-\mu| \leq \epsilon)$$

移項して

$$P(|Y-\mu| \geq \epsilon) = 1 - P(|Y-\mu| \leq \epsilon)$$

これを $(1)$ 式に代入すると

$$1 - P(|Y-\mu| \leq \epsilon) \leq \frac{\sigma^{2}}{\epsilon^{2}}$$

よって

$$\begin{align}
P(|Y-\mu| \leq \epsilon) \geq 1 - \frac{\sigma^{2}}{\epsilon^{2}} \tag{2}
\end{align}$$

と求まる。

$(2)$ 式に、$Y = \hat{\mu_{1}}$、$\sigma^{2} = V[\hat{\mu_{1}}] = \frac{1}{2}\sigma^{2}$ を代入すると

$$\begin{align}
P(|\hat{\mu_{1}}-\mu| \leq \epsilon) \geq 1 - \frac{\sigma^{2}}{2 \epsilon^{2}}
\end{align}$$

$n \to \infty$とすると

$$\lim_{n \to \infty}P(|\hat{\mu_{1}}-\mu| \leq \epsilon) \geq 1 - \frac{\sigma^{2}}{2 \epsilon^{2}}$$

これは $1$ に収束しないため、$\hat{\mu_{1}}$ は一致推定量ではないことが分かる。

よって、誤りである。

### Ⅲ

$$
E[\hat{\mu_{2}}] = E[\frac{1}{n-2}\sum_{i=2}^{n-1}X_{i}]$$

$$=\frac{1}{n-2}E[X_{2} + X_{3}+ \cdots + X_{n-1}]$$

$\\{X_{2} + X_{3}+ \cdots + X_{n-1}\\}$ は、$\\{X_{1} + X_{2}+ \cdots + X_{n}\\}$ という $n$ 個の集まりから<br>
$X_{1}$ と $X_{n}$ の2つを引いたものなので、$(n-2)$ 個となる。

$$=\frac{1}{n-2} \cdot \mu \cdot (n-2)$$

$$=\mu$$

よって、不偏推定量であるので、正しい。

### Ⅳ

$$V[\hat{\mu_{2}}] = V[\frac{1}{n-2}\sum_{i=2}^{n-1}X_{i}]$$

$$(\frac{1}{n-2})^{2}V[\frac{1}{n-2}\sum_{i=2}^{n-1}X_{i}]$$

$$=(\frac{1}{n-2})^{2} \cdot \sigma^{2} \cdot (n-2)$$

$$=\frac{1}{n-2}\sigma^{2}$$

$(2)$ 式に、 $Y = \hat{\mu_{2}}$、$\sigma^{2} = V[\hat{\mu_{2}}] = \frac{1}{n-2}\sigma^{2}$ を代入すると

$$\begin{align}
P(|\hat{\mu_{2}}-\mu| \leq \epsilon) \geq 1 - \frac{\sigma^{2}}{(n-2)\epsilon^{2}}
\end{align}$$

$n \to \infty$とすると

$$\lim_{n \to \infty}P(|\hat{\mu_{2}}-\mu| \leq \epsilon) \geq 1 - \frac{\sigma^{2}}{(n-2)\epsilon^{2}}$$

これは $1$ に収束するため、$\hat{\mu_{2}}$ は一致推定量であることが分かる。

よって、正しい。
[シリーズ 全3回] docker-composeを活用して即座にPython 3.9.4 を立てる


# はじめに

次の記録である.

限られた物理PC の中で、複数の Python バージョンをインストールして
プログラムを作成することになった.
　 
ただし、物理PC を汚染させるわけにもいかないので Docker を活用した.
(操作しやすいように docker-compose を導入した)



|コンテンツ|掲載時期|
|:--|:--|
|[[03] docker-composeを活用して即座にPython 3.9.4 を立てる ... 使い捨てコンテナで実行する](https://qiita.com/robozushi10/items/3a040b948586b1cd330a)|2021/08|
|[[02] docker-composeを活用して即座にPython 3.9.4 を立てる ... ビルドコンテナ実行ツール作成](https://qiita.com/robozushi10/items/7a087b78f1c7f7d46cd0)|2021/08|
|[[01] docker-composeを活用して即座にPython 3.9.4 を立てる ... ビルドコンテナを作る](https://qiita.com/robozushi10/items/fd5f3b0e503db1d62b47)|2021/08|
[03] docker-composeを活用して即座にPython 3.9.4 を立てる ... 使い捨てコンテナで実行する


|本シリーズのトップページ|
|:--|
|https://qiita.com/robozushi10/items/eebd8068a0533ba49bea|

# はじめに

限られた物理PC の中で、次の Python バージョン
・Python 3.6.8
・Python 3.7.3
・Python 3.8.3
・Python 3.9.4 
をインストールしてプログラムを作成することになった.

今回は参考として「使い捨て型のコンテナ」の作成方法についても記しておく[^1]


　

# 参考にした情報

|書籍|
|:--|
|[Docker/Kubernetes 実践コンテナ開発入門 (山田明憲　著)](https://gihyo.jp/book/2018/978-4-297-10033-9)|

　

# 手順


# 構築後のファイル構成

```
.
|-- PV ......................... 永続ボリューム
|   `-- py
|       `-- app ................ この直下に *.py を配置する
|           `-- a.py ........... サンプルコード
|-- assets
|   `-- py
|       |-- Dockerfile
|       `-- requirements.txt ... 導入したい Python パッケージを記述しておく
`-- docker-compose.yml
```


# 手順

## 1. 永続ボリュームを作成する

コードやデータを配置するために使用する.

```
$ mkdir -p PV/py/app
```

## 2. Dockerfile を作成する

独自拡張するために使用する. 
なお、「[常駐型コンテナを作る](https://qiita.com/robozushi10/items/fd5f3b0e503db1d62b47)」との差異は末尾 2行の ENTRYPOINT と CMD のみである.

```bash
$ mkdir -p assets/py/
$ vim assets/py/Dockerfile
```

### assets/py/Dockerfile

```dockerfile
FROM python:3.9.4-buster
 
## プロキシサーバを使う場合
# ENV http_proxy="http://proxy.co.jp:8080"  
# ENV https_proxy="http://proxy.co.jp:8080"
 
# コンテナ内での作業場所を /usr/src/app とする
WORKDIR /usr/src/app
 
# Python に関する環境変数
# pyc を作成しない
ENV PYTHONDONTWRITEBYTECODE 1
# python -u 相当. バッファリングしない. 
ENV PYTHONUNBUFFERED 1
 
# 日本環境に合わせる
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ENV LANGUAGE ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
 
# pip を更新したうえで必要なパッケージをインストールする
RUN python -m pip install --upgrade pip==21.0.1
COPY requirements.txt .
RUN pip install -r requirements.txt

# コンテナ起動すると同時に python を実行するための定義をする
ENTRYPOINT ["python"]
CMD [""]

```

## 3. requirements.txt を作成する

ここでは `assets/py/requirements.txt` に定義する

### assets/py/requirements.txt

以下は例である.

```
requests==2.23.0
sh==1.13.1
urllib3==1.25.9
```

## 4. docker-compose.yml を作成する

### docker-compose.yml

```yaml
version: '3.7'
 
services:
  py:
    build: ./assets/py
    image: mypy0394
    container_name: mypy0394
    volumes:
      - ./PV/py/app/:/usr/src/app/
```

## 5. イメージビルドをする

次のコマンドによって、Dockerイメージ「`mypy0394`」が作られる

```bash
$ docker-compose build --no-cache
```


## 6. サンプルコードが動作するか確認をする

### ./PV/pv/app/a.py

物理ホストで次の `./PV/pv/app/a.py` を作成する. 

コンテナ内からは `/usr/src/app/a.py` として見えている.

```python
#!/usr/bin/env python
#import requests
import urllib3
import sh
import sys

print("Hello Python 0394")

for a in sys.argv[1:]:
  print(a)

```

## 7. コンテナを使い捨てで実行する

docker-compose のコマンドとして `run --rm` を使えば良い.

```bash
$ docker-compose run --rm py a.py 1 2 3
Hello Python 0394
1
2
3

```

　
[^1]: 普段は「使い捨て型のコンテナ」をほとんど使用しない
【Android】Emulatorが起動しない不具合の解決法

# 不具合内容
API 29/30でAndroid Emulatorを起動しようとすると下記のような不具合発生。
![error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/16943c68-97d6-7684-f1ce-409879fdfbe4.png)
![error_detail_edit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/7d75f877-1667-401b-4286-1aa794d7af09.png)


# 解決法
`C:\Users\<name>\.android`フォルダ内に`advancedFeatures.ini`を追加し、以下のように記述することで解決。

```advancedFeatures.ini
Vulkan = off
GLDirectMen = on
```


参考サイト:https://stackoverflow.com/questions/62277774/android-emulator-on-windows-10
VBAでRedimがEnumを変数扱いしてくる件【闇の魔術に対する防衛術 第9⁴ ⁄ ₃章】

# なにごと？

VBAでコーディングをしていると、たまに、「定数式が必要です」というエラーメッセージに遭遇することがあります。

これは多くの場合、配列の宣言時に次元の要素数を指定する際に、変数を使って指定していることに起因します。

例えば、以下のようなプログラムは、２行目で静的解析エラーになります。

```vb
Dim A As Integer = 2
Dim TestArray(A) As String
```

これは、`ReDim`構文により回避可能です。

```vb
Dim A As Integer = 2
Dim TestArray() As String
ReDim TestArray(A) As String
```

ところが、`ReDim`構文を使っているにも関わらず、「定数式が必要です」というエラーメッセージが出ることがあるのです。

それは`Enum`を使っているときです。

# Enumとはそもそも何？

[Enum](https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/enum-statement)とは日本語で列挙型といい、その要素は定数として扱われるものです。

```vb
Private Enum Animals
    Lion = 1
    Bastet
    Horus
    Cerberus
End Enum
```

上記のような`Animals`という列挙型を定義した場合、`Animals.Horus`は`3`として扱われます。

# 「定数式が必要です」に遭遇したコード

実際に「定数式が必要です」に遭遇したコードがこちらです。

```vb
Private Enum ColumnIndex
        Partname = 1
        SpecificationNumber
        Dimensions
        Tolerances
        Actuals
        Judge
End Enum

Sub Export()
    Dim SourceSheet As Worksheet
    Set SourceSheet = ThisWorkbook.Worksheets("DataBase")
    Dim SourceTable As ListObject
    Set SourceTable = SourceSheet.ListObjects(1)

    Dim SourceArray() As String
    ReDim SourceArray(SourceTable.ListRows.Count, ColumnIndex.Judge - 1)
    ' any code
    MsgBox "Finish Export"
End Sub
```

一見すると、`Redim`を利用しているので問題なさそうです。

# 「定数式が必要です」を回避できた方法

そして、これを「定数式が必要です」から解放した方法が、まさかの`Enum`の宣言方法の変更でした。

```vb
Private Enum ColumnIndex
        Partname = 1
        SpecificationNumber = 2
        Dimensions = 3
        Tolerances = 4
        Actuals = 5
        Judge = 6
End Enum
```

このように、`Enum`の宣言にて省略していた数値と等号を復活させたら、「定数式が必要です」が消えてくれました。

# まとめ

この現象及び方法は、再現性を確認しておりません。鵜呑みにする前に各自の環境にて試し、その有用性をお試しすることをお勧めします。念のため、当記事執筆時の環境を記しておきます。

環境：Windows10, Office Home and Business 2013

**Excelsior!**
Java PDFファイルのプロパティを設定

<p><strong>今日から、Javaについての話にします。PDF のプロパティは、文書のタイトル、使用しているフォント、セキュリティ設定などのファイル情報を含んでいます。従って、今回はSpire.Doc for Javaというライブラリを使ってPDFファイルのプロパティ、及びカスタムプロパティを設定する方法を紹介させていただきます。</strong></p>
<h4><strong>下準備</strong></h4>
<p><strong>1.E-iceblueの公式サイトから<a href="https://www.e-iceblue.com/Download/pdf-for-java.html">Spire.PDF for Java</a>をダウンロードしてください。</strong></p>
<p><strong><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210804/20210804142827.png" alt="f:id:lendoris:20210804142827p:plain" width="554" height="188" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></strong></p>
<p><strong>2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire.PDF.jarを参照に追加してください。</strong></p>
<p><strong><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210804/20210804142834.png" alt="f:id:lendoris:20210804142834p:plain" width="268" height="108" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></strong></p>
<h4><strong>プロパティを設定</strong></h4>
```JAVA
import com.spire.pdf.PdfDocument;
import java.util.Date;
public class SetDocumentProperties {
    public static void main(String[] args)
    {
        //PdfDocumentオブジェクトを作成します。
        PdfDocument pdf = new PdfDocument();
        //PDFファイルをロードします。
        pdf.loadFromFile("original.pdf");
        //タイトル
        pdf.getDocumentInformation().setTitle("パンダのファイル");
        //作者
        pdf.getDocumentInformation().setAuthor("Spire Team");
        //サブジェクト
        pdf.getDocumentInformation().setSubject("ファイルのプロパティ");
        //キーワード
        pdf.getDocumentInformation().setKeywords("プロパティ");
        //日付
        pdf.getDocumentInformation().setCreationDate(new Date());
        //作成者
        pdf.getDocumentInformation().setCreator("パンダ");
        //制作者
        pdf.getDocumentInformation().setProducer("Lendoris");
        //保存します
        pdf.saveToFile("SetProperties.pdf");
    }
}
```
<h4><strong>実行結果</strong></h4>
<p><strong><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210804/20210804142923.png" alt="f:id:lendoris:20210804142923p:plain" width="554" height="556" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></strong></p>
<h4><strong>カスタムプロパティを設定</strong></h4>
```JAVA
import com.spire.pdf.*;
public class PDFCustomProperties {
    public static void main(String[] args) throws Exception {
        String inputPath = "Sample.pdf";
        PdfDocument doc = new PdfDocument(inputPath);
        doc.loadFromFile(inputPath);

        //カスタムプロパティを設定します
        doc.getDocumentInformation().setCustomerDefined("番号", "123");
        doc.getDocumentInformation().setCustomerDefined("名前", "Lendoris");
        doc.getDocumentInformation().setCustomerDefined("会社", "パンダ会社");

        //保存します
        doc.saveToFile("Output/Result.pdf");
        doc.close();
    }
}
```
<h4><strong>実行結果</strong></h4>
<p><strong><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210804/20210804143015.png" alt="f:id:lendoris:20210804143015p:plain" width="554" height="413" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></strong></p>
<p><strong> </strong></p>
djangoの開発中に気になったこと覚書

これまで業務では使ったことがなかったPythonですが、この度Djangoで実装されたサイトを修正する案件があったためその時に調べて「へぇ〜」となったTipsを残しておきます。  
Djangoの書き方というよりは、Pythonの知識になります。 　

### with  
https://docs.python.org/ja/3/reference/compound_stmts.html#with  

```
try/finally の標準的な使い方を抽出する目的で追加したとのことです。
```
[参考](https://qiita.com/QUANON/items/c5868b6c65f8062f5876)

with文を使うと、↓これが  

```py
manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(manager, None, None, None)
```

↓こうなる  

```py
with EXPRESSION as TARGET:
    SUITE
```

具体的な利用例はこんな感じ  

```
>>> with open('hidamari.txt', 'r') as f:
...   divide_by_zero(len(f.read()))
...
ZeroDivisionError: division by zero
>>> print(f.closed)
True
```

### contextlib.contextmanager  
with文を使うには、渡すオブジェクト（コンテキストマネージャー）に `__enter___` （前処理）と `__exit__` （後処理）が定義されていないといけない。  
コンテキストマネージャを定義するためデコレーターがこれ。  
https://docs.python.org/ja/3/library/contextlib.html#contextlib.contextmanager  

↓こんな感じに定義しておくと  

```py
import contextlib

@contextlib.contextmanager
def reading(filename):
  file = open(filename, 'r')
  try:
    yield file
  finally:
    file.close()
```

↓こういう風に使える  

```py
with reading('hidamari.txt') as f:
  print(f.read())
```

### 自作フィルター
Djangoにはフィルターと呼ばれるtemplateの変数をtemplate内で成形してくれる便利な関数があります。
例↓

```
<p>{{ value | upper }}<p>
-- この例ではvalueの文字をすべて大文字にして出力する。
```

フィルターを自作することが可能。
アプリケーション配下に`templatetags` というフォルダを作成し、その下に `@register.filter` アノテーションでフィルターと宣言して、値を変換する関数を記述する。

参考：https://e-tec-memo.herokuapp.com/article/22/  

### その他、同僚から聞いて「確かに」と思った事柄、疑問 　

- self とは
なぜクラスメソッドに書くのか

- メソッドと関数の違い  

- __ がメソッド名の頭につく意味
クラス内でしか呼び出しをしないプライベートなメソッドを慣例的にそう書いているようにみえる 　

- pythonの三項演算子の書き方がちょっと不思議

- リストの内包表記がわかりにくい

- インデントの重要性

- スコープがわかりにくい

- pythonは多重継承可能

できれば上記の疑問については随時調べてアップデートしていきたい
更新ボタンが削除ボタンとして機能してしまう

「更新する」ボタンを押したら、ユーザーが削除される現象が起きてしまい、原因がわかったのでメモ。

## 状態

編集内容を入力後、「更新する」を押すとユーザーが削除された。

![スクリーンショット 2021-08-04 13.58.00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292027/b47ab5d7-7e48-3985-bfc2-a7f048ec03c9.jpeg)

```
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  ・
  ・
  <div class="actions mt-3 text-center">
 　　  <%= f.submit "更新する", class: "btn btn-primary" %>
    <%= button_to "削除する", registration_path(resource_name), data: { confirm: "本当によろしいですか？" }, method: :delete, class: "btn btn-danger" %>
　　</div>
  ・
  ・
<% end %>
```

## 原因
以下のように「更新する」を押した際にDELETEリクエストが送信されていた。

![スクリーンショット 2021-08-04 14.04.38.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292027/606a989b-8977-4290-3c99-4ead04699dbc.jpeg)


## 対策1: フォームの外にbutton_toを設置
button_toではlink_toと違いフォームを作り、その中にinputタグでボタンが生成されるものだそう。
そのため、formの外で使用しないと思うようなbutton_toの役割ができないみたい。
フォームの外にbutton_toを設置することで「更新する」が正常に動作した。
[【Rails】 button_toの使い方をどこよりもわかりやすく解説！]
(https://pikawaka.com/rails/button_to#link_to%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84)

```
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  ・
  ・
  <div class="actions mt-3 text-center">
 　　  <%= f.submit "更新する", class: "btn btn-primary" %>
　　</div>
  ・
  ・
<% end %>
<%= button_to "削除する", registration_path(resource_name), data: { confirm: "本当によろしいですか？" }, method: :delete, class: "btn btn-danger" %>
```
![スクリーンショット 2021-08-04 14.25.23.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292027/7fb2995f-8768-27d1-075e-5f5d9848c89d.jpeg)


## 対策2: button_toをlink_toに変更
```
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  ・
  ・
  <div class="actions mt-3 text-center">
 　　  <%= f.submit "更新する", class: "btn btn-primary" %>
    <%= link_to "削除する", registration_path(resource_name), data: { confirm: "本当によろしいですか？" }, method: :delete, class: "btn btn-danger" %>
　　</div>
  ・
  ・
<% end %>
```

![スクリーンショット 2021-08-04 14.27.26.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292027/17727ab4-4cdd-27e6-39c0-404bdc170f36.jpeg)
【Docker】-v,--mount,docker-composeの対応についてマウントタイプ毎に整理する

#docker runの-vオプションと--mountオプションについて
公式ドキュメントのヒントにはこのように書いてあります。
<br>

https://matsuand.github.io/docs.docker.jp.onthefly/storage/bind-mounts/

>ヒント: はじめて利用する方は --mount を利用してください。 上級ユーザーは -v や --volume を用いることに慣れているかもしれませんが、--mount を利用するように心がけてください。 --mount の方が簡単に利用することができるとの調査もあります。
>


おそらく、-vコマンドはある程度ボリュームについて理解していないと、どのマウントタイプを使っていて、どんな挙動をするのかが分からなくなってしまうからでしょう。



#ボリュームタイプのマウントを使用する場合


```shell:-vを使用するパターン
docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest
```

```shell:--mountを使用するパターン
docker run -d \
  --name devtest \
  --mount source=myvol2,target=/app \
  nginx:latest
```

```yml:docker-composeを使用するパターン
version: "3.3"

services:
 web:
   container_name: 'devtest'
   image: nginx:latest
   volumes:
     - myvol2:/app

volumes:
  myvol2:
    name : myvol2
```

docker-composeの場合、トップレベルのvolumesが「docker volume create」に対応します。
また、ボリュームタイプのマウントは、「docker volume ls」 で一覧を確認することができます。

#バインドタイプのマウントを使用する場合

```shell:-vを使用するパターン
docker run -d \
  --name devtest \
  -v "$(pwd)"/target:/app \
  nginx:latest
```

```shell:--mountを使用するパターン
docker run -d \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest
```

```yml:docker-composeを使用するパターン
version: "3.3"

services:
 web:
   container_name: 'devtest'
   image: nginx:latest
   volumes:
     - ./target:/app
```

**volumeタイプのマウントが<ボリューム名>:<コンテナのパス>だったのに対して、
bindタイプのマウントでは、<ホストのパス>:<コンテナのパス>になっています。**

----
上記の二つ以外にもtmpfsというマウントタイプがあります。こちらはホストのメモリ上にデータを保存し、コンテナが停止すると削除されるため、使用用途は機密データを扱う場合などに限られます。
【React】snackbarsを親コンポーネントから子コンポーネントにメッセージを渡せるようにカスタマイズした例【Material-UI】

<h2>カスタマイズした箇所について</h2>
MaterialUIのsnackbarsを親コンポーネントから渡されたメッセージを子コンポーネントのsnackbarsに渡して、そのメッセージを表示するような簡単なカスタマイズをしました。

なお、今回はスタンダードな<a href="https://material-ui.com/components/snackbars/#customized-snackbars">Customized snackbars</a>を使用しました。

<h2>実装</h2>
まず親コンポーネントの実装例です。
簡単に呼び出す箇所のみを抜き出して記載します。
buttonを押下すると、メッセージが更新されるようになっています。


```react:Hoge.jsx
import React, {Fragment,useState} from "react";
import {CustomizedSnackbars} from "../component/MaterialUISnackber";

export const Hoge= () => {
  const [messageState,setMessage] = useState("");
  const [count,setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    if(messageState === ""){
      setMessage("SNACKMESSAGE");
    }else{
      setMessage(count + "回目");
    }
  }

  return (
  <Fragment>
    <Button variant="outlined" onClick={handleClick}>
        ADDMESSAGE
     </Button>
    {
    state.message !== ""?
      <MessageWrapper>
        <CustomizedSnackbars message={state.message}/>
      </MessageWrapper>
    :
      null
    }
  </Fragment>
  )
}
```

こちらが肝心の子コンポーネントのsnackbarになります。
デフォルトからの主な変更点としては、
・useEffectでopenとcloseをmessageが変更された時に動作するようにしました
・messageがない時や想定していない値(undefined)が入った時に表示しないようにしました(念のため)

```react:CustomizedSnackbars
import React, {Fragment, useEffect,useState } from 'react';
import Button from '@material-ui/core/Button';
import Snackbar from '@material-ui/core/Snackbar';
import MuiAlert from '@material-ui/lab/Alert';
import { makeStyles } from '@material-ui/core/styles';

function Alert(props) {
  return <MuiAlert elevation={6} variant="filled" {...props} />;
}

const useStyles = makeStyles((theme) => ({
  root: {
    width: '100%',
    '& > * + *': {
      marginTop: theme.spacing(2),
    },
  },
}));

export function CustomizedSnackbars({message}) {
  const classes = useStyles();
  const [open, setOpen] = useState(false);
  
  useEffect(() => {
    if(message === ""){
      setOpen(false);
    } else {
      setOpen(true);
      console.log(message)
    }
  },[message])

  const handleClose = (event, reason) => {
    if (reason === 'clickaway') {
      return;
    }

    setOpen(false);
  };

  return (
    <Fragment>
      {
      message === undefined || message === null || message === ""?
        null
      :
      <div className={classes.root}>
        <Snackbar open={open} autoHideDuration={5000} onClose={handleClose}>
          <Alert onClose={handleClose} severity={"success"}>
            {message}
          </Alert>
        </Snackbar>
        </div>
      }

    </Fragment>
  );
}
```


<h2>参考</h2>
https://material-ui.com/components/snackbars/#customized-snackbars

https://kakakakakku.hatenablog.com/entry/2019/10/15/064749
JavaScriptでsleep

# sleep関数

```javascript
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
```

# sleep関数の使い方

```javascript:sample.js
async function hoge() {
    console.log("5秒スリープ");
    await sleep(5000);
    console.log("1秒スリープ");
    await sleep(1000);
    console.log("END");
}
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
hoge();
```

※asyncが付いた関数の中でawaitと一緒に使う。

# 参考
https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep

https://techplay.jp/column/548

https://qiita.com/ueokande/items/807a6c9a64c3874a0f83

https://qiita.com/may88seiji/items/4a49c7c78b55d75d693b
SAP Download Managerの使い方

# SAP Download Managerとは
SAPの各種インストールメディア等のダウンロードツールです。
インストールメディアはブラウザでダウンロードすることも可能ですが、場合によってはダウンロード対象が数十個～数百個、サイズも数TBに及ぶ場合もあるためブラウザから1つ1つダウンロードするのは現実的ではありません。
SAP Download Managerを利用すれば大量のメディアを一括でダウンロードすることが可能です。

# 事前準備
SAP Download Managerの利用にあたっていくつか事前準備が必要です。

**・S-USER ID**
SAP Support Portalにアクセスするためのユーザです。
これが無ければSAP Download Managerや各種インストールメディアをダウンロードすることができません。
事前に管理者に依頼して払い出してもらいましょう。

**・Java実行環境**
SAP Download Managerの実行にはJavaが必要です。
対応しているJavaのバージョン等の詳細は以下URLの「Requirements」で確認できます。
https://support.sap.com/content/dam/support/en_us/library/ssp/my-support/help-for-sap-support-applications/online_help-download_manager.html#requirements

**・Download Basketへのメディアの追加**
ダウンロード対象の各種メディアは事前にDownload Basketに追加しておく必要があります。
Download Basketへの追加はSAP Support Portal経由で実施します。
※今回こちらの手順の記載は割愛しています

**・ディスク容量**
大量のファイルをダウンロードする場合はディスク空き容量の確保が必要です。
ダウンロード前にディスクの状態を確認することをお勧めします。

# インストール
Windows10にSAP Download Managerをインストールしていきます。

**・Javaインストール**
まずはJava実行環境をインストールします。
今回はOracle JREを使います。以下URLよりダウンロード可能です。
https://java.com/ja/download/

ダウンロードした実行ファイルをダブルクリックしてインストーラを起動し、「インストール」を選択します。
![Java_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/02c8b352-9277-c89e-d92e-fb1c594510fc.png)

インストールが開始されるので待機します。
![Java_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/1cc98419-a63a-cb2b-7185-b0d9686b3184.png)

「Javaが正常にインストールされました」と表示されたら「閉じる」を選択します。これでJavaのインストールは完了です。
![Java_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/f4d3d504-fb31-45a7-057a-46453ab2824f.png)

**・SAP Download Managerインストール**
以下URLにアクセスします。
http://support.sap.com/swdc

「Download now」を選択します。
![DownloadManager_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/608a1ae4-b111-d5e4-cdd3-17adba1bd9b5.png)

S-USER IDでログオンします。
![DownloadManager_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/5507dbd0-8c19-38da-89a6-d17f1984416b.png)

ログオンすると自動的にファイルのダウンロードが始まります。
ダウンロード完了後にファイルを解凍し、フォルダ内のDLManager.jarというファイルを実行すると設定画面が起動するので「User name」、「Password」にS-USER IDの情報を入力してOKを選択します。
![DownloadManager_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/eb56915a-d3ab-8a69-21df-b555596284f7.png)

事前にDownload Basketへ追加したメディアが表示されます。
左上の「Download all objects」ボタンを押すとメディアのダウンロードが開始されます。
※サイズにもよりますがダウンロードにはそれなりに時間がかかります
![DownloadManager_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/9c0a4078-102d-ce1c-2fe6-0e7a39d3f1dd.png)
dockerでgpuが使いたい

# 概要
dockerでpytorchの深層学習環境構築をしたい。
だいたいこの方のqiitaの記事と同じ。
[PyTorch+GPUをDockerで実装](https://qiita.com/conankonnako/items/787b69cd8cbfe7d7cb88)

# 目標
pytorchのmnistのサンプルを動かす

# 環境
[nvidia DGX station a100](https://www.nvidia.com/ja-jp/data-center/dgx-station-a100/)

```
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

$ nvidia-smi
Wed Aug  4 13:25:37 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
```

# 前提
dockerでgpu使うには以下をインストールする必要がある。

1. GPUドライバのインストール
2. dockerのインストール
3. Nvidia Container Toolkitのインストール


``nvidia-smi``のコマンドが使えなかったり、``nvidia-container-toolkit``, ``docker``のコマンドが使えなかったら、[PyTorch+GPUをDockerで実装](https://qiita.com/conankonnako/items/787b69cd8cbfe7d7cb88)を参照してインストールしてください。

# dockerfile
ディレクトリを作り、``$vim Dockerfile``でDockerfile作って、以下を貼り付けてください。

```dockerfile
FROM nvidia/cuda:11.0-devel-ubuntu20.04

RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip3 install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html

WORKDIR /work
```
``RUN pip3 install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html``の部分ですが、[ここ](https://pytorch.org/)で自分の開発環境をクリックして適宜変えてください。cudaのバージョンは``nvidia-smi``で確認できます。
![スクリーンショット 2021-08-04 13.38.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548975/5c9b0288-22f1-ca0b-d5dd-d132722cd967.png)

Dockerfileが作成できたらDockerfileがある場所で以下のコマンドを実行

```
$ docker build -t [作成するdocker image名] .
```

# docker run
忘れやすいのでメモ

```
docker run --rm -it  --gpus all -v $(pwd):/work [作成したイメージ名]:latest
```
## --rm
コンテナが終了した際にコンテナを消す

## --gpus all
使うgpuの数を指定。喧嘩にならないように1とか2とかにしよう

## -v $(pwd):/work
これがないと今いるディレクトリのファイルが見れない。

# pytorch sampleのmnistを動かす。

pytorchのサンプルファイルを落としてくる。
```
$ git clone https://github.com/pytorch/examples.git
```

```
$ cd mnist
$ docker run --rm -it  --gpus all -v $(pwd):/work [作成したイメージ名]:latest
# python3 main.py
```
これで動くはず。
[salesforce] table 文字列の折り返しを表現する

```aura.cmp
<td class="slds-table td-fixed-width" >
    <div class="slds-cell-wrap">
        nagai〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇
    </div>
</td>
```

```style.css
.td-fixed-width {
    width: 10rem;
}
```

tdの幅を固定した後、"slds-cell-wrap" tagにより、文字列の折り返しが可能になる。

# slds-cell-wrap
![スクリーンショット 2021-08-04 13.39.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1761599/55d25aae-461d-d8b0-4d9a-8838e85ccf0f.png)

# overflow-wrap: break-word;
overflow-wrap は CSS のプロパティで、インライン要素に対して、テキストが行ボックスをあふれないように、ブラウザーが不可分の文字列の途中で改行を入れるかどうかの設定を適用します。
https://developer.mozilla.org/ja/docs/Web/CSS/overflow-wrap
これも使える

[参考url]
・ https://www.lightningdesignsystem.com/components/data-tables/
・ https://salesforce.stackexchange.com/questions/270162/using-slds-td-in-a-table-has-overflowing-text-area-i-need-it-to-wrap
Android: dexOptions.preDexLibraries オプションは削除しよう

Android Gradle Plugin 7.0.0 から、dexOptions が Deprecated になりました。

> Using dexOptions is obsolete.

Android Gradle Plugin 7.0.0-alpha15 以上では、エラーメッセージがわかりやすくなり、以下のメッセージとなるようです。

* https://issuetracker.google.com/issues/183295952#comment4

> DSL element 'dexOptions' is obsolete and should be removed.
It will be removed in version 8.0 of the Android Gradle plugin.
> Using it has no effect, and the AndroidGradle plugin optimizes dexing automatically.

D8 が dexOptions を参照しなくなったため、preDexLibraries は指定する必要がなくなるとのことです。

対応としては、dexOptions.preDexLibraries は削除しましょう。
fluentdで出力ファイルをログローテーションさせる

## 参考
https://docs.fluentd.org/deployment/logging

## やり方

起動時に引数を渡せばOK
fluentd.confとかで設定するわけではないみたい

```
fluentd -c fluent.conf --log-rotate-age 5 --log-rotate-size 104857600
```

### kubernetes環境の場合
マニフェストファイルのargsに指定すればOK

```
    Host Port:     0/TCP
    Args:
      --log-rotate-age
      5
      --log-rotate-size
      104857600
```
cloudFunctions上でpuppeteerのuploadFileを扱う


cloudFunctions上のpuppeteerで画像アップロードする際、ハマってしまったことがあるので備忘録です。

## やりたいこと

①cloudFunctions内からpupeteerを動かす
②対象のファイルを`input type="file"`に入れる

この流れです。
簡単そうに見えますが、ここでハマってしまいました…

## ハマった原因

puppeteerで画像をuploadする際は[uploadFile](https://pptr.dev/#?product=Puppeteer&version=v10.1.0&show=api-elementhandleuploadfilefilepaths)という関数が用意されています。
uploadFileは以下のように書くことができます。

```js
// アップロードする対象を選択
const inputUploadHandle = await page.$('input[type=file]');
// アップロードするファイルのパスを選択
let fileToUpload = './upload_file.jpg';
// uploadFileでファイルをinputに入れる
inputUploadHandle.uploadFile(fileToUpload);
```

こちらは公式で以下のように説明があります。

> ...filePaths <...string> Sets the value of the file input to these paths. If some of the filePaths are relative paths, then they are resolved relative to the current working directory.

「filePathsの一部が相対パスの場合、現在の作業ディレクトリからの相対パスとして解決されます。」とあります。

cloudFunctionsでは静的ファイルを[cloudStrage](https://cloud.google.com/appengine/docs/flexible/nodejs/serving-static-files?hl=ja#serving_files_from)から取得することが推奨されているようで、その場合相対パスで取れなくないか？:no_mouth:となりハマりました。。

やりたい流れとしては

```
①cloudFunctions内からpupeteerを動かす
②cloudStrageから対象のファイルを取得する
③取得したファイルを`input type="file"`に入れる
```
といった流れになりました。

## 試したこと①　絶対パスだとどうなる？　（失敗）

では、`uploadFile(path)`の引数に絶対パスを入れることはできるだろうか:rolling_eyes:？と思い、試してみました。

結論から言うとできませんでした:innocent:
そもそも`input type="file"`にファイルを入れる際、セキュリティ上の観点から元のファイルへの実際のパスが見えないようになっているようです。[参照](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/file)
おそらく絶対パスを入れても動かない理由は同じような観点からできないようになっていると考えました。

ちなみに、以下のようなコードで試してみると

```js
const inputUploadHandle = await page.$('input[type=file]');
// 実際試す際は何らかのパスで
const filePath = 'https://~~~~~'
try{
  await inputUploadHandle.uploadFile(filePath);
}catch(e){
  console.log(e)
}

```

このようなエラーが出ます。

```log
Error: https:~~~~~ does not exist or is not readable
```

## 試したこと② 相対パスで取るにはどのようにする？　(解決策)

cloudFunctions内に一時保存できる`tmpディレクトリ`なるものがあるとわかりました。

> Cloud Functions では、「tmpfs」ボリュームと呼ばれるローカルのディスク マウント ポイント（/tmp）にアクセスできます。
[参照](https://cloud.google.com/functions/pricing?hl=ja)

tmpディレクトリはcloudFunctions内から相対パスでたどることができるので、
上記の流れの項目を以下のように変更すればできそうです！

```
①cloudFunctions内からpupeteerを動かす
②cloudStrageから対象のファイルを取得する
③対象のファイルを/tmpに保存する
④/tmpに保存したファイルを`input type="file"`に入れる
```

実際個コードは以下の通りです。

```tsx
  // ①cloudFunctions内からpupeteerを動かす
  const { Storage } = require('@google-cloud/storage');
  // ：

  const tempFilePath = "/tmp/"

  //ファイルダウンロード用の関数
  const downloadFile = async (fileName) => {
    const storage = new Storage()
    // ②cloudStrageから対象のファイルを取得する
    const file = storage.bucket('bucket_name').file(`ファイルのパス`)
    await new Promise(function (resolve, reject) {
      //③対象のファイルを/tmpに保存する
      file.download({
        destination: tempFilePath + fileName
      }).then(() => {
        resolve("OK");
      });
    }).then((result) => {
      //ダウンロード完了
      console.log(result);
    })
  }


 // fileNameは動的に取得
 await downloadFile(fileName)
 //④ /tmpに保存したファイルを`input type="file"`に入れる
 await firstMenuImage.uploadFile(tempFilePath + fileName);

```

難しくない工程ですが、tmpディレクトリの存在など知らないことが多く時間がかかってしまいました。
もっといい解決方法などありましたらコメントいただけると幸いです！！
railsでpictureタグによるwebp出し分けをする

# 概要

webpのを使いたいけど対応していないブラウザの場合にpngを出し分けるようにしたい

# 実装内容

```html
<picture>
  <source srcset="<%= image_path("slide_01.webp") %>" type="image/webp">
  <%= image_tag('slide_01_400.png') %>
</picture>
```

pictureタグはsourceで画像を指定していって条件の合うものをだす。ない場合は最後に用意している画像を出す。

pictureタグについて
https://developer.mozilla.org/ja/docs/Web/HTML/Element/picture

## pathの指定

imageタグでsourceを出す方法もあるが今回はsourceをそのまま書いている。この場合pathはそのまま書くのではなくimage_pathで生成しないと後ろのハッシュが生成されないのでうまく表示されない。
p5.playをやる記事#03_p5.playの基本

[前回の記事](https://qiita.com/sdkfz181tiger/items/a6abed8453f42545770a) | [次回の記事](https://qiita.com/sdkfz181tiger/items/4207d679375ddae11b20)

p5.playの使い方を解説しております。
[第1回の記事](https://qiita.com/sdkfz181tiger/items/c424b0777f7d7fe2203a)はこちらにありますのでご参照ください。

## p5.playの基本

p5.playを利用するとどんな事が出来るのでしょうか？
その答えは、"公式サイト"にあります。

[p5.play](https://molleindustria.github.io/p5.play/)

公式サイトの上部メニューにある"Examples"をクリックする事で、
サンプルプログラムを確認する事ができます。
(眺めているだけでワクワクしますよ!!)

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/82ce62e3-8161-1890-4e3f-bd158a797826.png)

それともう一つ、"Reference"にはp5.playで使われている関数やパラメータ等の詳細を確認する事ができます。("辞書"の様に使います)
p5.playに慣れると、こちらを参考にしながら開発を進めていく事になります。(勿論英語です!!)

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/274ee090-fc5e-cc6f-e20e-ae996f2a6fc5.png)


## 基本テンプレート
p5.playを始めるにあたって、3つの関数を覚えておく必要があります。

```JavaScript
function preload(){
   // 1, 画像や音声の読み込み
}

function setup(){
   // 2, キャンバスの用意
}

function draw(){
   // 3, キャンバスの表示と更新
}
```

この3つの関数は、1,2,3の順番で実行されます。
それぞれの関数には役割があるので覚えておきましょう。

1. preload関数(画像や音声の読み込み)
2. setup関数(キャンバスの用意)
3. draw関数(キャンバスの表示と更新)

手始めにsetup関数とdraw関数に必要な処理を実装してみます。

```JavaScript
function preload(){

}

function setup(){
   createCanvas(windowWidth, windowHeight);// 1, キャンバスを用意します
   frameRate(32);// 2, フレームレートを指定します(1秒間に32回更新をします)
   noSmooth();// 3, ドット絵がパリッと表示されます(個人的にオススメ!!)
}

function draw(){
   background(0);// 4, 背景を真っ黒にします
}
```

実行すると、キャンバスは真っ黒な状態です。
ここまでは、p5.jsの記述方法と変わりませんね。

## スプライトを作って表示する

createSprite関数は、スプライトを作る時に使います。(遂にきた!!)
引数にはそれぞれ下記の様に値を指定します。

```JavaScript
createSprite(x座標, y座標, 横幅, 高さ);
```

drawSprites関数は、スプライトを表示する関数です。
この関数が実行されるタイミングでスプライトが表示されます。

```JavaScript
drawSprites();
```

具体的に実装をするとこの様になります。

```JavaScript
function preload(){

}

function setup(){
   createCanvas(windowWidth, windowHeight);
   frameRate(32);
   noSmooth();
   let spr = createSprite(width/2, height/2);// 1, スプライトを作る
}

function draw(){
   background(0);
   drawSprites();// 2, スプライトを表示する
}
```

実行すると下記の様に、キャンバスの中央にスプライトが現れます。

![ss_mid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9823/5841322c-bf14-d1de-1708-2b1ecc4027d3.png)

表示されるスプライトの色は自動で決まります。
自分で色を指定したい場合は、
スプライトのshapeColorにcolorオブジェクトを設定します。

```JavaScript
スプライト.shapeColor = color(赤, 緑, 青);
```

全体のコードは下記の様になります。

```JavaScript
function preload(){

}

function setup(){
   createCanvas(windowWidth, windowHeight);
   frameRate(32);
   noSmooth();
   let spr = createSprite(width/2, height/2);
   spr.shapeColor = color(255, 255, 255);// RGB値で色を指定する事ができます
}

function draw(){
   background(0);
   drawSprites();
}
```

実行すると、スプライトの色が変化している事がわかると思います。
次回は画像を適用する方法についてのお話になります。

[前回の記事](https://qiita.com/sdkfz181tiger/items/a6abed8453f42545770a) | [次回の記事](https://qiita.com/sdkfz181tiger/items/4207d679375ddae11b20)

## おまけ動画(こちらもよろしくお願いします)

<iframe width="560" height="315" src="https://www.youtube.com/embed/bHtS5tgRmFY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>