OmniAICreator/Qiita-1.07M huggingface dataset:
Rubyの連想配列(ハッシュ)の基本について

# 連想配列(ハッシュ)
key(ラベル)とvalue(key)を使って、よりもわかりやすくした配列を***ハッシュ***と言います。

普通の配列だと
```rb
　japanese = 60
 english =  40
 science =  30
 history = 70
 math = 40   

#平均点
puts (60 + 40 + 30 + 70 + 40)/5

# もしくは
 puts (japanese + english + science + history + math)/5
```
しかしここで問題があります。

```rb
scores = [60,40,30,70,40]
puts (scores[0] + scores[1] + scores[2] + scores[3] + scores[4])/5
```
これだけ見て何のスコアかわかるでしょうか。

そこで```ハッシュ```が登場します。

```rb
scores = {"japanese"=>60,"english"=> 40,"science"=> 30,"history"=>70,"math"=>40}
```
これだとさっきよりわかりやすいですよね。

```rb
scores = {"japanese"=>60,"english"=> 40,"science"=> 30,"history"=>70,"math"=>40}
puts scores["japanese"] 
```
で実行し６０と出力されます。

平均点を出すと

```rb
scores = {"japanese"=>60,"english"=> 40,"science"=> 30,"history"=>70,"math"=>40}
puts (scores["japanese"] + scores["english"] + scores["science"] + scores["history"] + scores["math"]/5
```
で実行すると48となります。

***別の書き方***にすると

```rb
scores = {japanese: 60,english: 40}
puts scores[:japanese]
```
でも60はとり出せます。
そして***順番を気にせず取り出せます。***

***ハッシュは文字列とシンボルで取り出す方法の2つがあります。***
シンボルはシンボル、ハッシュはハッシュで合わせる必要があります。



# もう少しハッシュを使う
 ハッシュを使って５教科の平均点を見てみましょう。

```rb
scores = {"japanese" => 80, "english" => 80, "science" => 50, "history" => 60, "math" => 70}

 puts (scores["japanese"] + scores["english"] + scores["science"] + scores["history"] + scores["math"])/5
```
出力すると

```
６８
```
このように変数と配列を組み合わせて何をやっているのかをわかりやすくしたのがハッシュです。
ちなみに科目の部分が***key***で点数が***value***です。

他にもwebサービスだと下のようにすることがよくあるみたいです。

```rb
 user = {"name" => "taro","email"=> "taro@example.com","job" => "programmer"}
puts user["name"]
```

```
taro
```
と出力。

# ハッシュの使い方(シンボル)
上記は文字列で指定(""をつけると文字列)でしたがコロンがつく形式のシンボルにすると
下のようになります。


文字列にしない場合はシンボル(:)で指定

```rb
 car number = {honda: 8410, toyota: 2089,history: 1207}
 puts car　number[:honda]
```
出力すると

```
8410
```

***:(シンボル)で指定すると文字列にしなくてもできます。***

# 参考記事

https://qiita.com/Hashimoto-Noriaki/items/866192241423a579ce2e
SNSシェアボタンの導入

##目次
- 概要（SNSシェアボタンって何？）
- 導入方法
- Facebookボタンの注意点
- ボタンサイズの変更
- 参考サイト
- 振り返り

##概要
SNSシェアボタンとはニュースサイト等でよく使われる、クリック一つで投稿できるボタンのことです。
こちらはQiitaのもの。
![スクリーンショット 2021-09-02 173324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1518966/dbd3fbd2-e2bc-44f1-c28a-177441a0dade.png)
私の場合、出欠サイトを作成したため、対象者に入力を促す目的で導入しました。
[Githubはこちら](https://github.com/huacnlee/social-share-button)
##導入方法
```Gemfile.
gem 'social-share-button'
```
Gemを記載したら、下記コマンドを入力します。

```
$ bundle install
$ rails generate social_share_button:install
```
作成されたファイルを編集してボタンの表示を制限しましょう。
今回はtwitterとfacebookに絞ります。

```config/initializers/social_share_button.rb
SocialShareButton.configure do |config|
  config.allow_sites = %w(twitter facebook) #　()内の不要な記載を削除
end
```
次はCSS(SCSS)、JSへの記載です。

```stylesheets/application.scss
@import "social-share-button";
```

```javascripts/application.js
//= require_tree .
//= require social-share-button #追記
```
最後にviewです。
social_share_button_tag以下がシェアされるときの表示文言です。
私の場合、@practice.scheduleで日付を取得しているため、画像のような表示になります。
ご自身の仕様に合わせて実装ください。

```show.html.erb
<%= social_share_button_tag("#{@practice.schedule}の練習予定をご確認ください。") %>
```
![スクリーンショット 2021-09-02 183216.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1518966/42ea44bb-28f1-657b-e59c-670227d297f7.png)

##Facebookボタンの注意点
ローカル環境からはシェアボタンを使用できません。
テストを行うには本番環境で行う必要があります。
![スクリーンショット 2021-09-02 183948.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1518966/41cccf3a-e5cb-3483-0e19-d7a7a414afbd.png)

##ボタンサイズの変更
下記の記載でボタンサイズを変更できます。
今回はh2タグの横に置きましたので、ボタンも同じサイズに変更しました。

```stylesheets/application.scss
$size: 2rem;

.social-share-button {
  .ssb-icon {
    background-size: $size $size;
    height: $size;
    width: $size;
  }
}
```
## 参考サイト
https://qiita.com/ryo___eng/items/e56f3024f56dc34ff923

##振り返り
簡単に実装できて、実用性も高いGemです。
今回使用したtwitter、Facebook以外を実装する場合には[公式のUsage](https://github.com/huacnlee/social-share-button#usage)をよくご確認ください。
最後までご覧頂きありがとうございました。
Swiftで「@privaterelay.appleid.com」にメールを転送させる

iOS開発でAppleIDログインを実装し、
ユーザーがメールアドレスを非公開設定にした場合に取得できる
転送用のメールアドレス「@privaterelay.appleid.com」

ただ「@privaterelay.appleid.com」にメールを送っても、転送されないのでApple Developerの設定画面を触る必要がある。

# 手順

Apple Developer Programの
Certificates, Identifiers & Profilesの
Moreメニューに移動
https://developer.apple.com/account/resources/services/list


Configureボタンへ
https://developer.apple.com/account/resources/services/configure
![スクリーンショット 2021-09-02 18.49.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/a6a58c0c-ee82-93ec-c3b8-1840b4a52b49.png)


「＋」ボタンを押すとドメインかアドレスが入力できるボックスが表示されるので、「@privaterelay.appleid.com」に送信するメールの送信元の情報を入力。

![スクリーンショット 2021-09-02 18.48.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/e67343da-18ca-0e00-bf14-1381582f7d40.png)


最後にSTATUSが「SPF」になっていれば完了。
![スクリーンショット 2021-09-02 18.50.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/0b4f4397-780f-8271-703f-f5a91e3b6367.png)

# 参考


https://zenn.dev/nekoniki/articles/3694b2b006a1d0e57bc5

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
【IQ Bot】「PDF ドキュメントに画像はありません」のチェックってどういう意味？

IQ Bot でインスタンスを作成する際、OCRを選択するプルダウンリストの下に、「PDF ドキュメントに画像はありません」と書かれたチェックボックスがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/cbd8a8e9-0e2a-afd9-19ce-45da841df0b7.png)

このチェックってどういう意味なんですか？　という質問を、かれこれ100回くらい受けているので、この記事で説明します。
（むしろ今まで書いてなくてすみません）

## このチェックは、画像があるかないかを聞いているわけではない

まず、このチェックに関して言いたいことは、文言がめちゃめちゃ紛らわしいです。
「画像はありません」と書かれると、まるで下記の図の左側（画像あり）みたいなPDFじゃなくて、右側（画像なし）みたいなPDFを扱いますよ、という意味のチェックなのかと思ってしまうと思いますが、**そういう意味ではありません。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/9b132261-27bc-903a-7edc-5a5e578ad09c.png)

## チェックの本当の意味

このチェックの本当の意味は、以下のとおりです。

| チェック | 意味 |
|:-----------|:------------|
| チェックあり | アップロードしたPDFが、デジタルPDF（テキストデータが埋め込まれたPDF）の場合は、埋め込まれたテキストを活用する（OCRはかけない）。<br>アップロードしたPDFがデジタルPDF以外の場合、およびPDF以外の画像ファイル（jpg,tiff,png）を読み込んだ場合は、OCRをかけにいく。|
| チェックなし | アップロードしたファイルがデジタルPDFだろうが何だろうが、問答無用でOCRをかけにいく。（デジタルPDFに埋め込まれたテキストデータは無視する）|

## チェックの有無の使い分け

チェックの有無を使い分けるコツとしては、以下になります。

| チェック | 使いどころ |
|:-----------|:------------|
| チェックあり | 基本的にはチェックありでいいと思います。<br><br>WordやExcelなどから出力されたPDFのデジタルデータを活用できれば、OCRによる誤読の心配もないため、安定した読み取り結果が得られます。|
| チェックなし | 上記の例外として、以下のような場合には、チェックを外した方がいいケースもあります。<br><br>例１：複合機のOCR機能の結果を無視したい場合<br>複合機（スキャナ）自体にOCRの機能がついており、スキャンしたPDFがすべてデジタルPDFの形になるが、複合機側のOCRの精度が悪いため、その結果を無視して改めてIQ Bot 内蔵のOCRをかけ直したい場合は、チェックを外しておきます。<br><br>例２：デジタルPDFのレイヤが何層にも分かれていたり、位置情報がずれているなど、ほしいデータが意図どおりに抽出できない場合<br>デジタルPDFの場合、基本的にはOCRによる誤読の心配もなく、正しいデータを抽出できるのですが、稀にデジタルPDF側のデータ構造が原因で、うまくマッピングができなかったり、SIRが生成されない場合があります。（SIRについては[こちらの記事](https://qiita.com/IQ_Bocchi/items/1e0a36fb69393106d025)を参照）。<br>このような場合も、チェックを外しておきます。|

## 制約と留意点

このチェックについて、いくつか制約と留意点を述べておきます。

### 制約１：チェックの有無は、インスタンス単位でしか選べない

チェックの有無をグループ単位で切り分けることはできず、インスタンス単位で一意になります。

### 制約２：チェックの有無は、インスタンス作成後には変更できない

チェックの有無を選択できるのはインスタンス作成時のみで、作成後に変更することはできません。

### 留意点

以上の制約を踏まえると、チェックをつけるべきか否かは、本番のインスタンスを作成する前の試行段階で検討しておく必要があります。

カスタムドメインを作成するための試行インスタンスを作る際、まずはチェックありの状態で作成し、デジタルPDFが分類不能になるケースがないか、SIRが正しく認識できているかを確認します。

上記の確認の結果、インスタンス内の全体最適をとってチェックの有無を決めるのがよいでしょう。
【jquery】filter()の使い方   奇数行を非表示

#jQuery 

```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <ul>
      <li>リスト 項目 1</li>
      <li>リスト 項目 2</li>
      <li>リスト 項目 3</li>
      <li>リスト 項目 4</li>
      <li>リスト 項目 5</li>
      <li>リスト 項目 6</li>
  </ul>
  <button>ここをクリック</button>
  <p style="display: none;"> 表示されました</p>
    <script src="jquery-3.6.0.min.js"></script>
    <script>
      $(function(){
        $('li').filter(':even').hide();
        $('button').on('click', () => {
            $('p').show();
        });
      });
    </script>
```

#出力結果
```
リスト 項目 2
リスト 項目 4
リスト 項目 6
```
FirebaseUIが新しくなってimport FirebaseUIが指定できなくなった


6/9にリリースされたバージョン11.0でFirebaseUIが新しくなりSwiftで

```
import FirebaseUI
```
が指定できなくなった。

teratailの回答の通りにimport FirebaseAuthUIを書いてみても、「Cannnot find XXX in scope」は無くならず。





https://teratail.com/questions/349444

# 解決策

```swift
import FirebaseAuthUI
import FirebaseEmailAuthUI
import FirebaseFacebookAuthUI
import FirebaseAnonymousAuthUI
import FirebasePhoneAuthUI
import FirebaseOAuthUI
import FirebaseGoogleAuthUI
```

を書いたところエラーが解決されました。

ちなみにFUIGoogleAuthとFUIFacebookAuthは( )内に authUI 引数を指定しないとビルド後にエラーになります。

```swift
var authUI: FUIAuth { get { return FUIAuth.defaultAuthUI()!}}

let providers: [FUIAuthProvider] = [
    FUIGoogleAuth(authUI: self.authUI),
    FUIFacebookAuth(authUI: self.authUI),
    FUIEmailAuth(),
    FUIOAuth.appleAuthProvider(),
    FUIOAuth.twitterAuthProvider()
]

```

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
Column order changes results of XGBoost model prediction

In this short note I would like to share something I have myself learned only recently. Although this will be familiar to those
of you who are expert ML practitioners, to me this fact was highly counter-intuitive and costed my a few hours of debugging recently.
Therefore, I write this article more as a memo for myself.

So, here is the deal: **column order changes results of XGBoost prediction**. Let me explain what I mean with an example (the notebook is available at [Kaggle](https://www.kaggle.com/alexleontiev/column-order-changes-xgboost-results)):

First, let us make ourselves a simple "dataset" filled with random values and an XGBoost model:

```py
import xgboost as xgb
import pandas as pd
import numpy as np
import sklearn

np.random.seed(42) #reproducibility
X = pd.DataFrame(data=np.random.randn(1000,10),columns=[f"f{i}"for i in range(10)])
y = np.random.randn(1000)
X_train,X_test,y_train,y_test = sklearn.model_selection.train_test_split(X,y)
model = xgb.XGBRegressor()
```

Next, we define a simple function to compute the squared mean error of a model on validation set:

```py
def grade(X_train,X_test,y_train,y_test,model):
    model.fit(X_train,y_train)
    y_pred = model.predict(X_test)
    return sklearn.metrics.mean_squared_error(y_pred,y_test),y_pred.sum()
```

Note, that the function returns not only the error, but also the sum of the predictions (we will use this data later, in order to determine whether predictions changed).

Now, we establish a baseline score:

```py
> grade(X_train,X_test,y_train,y_test,model)
(1.1874636567148573, -16.174873)
```

Next, we permute the rows of training dataset and see whether this changes the results:

```py
> permuted_rows = np.random.permutation(range(X_train.shape[0]))
> grade(X_train.iloc[permuted_rows,:],X_test,y_train[permuted_rows],y_test,model)
(1.1874636567148573, -16.174873)
```

so we see, that permutation of rows in training dataset does not change the result.

Similarly, row-permutation of validation dataset does not change the result:
```py
> permuted_rows = np.random.permutation(range(X_test.shape[0]))
> grade(X_train,X_test.iloc[permuted_rows,:],y_train,y_test[permuted_rows],model)
(1.1874636567148573, -16.174873)
```

However, if we change the *columns* order, the result changes!

```py
> np.random.seed(42)
> permuted_col_names = np.random.permutation(list(X))
> grade(X_train[permuted_col_names],X_test[permuted_col_names],y_train,y_test,model)
(1.17516067774827, -16.930027)
```

As a final note, I would like to point out that the same thing happens in [Bigquery ML](https://cloud.google.com/bigquery-ml/docs?hl=ja)'s 
[version of XGBoost](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create-boosted-tree?hl=ja) (where I myself originally discovered this issue). 
This was especially counter-intuitive for me, as I have used to think that column order does not matter in tables. 
However, as seen above, changing column orders in the table one submits for Bigquery ML XGBoost changes the prediction results one gets.
WSL2 Dockerのイメージ・コンテナの格納先を変更したい

# Cドライブが苦しい

なのでDocker for windows用のVHDをDドライブに移します。

### Docker Desktopの停止

タスクトレイのDockerマークを右クリックし、Quit Docker Desktopを押下する。

### 停止確認

``` powershell
wsl --list  -v
```

### ディストリビューションのエクスポート

``` powershell
wsl --export docker-desktop "D:Program\Docker\data\docker-desktop.tar"
wsl --export docker-desktop-data "D:Program\Docker\data\docker-desktop-data.tar"
```

### ディストリビューションの削除

``` powershell
wsl --unregister docker-desktop
wsl --unregister docker-desktop-data 
```

### ディストリビューションのインポート

``` powershell
wsl --import docker-desktop D:Program\Docker\wsl\docker-desktop "D:Program\Docker\data\docker-desktop.tar"
wsl --import docker-desktop-data D:Program\Docker\wsl\docker-desktop-data "D:Program\Docker\data\docker-desktop-data.tar"
```

### 結果

15GBくらいは空きが増えました。
最近学んだ用語や仕様

#仕様

##mobx
### スーパークラスとサブクラスのmakeAutoObservable
スーパークラスとサブクラスではmakeAutoObservableを使えず、makeObservableを使用しなければならない。

https://mobx.js.org/observable-state.html

##react-router
###Redirect
Routeコンポーネントと同等の扱いをしてよい
以下はどのパスにも当てはまらないものは強制的に`/home`に遷移する

```xml
    <BrowserRouter>
      <Switch>
        <Route exact path="/home" component={Home} />
        <Route exact path="/about" component={About} />

        <Redirect to="/home" />
      </Switch>
    </BrowserRouter>
```

以下の使い方しかしてなかったからちょっとびっくりした

```xml
<Route exact path="/">
  {loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
</Route>
```

## firebase
### 配列中にServer.TimeStampを使用できない
まだ対応していないらしい
どうしても時間を保存したい時はString型とかで保存するしかない

### functionsでmomentを返せない
値を返す時は必ずJsonにしないといけないので、StringかNumberで返さないといけない。

ちなみに、Date型を返すと`Thu Sep 02 2021 18:29:22 GMT+0900 (日本標準時)`といったように強制的にStringに変換される。

## react、JS、TypeScript
###コメントアウトの切り替え
AとBの処理を切り替えて確認したいときに便利
一番上のスラッシュを増やしたり減らしたりするとa、bの処理が切り替えられる

以下はbが代入される

```js
test = () =>{
  let tmp 

   /*
 
     tmp = a

   /*/

     tmp = b

   //*/
 }

```

以下はaが代入される

```js
test = () =>{
  let tmp 

   //*
 
     tmp = a

   /*/

     tmp = b

   //*/
 }

```


###  React.Fragment
コンポーネントの要素を一つにまとめられず、複数返す時にフラグメント (fragment) を使うことで、DOM に余分なノードを追加することなく子要素をまとめることができる。

```jsx
const TestComponent = () => {
  return ( 
    <React.Fragment>
      <div />
      <div />
      <div />
    </React.Fragment>
  )
}

```

https://ja.reactjs.org/docs/fragments.html

##オプショナルチェイニング
undefindかもしれないものを?で無理矢理参照すること

```js
let anumal ={ dog:string }
console.log(animal?.cat)
```

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Optional_chaining

## flatMap
配列の深さを1つ下げてくれる。下の例では['1', '2']が返る。
`default: return ''`が嫌だったので嬉しい。

```js
  const array = [{type:'type1}, {type:'type2'}, {type:'type3'}]

  const testList = array.flatMap((item) => {
      switch (item.type) {
        case 'type 1':
          return '1'
        case 'type2':
          return '2'
        default:
          return []
      }
    })

   console.log(testList)
```

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap

## void 0
`undefind`を`void 0`と置き換えることができる
例は、上も下もundefiendになる

```js
const test1 = undefined
const test2 = void 0

```
Web APIについて調べてみた -6章編-

##背景
API作ることは出来るなーと実感しつつも、安全に作れるか不安だった。
本章では「安全性」「安定性」を軸に堅牢なAPIの作り方が記されているとのことだったので、知りにきた。

###読んだ本
O'Reillyの本を読んでみた
[WEB API The Good Parts](https://honto.jp/netstore/pd-book_26352551.html)

###章立て
前回のはこちら
[Web APIについて調べてみた -5章編-](https://qiita.com/danbo_lobo/items/b77dd4f2e0ce61942ef4)
今回は6章についてまとめてみた。
いよいよ最後の章、メモ程度でも備忘録として記してみる。

##Web APIを安全にする
Web APIを安全に公開するのが第一の条件となってくる昨今、安全を考える時にどういった時に問題が生じるのかを考えてみると、対策をしやすいので問題をまず列挙する。

- サーバとクライアントの間での情報の不正入手
- サーバの脆弱性による情報の不正入手や改竄
- ブラウザからのアクセスを想定しているAPIにおける問題

こうした問題に対する対策を記していく。

####対策① HTTPS通信の暗号化
最も簡単な対策はHTTPSによる通信の暗号化である。
ただし、HTTPSを使えば100％安全という訳ではない。
HTTPS通信を行う場合はSSLサーバ証明書を受け取り通信を行うので、この部分の管理も怠ることが許されない。

####対策② 脆弱性がどこなのか意識して気を配る
Webアプリケーションにおける脆弱性としてよく知られている一つに、**XSS**というものがある。
脆弱性に対して、最適なヘッダを利用することが望ましいとされる。
#####脆弱性① XSS
######XSSとは？
クロスサイトスクリプティングのことを指し、攻撃名のこと。DoSみたいな。
ユーザーの入力を受け取って、それをページのHTMLに埋め込んで表示する際に、ユーザーから送られたJavascriptなどを実行できてしまうというもの。
詳細は[クロスサイトスクリプティングって何？](https://www.kagoya.jp/howto/it-glossary/security/xss/)を参照するべし。

#####脆弱性② XSRF
もう一つの脆弱性として、**XSRF**というものがある。
######XSRFって何？
クロスサイトリクエストフォージェリのことを指し、攻撃名の1つ。
認証データを利用して攻撃する。

######XSRFに対応するには？
2つの手段がある。
- サーバ側のデータが変化するようなアクセスに関しては、GETメソッドを利用せず、POSTやPUTメソッドを用いる
- XSRFトークンを利用する(最もよく使われる)

######XSRFトークンとは？
送信元となる正規のフォームに、そのサイトが発行したワンタイムトークン、あるいは少なくともセッションごとにユニークなトークンを埋め込んでおき、そのトークンがないアクセスは拒否するというもの。

#####脆弱性③ JSONハイジャック
APIからJSONで送られてくる情報を悪意のある第三者が盗み取ることを指す。

######JSONハイジャックに対応するには？
いくつか方法がある。本文には以下のように記述あり。

- JSONをSCRIPT要素では読み込めないようにする
- JSONをブラウザが必ずJSONと認識するようにする
- JSONをJavascriptとして解釈不能、あるいは実行時にデータを読み込めないようにする

####対策③ セキュリティ関係のHTTPヘッダを利用する
セキュリティ関連で広く利用されているHTTPヘッダをいくつか列挙していた。

- X-Content-Type-Option
- X-XSS-Protection
- X-Frame-Option
- Content-Security-Policy
- Strict-Transport-Security
- Public-Key-Pins
- Sed-Cookie

####対策④ レートリミットを設定する
ここまで、さまざまな攻撃に対しての対策を行なってきたが、上記のような攻撃だけで攻撃されるとも限らない。
仮に、攻撃がなかったとしても、（攻撃があったとしても）一度に大量のアクセスを受けるということも考えられるからだ。
では、大量のアクセスを受け取った場合、どのようにさばくのが良いのか。その答えとして**レートリミット**がある。

#####ユーザーごとのアクセスを制限する
大量のアクセスが来た時の対処法として、アクセス数を制限することが挙げられる。
つまり単位時間あたりの最大アクセス回数(レートリミット)を決め、それ以上のアクセスがあった場合はエラーを返すようにしてしまえば良い。

#####レートリミットの伝え方
APIによっては、レートリミットの伝え方として`429`のステータスコードを返すところもある。
世間が使っている返し方の例は以下になる。

|サービス名|ステータスコード|
|---|---|
|Twitter|429|
|GitHub|403|
|Instagram|503|
|Pocket|403|
|HipChat|403|
|ZenCoder|403|

##まとめ
・特定のユーザー以外に情報が漏洩してほしくない時はHTTPSを使う
・セキュリティ強化につながるHTTPヘッダをしっかりつける
・レートリミットをつけることで一部のユーザーによる過度なアクセスによる負荷を防ぐ

##感想
初歩中の初歩を学ぶには良い1冊だった。
Pythonを利用したMP3メタデータ編集のやり方

Pythonのmutagenライブラリを利用したMP3音楽メタデータの編集方法について紹介します。

下記サイトのフリーBGMをMP3のサンプルデータとして利用しています。
[なんでしょう？ @ フリーBGM DOVA-SYNDROME](https://dova-s.jp/bgm/play710.html)

# 実行環境

下記pipコマンドにより音楽メタデータを操作するためのライブラリ**mutagen**をインストール
`pip install mutagen`

https://github.com/quodlibet/mutagen

**python 3.8.10** で実行可能なことを確認

# 基本的なメタデータ一覧取得

mutagenライブラリの**EasyID3**を利用することで、基本的なメタデータを取得できる。
より詳細なメタデータ編集(コメント、アルバムアート等)をする場合は、**ID3**を利用する。
※ ID3はEasyID3と比較して、データ編集方法が煩雑

```python:
from mutagen.easyid3 import EasyID3

mp3_file_path = "なんでしょう？.mp3"

tags = EasyID3(mp3_file_path)

# 辞書型で格納されたメタデータ表示
for key, value in tags.items():
    print(key,":", value[0])
```

```text:メタデータ出力結果
composer : KK
encodedby : iTunes 12.3.2.35
title : なんでしょう？
artist : KK
composersort : KK
artistsort : KK
titlesort : なんでしょう？
date : 2013
```
曲名(title)、アーティスト(artist)、作曲者(composer)等のメタデータ取得結果が確認できる。
※ 利用可能なメタデータ一覧は`EasyID3.valid_keys.keys()`で取得可能

# メタデータ更新・追加・削除

メタデータタグを更新・追加・削除後に、`save()`することでファイルが更新される。

```python
from mutagen.easyid3 import EasyID3

mp3_file_path = "なんでしょう？.mp3"

# メタデータ更新・追加・削除
tags = EasyID3(mp3_file_path)
tags["artist"] = "update_artist"
tags["album"] = "add_album"
tags["date"] = ""
tags.save()

# 更新・追加・削除結果の確認
tags = EasyID3(mp3_file_path)
for key, value in tags.items():
    print(key,":", value[0])
```

```text:メタデータ更新・追加・削除結果
album : add_album
composer : KK
encodedby : iTunes 12.3.2.35
title : なんでしょう？
artist : update_artist
composersort : KK
artistsort : KK
titlesort : なんでしょう？
```
元データからの下記のメタデータ更新・追加・削除が確認できる。

- artist = `update_artist` に更新
- album = `add_album` が追加
- date = `2013` が削除

# 参考

- [ID3タグ - Wikipedia](https://ja.wikipedia.org/wiki/ID3%E3%82%BF%E3%82%B0)
- [mutagen docs](https://mutagen.readthedocs.io/en/latest/)
- [Pythonでmp3などのID3タグを編集するmutagenの使い方](https://note.nkmk.me/python-mutagen-mp3-id3/)
[Rails]状況によって使い分けるRollback


##いつ使うの？
-作成途中にカラム不足や追加など気がついてもう一度、テーブルを再編集したいとき

##どんなのあるの?
ーテーブルが少ないときに、一個ずつ編集状態にするrollback方法
ーテーブルが多いときに、一気に編集状態にするrollback方法

##(1)まずはUPとDOWN状態の確認方法
下記のコマンドをターミナルに記入。

```
 rails db:migrate:status
```
####・結果例・
-UP状態のDBは保存している状態。migrationファイルの編集をしても設定できない。
-DOWN状態のDBは編集可能状態。migrationファイルを編集し更新すると編集ができる。
![status sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/e8116354-4afe-3317-e232-f10375d98376.png)

##(2-1)DOWN状態にする方法の記入欄(少ないときにおすすめ)
下記のコマンドをターミナルに記入。

```
rails db:rollback
```

####・結果例・
![rollback status sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/d5fcd9d9-9a52-a3e9-8d61-82ecfc095120.png)
この状態になったらファイルを編集する。下記のコマンドを記入してテーブルを更新をするのを忘れないように！

```
rails db:migrate
```

##(2-2)DOWN状態にする方法の記入欄(多いときにおすすめ)

```
rails db:rollback STEP=3
```
####・結果例・
![rollvack step sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/5284c6d1-0543-e7fb-ee32-09623207f746.png)
ー今回は、UP状態の最新テーブル（records）から最古テーブル(users)まで３つテーブルがあるのでSTEP=3と記述。このように、編集したいテーブルまでのファイル数がわかれば一気にrollbackできる！

---
これでrollbackは完璧かな？
ここまで読んでいただきありがとうございました！
Automation 360の画像認識の一致率

# はじめに
https://qiita.com/etoootak/items/be73c7ae12dcf49e5434
の続きです。
画像認識アクションの「一致率」で遊んでみます。

#  そもそも「一致率」って何？
Webマニュアルによると以下です。

>フィールドで、2 つの画像で一致するピクセルの許容可能なパーセントを指定します。
>たとえば、一致パーセントとしてフィールドに「20」と指定した場合は、2 つの画像間で最大 80% のピクセル不一致があっても、システムは画像が一致していると見なします

では、「一致するピクセル」って何でしょう？
ピクセル単位にRGB値が完全に一致しなければいけないか、それともある程度のブレは許容してくれるのか。

結論から言うと、「ある程度のブレは許容」してくれるようです。

#試したこと
「画像認識: ウィンドウで画像を検索」を使いGoogle Mapから駅アイコンを探してみました。
![map_small.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/26640b12-4ac4-61e1-4245-1c6a07728a6f.jpeg)

ターゲット画像は以下。１９×１９ピクセルのjpg画像を準備しました。
![eki.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/b6d4133f-0360-e2c3-ba0f-c6d607edc51f.jpeg)

pythonを使いターゲット画像のRGB値を全体的に５ずらしましたが、問題なく検知します。

#  トレランス（tolerance）
実はAutomation Anywhere V11の画像認識では「一致率」とは別に「トレランス」という指定ができました。このトレランスでピクセルのRGB値がどのくらい違っていても一致とみなすか指定します。
Automation 360ではこのトレランス指定は見えなくなっているようです（V11のAdvancedモードの画像認識だけになっている？）。

いえ、トレランスを自分で調整するなんて面倒な事はしませんから、すっきりしていいと思います。

# おまけのひとこと
手元のPCに落ちたimage-recognitionパッケージを展開してJavaを眺めるとtoleranceあるなぁ。
正規表現が開発者ツールでは動くのに、サーバーサイドではInvalid quantifier ?ってエラーが発生

忘れて調べそうなので、メモ程度に書きます。
私は頭が悪いので、正規表現もググって感覚で使っています。
変な書き方していたらごめんなさい。

# エラーの内容
`SyntaxError: Invalid quantifier ?`
ってエラーが出ました。

# 使ったコード
```javascript
let a = "2021/09/08 11:00:00";
console.log(a.replace(/\/|(?<= ).*$/g, ""));
// 実行結果: 20210908 
```

スペース以降と`/`を削除する処理になっています。
開発者ツールとか使うとエラーは出なかったです。
でも、私の使っている環境だと動かない。

# 原因
私の使用しているJavaScriptの環境がES5?だったのが原因でした。
`(?<= )`このところがダメっぽいです。
これは後読みって処理をするらしいんですけど、後読みは`ES2018`から対応しているらしいです。
なので、ES2018以前の環境では別の方法を考えないとダメっぽいですね。

# 修正後
```javascript
let a = "2021/09/08 11:00:00";
console.log(a.replace(/\/| .*$/g, ""));
// 実行結果: 20210908
```
一応できました。今気づいたんですけど、修正前のコードだとスペースが入っちゃってますね。
【最新】スマホを使ってカメラの映像をクロマキー合成

#はじめに
こんにちは！
今回はスマホだけでカメラの映像を合成して配信の背景を自由に変更する方法についてご紹介します。

##環境と前提条件
###デバイスとソフト
この記事ではサムスン S20+にインストールしたCasttingoを使っています。
[Casttingo] (https://www.apowersoft.jp/casttingo?apptype=qiita)というのは配信向けの専門アプリであり、このアプリを使って配信画面の背景を別の映像と素材をクロマキー合成して、自由に背景を変更できます。
*公式サイトにより、Casttingoはアンドロイド・iOS・Windowsなどのデバイスと互換性があります。*
###緑色の背景
映像のクロマキー合成を実行するためには、クロマキー用の緑色の背景布が必要です。
背景布がない場合、緑色の紙あるいはほかのものも利用できます。
![背景.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417797/a8b0919e-028b-3ed4-b6c8-811108533dc9.jpeg)


#ガイド

Casttingo[公式サイト] (https://www.apowersoft.jp/casttingo?apptype=qiita)にアクセスして、QRコードをスキャンしてスマホ側はAppStoreあるいはGoogle Playに行ってアプリをダンロードし、インストールする。
![topic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417797/39579141-e06c-07b7-1eee-c1ef4d20b5c5.jpeg)
☟
画面の下にある「作成」をタップしてライブプランを作成する。
☟
*右側にはレイヤーが表示されます。レイヤー設定からカメラの方向、窓のサイズ、クロマキーの効果を変更できます。画像のフィルターを追加したり、ポートレートを美化したりできます。素材ライブラリまたはスマホのアルバムに保存された背景を自由に変更できます。*
VBAとPythonのSeleniumでvalue属性の値を変更する

## 前置き
**何をしたかったのか。**
valueの値を変更して、最大値を超えた件数を表示させる。
`"次へ"`や`"nextBtn"`などを探せばいい…？たった数ページのために？
というところから。

いろいろな単語で検索しましたよ、ええ。
`python value 置き換え`
`selenium value 置き換え`
`select option value 変更`

全部だめ。自分が求めていた答えではなかった。
んで、最終的にたどり着いた検索の単語が
`selenium value change`と`setattribute selenium`
~~**アメリカ最高！英語検索しか勝たん。**~~
ちなみに英語わからなくても超優秀な**Deepl翻訳**が何とかしてくれる。
以下、参考にしたサイト。
[How to set "value" to input web element using selenium?](https://stackoverflow.com/questions/35127108/how-to-set-value-to-input-web-element-using-selenium/35127217)
[RubyのSeleniumでAttributeの値を変更したい](https://qiita.com/omomukumamani_piroshi/items/e586df69a7c1dd54553a)



## 本題
```HTML:HTML
<!-- リスト -->
<select name="LIST">
    <option value="25" id="LIST">25件</option>
    <option value="50" id="LIST">50件</option>
    <option value="100" id="LIST">100件</option>
    <option value="200" id="LIST">200件</option>
</select>

<!-- 検索ボタン -->
<input type="Search" name="Search" onclick="return SearchCheck()" value="検索する">
```
上記のようなHTMLだったとして、
`<option value="200" id="LIST">200件</option>`を
`<option value="500" id="LIST">200件</option>`に変更して検索する。


## 注意書き
:::note warn
コードを書く前に、実際のページでvalueの値を変更してみて問題ないか確認すること。
:::

`Dim Driver As New Selenium.WebDriver`
SeleniumBasicがインストールされていると使える。
詳しくは下記URL
[VBAからchromeスクレイピング](https://qiita.com/400800mkouyou/items/735704557e52bd5c08dc)

`driver = webdriver.Chrome(ChromeDriverManager().install())`
webdriver_managerがインストールされていると使える。
詳しくは下記URLか`chromedriver.exe`のPATHを通してください。
[Python+SeleniumWebDriverではwebdriver_managerを使うといちいちdriverのexeを置き換えなくて済む](https://qiita.com/YoshikiIto/items/000f241f6d917178981c)



## VBAでやってみる
```Python:VBA
Dim Driver As New Selenium.WebDriver
Driver.Get "https://hoge.jp"

# ------ option value 変更 ------
Dim target_element As Object
Set target_element = Driver.FindElementsById("LIST")(4)
Driver.ExecuteScript "arguments[0].setAttribute('value','500')", target_element

# ------ 変更したvalue を選択、検索 ------
Driver.FindElementByName("LIST").AsSelect.SelectByText "200件"
Driver.FindElementByName("Search").Click
```



## Pythonでやってみる
```Python:Python
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.select import Select

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://hoge.jp')

# ------ option value 変更 ------
target_element = driver.find_elements_by_id('LIST')[3]
driver.execute_script("arguments[0].setAttribute('value','500')", target_element)

# ------ 変更したvalueを選択、検索 ------
select_element = driver.find_element_by_name('LIST')
list_object = Select(select_element)
list_object.select_by_visible_text('200件')
driver.find_element_by_name("Search").Click
```
はじめての投稿。マークダウンを練習します。

#初投稿です！
みほと申します。今からLaravelを勉強していきます。
毎日学んだことをQiitaの記事に投稿していくのでベテランエンジニアさん暖かく見守ったり辛口コメントも大歓迎です！！
反応いただけると嬉しいです。よろしくおねがいします :)

##今日学んだこと
【create.blade.php】

```php
@extends('layouts.app')
@section('content')
<dic class = "row">
<h1>モツ鍋食べたい！</h1>
</div>
@endsection
```
RaspberryPi4でのWiFi速度向上のおまじない

RaspberryPi4を利用したときに，
WiFi遅延が気になったため，調べたことをメモ．

#パワーマネジメントを切る

どうやら，ラズパイの省電力機能が邪魔をしているようなので，
その機能を切ってあげる．

切り方は単純でカーネルモジュールへのオプションを渡してあげればいい．
まず，nanoでもvimでもgeditでもいいので，エディタでファイルを開く．

```
sudo nano /etc/modprobe.d/8192cu.conf
```

その後，以下の内容で書き込む

```
options 8192cu rtw_power_mgnt=0 rtw_enusbss=1 rtw_ips_mode=1
```

これで再起動すれば，モジュールへオプションが適用される．

```
sudo reboot
```

基本的にはこれだけで，速度は十分改善されるはず．


#これでも速度が出ない場合

TSOを無効化することで，速度が出るらしい．
TSOは参考資料に丸投げする．

https://e-words.jp/w/TSO.html

自分の環境では効果はわからなかったが，
カーネルバージョンにより，修正されているかもしれない．参考までに．

```
sudo ethtool -K eth0 tx-tcp-segmentation off tx-tcp6-segmentation off
```

#参考

- [Raspberry Piで無線LANの反応が悪い時の対処法](http://denshikousaku.net/fix-sluggish-response-of-raspberry-pi-wifi-adaptor)
- [新型Raspberry Pi 3B+はネットワーク周りに問題を抱えている？？　ネットワークが遅い！解決？！(Solved)](https://raspida.com/lan-issues-3bplus)
Android アクセシビリティ

#はじめに
近年、日本でも多様性が求められる世の中になっており,アプリ開発においてもアクセシビリティを意識する必要があると思います。本記事ではAndroidアプリに関するアクセシビリティについてご紹介します。

# 目次 
* アクセシビリティとは
* Android
 - フォントサイズ
 - 表示サイズ
 - TalkBack
 
#アクセシビリティとは
障害を持つユーザーが情報を利用できるようにすることだけではありません。
ユーザーの能力や状況に関係なく、すべての人が情報を利用できるようにすることです。
アクセシビリティを念頭に置いてアプリを設計するということは、
シンプルさと知覚可能性を優先し、すべての設計上の決定を調べて、
さまざまな能力を持つユーザーやさまざまな方法で、
デバイスを操作するユーザーを除外しないようにすることを意味します。

# フォントサイズ
Android上のフォントサイズを調整して、画面上のアイテムのサイズを変更できます。

確認方法
設定→ユーザー補助→フォントサイズ→小・デフォルト・大・最大　から選択

|デフォルト | 最大|
| :-: | :-: |
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542499/052bf118-3fc6-0de4-0db4-958f74fec004.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542499/848bc80d-32ee-50f9-e21c-7ab658e2bf06.png)|

# 表示サイズ
Android上の表示サイズを調整して、画面上のアイテムのサイズを変更できます。

確認方法
設定→ユーザー補助→表示サイズ→小・デフォルト・大・最大　から選択

|デフォルト | 最大|
| :-: | :-: |
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542499/582d457e-ec28-9bf9-4576-63b8a0c49e2d.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542499/0457650f-7778-b2f2-ef32-128cd36dd11f.png)|

# TalkBack
タップと音声フィードバックを使用してデバイスを操作できます。TalkBackが、操作の内容を説明したりアラートや通知を知らせたりしてくれます。

確認方法
設定→ユーザー補助→TalkBack→サービスの使用をON

## エミュレーターでの確認方法
エミュレーターで確認する場合は、標準で機能が搭載されていないため、エミュレーター内のGoogle Playから「Androidユーザー補助設定ツール」をダウンロードする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542499/a6cd9060-32c9-2e22-7081-a102f95ce540.png)


## 基本的な操作方法

|制御| 操作|
| :- | :- |
|要素(テキスやボタン)の選択 | タップ|
|遷移 |フォーカスが乗った状態で画面内（もしくはその要素）をダブルタップ|
|前の要素にフォーカス |画面上で左方向にスワイプ|
|次の要素にフォーカス |画面上で右方向にスワイプ|

※緑の枠線で囲んでいる部分にフォーカスが当たっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542499/8bd4cb4f-5a8d-1b31-651d-8da3812164fe.png)

## 実装時の対応
### contentDescription
* 読み上げる文言を設定できる。
* ButtonやCheckBoxなどは、標準の文言が追加で読み上げられるため注意が必要

|要素|読み上げられる文言|
| :- | :- |
|TextView | contentDescriptionの文言|
|Button|contentDescriptionの文言＋ダブルタップすると有効になります|
|CheckBox|contentDescriptionの文言+チェックボックス切り替えるにはダブルタップします|

(デフォルトで設定されている読み上げ内容で問題なければ設定する必要がない)

### importantForAccessibility
* 読み上げ対象として含めたいか否かを設定できる。

### labelFor
* Viewを別のViewのコンテンツラベルとして使用することを指定できる
 - View1にlabelForにView2を追加した場合、View2選択時にView1も読み上げる

### screenReaderFocusable
* 細かくフォーカスが変更されるのではなく、親レイアウト内の子ビューを順に読み上げる
 - 親レイアウトにscreenReaderFocusableをtrueに設定
 - 子レイアウト全てにfocusableをfalseに設定
Web Componentsを利用するメリット

##Web Componentsを利用するメリット
HTMLのマークアップがスッキリする
汚い内部構造を外から見えなくする
内部のスタイルが外部に漏れないと同時に、外部のスタイルも内部に染み込まない
一度新しい要素を作ってしまえば、至る所で再利用できる
コンポーネントの流用だけなら、わざわざJavaScriptを書く必要がなくなる


##iframeとは似て非なるもの
上記の説明を見て、勘の良い人なら、「これってiframeじゃない？」って思ってくれるでしょう。

要はFacebookの「いいね!」ボタンのように、CSSやjsやHTML、それら全てをカプセル化して、iframe 1つで引用して使っているわけですね。尚且つ、引用する側のページはiframe内のスタイルやjsの影響を受けないというメリットもある。

確かに似ていますよね？だが！考え方としては参考になっても、Web Components は iframeとは似て非なるものです！どこが違うのか、詳しく見ていけば分かって頂けると思いますが、「Web Components」に出来てiframeにできない事として、以下の点が挙げられると思います。

HTTPリクエストは発生しない
タグ名を自分で定義できる
タグの中にさらに別のタグを入れることもできる
独自のAPIを外部に提供することができる
オンライン型ハッカソン「Tornado」に参加してみた（チーム開発について）

#初めに
　2021年よりスタートしたハッカソン「Tornado」の記念すべき第一回へ参加してきたので、以下の要領でまとめてみた。特にこれからチーム開発を始めた方に参考になるかもしれない。
　　　1.どんなプロダクトを作成したか
　　　2.開発環境
　　　3.チーム開発初心者の苦悩(ソースコードの共有等)
　　　4.まとめ

#プロダクト説明
　課題テーマ：「地方が抱える課題を解決するプロダクト」

．．．なかなか広いテーマである（笑）チームで話し合い、私達は伝統産業を
活性化させるため、「若者のアイデア×伝統産業の優れた技術」を実現させる
webサービスを作成した。
　●サービス概要： 1.コラム→ 伝統産業の技術や素晴らしさ、職人さんの熱意や
　　　　　　　　　　　　　　  世界観を知ってもらう
　　　　　　　　　　
　　　　　　　　　 2.アイデア→ 共感してくれた人によるアイデアを実現するため
　　　　　　　　　　　　　　　 のアイデアマン×職人さんのコラボページ
　　　　　
　　　　　　　　　 3.商品化販売→ 見事商品化されたアイテムを販売し、多くの人
　　　　　　　　　　　　　　　　 に購入してもらうためのページ 

#開発環境
　今回、私がサーバサイド構築で使用した開発環境を以下に記載する。普段の
コーディングで使用する言語がpythonであるため、今回もそのまま使用した。

　使用言語　 　　: python3.8.5
　フレームワーク : Flask
　統合開発環境　 : Pycharm
　Webアプリ公開用プラットフォームサービス : heroku
　ソースコード共有 : github


#チーム開発初心者の苦悩...（問題提起編）
　私自身、普段は個人開発がメイン+ webサイトの構築なんてしたことがない。
　　　　　　　　　　　　　　　　　　　(普段はロボット等の制御がメイン)
そんな中、私ともう一人のエンジニア2名で開発を分担して行った。また、一か月という短期間でプロダクト完成を目指さなければならないので相当苦労した。
今回は数ある苦労の中でも「チーム開発」にフォーカスして記事を書いてみる。
　
　● 苦労ポイント　　1.どのようにして自分のソースコードを共有するのだろう?
　　　　　　　　　　　2.他メンバーとのプログラム組み立て作業の方法は?



#チーム開発初心者の苦悩．．．（解決編）
1.どのようにして自分のソースコードを共有するのだろう?
　→ 解決策 : githubを使用する。

　githubは、これまでソースコードの参考程度にしかお世話になっていなかったが、チーム開発でのソースコード共有、共同作業を行うのに欠かせないツールである事を恥ずかしながら今回知った。（笑）
 詳細な機能については以下のサイトを参考にすると分かりやすい。
　リンク : https://www.sejuku.net/blog/7901

2.他メンバーとのプログラム組み立て作業の方法は?
　→ 解決策 : github + zoomで画面共有しながら共同作業する。
　今回の場合、エンジニア2名でwebサービスの構築を行うので、
エンジニア１→ フロントエンド　エンジニア2 → バックエンド という分担で作業を行った。それぞれの基本機能を作成後、フロントエンドとバックエンドの連携作業を最後に行う。その際に行った手法がこれだ。正直、これがベストプラクティスと言えるかは懐疑的であるが、比較的誰もが再現可能な手法だろう。互いのプログラムは担当した本人たちが一番よく知っている。従って、直接コミュニケーションを取りつつデバックを行うことで、効率的に作業を進行させられるようにした。


#まとめ
　簡略的であるが、チーム開発手法に悩む方々がざっくりとした方向性を見出す
ことができれば見えれば幸いである。私自身もこのハッカソンを通じてとても収穫の多い経験を積むことが出来た。興味がある方は来年も開催されるであろうこのイベントに参加してみてはいかがだろう?

ハッカソン紹介URL : https://tornado.humanrock.jp/
DB　マイグレーションファイル

マイグレーションファイルとは、DBのテーブルの作成や変更を管理するファイルである。
書式は
def change
　create_table :テーブル名 do |t|
　　t.データ型 :カラム名
　end
end
である。
記述を終えたら、コマンドを実行する必要がある。これは作成時も修正時も同様である。
コマンドは、
＄　rails db:migrated
である。

上記は、カラムの定義に当たるが、カラムを追加または削除する方法もある。
カラムを追加するには、
＄　rails g migrate Addカラム名Toテーブル名 カラム名:型名
のコマンドが必要である。
カラムの削除は、
＄　rails g migrate Removeカラム名Fromテーブル名 カラム名:型名
のコマンドが必要である。
Web APIについて調べてみた -5章編-

##背景
Web APIではHTTP構造を多分に利用して構築をしていくと良いと学んできた。
実際にWeb　APIは作って終わりではないので、運用中に修正が入ることもあると聞く。
そういった時にどう対処するのが望ましいのか、考えていくのがこの章だったので、読んでいく。

###読んだ本
O'Reillyの本を読んでみた
[WEB API The Good Parts](https://honto.jp/netstore/pd-book_26352551.html)

###章立て
前回のはこちら
[Web APIについて調べてみた -4章編-](https://qiita.com/danbo_lobo/items/b93f254a23d907e2b464)
今回は5章についてまとめてみた。
メモ程度の記述なので備忘録になれば。

##設計変更がしやすいのはどのAPIか？
この章では、仮に設計変更が入った場合どのAPIが変更しやすいのかを筆者なりの意見で述べられている。
突然だが３パターンのうち、一番影響範囲が小さく済むAPIはどれか？と問われたらどうするか。
1.外部に公開しているAPI
2.モバイルアプリケーション向けのAPI
3.ウェブサービス上で使っているAPI
答えはこの3つのどれも、小さく済む保証はないというものだった。悲し。。
筆者は、**一度公開したWeb APIの仕様を変更するのはいずれにせよ問題が発生する危険性がある**と結論づけている。
え、じゃあどうやってAPI変更するの？って話が次から出てくる。

###バージョンで管理する
結論から言うと、仮に変更が起きた場合、古いAPIを修正して利用するのではなく古いAPIを提供しつつ新しいAPIも提供していくのが望ましいとしている。
まあ、いきなり変えることは出来ないよな。。アクセス出来なくなる。
さて、同時にAPIを公開するとなると、見せ方が問題になってくる。
そこで出てくるのがタイトルにもある**バージョンによる管理**である。方法としては3つある。

####①URIに埋め込んでバージョン管理する
この方法が最もよく使われるバージョン管理方法。
例えば、以下のような記述になる。

`http://api.tumblr.com/v2/blog/good.tumblr.com/info`
ここでいう`v2`の部分がバージョンに当たる。

#####バージョン番号はどう付けるのが良いか？
バージョン番号はどうやって付けるのが正解なのかを考えるのに、[セマンティックバージョニング](https://semver.org/)を利用するのが一般的とのこと。
基本は数値をドットでつないだものを利用する形となっている。

####②URIのパス以外の場所にバージョンを入れて管理する
パス以外ってどこ？っと思ったが、答えはURIのクエリ文字のことだった。
例とて以下のような記述がある。

`http://api-public.netflix.com/catalog/titles/series/70023522?v=1.5`
パスとクエリ文字列の最大の違いは、それが省略可能になると言う点である。
こうしたクエリ文字でのバージョン指定となる場合、大概の場合デフォルトバージョンが決まっているのが普通らしい。
筆者はパスに入れちゃった方が好みとも言ってた。

####③メディアタイプでバージョン管理する
メディアタイプ＝データ形式なので、HTTPでは`Context-Typeヘッダ`を指定するが、メディアタイプで指定する場合は`Acceptヘッダ`を利用する。
書き方例は以下となる。

```
Accept: application/vnd.example.v2+json
```

##まとめ
・APIのバージョン更新は最低限に止め、後方互換性にも注意する
・APIのバージョンはメジャーバージョンをURIに含める
・APIの提供終了時はすぐ終了するのではなく、最低6ヶ月公開期間を設ける

##感想
いきなりはAPIをサクッと変えられないし、変えられないからこそ同時運用していく必要がある。
その運用も鍵だなーと読みながら思った。
いよいよ次がラスト。安全性と安定性を考えてAPIを作るにはどうしたらいいのか、を知りにいく。
【jquery】includesの使い方  指定した要素が格納されているか判定する

#jQuery 

```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <title>serializeArray_01_jq</title>
   <script src="jquery-3.6.0.min.js"></script>
   <script>
    $(function () {
      var myarray = [1,2,3,4,5];
      var res1 = myarray.includes(3);
      var res2 = myarray.includes(7);
      console.log(res1)
      console.log(res2)
    });
  </script>

```

#出力結果
```
true
false
```
ルーティングの記述

ルーティングでは、ユーザーが特定のURLにアクセスした時に、どのコントローラーのどのアクションに処理を振り分けるかを定義する。
それは、HTTPリクエストを指しており、HTTPリクエストは、
HTTPメソッド'URL'=>'コントローラ名#アクション名'
となっており、
HTTPメソッドは要求の主な内容を表しており、「どのURLにアクセスした時に、どのコントローラのどのアクションを呼び出すか」を定義している。
GoogleCloudで古いOSバージョンのComputeEngineを作成する方法

##概要
GUIでComputeEngineをRHELなどの公開イメージを選択しデプロイすると、各OSの最新のバージョンでしかでデプロイすることができません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1855066/9dafb455-b61d-336e-9af3-83ff19aaeb7d.png)
2021年9月時点ではRHEL8の場合はRHEL8.4がデプロイされますが、諸事情によりRHEL8.3や8.2でデプロイしたいことがあると思います。
今回は古いOSバージョンのデプロイ手順を紹介します。

##手順
全てCloudShellで実行します。
今回はRHEL8.3でデプロイする方法を記載します。

###非公開になっているイメージの表示方法

```
gcloud compute images list --show-deprecated --filter="name~rhel-8"
```
実行することで非表示になっているイメージの一覧が表示されます。

```
NAME                    PROJECT         FAMILY           DEPRECATED  STATUS
rhel-8-v20190507        rhel-cloud      rhel-8           DEPRECATED  READY
～中略～
rhel-8-v20210512        rhel-cloud      rhel-8           DEPRECATED  READY
rhel-8-v20210609        rhel-cloud      rhel-8           DEPRECATED  READY
rhel-8-v20210701        rhel-cloud      rhel-8           DEPRECATED  READY
rhel-8-v20210721        rhel-cloud      rhel-8           DEPRECATED  READY
rhel-8-v20210817        rhel-cloud      rhel-8                       READY
```

RHEL8の場合は下記がおそらく各バージョンの最終アップデートになります。

Version |    Name    |
------------------:|-------------------:|
           RHEL8.0 |    rhel-8-v20191014            |
           RHEL8.1 |   rhel-8-v20200403           |
           RHEL8.2 |    rhel-8-v20201014            |
           RHEL8.3 |  rhel-8-v20210512                |

GoogleCloudの公式ドキュメントでは見つけられませんでしたが、下記サイトでアップデートの内容は確認できました。
https://groups.google.com/g/gce-image-notifications

###デプロイ
使用するイメージがわかれば後は下記コマンドでデプロイすれば完了です。
作成コマンドのオプションはマニュアルを参照してください。
https://cloud.google.com/sdk/gcloud/reference/compute/instances/create

```
gcloud compute instances create <hostname> \
--image=rhel-8-v20210512 \　 ★使用するイメージを指定
--image-project=rhel-cloud \　★イメージのPROJECT
--project=<プロジェクトID> \
--zone <Zone> \
--subnet <サブネット> \
--service-account <サービスアカウント名>
```

デプロイ後ログインし、RHEL8.3で作成されていることが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1855066/a19737a4-3c9d-0ecb-0f5d-49fbd86bc2a5.png)

##さいごに
今回はRHEL8.3で実行しましたが、同じ手順でCentOSなどの他OSもデプロイすることができますのでコマンドのRHELの部分を読み替えて実行してください。
プログラミング初学者のすゝめ

#プログラミング初学者へのすゝめ
初めまして！都内でシステムエンジニアとして働き始めて1年半が経過したmartinです。
投稿日は2021年9月2日ですが、この時点で涼しくなったり暑かったりとで体調崩し気味です。
基本は、WFHなのですがもうそろそろ外に出て遊んだりしたいですよね....

今回は初投稿ということもあり、エンジニアとして働き始めて1年半が経過した今だからこそ言える「プログラミング初学者へのすゝめ」を題材にしたいと思います。（まだまだエンジニアとしては経験不足ですがお許しください。）
また、いきなり文章を書くのは苦手なので投稿内容をスライド形式で掲載したいと思います。
見づらかったらすみません！！

##目次
- 第１章　作成するソースコードについて
    - 作成するソースコードはどんなものが良いのか？
    - ソースコードの品質について
- 第２章　利用するツールの特性
    - IDEとエディターの違い
    - ツールを理解するということ
- 第３章　言語習得には座学よりもまず話す事！
    - そもそもプログラミング言語って何？
- 第４章　まとめ

#第１章　作成するソースコードについて
![プログラミング学習の進め0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/ae9eccd0-459c-b4f0-3a46-42ae77db9b47.png)

![プログラミング学習の進め.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/eff57b97-d65e-47f4-cf15-80911616bdaa.png)

![プログラミング学習の進め2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/2623c919-11c9-861c-4f7e-cf6903e2c6a8.png)
![プログラミング学習の進め3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/761bc58a-4cd2-054e-ae61-cef176800a38.png)

#第２章　利用するツールの特性
![プログラミング学習の進め4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/2139a8af-6aa3-793d-3d58-ebcd8146ba62.png)
![プログラミング学習の進め5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/654522ce-0ad4-45fb-5162-465012b8e324.png)

![プログラミング学習の進め6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/119a9dfc-d890-17b8-bd23-bbe49243008b.png)
![プログラミング学習の進め7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/d790a506-eed4-f2c5-3fcd-0eebdc073146.png)
![プログラミング学習の進め8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/3227096f-3d26-4ff5-58a5-7664a1c86cce.png)
![プログラミング学習の進め9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/ac85b446-335f-3274-05a0-6df80d558795.png)

#第３章　言語習得には座学よりまず話す事！
![プログラミング学習の進め10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/87a4feaa-fc7b-6d88-1d2a-0620ec87a851.png)
![プログラミング学習の進め11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/fb756e26-beca-c829-7866-6dc331571069.png)
![プログラミング学習の進め12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/84eafedb-cce3-6dcb-2078-ca348c3c73aa.png)
![プログラミング学習の進め13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/28a679fc-e934-6c61-ce21-374746e5d697.png)

#第４章　まとめ
![プログラミング学習の進め14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/2e05dd7f-37a1-f299-0b05-5a9918a8c52d.png)
![プログラミング学習の進め15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182987/5e770f30-9f64-ca9e-25aa-1e1741856208.png)

#最後に
今まで、エラーなどが出るたびにお世話になったQiitaにまさか自身が投稿するなんて思ってもみませんでした。少し感動していますw
また、冒頭にも述べた通り、あまり文章をまとめたり書いたりするのが得意ではないため、今回はあえてパワーポイントで文章を作成し、投稿してみました。
多分、あまり見ないQiitaの投稿の仕方だと思います。
個人的には、じっくり読んでほしいというよりは、ふらっと訪れて「ふーん、そうなんだ」で、また次の記事へ飛ぶというほうが好きなので、極力短時間で閲覧できるようにしたつもりですw
好みは人それぞれなので、コメントをしていただく際には、優しくしてください....
[Swift] 同じ値を毎回代入するのと同じ値じゃない時だけ代入するのってどっちが早いのか今更だけど検証した

## モチベーション

varで宣言された値があるとします。

```swift
var foo = false
```

それを上書きするとします。

```swift
foo = true
```

ということを複数回繰り返すとします。

```swift

(0...10000).forEach { _ in
    foo = true
}
```

この時に毎回trueを代入しても、fooがfalseの時だけ代入しても結果fooはtrueになります。

```swift

(0...10000).forEach { _ in
    foo = true
}

(0...10000).forEach { _ in

    if foo { return }

    foo = true
}

// どっちにしろfooはtrueになる。

```

今更なんですが、パフォーマンス的にはどっちがいいのか気になったので検証してみました。
（もう誰か試してる気がするけど簡単にできそうだったので今のバージョンで改めてということでお許しください。。。）

仮説としては毎回代入する方がメモリをいじる分遅くなる気がします。

## 計測方法

こちらを参考にさせていただきました。

https://qiita.com/osamu1203/items/9160f5f4951ebe205ea3

上記の方法で同じ繰り返しの処理の中に毎回値を代入するパターンと代入が必要な時だけ代入するパターンの２つを挟んでみて、最終的にかかった時間を計測します。

## 計測環境
- Swift5.4
- Xcode12.5

Playgroundで試しています。

## パターン1: 毎回代入する場合

こちらを実行してみます。

```swift

var foo = false

let start = Date()

(0...100000).forEach { _ in
    foo = true
}

let elapsed = Date().timeIntervalSince(start)

print("result: " + elapsed.description)

```

結果は以下になりました。

```
"result: 1.4446409940719604\n"
```

1.5秒くらいですね。結構かかりました

## パターン2: 代入する必要なければreturnする場合

こちらを実行してみます。

```swift

var foo = false

let start = Date()

(0...100000).forEach { _ in
    
    if foo { return }

    foo = true
}

let elapsed = Date().timeIntervalSince(start)

print("result: " + elapsed.description)

```

結果は以下になりました。

```
"result: 0.31178009510040283\n"
```

大体0.3秒です。パターン1と比べると結構差がつきました。

## 結論
重複した値を代入するより、重複のチェックをして重複しない時だけ代入した方が早そうです。

よくViewのUtilityメソッドで`translatesAutoresizingMaskIntoConstraints`を毎回falseにするコードとか見かけるんですが、そういう時もtrueかどうかチェックして必要な時だけfalseを代入する方が早そうだよってコメントしてみようと思います。
ネットワークのコミュニティ構造の時間発展をalluvial plotで可視化する

時間発展するグラフ（ネットワーク）においてコミュニティがどのように時間発展するかを可視化したいことは多い。
例えば、SNSなどのネットワークにおいて各時刻におけるネットワークのコミュニティを検出し、それらのコミュニティ内のノードのメンバーがどのように時間変化するかを可視化したいということはよくあるだろう。

ここではそのようなコミュニティ構造の時間発展を可視化する方法の一つalluvial plotを作成する方法についてまとめておく。

今回、図の作成に使うツールはこちらのオンラインのツール [Alluvial Generator](https://www.mapequation.org/alluvial/)。
こちらのツールを使うと例えばこんな感じのかっこいい図が作成できる。
しかも、インタラクティブに、階層的なコミュニティ構造を表示できたり、特定のノードやモジュールに色をつけたりでき、作成した図はsvgやpngなどのフォーマットに保存することができる。
また、可視化時の設定なども含めてjsonにエクスポートすることが可能である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/12eb4144-1998-d57e-76a9-1e56e53ace6c.png)

しかし、このツールは便利な反面、入力ファイルのフォーマットがあまりわかりやすくないので、今回はここでその手法をまとめておく。

このツールの入力のファイルのフォーマットとしては、infomapで出力される形式のファイルを想定している。
infomap以外のツールで検出したコミュニティ構造を可視化したい場合にはこれらのファイル形式に変換する必要がある。
`.clu`, `.map`, `.tree`, `.ftree` などのフォーマットがあるが、ここでは階層的なコミュニティ構造を表現でき、かつシンプルなフォーマットであるtreeフォーマットでデータを指定することにする。
treeフォーマットのドキュメントはこちらにある。
https://www.mapequation.org/code_old.html#Tree-format
treeは次のようなファイルの形式である。

```txt
1:1:1 0.0384615 "7" 6
1:1:2 0.0384615 "8" 7
1:1:3 0.0384615 "9" 8
1:2:1 0.0384615 "4" 3
1:2:2 0.0384615 "5" 4
...
```

各行がノード一つ一つを表している。
まず最も左の列にあるコロンで区切られた数字が、モジュールのIDである。階層的なコミュニティ構造を表現しており、一番左の数字がトップレベルモジュール（もっとも粗視化したコミュニティ）のID、次の数字がそれよりも階層が下のモジュールのID、さらに下のモジュールのID、、、と続いていき、最後に各モジュール内でのノードのIDというように番号付けされている。
infomapでは1から始まる連番を使うことが一般的なようなので、その慣習に習っておくのがよいだろう。（０から始めるとどうなるのかはよくわからない。）

２列目の不動小数点はtotal flow(Page Rank)という数字となる。どれくらい中心性があるかという数値になるが、今回の可視化には特に必要ないので任意の数字を入れておけば良いだろう。

３列目はノードの名前。４つ目がノードの（グローバルな）IDとなる。

一つのtreeファイルが一つの時点でのコミュニティ構造を表しており、alluvial plotでは複数のtreeファイルを読み込んで図を作成する。その際に、異なる時点でどのノードとどのノードが対応しているのかを判定するのにノードの名前が使われる。

このように複数の時点に対応するtreeファイルを複数用意したらデータを読み込めば可視化することができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/8d32988c-b6fb-c693-2fdf-089128674d56.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/341d2743-1f04-85f0-cb5c-644ee6d02560.png)

作画できたら画面右のほうに可視化のオプションを指定する箇所があるので、色などを指定するときれいな図が作れるだろう。

## 最後に

こちらの方法はネットワークのコミュニティの時間発展を可視化するために提案されたものだが、実は一般的に複数の時点での集合関係がどのように発展しているかを可視化するのにも利用することができる。
Slack bot開発初心者がFlask/Vue.js/GoogleAPIでbotサービスを作ったらこうなったという話

リバネスでCIOをやっています、geeorgeyです。

結論から言うと結構時間がかかりました。
開発自体はこちらの投稿あたりからスタートしているので、2ヶ月ほどかかったことがわかります。[Vue.js / FlaskアプリにSlack for boltを組み込むには](https://qiita.com/geeorgey/items/7844dee644524dacac41)

## どんなサービスを作ったのか
詳細はこちらにございます
[Slackアシスタント -OYASUMI bot-](https://lne.st/slack-oyasumi/)
簡単に言うと、Googleカレンダーに休暇と入れておけば、その日のSlackメンションは非通知化されるというBotです。
SlackとGoogleWorkspaceを利用されている組織におすすめな機能となっています。
![649ed1b82354815f11b8525fd5e290de.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/8f509ad1-a8f9-9227-1306-2301a3f120ae.png)


## 何を使ったか
色々と右往左往しながら開発しましたが
データソースは以下の２つです。API叩きまくりました。
- slack API
- Google API

Webサービスについては以下の構成になっています
- バックエンド：Flask(python)
- フロントエンド：Vue.js

デプロイ先はHerokuです。

処理ロジックは入っていませんが、同様な構成でWebサービスを作るためのテンプレートをこちらで開発中です。もしよろしければ使ってみてください。
[pythonを使ってリアクティブなWebアプリを作りたい【開発編5】Slack boltの組み込み](https://qiita.com/geeorgey/items/ca2942ff054e30587c78)

## 難しかったこと
### Google APIについて
こちらは別途記事化しようと思いますが、一般開放でサービス展開するためには、Google側とコミュニケーションを取る必要があります。利用の用途、Webの作成、プライバシーポリシーと利用規約の整備といった準備が必要です。
途中、動画でどんな処理をしているのかを説明する必要があったりと、物理的に時間を結構持っていかれます。
このために利用規約に加筆が必要になったりするのでなおさら時間がかかるのは間違いありません。
Google APIの利用自体は、python用のコードもサンプル提示されるのでかんたんに使えると思います。
Vue.jsからOAuthする部分にはめちゃくちゃハマりました。こちらに書いてあります。
[Vue.js から Google OAuthでaccess_token,refresh_tokenを取得する](https://qiita.com/geeorgey/items/d4196118119734fb5942)

### slack APIについて
こちらは、[slack bolt for pythonという開発キット](https://slack.dev/bolt-python/ja-jp/tutorial/getting-started)がSlackから提供されているので、それを使っています。
非常にかんたんに実装できるので、pythonでSlack Botを作る場合はこれ一択です。
slackにはたくさんのAPIが備わっていて、知っていればスマートな実装ができるというものばかりです。この辺については、そうはいっても知らないものは使えないのでSlackの @seratch さんには多大な協力を頂きました。ありがとうございます。

### slack appについて
自社利用のみであれば、環境変数にbotの情報を入れて使えばよいのですが、配布アプリにする場合はそうは行きません。やり方についてはこの辺を参照してください。
[続：Slack Bolt for Pythonを使ってのbot構築 アプリ配信に向けた対応](https://qiita.com/geeorgey/items/f117ee14a85c07ef8ea9)

## βテスターを募集しています
ということで、無事にリリースが出来ましたので、現在βテスターを募集しています。
業務の中心にSlackとGoogleカレンダーがあるチームは是非使ってみてください。
[導入にあたっての資料はこちらに準備してあります](https://docs.google.com/presentation/d/1f4TzqHUFOv49f4C2vKh6m2RZ82lM7NENxII5SOM42DY/edit#slide=id.gc89f7adc56_0_346)。

## Slack botは業務パフォーマンスに直結する
以下は、私の個人的な想いではあるのですが、Slackbotは組織のパフォーマンスに強く貢献すると考えています。
コミュニケーションのハブとして、かなりの時間がSlack上で流れている弊社では、色々な情報をとにかくSlackに集めています。
これらの情報から新しいアクションがスムーズに生むことが出来たり、より大きな動きへと加速させることが出来たらどうでしょう。本当に強い力となると思います。

今回はSlackユーザーをサポートするようなツールを作ってみましたが、より色々なサービスを展開できるような気がしてワクワクしています。まずはリバネスの社内でゴリゴリに使い倒せるようなものを、徐々に外側にリリースしていけると良いのですが。
引き続き、こちらの方向性での開発を進めていきたいと思っています。

## 人材募集中！
Slack/Salesforce/Heroku/PHP/Nuxt.jsなんかに興味のあるエンジニアを募集しています。
是非お声がけください。
こんな感じで開発してみませんか？https://note.com/geeorgey/n/ncbfc82c87cf8
![rectangle_large_type_2_acef530774c88b34fb063a666653aa50.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/9ec6f023-92a5-079a-eb24-efed358578fe.jpeg)
Azure から Cloudflare への外向き通信料金



# 概要

オリジンに Azure を使う場合の、Azure から Cloudflare への外向き通信料金について、調べてみました。

![image-20210902161105276](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210902161105276.png)

# Bandwidth Alliance とは

クラウドプロバイダーと Cloudflare との間で、余計な ISP が途中に入らないように通信させ、その分の通信コストをユーザーに還元する形で割引を行うプログラムです。
具体的には、クラウドプロバイダーと Cloudflare との間で、ピアリングや物理的な直接接続がグローバルに行い、クラウドプロバイダーの料金が割り引かれます。（いわゆるインターネットを経由するよりかはパフォーマンスも良くなります。）

> [Cloudflare customers can now use Microsoft Azure Data Transfer Routing Preference to enjoy lower data transfer costs](https://blog.cloudflare.com/discounted-egress-for-cloudflare-customers-from-microsoft-azure-is-now-available/)

# 適用対象サービス

以下、抜粋です。

> [Azure でのルーティング優先設定 | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/virtual-network/routing-preference-overview#supported-services)
>
> - 仮想マシン
> - 仮想マシン スケール セット
> - Azure Kubernetes Service (AKS)
> - インターネットに接続するロード バランサー
> - Application Gateway
> - Azure Firewall
>
> - BLOB
> - ファイル
> - Web
> - Azure Data Lake

# 通常料金

> [料金 - 帯域幅 | Microsoft Azure](https://azure.microsoft.com/ja-jp/pricing/details/bandwidth/)
>
> ![image-20210902161813000](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210902161813000.png)

# 割引料金

> [料金 - 帯域幅 | Microsoft Azure](https://azure.microsoft.com/ja-jp/pricing/details/bandwidth/)
>
> ![image-20210902161800282](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210902161800282.png)

# 設定方法

以下の手順で簡単にセットアップが可能です。

> [Reduce data transfer (egress costs) between Azure and Cloudflare – Cloudflare Help Center](https://support.cloudflare.com/hc/en-us/articles/4407207972109)
>
> 1. In the Azure portal, go to your storage account. 
> 2. Navigate to **Network Routing > Firewalls and virtual networks**.
> 3. For **Routing preference**, choose **Internet routing**.
> 4. Publish route-specific endpoint to **Internet routing**.
>    ![image-20210902163048235](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210902163048235.png)
> 5. Navigate to **Properties**.
> 6. Locate the endpoint values for **Internet Routing**.
>    ![image-20210902163120603](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210902163120603.png)
> 7. Enter these endpoint values in your Cloudflare Dashboard.
>    ![Enter endpoint URLs from Microsoft Azure into your Cloudflare dashboard.](https://images.ctfassets.net/slt3lc6tev37/5oqqiiwMvDQgGsoOKQQ85C/16f51484a2db8c12fd383b412fa9cbee/Screen_Shot_2021-08-16_at_1.11.27_PM.png)