OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】RSpecのテストコードの書き方

## はじめに
　本記事は、プログラミング初学者、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## RSpecのテストコードの構成
RSpecのテストコードは以下のように記述します。

```article_spec.rb
RSpec.describe Article, type: :model do
  context 'タイトルと内容が入力されている場合' do
    let!(:article) do
      Article.new({ title: 'RSpecテスト', content: 'RSpecテストの内容' })
    end
    it '記事を保存できる' do
      expect(article).to be_valid
    end
  end
end
```

* __describe__
大分類のようなもので、何についてテストをするかを記述します。

* __context__
中分類のようなもので、状況を記述します。分類が少ない場合には省略することもできます。

* __let!__
変数を定義する場合に使用します。

* __it__
個々のテストケースを表します。期待する振舞いを記述します。

* __expect__
テストしたいものを指定します。
【AWS】踏み台サーバーを経由してSSHで接続するメモ

amazon web services 基礎からのネットワーク&サーバー構築
のCHAPTER6でつまったので記事にします。

#### ①AWSコンソール上でのデータベースサーバーのセキュリティー設定
#### ②キーペアをウェブサーバーにコピー

上記の二つが原因でつまっていました。


### ①AWSコンソール上でのサーバーのセキュリティー設定
データベースサーバーICMPが通るように構成する
のところでセキュリティーグループのDB-SGにルールを追加するときに
”すべてのICMP-IPv4］を選択し、送信元には［任意の場所］を指定します。最後に、［保存］”
とあるのですがAWSの仕様が変わっていて送信元には［任意の場所］がないのでルールがうまく作れていなかった。

##### ルールを二つ追加しなくてはならなくて、ソースが0.0.0.0/0のルールと::/0のルールを追加しないといけなかった。

### ②キーペアをウェブサーバーにコピー
```
scp -i ~/my-key.pem ~/my-key.pem ec2-user@サーバーのDNS:~/
```

というローカルのmy-key.pemをウェブサーバー上のホームディレクトリにコピーすると言うところも詰まった。
原因は実行権限かと思われる。

特に何もぜず、書籍にならって
```
$ scp -i ~/my-key.pem ~/my-key.pem ec2-user@サーバーのDNS:~/
```
とするとエラーが出た。

### 解決策

ローカル上でまず

```
$ chmod 700 my-key.pem
```

でmy-key.pemの権限をrwx------に変更し再度実行

```
$ scp -i ~/my-key.pem ~/my-key.pem ec2-user@サーバーのDNS:~/
my-key.pem                            100% 1700    12.8KB/s   00:00 
```
エラーが消えて上記のような表示が出ます。

で
ウェブサーバーに接続して
lsコマンドでホームディレクトリにコピーされたmy-key.pemがあるのか確認してあったら

```
chmod 400 my-key.pem
```
で権限をrwx------から-r--------に変更して

```
ssh -i my-key.pem ec2-user@プライベート IPv4 アドレス
```

　で接続できました。
Discord.jsで作成したbotのコマンドが使えない場合に確認したこと

# 困っていたこと
テスト用のDiscordサーバーで使えていたスラッシュコマンドが
本番用のサーバーでは表示されなかった。

# 確認したこと1
[OAuth]-[SCOPES]の"applications.commands"にチェックが入っているか
![スクリーンショット 2022-03-30 010601.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20061/ae40adbd-b59a-3ae0-c7a1-4725c8990693.png)

# 確認したこと2
```index.js
// コマンド登録
client.on('ready', async () => {
  const data = []
  for (const commandName in commands) {
      data.push(commands[commandName].data)
  }
  await client.application.commands.set(data, process.env.SERVER_ID);
})
```

コマンド登録時にサーバーIDを指定していました。
そのため、特定のサーバーでしかコマンドが登録されていなかったのが原因でした。

以下のようにサーバーIDを指定しないとグローバルコマンドとして登録されます。

```index.js
client.on('ready', async () => {
　・・・・
  // コマンド登録
  await client.application.commands.set(data);
})
```
[Python]リストの要素全てに処理を行いたいメモ

例えば`a=[1,2,3,4,5]`などのリストに対して、中の要素それぞれに1を足したり2を掛けたりする方法についての羅列 & 自分用メモです。

今回は、以下の配列を例に操作を行います。全ての要素を2倍することを考えます。
```python
a = [1, 2, 3, 4, 5]

# 完成形 -> a = [2, 4, 6, 8, 10]
```

## 頑張って全部書く

```python
a[0] *= 2
a[1] *= 2
a[2] *= 2
a[3] *= 2
a[4] *= 2

print(a)
# -> [2, 4, 6, 8, 10]
```

+ ......

## 上の操作をループで行う

```python
for i in range(len(a));
    a[i] *= 2
```

+ さっきよりは簡潔。

ちなみに、`for num in a:`で`num *=2`を処理しても、元の配列の要素には反映されないので注意。
別で配列を作ってappendしたりするなら`for num in a:`でも可？


## map関数を利用する

```python
def func(x):
   return x*2

a = list(map(func, a))

# もしくは
a = list(map(lambda x: x*2, a))
```

+ map関数と関数、もしくはlambda式を用いる方法
+ aへの上書き可能。
+ 返り値はmapオブジェクトのため、配列にしたい場合はlistで受け止める必要がある。

## リスト内包表記を利用する

```python
a = [x*2 for x in a]
```

+ for文を内包表記した形。
+ aへの上書き可能。
+ 簡潔！


## 結局

2を掛けたり1を足すぐらいの操作だったらリスト内包表記が最も簡潔だけど、複雑な処理だったりすると、別で関数を定義できてループが要らないmap関数が便利な気がします。

他にも良い方法があれば是非共有してください。
ラズパイでcronを使う

<h1>プログラムの動作確認</h1>

1. 多分エディタでコードを書いていると思います。エディタ上で正しく動作するかまずは確認してください。
1. 次にターミナル上で動作するか確認します。hoge.pyを動作させたい場合は、
`python3 /home/pi/Document/hoge.py` と記述します。
**python3を頭に書いて絶対パスで指定**します。

エラーが出た場合は修正してください。もしも権限が付与されていません。と表示された場合は
`chmod 777 /home/pi/Document/hoge.py`と記述しします。読込、書込、実行のフル権限を付与します。

<h1>cronの設定をする。</h1>
まずはログを見れるようにしましょう。
#cron.* の「＃」を消しましょう

~~~Terminal.log
$ sudo nano /etc/rsyslog.conf
_____________________________
###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
#cron.*                          /var/log/cron.log     <-ここの＃を消します。
daemon.*                        -/var/log/daemon.log
kern.*                          -/var/log/kern.log
lpr.*                           -/var/log/lpr.log
mail.*                          -/var/log/mail.log
user.*                          -/var/log/user.log
~~~

終わったら再起動します。
実行結果の格納先`/var/log/cron.log`


<h1>cronの使い方</h1>

~~~Terminal.cron
ステータス確認
$ sudo /etc/init.d/cron status

起動
$ sudo /etc/init.d/cron start

再起動
$ sudo /etc/init.d/cron restart

停止
$ sudo /etc/init.d/cron stop

ジョブの設定
$ crontab -e

ジョブの確認
$ crontab -l
~~~

ステータス確認の際、runningって書いてある場合は起動されています。


<h1>ジョブの設定方法</h1>

ここがめちゃくちゃわかりやすい。
「さっそく設定ファイルにcronの登録」のところから見るといいです。
（リンク押したら勝手に飛びます。）

https://qiita.com/katsukii/items/d5f90a6e4592d1414f99#%E3%81%95%E3%81%A3%E3%81%9D%E3%81%8F%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%ABcron%E3%81%AE%E7%99%BB%E9%8C%B2

~~~crontab.e
$ python3 /home/pi/Document/hoge.py
上記をcronに定期実行させたい場合
$ crontab -e
____________
# 
# m h  dom mon dow   command
0 * * * * python3 /home/pi/Document/hoge.py
~~~
意味があるかわからないがArduinoで1200bpsのソフトシリアルライブラリ化


目的
ソフトウェアシリアルのテスト


![o_con295.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d92c6fbd-0a37-2ec8-5145-98625edb2e30.jpeg)



メインプログラム


```c++


//SER_LB_1200_UNO_1

#include <Arduino.h>

#include "SER_1200_UNO_1.h"

//初期化
void setup()
{

  //シリアルの初期化
  pc.beginNS(1200);

} //setup


//メインループ
void loop()
{

  //データの表示
  pc.printNS("HELLO WORLD\r\n");
  
  delay(1000);

} //loop



```


SER_1200_UNO_1.hのプログラム


```c++


#ifndef TEST_H
#define TEST_H

//SER_LB_1200_UNO_1_LIB


#define TX1      1

#define DW   digitalWrite


//クラスの定義
struct _pc
{
  void beginNS(int sp);      //メソッドの宣言
  int  putcNS(char ch);      //メソッドの宣言
  int  printNS(char *str1);  //メソッドの宣言
};


//ポートをhiにする 初期化
//メソッドの定義
void _pc::beginNS(int sp)
{
  //ポートをhiにする初期化
  pinMode(TX1, OUTPUT);
  DW(TX1, HIGH);
}


//仮想シリアルへの一文字出力 1200bps
//メソッドの定義
int _pc::putcNS(char ch)
{
  DW(TX1, HIGH);

  DW(TX1, LOW);//START
  delayMicroseconds(832); //START BIT WAIT

  for (int ii = 0; ii < 8; ii++) {
    DW(TX1, (ch >> ii) & 1  );
    delayMicroseconds(832); //DATA 1-8BIT WAIT
  }//for

  DW(TX1, HIGH);//Stop
  delayMicroseconds(832); //StOP BIT WAIT

  return (0);
}


//文字列の表示
//メソッドの定義
int _pc::printNS(char *str1)
{
  //文字の中身がゼロか
  while (*str1) {

    //一文字出力
    putcNS(*str1 ++);

  } //while

  //戻り値
  return (0);
}


//実体の作成
_pc pc;


#endif





```
一問一答の問題集を作成する。

使い方
please input questionで「nothing」と入力すると問題集の作成が終わります。
回答時に「finish」と入力すると回答が終わり◯の数、×の数、正解率を表示します。

①実行
```python:
import random

print("START")
questions = {}

while True:
    question = input("please input question")
    if question == "nothing":
        break
    answer = input("please input answer")
    questions[question] = answer
    print(questions)    

    
o = 0
x = 0    
while True:	
    g = random.choice(list(questions.items()))
    your_answer = input(f'{g[0]}？')
    if your_answer == g[1]:
        print('◯')    
        o += 1
    elif your_answer == "finish":
        break
    else:
        print('×')
        x += 1
       
print(f'◯→{o}\n×→{x}')
print(f'{(o/(o + x))*100}%')

```
②上のコードで終了するとせっかく作った問題集が消えてしまうため、辞書型{}の部分をコピペして下のコードに貼り付けてください。(①はプレビューとして使ってください)
```python:
import random
  
questions = {この中に入れてください}
    
o = 0
x = 0    
while True:	
    g = random.choice(list(questions.items()))
    your_answer = input(f'{g[0]}？')
    if your_answer == g[1]:
        print('◯')    
        o += 1
    elif your_answer == "finish":
        break
    else:
        print('×')
        x += 1
       
print(f'◯→{o}\n×→{x}')
print(f'{(o/(o + x))*100}%')

```
ジョボヌーレーボー（自作言語で）

```
5 @ ary
"ボ" 0 @s ary
"ジョ" 1 @s ary
"レ" 2 @s ary
"ヌ" 3 @s ary
"ボ" 4 @s ary

4 $ i {
    { 5 '' $ r r @g ary _ 0 = ( ` } )
    0 r @s ary i ! ( [ ) i 1 - $ i
} ]

.s .s .s "ー" .s .s "ー" .s .s "ー" .s

```

最後怒涛の`.s`がなんかかわいいですね。

# 一応解説

一番重要なのは他言語で言う`shuffle`だと思います。`shuffle`は配列の中身をごちゃまぜにする関数なのですが、そんなものが`nouzen`にあるわけがないので、そこらへんの実装に時間を使いました。

```
4 $ i {                                 # 4が0になるまで（つまり5回ループ）
    {                                   # 　内部ループ上端
        5 '' $ r                        # 　　5未満の乱数を生成し変数rに代入
        r @g ary                        # 　　変数rを配列aryの添え字としてアクセス
        _ 0 =                           # 　　その文字列アドレスが空（すでに取得済み）だったら
    ( ` } )                             # 　内部ループ上端へジャンプ
    0 r @s ary                          # 　aryのrを空にする
    i ! ( [ ) i 1 - $ i                 # ループカウンタを進める
} ]
```
上を見てもピンと来るかどうか自信が無いので簡潔に申し上げますと、乱数で文字列から取得しスタックへ`push`、一度取得したものは`0`で埋めてアクセスしたことを示すマーカーとして扱う、もし乱数で取得したものが`0`、つまり取得済みだった時にはもう一度乱数を生成して取得をし直す、それを5回ループすることでスタック上にばらけた文字アドレスが格納される、という感じです。

# 元ネタ

@mattn 様の[ヌジョレーボーボー](https://qiita.com/mattn/items/ae764601862b0073071e) です。
コメントまで楽しい記事なので是非ご一読ください。

# nouzenってなんだよ

という方は私の過去の記事 [スタック指向なgoto言語 nouzen を作ってみた](https://qiita.com/asana_yui/items/c3b48707584f9cb738f5) をどうぞ
RailsにVue3を入れて、webpack-dev-serverで失敗　"export 'default' (imported as 'Vue') was not found in 'vue'


## 環境
Rails  6.1.4
Vue.js 3.2.31

## 背景
`bin/webpack-dev-server`を実行して以下のエラーが出た。
```shell
ERROR in ./app/javascript/packs/hello_vue.js 11:16-19
"export 'default' (imported as 'Vue') was not found in 'vue'
```

# 対処法
Vueなんて無いよと言われたので、hello_vue.jsを見に行きました。
```javascript
import Vue from 'vue'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)
})
```
何も異変に気づかず、、
公式ドキュメントを読んだ結果、Vue3系を使っているのにVue2系の書き方をしていることがわかりました。
[Vue 2.x からの破壊的変更](https://v3.ja.vuejs.org/guide/migration/global-api.html#%E6%96%B0%E3%81%97%E3%81%84%E3%82%AF%E3%82%99%E3%83%AD%E3%83%BC%E3%83%8F%E3%82%99%E3%83%AB-api-createapp)

Vueオブジェクトではなく　`import { createApp } from 'vue'`と名前付きインポートをしなければなりませんでした。
```javascript
import { createApp } from 'vue'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const app = createApp(App)
  app.mount('#app')
})
```

再度`bin/webpack-dev-server`をしてみると
```shell
ℹ ｢wdm｣: Compiled successfully.
```

正常にコンパイルできました。

3系の変更点で詰まったお話でした。
バナー職人だった私が、業務でコーディングするようになって感じたこと


元々は社内でバナー職人みたいな立ち位置だった私ですが、ここ1〜2年で、少しずつサイトのデザインやコーディングも任せて頂く機会が増えました。

今回は業務でコーディングをしてみて感じたことを書いてみたいと思います。

※HTML,CSS,jQueryのみを使った静的サイトのコーディングのお話です


## ① 綺麗にHTMLマークアップをする

正しく書かれたHTMLはコメントがなくても普通に理解できます。これはお手本のように美しくマークアップされたHTMLを見ればわかります。
本当に「スラスラ読める」んですよね。

文書構造がめちゃくちゃなdivだらけのコードは読んでて苦痛ですし、SEO的にも最悪です（私）

これまでテキトーにコーディングしてましたが、上司に注意を受けてからはマークアップの練習をするようになりました。


## ② classの命名規則を統一化する

これは今も迷う問題です。

というのも、弊社にはこれといった命名規則が明文化されていません…。
デザイナー、エンジニア各個人によって命名規則がバラバラすぎて気持ち悪いので、どうにか統一したい（しかしそんな権限はない）

一応自分は、アンダースコアで位置を、ハイフンで要素を示すようにしてます。


```sample.html
<span class="main_wrapper-text">あああ</span>
```


正しいのかどうかはわかりませんが、とにかく自分の中だけでも **「俺はこのルールでやってんだよォ！」** というのはあった方がいいと思います。

なにより、自分で管理していて楽です。


## ③  便利なサービスを使って、簡単につくる方法を考える

デザインにスライダーがあったら「じゃあ**Slick**を使おう」って考えたり、

https://kenwheeler.github.io/slick/

アイコンが使われていたら、SVGで書き出す前に、**Font Awesome** か **Material Icons**で代用できないか考えたり、

https://fontawesome.com

https://fonts.google.com/icons


イラストを使ったサイトにしたいんだけどって言われたら、
モダンで汎用性高い、商用利用可のフリーイラストサイト様を使わせていただこうかと思ったり。

https://soco-st.com


あと、スクロール連動のアニメーションをつけたいといった要望があれば、ここからjsとってきたり。
（柴犬のインパクトがすげーのよ）

https://wowjs.uk


どう実装したらいいのかわかんない動きは、とりあえずここに助けを求めたり…。
(WEBサイトの動きはほぼすべて解説してくれている神サイト)

https://coco-factory.jp/ugokuweb/



上のサービス（サイト）は超メジャーなものばかりなので、デザイナーさんからは「そんなん誰でも知っとるわ！！」と言われそうですが…。

一つ一つ自分で学んでいったのもあるのですが、
有名サイトの内側を調べてみると、上のようなサービスがどれか一つは絶対に使われているのがわかるかと思います。
そういった便利サービスの使い方を真似していくことで、簡単に、そこそこリッチな見た目のサイトを作る方法を学んでいったような気がします。


以上、まとまりのない記事になってしまいましたが、私が業務でコーディングをするようになってみての所感でした。
基本情報技術者試験対策　19日目

基本情報技術者試験勉強　19日目
-
この記事の目的
-
今年の5月に基本情報技術者試験を合格するために、過去問で間違えた箇所をただまとめる自分のための記事

プロフィール
-
・文系大学の３年生
・ITパスポートは保有
・ウェブアプリやサイト作成を個人で行ったことがある程度
・猫好き

本日の目標
-
苦手分野の克服（テクノロジ系）

間違った箇所
-
1、監視ソフトウェア
ハードディスク障害やメモリエラー、トラフィック障害などのようにシステム障害に繋がる事象が発生しているかをモニタリング

2、可逆符号化方式
圧縮前の画像を復元できる
圧縮前のデータと、圧縮後のデータを展開したデータが完全に等しくなる圧縮方法
圧縮率は低い
静止画像フォーマットではPNGやGIF
音声フォーマットではWMA Lossless，Apple Lossless，FLACなど

3、不可逆符号化方式
圧縮前のデータを復元できない
圧縮前のデータと、圧縮後のデータを展開したデータが完全には一致しない圧縮方法
圧縮率は高い
静止画像フォーマットではJPEG
音声フォーマットではMP3，Dolby Digital、動画フォーマットではMPEG1～4，WMV9など

4、投機実行
、分岐判断の結果が出る前に分岐先を予測して命令を先行実行していく方式
予測の精度が高いほど、性能向上

5、アウトオブオーダ実行
依存関係にない複数の命令を、プログラム中での出現順序に関係なく、実行する

6、同時マルチスレッディング
パイプラインの空き情報を利用して2つのスレッドを実行し、2つのプログラムがあるかのように見せる

7、RAD（Rapid Application Development)
用者の参画，少人数による開発，開発ツールの活用によって短期間に開発す

振り返り
-
本日も引き続き、テクノロジ系を中心に取り組んだが、思ったよりも時間が取れなく、30問程度しか取り組めなかった。残り2日で、テクノロジ系と計算問題を7,8割取れるようにする。
>引用
基本情報技術者試験ドットコム
https://www.fe-siken.com
nvidia-smiでエラーが出る

サーバー用PCにGPUを挿して計算機として運用する状況を想定した備忘録です。n番煎じ。
ディスプレイ周りはよくわかんない。

## NVIDIA Driverのインストール方法
[NVIDIA Dockerって今どうなってるの？(20.09版)](https://medium.com/nvidiajapan/nvidia-docker-%E3%81%A3%E3%81%A6%E4%BB%8A%E3%81%A9%E3%81%86%E3%81%AA%E3%81%A3%E3%81%A6%E3%82%8B%E3%81%AE-20-09-%E7%89%88-558fae883f44)という記事が非常に参考になります。あとは公式のcudaのマニュアルとか。

基本的には[CUDA Toolkit](https://developer.nvidia.com/cuda-downloads?target_os=Linux)のwebページのコマンドからインストールすることが推奨されています。
aptからインストールするのは事故の元なので自分はやらないようにしています。
これはUbuntu18.04用のコマンド。
```bash
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /"
sudo apt-get update
sudo apt-get -y install cuda-drivers
```
サイトのスクリプトそのままだとcuda toolkitをインストールしますが、最後の行をcudaではなくcuda-driversに変更するとドライバーのみインストールすることができます。
minicondaやnvidia-docker2を使って深層学習をやるような人はcuda toolkitが必要ないので、こちらのほうが良いと思います。

### 再インストールする場合
1.既存のドライバーをパージします。
```bash
sudo apt purge nvidia-*
sudo apt purge cuda-*
```
2.[CUDA Toolkit](https://developer.nvidia.com/cuda-downloads?target_os=Linux)のwebページを使ってドライバをインストールします。
3.nvidia-docker2を使っている場合は巻き込まれてパージされているので再インストールします。
```bash
sudo apt install nvidia-docker2
sudo pkill -SIGHUP dokcered
```

# 本題
## nvidia-smiが通らない
経験則的な対処方法です

### NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver.
稀に起こるやつです。
とりあえず再起動して、再起動してもダメならドライバを再インストールしましょう。

### Failed to initialize NVML: Driver/library version mismatch.
よく起こるやつです。
とりあえず再起動しましょう。九割直ります。
Dockerを仮想環境代わりに複数人でPCを強要している場合は若干注意が必要で、dokcerコンテナ側でGPUを占有しているとホスト側でこのエラーが出る場合があります。
再起動する前に誰かが使ってないか確認したほうが安全です。

## nvidia-docker2を使ったコンテナが起動しない
### OCI Container runtime 以下略
エラー文を読めばだいたい書いてありますが、GPUドライバ云々と出ている場合はnvidia-smiでエラーを吐く状態であることが多いです。
nvidia-smiが正常に動く状態なら立ち上がります。多分。
nvidia-docker2をそもそもインストールしていない場合も出てくるので、インストール忘れに注意。

### nvidia-smiが正常かつnvidia-docker2がインストール済みでOCI Container runtime以下略
変なアップデートの仕方をして依存パッケージのバージョンが足りていない場合に出たことがあります。
関連パッケージ(libnvidia-container1, libnvidia-comtainer-toolkitなど)を適当にアップデートしたら直りました。

おわり。
AWS公式資料で挑むSCS認定(24)-こんな時どうする(全分野その1)

##### [前回] [AWS公式資料で挑むSCS認定(23)-こんな時どうする(分野5:データ保護)](https://qiita.com/mingchun_zhao/items/2eed867d1841d4591c09)

## はじめに

前回まで分野別「こんな時どうする」をまとめてみました。
今回は「こんな時どうする」の補足となります。

## 分野1: インシデント対応

- ユーザのアクセスキーが誤って公開された
    - アクセスキーを削除またはローテート
    - 不正使用されていないか、すべてのリージョンにおけるAWS CloudTrailログを確認
    - 未承認リソースが存在したら削除

## 分野2: ログとモニタリング(監視)

- すべてのAPI呼び出しをログ収集、3ヶ月間のみオンライン状態で参照、その後コンプライアンス要求により5年間復元可能な状態で保存したい
    - すべてのアカウントでAWS CloudTrailを有効化
    - 集中型ログ記録アカウントのS3バケットにログを格納
    - 三ヶ月後Amazon Glacierに移動、5年後にデータを失効させるライフサイクルポリシーを作成

- AWS Lambda関数のデータをAmazon CloudWatch Logsにロギングさせたい
    - 最小権限ポリシーとしてCreateLogGroup、CreateLogStream、PutLogEvents権限をLambdaに付与

## 分野3: インフラストラクチャのセキュリティ

- CloudFrontディストリビューションでS3バケットから配信されるコンテンツに、ユーザーが直接アクセスできないようにしたい
    - オリジンアクセスアイデンティティ(OAI)と呼ばれる特別なCloudFrontユーザーを作成し、ディストリビューションに関連付ける
    - CloudFrontがOAIを使用しバケットにアクセスできるように、S3バケットのアクセス許可を設定
    - S3バケットへのダイレクトURLを使用したアクセスを拒否するように設定

## 分野4: アイデンティティ(ID)及びアクセス管理

- オンプレミスのADFS(Windows Active Directory Federation Services)を使用して、AWS Management Consoleにアクセスしたい
    - SAML2.0互換IDプロバイダー(IdP)とAWS Management Consoleへのタスク実行権限を付与したロールを使用
    - ユーザーがサインインすると、ADFSがユーザー識別アサーションとユーザー属性を含むSAMLアサーションレスポンスを生成
        - ADFSにコンソールセッションの有効期間を指定するSAMLアサーション属性SessionDurationを設定可
        - ADFSにセッションタグとして属性を渡すことも可能
    - ADFSはレスポンスをクライアントブラウザに送信
    - クライアントブラウザはAWSのSSOエンドポイントにリダイレクトされ、SAMLアサーションを投稿
    - SSOエンドポイントがユーザーの代わりに一時的なセキュリティ認証情報をリクエストし、コンソールのサインインURLを作成
    - AWSがサインインURLをクライアントにリダイレクト送信
    - クライアントブラウザがAWS Management Consoleにリダイレクトされる
        - SAML認証レスポンスに複数IAMロールに対応付けられた属性が含まれた場合、コンソールへアクセスするためロール選択が必要

- 新しいリソースを追加する度にリソースへのアクセス許可ポリシーを更新したくない
    - 属性(タグ)ベースのアクセスコントロール(ABAC)ポリシーを使用
    - プリンシパルのタグがリソースタグと一致するときのみオペレーションを許可する
    - 急速に成長している環境で役立ち、ポリシー管理が面倒な状況に役立つ

## 分野5: データ保護

- EC2インスタンスのEBSボリューム上のすべてのデータを暗号化したい
    - Amazon EBSボリューム作成時にKMSキーを指定
    - デフォルトでは、AWSアカウントのAWS管理キーを使用、ユーザーが作成/管理するカスタマー管理キーも指定可
        - カスタマー管理キーを使用する場合、ユーザーに代わってKMSキーを使用する許可をAmazon EBSに付与する必要あり

- S3への送信/保管データを暗号化、かつバケットが誤ってパブリックになっても、外部アカウントユーザからのアクセスを制限し、データを機密扱いできるようにしたい 
    - S3バケットのデフォルト暗号化方式を有効化、KMSキーを用いたサーバー側暗号化(SSE-KMS)を使用
        - KMSキーの使用権限を与えられた外部アカウントユーザーのみS3にアクセスできるため
    - バケットポリシーを追加し、PutObjectリクエストにaws:SecureTransportが含まれていない場合は拒否
        - HTTPS通信を強制し、送信データを保護

- S3保管データを暗号化し、不正アクセス対策のためすべてのアクセス監査証跡を記録したい
    - KMSキーを用いたサーバー側暗号化(SSE-KMS)を使用することで、KMSキーがいつ誰によって使用されたか監査証跡を記録可

## おわりに

各分野に対し「こんな時どうする」を追加しました。
次回も続きます、お楽しみに。

##### [次回] [AWS公式資料で挑むSCS認定(25)-こんな時どうする(全分野その2)](https://qiita.com/mingchun_zhao/items/58d4ad73ddd1631b9b87)
Teraranger Evo MiniをJetson Nano上のROSで動かす

2021/03/29の備忘録です。  
PPAのros-melodic-terarangerにEvo Mini用のROSノードが入っておらず、自前でビルドを行いました。  

## 環境  
- Jetson Nano 4GB
    - JetPack4.3
    - ros-melodic

Jetson NanoにROSをインストールする部分は[Getting Started with ROS on Jetson Nano - Stereolabs](https://www.stereolabs.com/blog/ros-and-nvidia-jetson-nano/)が参考になります。

## 本題
### 前提パッケージ
ROS Serialをインストールしておきます。
```bash
sudo apt install ros-melodic-serial
```
### TerarangerのROSモジュール
Terabee公式のリポジトリを利用します。
ユーザーディレクトリ直下の```~/catkin_ws```がROSのワークスペースです。適宜環境に合わせて変更してください。
```bash
cd ~/catkin_ws/src/
git clone https://github.com/Terabee/teraranger.git
git clone https://github.com/Terabee/teraranger_array.git
cd ~/catkin_ws/
catkin_make
source ~/catkin_ws/devel/setup.bash
```
teraranger_arrayはterarangerの前提モジュールです。無い場合ビルドが失敗します。
### ROS Serialを使うために
ROS Serialを使うためにはひと手間必要です。
dialoutグループにユーザーを追加します。
```bash
sudo adduser $USER dialout
```
グループに追加したら再起動が必要です。

### テスト
Teraranger Evo MiniをUSBで接続した状態で
```bash
roscore

#別窓
rosrun teraranger evo_mini

#別窓
rostopic echo /teraranger_evo_mini/range
```
距離センサの値が表示されれば成功です。

おわり。
docker使ってreactアプリの環境構築してみた(最低限だよ)

# ディレクトリ構成

```
AppName
  |-- Dockerfile
  |-- docker-composecompose.yml
```

# docker関連のファイルの記述

```Dockerfile:Dockerfile
FROM node:17-alpine
WORKDIR /usr/src/app
```

```yml:docker-compose.yml
version: '3.9'

services:
  node:
    build: ./
    volumes:
      - .:/usr/src/app:cached
    command: sh -c "cd react-sample && yarn start"
    ports:
      - "3000:3000"
```

# コマンドの実行

react-sampleは自身に合わせて変更。

```
docker-compose run --rm node sh -c "npm install -g create-react-app && create-react-app react-sample"
```

```
docker compose up
```

このようになれば完了。

![スクリーンショット 2022-03-22 20.02.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645779/15bb55c8-e42d-d840-fd54-3cf2b0ec3606.png)
[firebase_storage/unknown] An unknown error occurred, please check the server response. の時に確認すること

# はじめに
FlutterでCloud Storageに画像を保存しようとしたら、👇のようなエラーが。。。
![スクリーンショット 2022-03-29 23.15.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/ffaba418-e942-33be-b4b1-e92ee953a808.png)
 
初めてCloud Storageを使うのだが、、ソースコードの問題ではなさそう:expressionless:
「please check the server response」と言うけど、responseをどうやって確認するねん・・・と言う状態です。。。

、、、どうしたらいいのやら？？？

と思ったが、意外と簡単に解決しました！

# ルールの問題だった

![スクリーンショット 2022-03-29 23.19.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/2ce798f8-e7e1-6613-d631-3db2f3145c21.png)


```javascript
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if true;
    }
  }
}
```

このようにすれば解決しました。
**認証がなくても、誰でも読み書きができるようにしました。**


# 参考

https://teratail.com/questions/254979
AWS SWF とは

## 勉強前イメージ

なんだっけ・・・わからん・・・

## 調査

### AWS SWF とは

Amazon Simple Workflow Service の略で、マネージド型のサービスになります。
ワークフロー管理サービスで、複数サーバ間でアプリケーションを連携させるための開発になります。
要するに、複数サーバで商品の発注のようなワークフローを処理する際の順番や振り分け先を管理するサービスです。

Step Functionsの従来のサービスに当たるもので、同様の機能が使える際はStep Functionsを使用することを推奨されています。
Step Functionsの詳細は [こちら](https://qiita.com/miyuki_samitani/items/6c58d107cdc86d938fe3) に記載しているのでご確認ください。

### 用語の確認

- ワークフロー : 実行する一連の流れを定義したもの
- ドメイン : 作成したワークフローの名前
- ワークフロースターター : ワークフローを開始するアプリケーション
- スターター : ワークフローをキックするプログラム
- アクティビティタイプ : ワークフローの中の処理
- アクティビティ : アクティビティタイプごとに発生するタスクを実際に処理するプログラム
- タスクリスト : タスクを入れるキュー
- デザイダー : ワークフローでタスク処理の処理を決めるプログラム

## 勉強後イメージ

step functionの前のサービスってことか...
一旦step function使ってみてって感じなのかな。

## 参考

- [AWS再入門 Amazon Simple Workflow Service編](https://dev.classmethod.jp/articles/cm-advent-calendar-2015-getting-started-again-swf/)
- [Amazon SWF編～Simple Workflow Serviceを使ってみよう！パート①～](https://recipe.kc-cloud.jp/archives/2620)
AWS Application Migration Service とは

## 勉強前イメージ

アプリケーションを移行するやつ？

## 調査

### AWS Application Migration Service とは

略してAWS MGNと呼ばれ、(AMSの略語はほかのサービスの略称になっているため)
オンプレなどのサーバーをAWSへ移行するためのサービスとなります。
CloudEndure Migrationの後継となるサービスで、CloudEndure Migrationを使用している場合はMGNを推奨しています。
CloudEndure Migrationと同様の機能を提供していますが、AWSのマネジメントコンソールで利用することができ
またAWSの他のサービスと合わせて利用することができます。

### AWS Application Migration Service の特徴

- 移行を迅速に行うことができる

増分変更分のみ移行することで、ネットワーク帯域を最低限に抑えつつも移行ができます。

- 移行の進行状況を確認可能

大規模な移行を行う際はレプリスケジュールを作成し、管理 各移行を確認することができます。


### AWS Application Migration Service と CloudEndure Migration の違い

- エージェントのインストール可否

AWS MGN : インストールなし
CloudEndure Migration : OSごとにインストールが必要

- 同時実行VM数

AWS MGN : 最大50VMまで
CloudEndure Migration : 制限がなし

- ネットワーク帯域の制御

AWS MGN : 制限はできない
CloudEndure Migration : 制限ができる

- AWS Direct Connectの利用

AWS MGN : 利用不可
CloudEndure Migration : 利用可能

- データ転送先

AWS MGN : s3
CloudEndure Migration : 移行先サーバ

- 対応OS

詳細はAWS MGNのOS要件について確認いただきたいのですが、
古いOSにはAWS MGNは対応していない場合があります。

- 費用

AWS MGN : エージェントインストールしてから90日間は無料、それ以降費用が発生
CloudEndure Migration : 利用自体は無料

## 勉強後イメージ

最近できたサービスかな？
これ見てたら大規模に移行するときにいいみたいな感じするね。
元のサーバのOSが古かったり、合わない場合はCloudEndure Migrationって感じかな。

## 参考

- [ホームコラム【新サービス】AWS Application Migration Serviceが発表【新サービス】AWS Application Migration Serviceが発表](https://www.sunnycloud.jp/column/20210524-01/)
- [CloudEndure Migrationを使ってクラウド移行する](https://www.acrovision.jp/service/aws/?p=2933)
- [AWS Application Migration Serviceとは？ ～CloudEndure Migrationとの機能比較～](https://www.cloudsolution.tokai-com.co.jp/white-paper/2021/1126-273.html)
rails でアプリを立ち上げ時に、データベースを指定する方法

# 結論

```
% rails new -d データベース名
```
これでデータベースを指定することができます。

ちなみに,

## データベースを作成する方法
```
% rails db:create
```
これで指定したデータベースを作成することができました。

これはまだ、データベースというデータを入れる箱を作ったに過ぎません。

例えるなら

弁当作った←弁当箱を作った段階です。

## 中身のデータを作成する方法

```
% rails g model モデル名（単数）　　カラム名：データ型（カラム名：データ型は複数指定可能）
```
これで例えるなら弁当箱のどこに何を入れるのかなんとなく決めた状態です。

実は、この時に`maigrateファイル`というファイルが作成されてます。`migrateファイル`とはデータベースの中身の表（テーブル）の構造を指定するファイルです。例えるなら弁当箱の仕切り（アルミ箔やバランなど）ですかね、、、

ちなみに
```
g = generate :　生成する
model : 模型
column : データ表の縦列
データ型 : 整数なのか、文字なのか
migrate : 移行する
```
## `migrateファイル`の指定をデータベースに反映させる
```
% rails db:migrate
```
これで中身の構造を具体的に指定した、データベースという箱を作ることができました。
データベースはアプリに紐づいています。
modelを介してデータのやり取りを行うことができます。

ちなみにテーブル名はモデル名（複数系）。

例えるなら、あとは唐揚げ、卵焼きを入れるだけの弁当箱が出来た感じですかね、、、

例えが下手で混乱していたら申し訳ないです。

以上です。
recsys-pythonを進めていく(第2章)

# 参考文献とか
1. https://recsyslab.github.io/recsys-python/
2. https://techbookfest.org/product/5547509835366400?productVariantID=5739222210183168
3. https://note.nkmk.me

# 前回の記事
https://qiita.com/yaminabeworks/items/538cd15bab614683e9b3

# やったこと
- google colabで参考文献1.の第2章を解いた。
- 以下の場所に.ipynbファイルを置いておいた。暇だったら見ていってほしい。
  - https://github.com/yaminabeworks/qiitakiji/blob/main/numpyknock_recsys02.ipynb

# 感想

- `ndarray`の形を扱う部分やブロードキャスト周りの理解が浅いことに気づいてしまった。
  - 多分参考文献2.あたりをすらすらとこなせるようになるといいんじゃないのかなという思い。
    - Amazonでも売ってたけど確かこっちの方が安い。なんでだろう。
  - そこまでガチガチに`NumPy`をいじらない人は無料かつ完成度の高い参考文献3.がとてもお勧めな気がしている。
- 2章の21問分も慣れてないのでそれなりにきつかった。所要時間は3h程度。
- `NumPy`による計算を`jax`や`Julia`の計算に書き直すやつを作りたい定期。
  - `NumPy`でxxx作ってみる系の資料をまとめて、ノック作ってみたさある。
- colabからgistに保存するというやつをやってみたがgist何もわからんので知りたいなーという気持ち。

# 次にやること

- 参考文献1.の第3章
  - <del>多分3、4章は機械学習アルゴリズムの話だからなんとかなる</del>
pandasのリストをコピーする

## データの用意
```
df = pd.DataFrame([[None for j in range(2)]  for i in range(3)], columns=['before', 'after'])
df['before'] = df['before'].apply(lambda x:[0,0])
```
| before  | after    |
|:-------:|:--------:|
| [0, 0]  | None        |
| [0, 0]   | None        |
| [0, 0]   | None        |

上記のようなテーブルがあったときに、beforeをafterへコピーしたいと思います。

## 完成予想図

| before  | after    |
|:-------:|:--------:|
| [0, 0]  | [0, 0]    |
| [0, 0]  | [0, 0]    |
| [0, 0]  | [0, 0]    |

## OKな例

```
import copy
df["after"] = df["before"].apply(lambda x:copy.deepcopy(x))
```
このように一行づつdeepcopyする必要があります。

## NGな例

以下、間違えていた方法を挙げます。

### 浅いコピー

```
df["after"] = df["before"].copy()
```
カラムの中身がstrやintであれば実行できますが、listは参照になってしまいます。

### カラムをdeepcopy

```
df["after"] = copy.deepcopy(df["before"])
```

deepcopyしているので実行できそうですが、こちらもダメです。


### 確認する

```
# カラムの識別値
print(id(df["before"])) # >>> 140355706322576
print(id(df["after"]))  # >>> 140355202828368

# リストの識別値
print(id(df["before"][0])) # >>> 140355188788272
print(id(df["after"][0]))  # >>> 140355188788272
```

id関数を使用するとオブジェクトの識別値を確認することができます。
カラムは識別値が違うため異なるオブジェクトとして存在していますが、リストは値が同じで参照していることがわかります。

そのためafterの中身を変更しようとするとbeforeまで変わってしまいます。

なのでOK例のように1行づつdeepcopyするのが良さそうです。


## 参考文献

https://qiita.com/kokorinosoba/items/e9ab9398af5b44d2ac9a
python 仮想環境でファイルを実行する

## はじめに
このページはpython初心者が勉強したことを書き記す忘備録的な意味合いで作成しています。
Qiitaへの投稿も初ですので、何かあればこっそりご指摘いただけますと幸いです。

## このページのゴール
新規で仮想環境を作成し、モジュールを設定してプログラムファイルを実行する。
⇨Googleの検索画面のソースコードがコマンドライン上に表示されること。

## 作業環境
>OS: macOS moterey(12.3)
>PC: macbook pro(2016)
>Python 3.8
>実施者: ど素人

## 内容
### 参考資料
https://www.python.jp/install/macos/virtualenv.html
### 前提
pythonがインストールされていること
### 実行手順
テキストエディタで以下のコードを記述したファイルを作成する
```python:sample.py
import requests
print(requests.get("https://www.google.com/").text)
```
コマンドラインで以下のコマンドを順番に入力していく
```:作業用ディレクトリ「dev」を作成する
mkdir ~/dev
```

```:作業用ディレクトリ「dev」へ移動する
cd dev
```

```:作業用ディレクトリの中に仮想環境「.test」を作る
python3 -m venv .test
```

```:「.test」へ切り替える
. .test/bin/activate
```
% ⇨ (.test) % という表示になる

```:モジュール「requests」を追加する
python3 -m pip install requests
```

```:ファイル「sample.py」を実行する
python3 sample.py
```
出力結果は自分の目で確かめよう☆
（コマンドライン上にソースコードがドババと表示されて目が痛くなるので注意）

課題：文字化けしている箇所があるのでそれを治す方法を今度調べる。

## おまけ
```:仮想環境の使用を終了する
deactivate
```
(.test) % ⇨ % 表示に戻る
【React Native】PressableStyleをつくってopacity制御の記述を簡潔にする

# はじめに
v0.63から追加された`Pressable`は、コンポーネントをタップしたときのスタイルや描画内容を制御できる非常に便利なAPIです。
例えば、v0.63以前だと`TouchableOpacity`でしか制御できなかったタップ時のopacityを、`Pressable`だと`style`をちょっといじるだけで変更することができます。

この便利さ故、`TouchableOpacity`と`TouchableWithoutFeedback`のページにも、拡張性の高いボタンをつくるなら`Pressable`を使え的なことが書かれています。
![スクリーンショット 2022-03-29 22.04.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/7e3f563b-6ae3-0f4c-ae4f-1f14e9e33f69.png)

ただ、各ファイルで`Pressable`を使うことになったとき、以下のようにstyleを定義していくと、タップ時のopacityをただ変えたいだけなのにも関わらず、冗長な記述となってしまいます。

```tsx
      <Pressable
        onPress={onPress}
        style={({ pressed }) => [
          {
            opacity: pressed
              ? 0.5
              : 1
          },
          styles.container
        ]}>
        {children}
      </Pressable>
```
各ファイルへのこのような記述の点在を避けるために、opacityを簡単に制御できる`PressableStyle`を作成しました。

# 実装
かなり冗長なタップ中のopacityの記述を`PressableStyle`でラップします。

```ts
type PressableStateCallbackType = Readonly<{
    pressed: boolean;
}>;

const PressableStyle = {
  opacity: ({ opacity = 0.5, style = [] }: { opacity?: number; style?: StyleProp<ViewStyle> }) => {
    return ({ pressed }: PressableStateCallbackType) => [{ opacity: pressed ? opacity : 1 }, style];
  },
};
```
以下が`PressableStyle`を適用したコンポーネントの例です。
デフォルト値(0.5)以外のopacityを設定したい場合は、`opacity: 0.2`のように指定します。

```tsx
type Props = {
  onPress: () => void;
  containerStyle?: StyleProp<ViewStyle>;
  children: React.ReactNode;
}

export const StyledButton: React.FC<Props> = React.memo(
  ({ onPress, containerStyle, children }) => {
    return (
      <Pressable
        onPress={onPress}
        style={PressableStyle.opacity({
          opacity: 0.2,
          style: [styles.container, containerStyle],
        })}
      >
        {children}
      </Pressable>
    );
  },
);
```

# おわりに
`TouchableOpacity`だとopacityは0.2で固定で、コンポーネントによってはタップ時の透過が強く感じるときがあります。
そんなときは`Pressable`を使って柔軟にスタイルを制御しましょう。

# 参考資料

https://zenn.dev/nekoniki/articles/ef304778ada8a6
Postman での Google OAuth2.0 トークン取得（デフォルトブラウザ利用版）

2017年にリリースされた[Postman v7.24](https://blog.postman.com/whats-new-in-postman-7-24/)からは、OAuth2トークンを取得するのに組み込みブラウザではなく、普段使っているデフォルトブラウザを利用できるオプションが追加されました。何が嬉しいかというと、組み込みブラウザが未サポートだという理由で認可サーバから弾かれることを回避できるということに加えて、デフォルトブラウザを使うのでブラウザに保存されている認証情報を流用できたり、1Passwordが使えるようになります。
先日正式版となった[Google Forms API](https://developers.googleblog.com/2022/03/introducing-google-forms-api.html)を叩く際にこのオプションを使ったので、その手順を残しておきます。

おそらくいま、Postmanの組み込みブラウザを使うとこういうエラーとなるんじゃないかと思います。
![Screen Shot 2022-03-29 at 21.49.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118448/8b9e1c59-3497-e5e8-3cf8-57cfe35be8d9.png)

# 1. OAuth同意画面の設定をする
作業場所： GCPコンソール

OAuthクライアントIDを作成するのに先んじて必要となるので設定をします。

1. 任意のプロジェクトのナビゲーションメニューより、「APIとサービス」＞「OAuth同意画面」を選択します
1. ガイドに沿って必要情報を入力して進めます。テストユーザーには、自分のGoogleアカウントを追加しておけば良いと思います

# 2. OAuthクライアントIDの作成をする
作業場所： GCPコンソール

1. ナビゲーションメニューより、「APIとサービス」＞「認証情報」を選択します
1. 「認証情報を作成」をクリックし、「OAuthクライアントID」を選択します
1. 次の情報を入力してクライアントを作成します
    1. アプリケーションの種類： ウェブアプリケーション
    1. 名前： 任意
    1. 承認済みのリダイレクトURL： https://oauth.pstmn.io/v1/callback
1. 画面に表示されるクライアントIDとクライアントシークレットを控えます

# 3. Postman側の設定をする
作業場所： Postman

1. コレクションまたはリクエストの「Authorization」タブを開きます
1. 次の情報を入力します。指定以外はデフォルト値でOKです
    1. Type: OAuth2.0
    1. Callback URL: 「Authorize using browser」をチェック
    1. Auth URL: https://accounts.google.com/o/oauth2/v2/auth
    1. Access Token URL: https://www.googleapis.com/oauth2/v4/token
    1. Client ID: 手順２で控えたもの
    1. Client Secret: 手順２で控えたもの
    1. Scope: 任意のスコープ

# 4. トークンを取得する
作業場所：Postman

手順３を終えたら「Get New Access Token」ボタンをクリックします。すると、普段使っているブラウザが起動します。ログインすると、Postmanに戻ってくるので「Use Token」ボタンを押せば、トークン取得は完了です。
![Screen Shot 2022-03-29 at 22.41.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118448/2c02acc6-3d25-b481-c175-635aed303355.png)

以上。

# 参考
- [Google OAuth2.0 | Google Cloud API | Postman API Network](https://www.postman.com/speeding-resonance-133102/workspace/google-cloud-api/documentation/12689164-9400e5f3-afac-4759-afe4-630a3842b2eb)
Amazon CognitoのホストされたUIを表示しないIDフェデレーション 

# はじめに

　Amazon CognitoでIDプロバイダーを設定して、ホストされたUI（Hosted UI）を利用した際にホストされたUI（Hosted UI）を表示せず、IDプロバイダーのサインイン画面を表示する方法を残します。


# 前提
　Amazon CognitoにIDプロバイダーとしてGoogleを設定した例とします。設定方法は、以下を参照すると良いです。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/cognito-google-social-identity-provider/

こんな形でIDプロバイダー、ドメインを設定しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/0ee4b406-b1a6-8c18-7d42-8f80150cd1a6.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/27522c92-0551-8bed-6c75-33d41d62a3e3.png)


# 通常の場合
　ホストされたUI（Hosted UI）を利用した場合、以下の流れになります。
アクセス先→ホストされたUI（Hosted UI）→Googleサインインボタンをクリック→Google認証→アプリケーション

アクセス先
※サンプルになります。穴埋めしてお使いください。
```
https://[Cognitoで設定したドメイン].auth.[リージョン].amazoncognito.com/login?client_id=[クライアントID]&response_type=code&scope=email+openid+profile&redirect_uri=[リダイレクト先URL]
```

アクセスすると、以下の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/9ae9150e-9206-d0cd-f066-2d04d2000aec.png)

その後、「Continue with Google」をクリックすると、Googleのサインイン画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/f42bc682-c65e-662b-7926-db810d1a148f.png)

認証を行った後、リダイレクト先に遷移することになります。

# ホストされたUI（Hosted UI）を表示しない場合
　ホストされたUI（Hosted UI）を利用した場合でホストされたUI（Hosted UI）を表示せず、Google認証へ遷移させたい場合は、以下の流れになります。
アクセス先→Google認証→アプリケーション

アクセス先
※サンプルになります。穴埋めしてお使いください。
```
https://[Cognitoで設定したドメイン].auth.[リージョン].amazoncognito.com/oauth2/authorize?client_id=[クライアントID]&response_type=code&scope=email+openid+profile&redirect_uri=[リダイレクト先URL]&identity_provider=[IDプロバイダー名（今回だとGoogle）]
```

アクセス先にアクセスすると、すぐに以下へ遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/629c341f-9154-9af5-3cd2-e4131907a40c.png)

# まとめ
　アクセス先を変えるだけで「Continue with Google」をクリックすることなく、すぐに認証できる流れになるため、スッキリした流れになります。もちろん、特定のIDプロバイダーで利用したい場合に限りますが、「それやりたかった！」という方もいるのではないでしょうか。他のIDプロバイダーでも利用できます。ぜひ、ご活用ください。

では。
【Windows Server】ファイルサーバの構築

# 概要
- ファイルサーバリソースマネージャーのインストール
- 共有アクセス許可の設定
※デフォルトでは権限がサブフォルダに継承される
- NTFSアクセス許可の設定
- アクセスベースの列挙の有効化
- ディスククウォータの設定
- シャドウコピー(VSS)の設定

# ファイルサーバリソースマネージャーのインストール
サーバマネージャ > 機能の追加　> 次へ > 次へ > 次へ > ファイルサービスと記憶域サービス >ファイルサービスおよびiSCSIサービス > ファイルサーバーリソースマネージャーにチェックを入れてインストール

![000006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/0bb989fd-00ec-3dce-0f55-5fb87a47829c.jpeg)

適当な場所にフォルダを作成する
![000014.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/4a75950b-87d9-1dba-0630-ffa5ff66f79c.jpeg)

# 共有アクセス許可の設定
・フォルダを共有して共有名の設定を行う。
・プロパティ > 共有 > 詳細な共有 > アクセス許可 > 追加 > 任意のユーザを追加する
![000022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/d0a69f83-bb91-9892-7ead-a694cbac3959.jpeg)

・アクセス権限をフルアクセスコントロールに設定する。
※NTFSアクセス権限で制限をするため共有アクセス権限はすべて許可にする。
![000024.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/ec0704e4-3c32-afa5-0394-e23cd5eecc81.jpeg)

# NTFSアクセス許可の設定
・プロパティ > セキュリティ > アクセス許可 > 追加 >　プリシンバルの選択 > 高度なアクセス許可を表示する任意のユーザを追加する > 閉じる
![000036.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/78f46460-d800-6cc0-5db7-0db9fe3c870e.jpeg)

# アクセスベースの列挙の有効化
アクセスベースの列挙とは、アクセス権限の無いファイルやフォルダを非表示にする設定。

・サーバマネージャ > ファイルサービスと記憶域サービス > 共有 > 右クリック > プロパティ > 設定 > アクセス許可設定に基づいた 列挙を有効にするにチェックを入れる
![000043.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/beab99fe-92fc-916f-f582-201afbcf4af8.jpeg)

![000045.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/a25f89ee-e738-42d4-26c1-163872f1edd6.jpeg)

# ディスククウォータの設定
・サーバマネージャ > ファイルサービスと記憶域サービス > 共有 > 右クリック > クウォータの構成 > テンプレートを選択 
![000049.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/a9b4a834-2351-3b8b-41ba-6c5c2f155a8e.jpeg)

![000057.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/600935fd-8dcb-d164-afdf-0774158f5069.jpeg)

# シャドウコピー(VSS)の設定
・共有フォルダのドライブを右クリック > シャドウコピー > 有効化 > シャドウコピーの容量とスケジュールを設定する。
詳細設定したい場合は、サーバマネージャーのファイルサーバリソースマネージャーから設定する。
![000068.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/3fe9241b-58df-10de-4291-d436538f8e59.jpeg)

# ファイルおよびフォルダのコピーと移動による権限の影響
- コピーによる影響
明示的に設定したアクセス許可は破棄され、コピー先フォルダからアクセス許可の継承を行う。
コピー先が同じボリューム内でも別ボリュームでも。

- 移動による影響
移動先が同じボリューム内なら、明示的に設定したアクセス許可は保持されたうえで移動先の上位フォルダのアクセス許可を継承する。
移動先が別ボリュームの場合は、明示的に設定したアクセス許可は破棄され、移動先の上位フォルダのアクセス許可を継承する。
yum update時にpython-urllib3がupdate failedした話

先日yum update業務を行っていたところ、
Python-urllib3というライブラリがupdate failedしてしまう事象に陥りました。


必須パッケージだったため、update完了させねばならず…
事象は解決したものの、少し奮闘したので備忘録として残しておきます。

****
**事象:**
yum updateコマンド実行→実行結果が表示される際、failedパッケージとしてpython-urllib3あり。
```
//Failed:  
python-urllib3.noarch 0:1.10.2-5.el7  
python-urllib3.noarch 0:1.10.2-7.el7 
```

<br>

**解決策:**
pip側の対象ライブラリ(python-urllib3)とrpm側の同ライブラリのバージョンを揃えてからyum update実行で事象解決

```
$ pip uninstall urllib3
$ yum update
```

$ pip uninstall urllib3
対象ライブラリをアンインストール(＝ダウングレードさせる)
一度実行しただけではrpm側のライブラリバージョンと同一にならなかったので
数回このコマンドをたたきました。
<br>
rpm側とpip側のバージョンは下記コマンドで確認できます。↓
```
#rpm側のライブラリVer確認
$ rpm -qa | grep urllib3
#pip側のライブラリVer確認
$ pip list | grep urllib3
```

<br>

**考察:**
pip側の対象ライブラリ(python-urllib3)と、rpm側の同ライブラリのバージョン違いにより
コンフリクト発生→アップデート失敗となる模様。
yum update前にバージョン違いを解消できれば問題なくアップデートできる。

<br>

**やったこと・参照したページ:**
エラー文コピペして検索→同じような事象で悩む方々発見→見当をつけて検証。
ちなみに参照したサイトは以下↓
https://bugzilla.redhat.com/show_bug.cgi?id=1187057
>Ralph Bean 2015-02-18 17:18:46 UTC
Yeah, this is not a bug.  You 'sudo pip install'd urllib3 at one point and that is conflicting with rpm.
Please 'sudo pip uninstall urllib3' and then try yum installing again after that.

https://bugzilla.redhat.com/show_bug.cgi?id=1738348
>Jonathan N. Winters 2019-09-19 02:13:50 UTC
Confirmed the 
pip uninstall urllib3
followed by
yum update -y
completed the updates successfully.
<br>
<br>
<br>

以上、簡単なまとめでした。
MAiX Qube 奮闘記01

OpenMVを使った画像処理に興味があって小型のMAiX Qubeを買っちゃいました!!
まずはラズパイからの癖でファームウェアを最新にアップデート。
ファームウェアはここから
https://dl.sipeed.com/shareURL/MAIX/MaixPy/release/master/maixpy_v0.6.2_72_g22a8555b5
いろいろ試したけど結局一番下の
「maixpy_*.bin」に相当する「maixpy_v0.6.2_72_g22a8555b5.bin」
が良さそうと解る。
てかその前にインストール　ツールが必要な事が分かる。
RaspberryPi4にラズパイ版のKflashをなんとかインストール成功。(簡単には出来なかったです;;)
![2022-03-28-225753_1920x1080_scrot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/076b412e-e4cd-da72-0114-4cec1c779ac0.png)
ファームウェアをダウンロードし書き込むと、、
あらら、青一色の画面になりなにも表示されなくなりました。
やらかした。
なにもしなければ良かった;;
![RIMG0009.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/6388e200-a762-b5c4-857a-e20152ded2b8.jpeg)
解決策としてjsonファイルを書き込んでみる。
製品毎に異なる周辺機器のGPIOピンへの割り付けを吸収するためのファイルみたい。
https://wiki.sipeed.com/soft/maixpy/zh/api_reference/builtin_py/board_info.html
ここから
0.6. Maix Cube#
を入手しPC上のMaixPy　ideから実行
ファイル操作は行わずこのプログラムを実行する事でプログラムが修正してくれるみたい。

いまくいかない時は、今あるjsonファイルを消してから実行してみてください。
ターミナルから
import uos
uos.remove('/flash/config.json')
と実行してから行うととうまくいく場合もありました。
(私は複数個体使用していますがこれで解決した場合もありました。)


```python:config_maix_cube.py
import json

config = {
    "type": "cube",
    "lcd": {
        "height": 240,
        "width": 240,
        "invert": 1,
        "dir": 96
    },
    "sdcard":{
        "sclk":27,
        "mosi":28,
        "miso":26,
        "cs":29
    },
    "board_info": {
        'BOOT_KEY': 16,
        'LED_R': 13,
        'LED_G': 12,
        'LED_B': 14,
        'LED_W': 32,
        'BACK': 11,
        'ENTER': 10,
        'NEXT': 16,
        'WIFI_TX': 6,
        'WIFI_RX': 7,
        'WIFI_EN': 8,
        'I2S0_MCLK': 19,
        'I2S0_SCLK': 35,
        'I2S0_WS': 33,
        'I2S0_IN_D0': 34,
        'I2S0_OUT_D2': 18,
        'I2C_SDA': 31,
        'I2C_SCL': 30,
        'SPI_SCLK': 21,
        'SPI_MOSI': 8,
        'SPI_MISO': 15,
        'SPI_CS': 20,
        'ESP32_MOSI': 28,
        'ESP32_MISO': 26,
        'ESP32_SCLK': 27,
        'ESP32_CS': 29
    }
}

cfg = json.dumps(config)
print(cfg)

# config lcd back_light
try:
    os.remove('/flash/boot.py')
except:
    pass
with open('/flash/boot.py', 'wb') as f:
    cfg_sensor = b'from fpioa_manager import fm\nfrom Maix import GPIO\nfm.register(17, fm.fpioa.GPIOHS28)\nlcd_en = GPIO(GPIO.GPIOHS28, GPIO.OUT)\nlcd_en.value(0)\n'
    f.write(cfg_sensor)
    del cfg_sensor

try:
    with open('/flash/config.json', 'rb') as f:
        tmp = json.loads(f.read())
        print(tmp)
        if tmp["type"] != config["type"]:
            raise Exception('config.json no exist')
#既にTYPE="cube" のconfig.jsonファイルが存在していると書き換えを行わないので注意。
#ターミナルを立ち上げ"os.remove('/flash/config.json')"などで消してからこのプログラムを実行すると良い。
except Exception as e:
    with open('/flash/config.json', "w") as f:
        f.write(cfg)
    import machine
    machine.reset()
```
そして再度起動させると
![RIMG0012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/fb9dbbb0-35f0-b928-5cd2-0628af1562a2.jpeg)
画面が表示されました。
めでたしめでたし。
Google Apps Script からGoogleフォームの回答を送信する



Google Apps ScriptからGoogleフォームの回答を送信する方法です。
GASからフォームの回答を送信する方法について、リファレンスからサンプルコードを起こしたものです。

# 送信までの流れ
回答を送信するまでの流れは以下の通りです。
1. 対象formを取得
1. formから各質問(Item)を取得
1. 2で取得できるItemはInterfaceなので、具体的なItemに変換(text項目なら、[TextItem](https://developers.google.com/apps-script/reference/forms/text-item)など)
1. 3のItemから、それぞれの回答を設定
1. FormResponseに回答をつめて、submitで提出


## ①対象formを取得
``` js
  // formを作成する場合
  const form = FormApp.create('New form');
  form.addTextItem().setTitle('text');
  // 既存のformを使用する場合
  // const existingForm = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
```

## ②formから各質問(Item)を取得
1で取得したFormからItem一覧を取り出します。
取り出したItemは[これ](https://developers.google.com/apps-script/reference/forms/item)
Itemからは質問のId、順番、タイトル、タイプがなど取得できます。

``` js
  // formからItem一覧を配列で取得
  // 型は Item[]
  const formItems = form.getItems();
  // 1要素目を取り出し
  const aItem = formItems[0];
```

## ③2で取得できるItemはInterfaceなので、具体的なItemに変換
[Item](https://developers.google.com/apps-script/reference/forms/item)はインターフェースでなので、具体的なItemに変換します。
ここでは、テキスト項目を追加しているので[TextItem](https://developers.google.com/apps-script/reference/forms/text-item)に変換しています。

``` js
  // 具体的なItemへ変換
  // 型はTextItem
  const textItem = aItem.asTextItem();
```

## ④3のItemから、それぞれの回答を設定
具体的なItemに変換出来たら、`createResponse()`で回答を設定します。
渡せる引数の形式は、質問の型によって違うので注意が必要です。
以下の質問への`createResponse()`については、[サンプルコード](#サンプルコード)に入っているので参考にしてみてください。
- 記述式
- ラジオ
- チェックボックス
- プルダウン
- 均等目盛
- 日付
- 時間


どの型のItemでも、`createResponse()`の戻り値の型は[ItemResponse](https://developers.google.com/apps-script/reference/forms/item-response)になってます。

``` js
  // 回答を作成。質問の型によって渡し方が違うので注意
  // 型は ItemResponse
  const textItemResopnse = textItem.createResponse('text resopnse');
```
## ⑤FormResponseに回答をつめて、submitで提出
4で作成した回答をFormResponseに設定して、最後にsubmit()して提出します。
1つの質問(Item)につきItemResponseは1つ、1対1関係になっています。
複数の質問項目があるフォームの時は、`withItemResponse(ItemResopnse)`を複数実行するか、つなげて書くことで2つ以上の項目について回答できます。(つなげて書くほうは試してないです。たぶん動きます。たぶん。)

``` js
  // FormResponseを作成
  const formResponse = form.createResponse();
  formResponse.withItemResponse(textItemResopnse);
  /** 複数の時
   * その1
   * formResponse.withItemResponse(ItemResopnse1);
   * formResponse.withItemResponse(ItemResopnse2);
   * formResponse.withItemResponse(ItemResopnse3);
   * 
   * その2
   * formResponse.withItemResponse(ItemResopnse1).withItemResponse(ItemResopnse2).withItemResponse(ItemResopnse3);
   */

  // 提出
  formResponse.submit();
```

## おわりに
GASからGoogleフォームの回答を送信するというテーマで流れの説明とサンプルコードを書いてみました。
意外にも先人がいなかったので、英語のリファレンスを読む羽目になりました。
誰かの助けになれば幸いです。

###### サンプルコード
この記事で使用したサンプルコード(simpleExample())と、複数の質問項目、質問タイプを使ったサンプル(main())を以下のリポジトリに置いてます。
参考にどうぞ。

https://github.com/nushitoritarou/gas_formSubmitTest

### 参考
Google Apps Script 公式リファレンス
https://developers.google.com/apps-script/reference/forms/form-app
typescriptのタイプガード


型を絞り込んでアクセスしたい時や、型によって処理を分けたい時などに使用されるType Guardについてです。

## typeof

``` ts
  const getData = (data: string | number): void => {
    if (data.length > 0) { //string | number
      console.log("string型：" + data); //string
    } else {
      console.log("number型：" + data); //number
    }
  };
```

getData関数の引数で入ってくるdataはstring型もしくはnumber型です。


``` ts
if(data.length>0){}
```
この部分でstring型に絞りたいところですが、ts側からnumber型の可能性もあるよねっと言われてしまいます。
if文の中で使われているdataの型はまだnumber | stringの状態だからです。

上記のメソッドを`typeof`によるタイプガードを利用して実装してみます。

``` ts
  const getData = (data: string | number): void => {
    if (typeof data === "string") { //string
      console.log("string型：" + data); //string
    } else { 
      console.log("number型：" + data); //number 
    }
  };
```

``` ts
if(typeof data = "string"){}
```
このif文でdataはstring型であると定義しているので、else文のdataは残りのnumber型だよねと推論してくれます。


## ユーザー定義型のtypeGuard : parameterName is Type

```ts
 type Fish = { swim: () => void };
 type Bird = { fly: () => void };
```

```ts 
const isFish = (pet: Fish | Bird): pet is Fish => {
  return (pet as Fish).swim !== undefined;
}
```
`parameterName is Type`
parameterName が typeであればtrueを返し、そうでなければfalseを返します。
　
ただ注意しておきたいのが、以下のような関数の場合です。
```ts
  const checkType = (value: string | number): value is string => {
    return typeof value === "string";
  };
```


```ts
  const checkType = (value: string | number): value is string => {
    return typeof value === "number";
  };
```
checkType関数の場合`value is string`と`returnのtypeof`で指定している型が矛盾しています。
ここの型が矛盾していてもtsではエラーが出ずにそのまま通ってしまいます。
 `value is string`と`returnのtypeof`で使用する型は、矛盾がないようにしないと予定していない処理が走ってしまいそうです。
TypeScriptでExponentialBackoffのリトライ処理を書いてみる

リトライ処理の作成メモです。
アルゴリズムはAWSでお馴染みのExponentialBackoffを使用しています。

## Function
```typescript
export function sleep (milliSec: number) {
  return new Promise(resolve => setTimeout(resolve, milliSec))
}

export async function backOff <T> (
  handler: () => T | Promise<T>,
  checkHandler: (val: T) => boolean,
  maxCount: number = 5,
  interval: number = 100
): Promise<T | undefined> {

  for (let retryNum = 0; retryNum < maxCount; retryNum++) {
    const handlerResult = handler()
    const result = await (handlerResult instanceof Promise 
      ? handlerResult : Promise.resolve(handlerResult))

    if (checkHandler(result)) {
      return result
    }

    await sleep(2 ** retryNum * interval)
  }

  return undefined
}
```

## Params
リトライ内で評価したい処理を定義します。
Promiseが返却されることも想定しておきます。
```typescript
handler: () => T | Promise<T>
```
リトライ処理を抜ける条件の評価式です。
```typescript
checkHandler: (val: T) => boolean
```

## 使い方
0 ~ 200のランダムな整数の生成を、100以上の整数が取得されるまで最大5回トライします。
```typescript
// expected output: 0 ~ 200
const getRandomInt = () => Math.floor(Math.random() * 200)

const isOver100 = (num) => num >= 100

const num = await backOff <number | undefined> (getRandomInt, isOver100)

console.log(num)
```

### 補足
今回は異常系は考慮していません。

例えば、apiリクエストをエラーレスポンスのコードでリトライか異常終了するか判断する場合は、
Error判定用のhandlerをbackOffの引数に追加してtry-catch内でcallすれば良さそう。
Nuxt.js サイトに埋め込んだ HubSpot フォーム が表示されない


Vue.js + Nuxt.jsで作成したサイトの問い合わせページに埋め込んだ HubSpot フォームが表示されない問題が起きました。

##### HubSpot から発行されたコード：

```
<script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/shell.js"></script>
<script>
  hbspt.forms.create({
	region: "xxx",
	portalId: "xxxxx",
	formId: "xxxxxxx"
});
</script>
```

##### 表示されない書き方
Pugを使用したソース：

* 書き方1

```
<template lang="pug">
#contact
  h2 お問い合わせ
  #form
    script
      | hbspt.forms.create({
      |   region: "xxx",
      |   portalId: "xxxx",
      |   formId: "xxxxxxx"
      | });
</template>
<script>
export default {
  head () {
    return {
      script: [
        { src: '//js.hsforms.net/forms/shell.js' }
      ]
    }
  },
}
</script>
```

* 書き方2

```
<template lang="pug">
#contact
  h2 お問い合わせ
  #form
    script(src='//js.hsforms.net/forms/shell.js')
    script
      | hbspt.forms.create({
      |   region: "xxx",
      |   portalId: "xxxx",
      |   formId: "xxxxxxx"
      | });
</template>
```

埋め込んだ直後にはフォームは表示されましたが、ページを更新したりすると表示されなくなりました。
コンソール画面に、"ReferenceError: hbspt is not defined" エラーが表示されました。

##### 原因
Nuxt.js において、フォーム生成スクリプトshell.jsがロードされる前に、shell.jsで定義されたメソッド hbspt.forms.create が先に呼び出されたことが原因でした。

##### 修正方法
shell.jsをロードした後に hbspt.forms.create を呼び出すようにします。

修正後のソース：

```
<template lang="pug">
#contact
  h2 お問い合わせ
  #form(v-if="isLoaded")
    script
      | hbspt.forms.create({
      |   region: "xxx",
      |   portalId: "xxxx",
      |   formId: "xxxxxxx"
      | });
</template>

<script>
export default {
  data() {
    return {
      isLoaded: false
    };
  },
  head () {
    return {
      script: [
        {
          src: '//js.hsforms.net/forms/shell.js',
          callback: () => { this.isLoaded= true }
        }
      ]
    }
  },
}
</script>
```


##### 参考になったサイト

* [hubspot Community](https://community.hubspot.com/t5/APIs-Integrations/Error-quot-ReferenceError-hbspt-is-not-defined-quot-with-embed/m-p/305533)
* [Vue.js Tutorials](https://vueschool.io/articles/vuejs-tutorials/how-to-load-third-party-scripts-in-nuxt-js/)