OmniAICreator/Qiita-1.07M huggingface dataset:
CCNA勉強 Section17 ネットワーク管理

#SNMP(Simple Network Management Protocol)
TCP/IP接続の機器を、ネットワーク経由で監視・制御するアプリケーション層プロトコル

###通信の種類
SNMPマネージャ:情報収集&監視役。UDP(161)を使用
SNMPエージェント:情報をマネージャに送信。UDP(162)を使用
SNMPポーリング:マネージャからの要求
SNMPトラップ:マネージャに通知(一度きり)
SNMPインフォーム:マネージャに通知(マネージャから応答無ければ再送)

###SNMPバージョンとセキュリティ
v2cが主流(なのか???)
コミュニティ名で認証を行う
v3はユーザー名あるいはMD5かSHAでの認証になり、最新版は暗号化も行う

#MIB(Management Information Base)
集めた情報をツリー構造にして保管
マネージャ「ポーリング(情報くれ!)」←このとき、欲しい情報が何であるかを、どのように伝えているのか?
→OID(Object ID)を共通認識している

#システムログ
出力先は4つ
コンソールライン
仮想ターミナルライン
ルータ・スイッチのRAM
Syslogサーバ

###プライオリティとログの内容
0 emergencies
1 alerts
2 critical
3 errors
4 warnings
5 nortifications
6 informational
7 debugging

出力時に指定した数値以下のログが出力される

```
出力ログレベル変更
Router(config)#logging console 4

VTY接続時
Router(config)#terminal monitor
Router(config)#logging monitor 5

ルータのRAMに保存
Router(config)#logging baffered <4096バイト〜>
Router(config)#logging baffered <0〜7>

サーバ指定
Router(config)#logging host <ip | ホスト名>

```


```
ログ確認
Router(config)#show logging

Console logging
Monitor logging
Buffer logging
```

###デバッグ
パケットの詳細・ネットワーク状況を確認できるが、CPU消費が激しい
オプションで処理内容を限定してうまく使う

#NTP
時刻同期は必須
UTCと同期するためのプロトコル
UDP123番
ストラタム(階層構造)

```
Router(config)#clock timezone JST 9
Router(config)#ntp master 9
Router(config)#ntp server 192.168.1.200

日本の標準時を設定、ストラタム9のNtPサーバとして有効化、同期先指定
```
```
SW(config)#clock timezone JST 9
SW(config)#ntp server 192.168.1.200
```
```
R1#show ntp status
Clock is synchronized, stratum 7, reference is 192.168.1.200
同期できているのでストラタム7、できてないときは9となる

R1#show ntp associations

*
```

#CDP(Cisco Discovery Protocol) LLDP(Link Layer Discovery Protocol)
データリンク層で作動
CDPはデフォルトで60s毎(保持180s)
LLDPはデフォルトで30s毎(保持120s)
LLDPはIEEE802.1ABで標準化されたもの
LLDPはトポロジチェンジの情報を伝える(CDPは伝えない)

```
RT(config)#no cdp run
RT(config-if)#no cdp enable

RT#show cdp
RT#show cdp interface
RT(config)#show cdp neighbors
RT#show CDP neighbors detail (show cdp entry *)

```
CCNAノート Section15 HSRP

#冗長化
障害に備えてバックアップ
HSRP GLBP VRRP

##HSRP
複数のルータでグループを組む(スタンバイグループ)
仮想IPと仮想MACを設定する

Helloパケット送り合う。
プライオリティ高いものがActive、次点がStandby、それ以下がListen。

状態一覧
Initial
Learn
Listen
Speak
Standby
Active


##障害発生時
ActiveルータはInitial状態に移行
Activeルータからの10s毎のHelloパケットが来ないことから、非Activeも障害を検知
StandbyがActiveに、ListenがStandbyにそれぞれ移行する

インターフェーストラッキング
スタンバイグループ外のインターフェースを追跡し、障害発生時に、そのルータのプライオリティを下げる。
下記のプリエンプトをグループ内の全ルータで有効にしておけば、Activeルータを切り替えられる。


##障害復旧時
デフォルトでは、Activeルータはダウンしない限りActiveであり続ける
プリエンプトを有効にすると、プライオリティが高いルータが自動でActiveになる　

##Multiple HSRP
VLAN作って、それぞれ異なるスタンバイグループを割り当てる。負荷分散が目的。

##GLBP
最大4つの仮想MACアドレスを持つのが特徴
プライオリティ最大のルータがAVG(Active Virtual Gateway)となり、最大4つ、AVF(Active Virtual Forwarder)を選んで、仮想MACアドレスを割り当てる。
AVGはパケット転送せず、グループ管理。ARP応答役か?
パケット転送はAVFの役目。
仮想MACアドレスは、00-07-B4-0x-xx-yy
(x:グループ番号、y:01-04)

##VRRP(Virtual Router Redundancy Protocol)
標準化された規格。
マスタールータとバックアップルータに分かれる。実際のルータIPアドレスを仮想ipに割り当てることができる?

##写経
HSRPの設定。
・スタンバイグループ11
・仮想MACアドレス 00-00-0C-07-AC-0B
・仮想IPアドレス 192.168.1.254

```
RT1(config)#interface FastEthernet 0/0
RT1(config-if)#standby 11 ip 192.168.1.254
RT1(config-if)#standby 11 priority 115
RT1(config-if)#standby 11 preempt
RT1(config-if)#standby 11 track FastEhernet 0/1 20
```

```
RT2(config)#interface FastEthernet 0/1
RT2(config-if)#standby 11 ip 192.168.1.254
RT2(config-if)#standby 11 preempt
RT2(config-if)#standby 11 track FastEthernet 0/1
```
CCNA勉強 Section14 EtherChannel

#Ether Channelの形成方法
PAgP　(Port Aggregation Protocol):シスコ独自。「ぱぐぴー」
LACP (Link Aggregation Control Protocol):IEEE802.3adで標準化。「らっくぴー」

それぞれのモードとネゴシエーションの有無が大事
PAgPはautoとdesirable
LACPはpassiveとactive

※Port channelの掛け持ちは不可

```
SW1#interface config range FastEthernet 0/1 - 3
SW1(config-if-range)#no switchport ←ルーテッドポート。L2機能を無効化???
SW1(config-if-range)#channel-group 1 mode active
creative a port-channel interface Port-Channel 1
SW1(config-if-range)#exit

SW1#interface Port-Channel 1
SW1(config-if)#ip address 192.168.1.1 255.255.255.0
SW1(config-if)#exit

```

ネイバー関係を見る
```
SW1#show lacp neighbor
```
web3.jsを用いてブラウザからスマートコントラクトにアクセスする

web3.jsをインポート

```html
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
```

ABI情報をjsにコンパイルして、`mycontract_abi.js`の`mycontractABI`という変数に格納  

プロジェクトに`mycontract_abi.js`を含める

## Metamask
ChromeとFirefoxのブラウザ拡張機能
ユーザは自身のイーサリアムアカウントと秘密鍵を安全に管理し、そのアカウントでWeb3.jsを使用しているウェブサイトとやり取りすることが可能

```javascript
window.addEventListener('load', function(){
  // web3がブラウザにインジェクトされているかチェック
  if (typeof web3 !== 'undefined'){
    // MetaMaskのプロバイダを使用
    web3js = new Web3(web3.currentProvider);
  } else {
    // Metamaskをインストールするようメッセージを表示 
  }
  startApp()
})
```

## コントラクトにアクセス
ABIをインポート
```html
<script language="javascript" type="text/javascript" src="mycontract_abi.js"></script>
```
ABIとアドレスを用いてコントラクトにアクセス
```javascript
var myContract;
function startApp() {
  var myContractAddress = "YOUR_CONTRACT_ADDRESS";
  myContract = new web3js.eth.Contract(myContractABI, myContractAddress);
}

```

## CallとSend
```javascript
// Callはview関数やpure関数に使われる。ブロックチェーン上のトランザクションを生成しない。
myContract.methods.myMethod(args).call()
// Sendはトランザクションを生成し、ブロックチェーンの情報を変更する。viewとpure以外の関数に用いる。
myContract.methods.myMethod(args).send({ from: userAccount })
```

## MetaMaskでのアカウント管理
MetaMaskの拡張機能内で、ユーザは複数アカウントの管理が可能
```javascript
var userAccount = web3.eth.accounts[0];
```

ユーザーはMetaMaskのアクティブアカウントをいつでも切り替えられるため、アプリケーションはこの変数が変更されているかをモニタリングし、それに応じてUIをアップデートする必要がある。
```javascript
// 100ミリ秒ごとにアカウントが変更されているかチェック
var accountInterval = setInterval(function() {
  if (web3.eth.accounts[0] !== userAccount){
    userAccount = web3.eth.accounts[0];
    // UIアップデート
    updateInterface();
  }
}, 100)
```

## 参考
https://cryptozombies.io/jp/
Vivliostyle-CLIでmermaid.jsを使用する


Vivliostyle-CLI v4.6.0から使えるようになったJavaScriptで、近頃話題のmermaid.jsが使えるか試してみました。

# 表示例

![スクリーンショット 2022-02-25 4.11.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57548/64d32824-8ba4-87d5-036b-246ff90786a6.png)

# VFMファイル

VFMの[Frontmatter](https://vivliostyle.github.io/vfm/#/vfm#frontmatter)のscriptプロパティにmermaid.jsと、後述のvs-mermaid.jsを記述します。

VFMのcode表記のファイル種別に"mermaid-render"を指定するとレンダリングの対象になります。

## 注意点

* mermaid.jsはローカルにあるファイルを指定しても動作します。
* vivliostyle.config.jsでworkspaceDirを指定すると作業ディレクトリにローカルのJavaScriptファイルがコピーされないため正しく処理されません。
* vs-mermaid.jsにdeferを付けて遅延読み込みするのがポイントで、deferが無いとレンダリング対象の要素を見つけられないことがあります。

````markdown

---
script:
  - type: 'text/javascript'
    src: 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'
  - type: 'text/javascript'
    src: './vs-mermaid.js'
    defer: true
---

```mermaid-render
stateDiagram
状態1: ノート付き状態
note right of 状態1
日本語も扱えます
end note
状態1 --> 状態2
note left of 状態2 : こちらにもノート
```

```mermaid-render:キャプション付き
graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
```
````

# JavaScript

デフォルトのレンダリング(onLoadイベントで.mermaidの要素を対象)をせずに、VFMの書き出す要素を選択してレンダリングを行ないます。

```javascript:vs-mermaid.js

mermaid.initialize({
  startOnLoad:false
});
function renderGraph(){

  // VFMが作るcode要素に付けられるクラスを指定したセレクタ
  const codeSelector = "code.language-mermaid-render";
  // レンダリング対象になる要素のリストを取得する
  const mermaidElements = document.querySelectorAll(codeSelector);

  let i = 1;
  for(let src of mermaidElements) {
    const dist = src.parentNode;
    const svg = mermaid.render('mermaid-graph-'+i, src.textContent, undefined);
    const div = document.createElement('div');
    div.innerHTML = svg;
    div.classList.add('language-mermaid-render');
    // code要素の親要素であるpre要素をdiv.language-mermaid-render > svg#mermaid-grahp-*に置き換える
    dist.replaceWith(div);
    i++;
  }
}

if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', renderGraph);
} else {
  renderGraph();
}

```

## CSS

div.language-mermaid-render内のsvgを中央に表示するためにtext-alignを設定しています。

```css
.language-mermaid-render {
  width: 100%;
  text-align: center;
}

figcaption {
  width: 100%;
  text-align: center;
}
```
jQueryのajax送信するデータを１行で取得する

jQueryでフォームデータを送信する時どうやってデータを集めていますか？
input属性を指定して一つずつ集めているならFormDataを使って1行になるかもしれません。

https://developer.mozilla.org/ja/docs/Web/API/FormData

before
```javascript
$('input').on('change', (e) => {
    let data = {};
    data[$('input').attr('name')] = $('input').val();
    // ...dataを集める処理
    // ajaxに投げる処理
}
```

１行コード！
```javascript
$('input').on('change', (e) => {
    $form = $(e.target).parents('form');
    const data = new FormData($form.get()[0]);
    // ajaxに投げる処理
}
```

# FormDataを使う際のTips

### 中身を知りたい
```javascript
// これで確認可能
console.log(...data.entries());

// 単純なconsole.log()だとわからない。
console.log(data);
>>>
FormData {}
  [[Prototype]]: FormData
    append: ƒ append()
    delete: ƒ delete()
    entries: ƒ entries()
    forEach: ƒ forEach()
    get: ƒ ()
    getAll: ƒ getAll()
    has: ƒ has()
    keys: ƒ keys()
    set: ƒ ()
    values: ƒ values()
    constructor: ƒ FormData()
    Symbol(Symbol.iterator): ƒ entries()
    Symbol(Symbol.toStringTag): "FormData"
    [[Prototype]]: Object
```

### 画像を送信したい
ajaxのパラメーターを追加する必要があります。
processData: クエリ文字列に変換するか
contentType: requestヘッダーのcontent-type、デフォルトで"application/x-www-form-urlencoded"

```javascript
$.ajax({
    type: type,
    url: url,
    data: data,
    // 追加
    processData: false,
    contentType: false,
})
```

### fileだけ上げたい
```javascript
let form = new FormData();
form.append("file", input.files[0]);
$.ajax({
    data: form
    processData: false,
    contentType: false,
    // ....
})
```

### putやdeleteが使えない
これはcontent-typeがapplication/x-www-form-urlencodedの特性上、putやdeleteのHTTPメソッドが使えない。
*もしかしたら送れる方法があるかも？
CustomCellを使う!!

# はじめに

XIBファイルを使ってCustomCellを作成した際に、どうやったらTableViewに反映できるのか、
その方法を備忘録的にまとめていきたいと思います。

### 1.CustomCellの作成

画面左ナビゲーターエリアのいずれかのファイルを右クリック、New File...を選択


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/18b458b2-b5bf-3eb4-62cc-9d761a551b7f.png" width=70%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/e88ee877-1e05-0b56-862f-1d10e454ed3e.png" width=70%>


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/0a3c01e3-3f5a-017d-ee7d-61b5c9937e5a.png" width=70%>

はい!画面のような操作をして頂くとXIBファイルが作成出来ます。
注意としましては[Also create XIB file] にチェックを入れる事を忘れないようにして下さい。

### 2.CustomCellをカスタマイズする!!

下記の図のように好きにカスタマイズしちゃって下さい!!

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/57c27cd9-d31e-b520-2169-b63417b532cd.png" width=70%>

### 3.CustomCellを表示しよう!!
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/88d6f38f-93c6-2012-540e-a1b3d817801c.png" width=70%>

画面右UTTエリアのIdantifierを(customCell)に設定する事を忘れないで下さい。

```swift:ViewController
import UIKit

class ViewController: UIViewController {
    
    let itemArray = ["cell 1","cell 2","cell 3"]
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let tableView = UITableView(frame: self.view.bounds, style: .plain)
//tableViewの設定を記述
        tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "customCell")
        tableView.delegate = self
        tableView.dataSource = self
        view.addSubview(tableView)
       }
}

extension ViewController:UITableViewDelegate,UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        itemArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//tableViewの内容を指定
        let cell = tableView.dequeueReusableCell(withIdentifier: "customCell",for: indexPath) as! TableViewCell
        return cell
    }
}
```


<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/89a7d532-5d08-1c9f-b1da-2206cb29f98c.png" width = 180％>

customCellが無事に反映されましたね!!
【Rails】APIモードのルーティング例

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

## Rails APIモードのルーティング

### ルーティング例

コメントで解説を記述していますのでご確認ください。

```config/routes.rb 
Rails.application.routes.draw do
  # namespaceで名前空間を付与する。
  namespace :api do
    # APIに大きな変更が発生する場合に備えてスイッチングしやすいようにURL自体にバージョンを持たせる。
    # ただし、バージョンは「必要な場合にのみ」つけることが推奨されている。
    namespace :v1 do
      # resouresはindex、show、new、edit、create、update、destroyアクションに対応するルーティングを作成できる。
      resources :restaurants do
        # only: %i[index]等と記述することで特定のアクションのみルーティングを設定することができる。
        resources :foods, only: %i[index]
      end
      resources :line_foods, only: %i[index create]
      # resourcesでは設定することのできないルーティングは以下のように記述することで設定可能
      put 'line_foods/replace', to: 'line_foods#replace'
      resources :orders, only: %i[create]
    end
  end
```

上記の通り記述すると以下のようなルーティングは以下のようになります。

```:ターミナル
 % rails routes
                                  Prefix Verb   URI Pattern                                                                                       Controller#Action
                 api_v1_restaurant_foods GET    /api/v1/restaurants/:restaurant_id/foods(.:format)                                                api/v1/foods#index
                      api_v1_restaurants GET    /api/v1/restaurants(.:format)                                                                     api/v1/restaurants#index
                                         POST   /api/v1/restaurants(.:format)                                                                     api/v1/restaurants#create
                       api_v1_restaurant GET    /api/v1/restaurants/:id(.:format)                                                                 api/v1/restaurants#show
                                         PATCH  /api/v1/restaurants/:id(.:format)                                                                 api/v1/restaurants#update
                                         PUT    /api/v1/restaurants/:id(.:format)                                                                 api/v1/restaurants#update
                                         DELETE /api/v1/restaurants/:id(.:format)                                                                 api/v1/restaurants#destroy
                       api_v1_line_foods GET    /api/v1/line_foods(.:format)                                                                      api/v1/line_foods#index
                                         POST   /api/v1/line_foods(.:format)                                                                      api/v1/line_foods#create
               api_v1_line_foods_replace PUT    /api/v1/line_foods/replace(.:format)                                                              api/v1/line_foods#replace
                           api_v1_orders POST   /api/v1/orders(.:format)                                                                          api/v1/orders#create
           
```
Rails コメント投稿機能　コード解説　（モデルの作成について）

``` user.rb
  has_many :comments
```
1つのUserオブジェクトに対して複数のcommentオブジェクトが存在するという意味になります。
また、has_many関連付けを宣言する場合、相手のモデル名は「複数形」で指定する必要があります。
[has_many関連付け](https://railsguides.jp/association_basics.html)
```post.rb
  has_many :comments
```
1つのPostオブジェクトに対して複数のcommentオブジェクトが存在するという意味になります。
投稿は複数のコメントを持つことを意味します。
[has_many関連付け](https://railsguides.jp/association_basics.html)
```comment.rb
class Comment < ApplicationRecord
  validates :content, { presence: true, length: { maximum: 100 } }
  belongs_to :user
  belongs_to :post
end
```
２行目のバリデーションはCommentにcontent属性がない場合に無効であることを知らせます
３行目・４行目
あるモデルでbelongs_to関連付けを行なうと、他方のモデルとの間に「1対1」のつながりが設定されます。
commentモデルとuserモデルとの間は「1対1」のつながり、
commentモデルとuserモデルとの間は「1対1」のつながりということになります。
[belongs_to関連付け](https://railsguides.jp/association_basics.html)
Github actions + windows-latest で cmake で  Visual Studio 16 2019    could not find any instance of Visual Studio.

## 背景

Github Actions で `windows-latest` で

```
cmake -G "Visual Studio 16 2019"
```

としていたら could not find any instance of Visual Studio. と出るようになった.

## 原因

`windows-latest` だとなんか勝手に Visual Studio のバージョンを変えていて, ある日突然 VS2019 を扱わなくなったっぽい.

https://github.com/actions/virtual-environments/issues/4856#issuecomment-1047801500

めんどいですね...

## 解決

VS 2022 を指定するようにする.


VS2019 を使いたい場合


https://github.com/actions/virtual-environments/issues/4856#issuecomment-1048149899

`microsoft/setup-msbuild` を追加すれば治ると思われる.
【PHP】'シングルクォート'と"ダブルクォート"の使い分け


# | 概要

- PHPで使用する場合
- 変数とは
- まとめ

## | PHPで使用する場合

PHPの学習を進めていると、文字列として文字を扱う時に'シングルクオーテーション'または"ダブルクォーテーション"を使うのを知ったが果たして違いはあるのか、またどっちがいいのか？など気になったので色々サイトをみて調べてみました。

#### 変数とは
以下の文書の中で変数と言う言葉がよくでてくるので、まず最初に変数について紹介させていただきます。

プログラムを書くときに、長い文字列や、同じ数値・計算式を何度も繰り返し使うこともあります。
その都度同じ文字列や数値をソースコード内に記述していくのは誤記しやすいですし、手間なのでその際に変数を使用します。

`変数　＝　データを保存しておく箱のイメージがいいと思います。`

#####  PHPにおいて変数名(箱)の名前を付ける際には、以下のルールに沿って変数名をつけます。

- 必ず【＄】から始まる
- 使えるのは半角英数字、_（アンダースコア）
- 大文字小文字は区別される
- 【＄】のあとに数字は使えない（＄name123 ○、＄123name ×）

###### (例)
```php
//↓箱の名前をnameにして
$name = 'yamada';
        //↑箱の中身に'yamada'をいれてあげる

echo "$name"; 
//変数名の$nameを指定して実行すると中の'yamada'が画面に表示されます。
```
参考URL：　https://www.sejuku.net/blog/28773
参考URL：　https://www.php.net/manual/ja/language.variables.basics.php

#### ① 'シングルクォート'では変数を使用しても変数が展開されず文字列となります。

→ つくっておいた変数を'シングルクォート'内で呼びだすと変数は展開されず文字列として出力されます。ですので、変数を出力する必要がある場合は"ダブルクォート"を使用する必要があります。
###### (例)
````php
$name = 'yamada';

echo "$name";
//画面には変数の中身のyamadaが出力されます。
echo '$name';
//画面には変数の中身ではなく、文字列で$nameとそのまま表示されます。
````

参考URL：　https://eng-entrance.com/php-basic-echo

#### ②　'シングルクォート'でも"ダブルクォート"でも文字列として入力を行えない特殊な文字があります。

→ 【エスケープシーケンス】とはキーボードから文字列として入力できない、改行やタブなどの 特殊な文字 のことを言います。
![スクリーンショット 2022-02-25 1.23.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422183/72f282cc-bbc2-bb72-b9b2-65658ab87bff.png)

上記の表にある記号の記述方法は【 \ 】または【 ¥ 】の後に 文字 や 記号 を記述しています。【 \ 】または【 ¥ 】の後に 文字 や 記号 を記述します。

この【 \ 】または【 ¥ 】のことを エスケープ記号 と呼び、【 \ + 文字】または【 ¥ + 文字】のことを 特殊文字 と呼びます。※ちなみに【 \ 】と【 ¥ 】は文字コードの関係で変化しますので、記述する際はどちらでも構わないとのことです。
またエスケープシーケンスを出力したい場合、特殊文字を置き換えて欲しいので、"ダブルクォート"で囲む必要があります。


## まとめ
【 ‘  ‘ 】'シングルクォート'は文字として出力するときに使用します。
【 ”  ” 】"ダブルクォート"は【変数】や【エスケープシーケンス】を展開するときに使用します。
参考URL:　https://www.php.net/manual/ja/language.types.string.php#language.types.string.syntax.single
Google cloud クライアントライブラリでやりがちなサービスアカウントの認証エラー

Cloud storageやBigqueryをpythonなどから操作するクライアントライブラリを使用する時に、下記のようなエラーに遭遇しました。

raise exceptions.DefaultCredentialsError(_HELP_MESSAGE)
google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, please see https://cloud.google.com/docs/authentication/getting-started


サービスアカウントの認証が原因のようです。そのためサービスアカウントの作成と、それにロール(権限みたいなものを)を与え、認証鍵のjsonファイルを作成します。

クライアントライブラリ使用時はこのjsonファイルを参照することで認証をパスします。

参考)
https://www.monotalk.xyz/blog/python-%E3%81%A6-google-cloud-storage-%E3%81%A8bigquery-%E3%82%92%E4%BD%BF%E3%81%86%E9%81%8E%E7%A8%8B%E3%81%A6%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC/

https://qiita.com/Hyperion13fleet/items/0e00f4070f623dacf92b
# 1. サービスアカウントの作成
https://cloud.google.com/docs/authentication/production?hl=ja を参考に以下の操作を行います。
リンク先の中段「サービス アカウントを作成する」以下の記載通りに作成すれば良いです。
# 2. 鍵の作成
1.で参照したリンク先の続きの記述を参考にサービスアカウントの鍵(jsonファイル)を作成します。
作成した鍵はクライアントライブラリを実行する環境(ローカルなど)にダウンロードしておきます。
# 3. サービスアカウントにロールを与える
Google cloud shellの左サイドメニューの「IAMと管理」を選択し下記画面でロールの追加を行います。今回はCloud StorageとBig Queryが使えるように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840215/41e91859-0bc6-0357-cfbd-93c2c69d8cd4.png)
# 4. 認証方法
shell上から鍵のある場所のpathを環境変数に追加する方法と、pythonから認証するパターンの2つがあります。

## 4.1 環境変数パターン
shell から以下のように打ちます。
```sh:
export GOOGLE_APPLICATION_CREDENTIALS="/鍵を置いた場所/[鍵のファイル名].json"
```

但しこれだとshellを立ち上げるたびに行う必要があります。（おそらく./bash_profileとかに書き込めば毎回打ち込む必要はないんだろうが）

## 4.2 pythonコード上で行うパターン
```python:
big_query_client = bigquery.Client.from_service_account_json(
   '/鍵を置いた場所/[鍵のファイル名].json') 
storage_client  = storage.Client.from_service_account_json(
   '/鍵を置いた場所/[鍵のファイル名].json')
```
として、それぞれのサービスのクライアントオブジェクトを作成します。
windowsにubuntuの仮想環境を作ってみた

<h1>まず仮想環境を作るソフトVirtualBoxをダウンロードしてインストールする

VirtualBoxとはアメリカのオラクルという会社の仮想環境をつくることができるフリーソフト。これを使うことでwindows上でubuntuやmac上でwindowsなどを仮想的に動かすことができる。

とりあえずVirtualBoxのホームページから最新の6.1.32のWindows hostsをダウンロードしてみる
![messageImage_1645708302154.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/c581833d-1e90-13b4-0092-9eb36fe6d0d1.jpeg)

なんかでたけどオッケーしておく![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/83ac3713-bf30-ec58-6521-24f37d095c89.png)
インストールできた。けど拡張パッケージもインストールしておいた方がいいらしい。USBメモリが仮想環境で使えるとか
それがVirtualBox Extension pack
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/cdede951-0a5e-c9f3-54f0-91dc8cd952e9.png)
こんなのが出るからインストールを押す
VirtualBoxのインストールは終了。
<h1>次に仮想マシンを設定していく

初めに新規を押して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/e6ecc4cf-042f-7d27-f8a8-0e59121f1ca7.png)
こんなのが出てくる。名前の欄にubuntuと入力したら勝手にタイプもバージョンも合わせてくれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/63b4917f-1c73-e9c0-de80-080e8238bf80.png)
次に仮想環境に割り当てるメモリを決める。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/7bb7f533-b91a-0465-50f6-015559ee5554.png)
なんか2GBの人が多かったから一緒にしといた
次はハードディスクで、仮想ハードディスクを作成するを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/9905dba4-5d48-0a92-a711-a06c928c9560.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/f48eb860-fc85-6cad-08e5-2de74c7e0f6a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/498667c4-77f5-1c47-8d4d-39918210ee87.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/e19a6a49-05a5-578d-3957-fdc58ee7cdfd.png)
これでVirtualBox側の設定は終わり
<h1>次に入れたいOSのisoファイルをダウンロードしてくる

ubuntuのホームページから入れたいバージョンを検索して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/9a55a75b-0cf6-e690-047c-b8b46f267f84.png)
ダウンロードできたらついに起動！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/b4402945-60d1-4347-4625-25ac3fd63093.png)
右下のファイルのアイコンをクリックして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/1b977398-f7d9-32aa-db49-93dbd1fc051c.png)
追加からさっきダウンロードしてきたisoファイルを指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/c137031f-9d3b-c306-4d07-65c597e58188.png)
あとは表示どおりに設定していけば終了！![VirtualBox_ubuntu 18.04_25_02_2022_00_14_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430631/5ae03590-a774-d8aa-06f5-23d1a1eeae35.png)
<h1>最後に

VirtualBoxのほかにVMwareというソフトも仮想環境をつくるのによく使用される。しかしVMwareにはスナップショット機能がないため今回はVirtualBoxを使って環境を作った。スナップショット機能とは環境を保存できる機能で、もし環境を壊してしまっても保存していた状態にすぐ戻ることができる。

参考文献
https://qiita.com/tarotaro1129/items/d7750e47574b0eca090f
https://slacknotebook.com/virtualbox-vmware-player-comparison-free-vm-tool/
https://invisiblepotato.com/virtualbox02/
https://eng-entrance.com/virtualbox-install
https://qiita.com/HirMtsd/items/225c20b77a7cd5194834
https://eng-entrance.com/vm-list
Quicksite上のVPC接続情報を削除or作成する権限は何か

Quicksiteから他アカウントのデータソースを参照しようとしました。
VPCピアリングを行い、Quicksite上にVPC接続情報を登録したまでは良かったのですが
あれ！？Quicksiteに作成したVPC接続情報が削除できない！
しかもQuicksiteのFullAccess権限を付与しても削除できない！
結局AWSサポートに問い合わせしてようやく解決したので備忘録として残します


# 前提
- QuicksiteとデータソースのAWSアカウントは違う
    - QuicksiteのAWSアカウントをQとする
    - 利用したいデータソースのAWSアカウントをAとする

# 結論
- Quicksite上に作成したVPC接続情報を削除するには、下記の権限が必要
    - ec2:DeleteNetworkInterface
    - quicksight:DeleteVPCConnection
- 上記の情報は<b>Quicksiteのドキュメントに記載なし</b>
- IAMポリシーの<b>ビジュアルエディタでは設定不可</b>
- ただしIAMポリシーのJSONを直接編集すれば設定できる

# やりたいこと
- Quicksiteから、他アカウントのデータソースを参照したい
- Quicksite上に設定したVPC接続情報を作成or削除したい

# やったこと
- アカウントQとアカウントAをVPCピアリングで接続（[こちら](https://dev.classmethod.jp/articles/quicksight-redshift-vpcpeering/)を参照ください)）
- IAMポリシーのJSONを直接編集し、下記権限を付与<br>（付与前に警告が表示されますが無視してください）

```text
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                -- 削除用 --
                "quicksight:DeleteVPCConnection",
                "ec2:DeleteNetworkInterface",
                -- 作成用 --
                "quicksight:GetVPCConnection",
                "quicksight:CreateVPCConnection",
                "ec2:CreateNetworkInterface"
            ],
            "Resource": "*"
        }
    ]
}
```

# 参考
[QuickSightから別アカウントにあるプライベートRedshiftに接続する(VPCピアリング編)](https://dev.classmethod.jp/articles/quicksight-redshift-vpcpeering/)
Lambdaの実行環境について(コールドスタートとウォームスタート)

### はじめに
* 昨年、awsブログにてOperating Lambdaシリーズの翻訳版が公開された。
* **Lambdaを使う開発者にとっては知っておくべきことが詰まったこのブログ**、3本から構成されています。今回はその内容から一部抜粋してLambdaのコールドスタートとウォームスタートについて取り上げまとめてみましたという記事です。

#### コールドスタートとレイテンシー、そしてウォームスタート
下記の図は、Lambdaの関数実行のrequestを受け取ってから、ハンドラ関数実行までの流れを表しています。
Lambdaは、Lambda APIを介して関数実行された時次のような動作をします。

1: S3バケットから実行するコードのダウンロードを行ったり、コンテナパッケージを使用している場合はECRよりダウンロードします。
2: 指定されたメモリ、ランタイム及び各種設定に基づいた環境を作成します。
3: Lambdaのハンドラ関数外の初期化コードを実行します。
4: Lambdaのハンドラ関数の実行

![スクリーンショット 2022-02-24 22.07.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/c3338240-7f8b-e32f-dcfe-5b10f63c0a3d.png)


* Lambdaにおける**コールドスタート**はこのコード準備と環境準備のステップです。
* lambdaがコールドスタートするのは有名だと思いますし、**課金対象もこのコールドスタートで起きる最初の環境準備は含まれません。**
 
![スクリーンショット 2022-02-24 22.14.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/c027a6fb-d0c9-4f47-217e-f3ede6e15ecc.png)


**実は、lambdaは必ずしもコールドスタートで始まるわけではありません。**
* **Lambdaの実行が完了した後、Lambdaは実行環境を不特定期間保持します。**
* その為、この時同じ関数にリクエストがあった場合、**Lambdaは環境の再利用を行うのです。**

これは、これはコールドスタートとは異なり、コールドスタートされていたステップ(コード準備と環境作成)が省略されるので、**ウォームスタート**となります。



#### 実行環境のライフサイクル

* **Lambdaは、関数実行後、その環境をすぐ破棄することなく保持します。**
* ただ、この環境破棄までの期間を指定することはできません。
* またLambdaのウォームスタートをパフォーマンスの最適化とし、ウォームスタート依存するのはよくありません。

=> なぜならば、LambdaがAZに跨って実行を管理するサービスだからです。
その為、実行されたLambdaがその後ウォームスタートすると思いきや、コールドスタートになるという可能性も考えられます。

=> さらに、Lambdaがスケールアップされる際に関数の追加が発生したとします。そうすると、その場合においても新たな実行環境の作成が行われるので、追加分の関数についてはコールドスタートになります。

=> また、コードの更新や、関数の設定変更等を行い新しいバージョンのコードのみが使用されるようエイリアス設定されている場合は、実行している既存の環境は破棄されます。この場合もコールドスタートになります。

**Lambdaを定常でウォームスタートされるために方法(EventBridgeを使い1分ごとに関数の呼び出しをpingで行う方法)もあるようだが、公式ブログ内ではこの方法だとコールドスタートを減らす保証がないことが記載されています。**

#### パフォーマンスの最適化
Lambdaにおける機能に**Provisioned Concurrency**があります。これを使用すると、コールドスタートの削減につながります。
**Provisioned Concurrency**の機能とは、事前に同時実行環境を準備しておく機能です。
準備される範囲としては、コードの準備、環境の作成、ハンドラ外の初期化コードの実行までを事前に構築実行しておきます。
これにより解決する課題は、2つで、初期リクエストに関して完全にコールドスタートとなりレイテンシーが大きくなる課題と、スパイクなリクエストが来た時にスケーリングが追いつかない課題です。
まあ、その分料金がProvisioned Concurrency料金 + リクエスト料金 + コンピューティング料金となるので、そこが注意点です。

![スクリーンショット 2022-02-24 23.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/c0bb6e77-c839-5261-c886-e779f9441930.png)


### 引用元
https://aws.amazon.com/jp/blogs/news/operating-lambda-performance-optimization-part-1/

https://aws.amazon.com/jp/blogs/news/operating-lambda-performance-optimization-part-2/

https://aws.amazon.com/jp/blogs/news/operating-lambda-performance-optimization-part-3/
Javaのクラスパス(classpath)の設定方法

クラスパスを設定する方法は下記の3つあります。
## 1 コマンドラインで指定する
```java
java -classpath C:\program
```
';'(セミコロン)区切りで複数のクラスパスを設定できます。
javaコマンドでは'*-classpath*'を'*-cp*'に省略可能です。
```java
java -cp C:\program1;C:\program2
```
## 2 OSの環境変数に設定する
```powershell:Windows
set CLASSPATH=C:\program1;C:\program2
```
```zsh:macOS
export CLASSPATH=~/program1;~/program2
```
```:linux
setenv CLASSPATH=/home/program
```
## 3 デフォルト(指定しない場合)
カレントディレクトリになります。
'*C:\program\sample*'で実行した場合は'*C:\program\sample*'がクラスパスになります。

### 参考文献
- https://docs.oracle.com/javase/jp/1.5.0/tooldocs/windows/classpath.html
- [スッキリわかるJava入門 第3版 スッキリわかるシリーズ](https://www.amazon.co.jp/dp/B07ZQWKL2Q/)
- https://www.k-cube.co.jp/wakaba/server/class_path.html
WidgetKitで天気予報アプリ作ってみた〜記事まとめ〜

## はじめに
この記事は**WidgetKitで天気予報アプリ作ってみた**シリーズで書いた記事のまとめです。

## 記事一覧
1.天気情報取得編

https://qiita.com/nkekisasa222/items/359192455b65fb60705d

2.位置情報取得 & 保存編

https://qiita.com/nkekisasa222/items/249240ad36128de05557

3.Widget Extension追加編

https://qiita.com/nkekisasa222/items/744754523172035cc9bf

4.タイムライン作成編

https://qiita.com/nkekisasa222/items/b22c98249330f3f5c459

5.View実装編

https://qiita.com/nkekisasa222/items/93991d64e8b5b5396b36

誰かの役に立てば幸いです！

## おしらせ
現在副業でiOSアプリ開発を募集しています。
ご依頼は[Twitter DM](https://twitter.com/ken_sasaki2)でお待ちしております。
![QR_615427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643372/4f8dff15-33fa-c042-44a3-b592f49c959c.png)
↓活動リンクはこちら↓
https://linktr.ee/sasaki.ken
CGI.escape

CGIモジュールのescapeメソッド

```
# @をエスケープ
>> CGI.escape('foo@example.com')
=> "foo%40example.com"
# 'とスペースと!をエスケープ
>> CGI.escape("Don't panic!")
=> "Don%27t+panic%21"
```
テストファイルでテスト用ユーザーのメールアドレスをエスケープできる
```
CGI.escape(user.email)
```
AWS Lambda Layersを使ったPythonライブラリーの追加

# はじめに

Lambda関数でサードパーティのライブラリーを使用したいときは、下記のいずれかの方法を使って、対象のライブラリーを追加する必要がある。
 - 追加したいライブラリーを含んだパッケージデプロイ
 - Lambda Layersを使って追加

今回は「**Lambda Layersを使って追加**」についてまとめていく。

# Lambda Layersを使った追加方法
## 環境
- Windows / Mac
- Dockerが使えること。
    - ここではDockerのインストール方法は省略するが、ローカルの場合はDocker Desktopを使うと簡単。
    - Linuxサーバー等にインストールする場合は下記記事記事を参照。
        - https://qiita.com/subretu/items/549bc720165004bca3c3
## やってみて分かったこと
- Layerにアップロードするライブラリーは、AmazonLinux環境で作成しないと読み取ってくれないことが分かった。
  - WindowsやMacのローカル環境で、pipを使ってインストールしたライブラリーをLayerに追加しても正常に読み取ってくれなかった。
  - 他のLinux環境では試していないので、もしかしたらそちらでも可能かもしれない（未検証）

- そこで、「docker-lambda」というLambda環境を構築できるDockerコンテナを利用してライブラリーを作成することでうまくいったので、次章ではその方法についてまとめていく。
    - docker-lambdaについては下記を参照。
        - https://github.com/lambci/docker-lambda
        - https://hub.docker.com/r/lambci/lambda/
## docker-lambdaを使ったライブラリーファイルの作成
- requirements.txtに必要なライブラリーを記載する。
- 下記コマンドを実行。
  - 初回だけイメージpullに時間がかかるが、2回目以降はしないので早くなる。
  - 作成するフォルダ名は「python」にしないといけないみたい。
    - これについては諸説あるみたいだが、「python」とするとうまくいった。
  - Pythonのバージョンは例として3.8とした。
    - どのバージョンをサポートしているかは上記に記載したURLを参照。

```docker
docker run --rm -v "$(PWD):/var/task" lambci/lambda:build-python3.8 pip install -r ./requirements.txt -t python/lib/python3.8/site-packages/
```

- カレントディレクトリに「python」フォルダができているのでzipファイルにする。

## Layerを追加
- Lambdaのページを開き、「レイヤー」で追加したいライブラリーを含んだレイヤーを作成する。
    - zipファイルが10Mを超える場合はS3経由のアップロードになるので注意すること。
- レイヤーを作成後は、Lambda関数の「レイヤーを追加」で対象のレイヤーを追加する。
    - 「ARNを指定」を選び、追加したレイヤーのARN貼り付ける。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264860/c9d6367f-bb7b-7982-e617-fb880285acb4.png)
- 正常にレイヤー追加されると、下記のように一覧に追加したレイヤーが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264860/48f26891-e9ab-c19f-839e-2f2933915fa0.png)
- その後は通常通り、```import XXXXX```でライブラリーをimportして使用することができる。
Rails いいね機能の非同期を実装する際の注意するべきポイント

いいねの非同期を行う際、何回かエラーでつまづいた。
そんな時に確認するべきポイントをまとめる！！

## 1.jQueryがちゃんと読み込まれているか

```Gemfile.
gem 'jquery-rails'
```
その後、bundle install　を忘れずに。

```app/assets/javascripts/application.js
//= require jquery
//= require rails-ujs
//= require jquery_ujs
```


```webpacker/environment.js
const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)

module.exports = environment
```

```app/javascript/packs/application.js
require('jquery')
```
jQueryはこの辺り。。

## 2.link_toにremote:true

```ruby:_like_button.html.erb
= link_to photo_like_path(@photo), method: :post, remote: true do 
```
```ruby:_lunike_button.html.erb
= link_to photo_like_path(@photo), method: :delete, remote: true do 
```
ajax用のviewファイル内のlink_toにremote: true を追加。
HTMLリクエストではなく、JavaScriptのリクエストがコントローラに送られる。

HTML
→画面にリダイレクトする(ページを読み込む)
JavaScript
→いいね部分のみの更新(ページ読み込みなし)


## 3.renderでテンプレートを読み込む&idで変更箇所に名前をつける

```ruby
<div id="like-button-<%= @photo.id %>">
  <% if current_user.likes.exists?(photo_id: @photo.id) %>
    <%= render 'likes/unlike_button', photo: @photo %>
  <% else %>
    <%= render 'likes/like_button', photo: @photo %>
  <% end %>
 </div>
```


## 4.js.erbファイル

```javascript:create.js.erb
$("#like-button-<%= @photo.id %>").html("<%= j(render 'unlike_button', photo: @photo) %>")
```
```javascript:destroy.js.erb
$("#like-button-<%= @photo.id %>").html("<%= j(render 'like_button', photo: @photo) %>")
```

以上。抜かりないよう。

# 参考

https://qiita.com/hapiblog2020/items/3ba7e7edc02f01d987b9
https://qiita.com/masahisa/items/eaacb0c3b82f4a11fc13
includesを使ってSQLの発行件数を減らそう（N+1問題）

## SQLの発行件数が多いと指摘を受ける。

業務にて、ある一覧画面を作成していたところ、
自分が書いたソースをみた先輩から、
「この一覧画面のSQLの発行件数が多すぎる。ちょっと減らしてみて。」とご指摘を受けました。

SQLの発行件数が多いのはN+1問題が起きていたことが原因で、
includesを使用することで
事象を解決できたのでアウトプットしてみようと思います。

## N+1問題とは
必要以上にSQLが実行されて、パフォーマンスが低下する問題。
今回指摘を受けた画面では、
ログを見ると、他のテーブルの情報を取得するため何度もSQLが発行されていました。

## includesとは

includesメソッドは、関連している複数のテーブルからデータをあらかじめ取得するメソッドです。

N+1問題を解決させるためには、
都度SQLを発行させるのではなく、あらかじめデータをすべて取得しておくことで解決することができます。

例えば、
UserクラスとPostクラスがあって、
投稿からユーザ名を取得する処理があったとします。

```rb
# models/user.rb
class User < ApplicationRecord
  has_many :posts
end

# models/post.rb
class Post < ApplicationRecord
  belongs_to :user
end
```
```rb
# 投稿の一覧を取得する
posts = Post.all
posts.each do |post|
  p post.user.name
end
```

上記のメソッドを実行すると、
投稿の数だけSQL文が発行されてしまい、
効率が悪いです。


そこで、下記のようにincludesメソッドを使用して、
あらかじめ投稿に関するユーザ情報を最初にすべて取得します。
そうすることで、
投稿がいくらあってもSQLの発行を一度で済ますことが可能です。

```rb
# 投稿と、投稿に関連したユーザ情報を取得する。
posts = Post.includes(:user)

posts.each do |post|
  p post.user.name
end

```

### 余談
※SQLの発行件数は画面に対してAlt+Pを押下したり、
　ログを見ることで確認できます。


参考記事：
https://techacademy.jp/magazine/22031
https://qiita.com/south37/items/b2c81932756d2cd84d7d
DockerfileのCMDはどこをみて書くのか

## Next.jsのDockerfileの例
```dockerfile
FROM node:lts AS development

ENV CI=true
ENV PORT=3000

WORKDIR /sample
COPY package.json /sample/package.json
COPY package-lock.json /sample/package-lock.json
RUN npm install
RUN npm ci
COPY . /sample
RUN npm run build

CMD [ "npm", "run" , "start" ]
```
`CMD [ "npm", "run" , "start" ]`

これはどこをみて確認するのか。
package.jsonを見る。
```json
{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"　//ここ
  },
 ...
}
```
【Rails】assert_matchメソッド

正規表現で文字列をテスト。

assert_match( regexp, string, [msg] )

stringは正規表現 (regexp) にマッチすると主張する。

```rb
assert_match 'foo', 'foobar'      # true
assert_match 'baz', 'foobar'      # false
assert_match /\w+/, 'foobar'      # true
assert_match /\w+/, '$#!*+@'      # false
```

[Rubular](https://rubular.com/)
登録が切れたSigfoxモジュールの再登録方法

<h2>登録が切れたSigfoxモジュールは・・・</h2>
Sigfoxモジュールには通常デバイスIDとPADというものを
Sigfoxのサイトで登録するのだが一度有効期限が切れたデバイスIDは
新しいPADを発行しなければいけない。

しかし新しく発行されたPADがわからない場合は、
そのSigfoxモジュールは2度と使えないことが今回わかった。

みなさんもPADの管理は必ずしましょう。

PADが切れた場合は、新しいPADが発行されるのでその新しいPADが
わからなくなった場合には使えなくなるみたいです。
プロパティとしてのクラス(Table Per Type編)０

EntityFrameworkで設計していると
「この項目、外部からはプロパティとして動作してほしいけど、内部的には別クラスのインスタンスとして実装したいな」と考えることがある。
そこでIDと値だけのジェネリックインターフェイスを定義してみる。

``` C#:IClassAsProperty.cs
    public interface IClassAsProperty<T> where T : struct
    {
        public T value { get; set; }
    }
```
でクラスをプロパティとして扱うにはジェネリック静的プロパティを定義する。
``` C#:ClassAsProperty.cs
    public static class ClassAsProperty
    {

        public static T? GetmethodT<T, T2>(ref T2 TargetPoperty) where T : struct where T2 : IClassAsProperty<T>
        {
            return TargetPoperty?.value;
        }

        public static void setMetgidT<T, T2>(T value, ref T2 TargetProperty) where T : struct where T2 : IClassAsProperty<T>, new()
        {
            if (TargetProperty is null)
            { TargetProperty = new T2(); }
            TargetProperty.value = value;
        }
    }
```
何をしているかというと
getメソッド時にはnull許容型にしておいてnullであればnullを返すようにする。
setメソッド時にはnullであれば新規インスタンスを生成して値を格納するとする。
実際の使い方は次回で
【iOS】AppleSilicon環境(MacOS)でiOSアプリを実行した時にMacで実行しているか判定する

# iOSアプリをAppleSilicon環境(MacOS)で実行した時の判定
以下質問にて@nukka123さんに回答いただきました。
https://qiita.com/Howasuto/questions/3fc5ba81ea6240470ac4

以下のコードでAppleSilicon環境での実行時の判定を可能にします。
またUIDevice.current.userInterfaceIdiomでの判定基準はあくまでユーザーインターフェースのため、AppleSilicon環境で実行した際にはiPad用のインターフェースが適応されるため、判定結果としてはiPadとして判定されます。

```swift
if ProcessInfo.processInfo.isiOSAppOnMac {
   // iOSアプリをMacで実行時
   print("iOSAppOnMac")
} else if UIDevice.current.userInterfaceIdiom == .phone {
   // iPhone用インターフェースで実行時
   print("iPhone")
} else if UIDevice.current.userInterfaceIdiom == .pad {
   // iPad用インターフェースで実行時
   print("iPad")
} else if UIDevice.current.userInterfaceIdiom == .mac {
   // Mac用インターフェースで実行時
   print("Mac")
}
```

# 参考
https://developer.apple.com/documentation/foundation/processinfo/3608556-isiosapponmac
https://developer.apple.com/documentation/uikit/mac_catalyst/choosing_a_user_interface_idiom_for_your_mac_app/
[AtCoder 初心者] Rubyで競プロ!!! 標準入力

# はじめに #
AtCoderを始めたので、自分用の整理、メモとして投稿します。
間違えている箇所があれば指摘して下さると幸いです!!!!!!!!!!!!

# 1つの要素を取得 #

```ruby:test.rb
A = gets.chomp
p A
```
例: 1を入力

```
-標準入力-
1
```

```
-出力-
"1"
``` 

・chompメソッドは文字列末尾の改行文字 \n を削除するメソッド。
・getsメソッドで入力した値は、文字列(Stringクラス)で返される。**数値(Integerクラス)として扱いたい場合は、to_iメソッドを使う。** to_iメソッドは **「整数と見なせない文字があればそこまでを変換対象とする」** ため、改行文字 \n は変換対象になる。ゆえに、chompメソッドは不要。

```ruby:test.rb
A = gets.to_i
B = gets

p A
p B
```

例: Aに1、Bに2を入力

```
-標準入力-
1
2
```

```
-出力-
1
"2\n"
``` 

# 1行の複数の要素を取得 #

```ruby:test.rb
A = gets.spilt(" ")
p A
```

例: 1 2 3 を入力

```
-標準入力-
1 2 3
```

```
-出力-
["1", "2", "3"]
``` 

・splitメソッドは引数に従って、文字列を分割し、分割された文字列を要素とする配列をつくる。今回は空白ごとに分割している。**引数を指定しない場合は、デフォルトで空白で分割する。**

・split(" ")のとき(引数を指定しないとき)、**先頭と末尾の空白を除いたうえで、空白で分割する**。また、入力した文字列末尾の改行文字 \n は空白と見なせるから、ここではchompメソッドは不要。



**!!!配列の要素を数値(Integerクラス)にしたいとき!!!**
配列(arrayクラス)に、to_iメソッドは使えない!!!この場合はmapメソッドを使う。
-mapメソッド-
ブロック内の処理を配列の要素それぞれに行い、その結果を返すメソッドのこと。

```ruby:test.rb
A = gets.spilt.map{|n| n.to_i}
p A
```

```
-標準入力-
1 2 3
```

```
-出力-
[1, 2, 3]
``` 

ちなみに、下記のように省略できる。

```ruby:test.rb
A = gets.spilt.map(&:to_i)
p A
```

# 二次元配列 #
H行、W列の行列を扱う問題で用いる。
例: 3行3列の行列

```ruby:test.rb
H, W = gets.split.map(&:to_i)
A = Array.new(H) {gets.split.map(&:to_i)}
p A
```

```
-標準入力-
3 3
1 2 3
4 5 6
7 8 9
```

```
-出力-
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
``` 

・A = Array.new(size) で要素の数を指定して、新しい配列Aを作成している。また、{　}内の処理を配列の各要素に行っている。Array.new(size) {　} という記法なため、mapメソッドは不要。

ちなみに、下記のようにすると

```ruby:test.rb
H, W = gets.split.map(&:to_i)
A = Array.new(H) {gets.split.map(&:to_i)}
A.each{|row| puts row.join(" ")}
```

```
-標準入力-
3 3
1 2 3
4 5 6
7 8 9
```

```
-出力-
1 2 3
4 5 6
7 8 9
```

・joinメソッドは、配列の要素を引数で結合して、1つの文字列をつくるメソッド。今回は配列Aの要素である配列の要素(配列Aの要素[1,2,3]の要素)を空白で結合している。

**!!!!個人的には3行目の puts がポイント!!!!**
p、print、putsメソッドそれぞれの出力後の改行について

-pメソッド-
出力後に改行される

-printメソッド-
出力後に改行されない

-pメソッド-
出力後に改行される

```ruby:test.rb
a = 1
p a
print a
puts a
```

```
-出力-
1
11
```

これらのことから、putsであるから綺麗な行列として出力されるといえる。

# おわりに #
実はQiita初投稿です~てへへ
少しでも誰かのお役に立てれば嬉しいです!!
今後もRubyや競プロについて投稿していこうと思います。
クエリパラメータ

# クエリパラメータとは
クエリパラメータとは、URLの末尾で疑問符「?」に続けてキーと値のペアを記述したもの。

```
.../edit?email=foo%40example.com
```

上記の場合、?email=foo%40example.comがクエリパラメータ。

? からクエリパラメータを示して、emailがキー（パラメータ）としてfoo%40example.comを指定している。


```
?キー（パラメータ）=キー（パラメータ）の値
```

#### %40はURLエンコード

値の表記に使用できない文字を含めたい場合は、「URLエンコード」あるいは「パーセントエンコーディング」と呼ばれる方式で安全な文字列に変換。
これは「エスケープ」と呼ばれる手法で、通常URLでは扱えない文字を扱えるようにする。

<br>

＠はURLエンコードだと%40となる。

<br>

[URLエンコード変換ツール](https://tech-unlimited.com/urlencode.html)


URLのクエリパラメータではキーと値ペアのを複数使うこともでき、その場合は&でつなぐ。

```
.../edit?name=Foo%20Bar&email=foo%40example.com
```
<body>要素と<html>要素に対するbackgroundの振る舞い

&lt;body>要素に背景色を設定すると、&lt;body>の高さがブラウザのウインドウより小さくても背景色は下図左側のようにウインドウ全体に拡がります。これ、実は&lt;html>要素に背景色が設定されていないからだったんですね。 実際、&lt;html>要素にも`transparent`以外の色を`background-color`に設定してやると、&lt;body>の矩形の外側はその色で塗り潰され、&lt;body>の背景色は矩形の中だけになります（図右）。

![fig21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/c87e4348-cebf-e569-4835-8e06a80d6cbf.png)

CSSで`background`の振る舞いは、&lt;html>要素と&lt;body>要素に対してはちょっと特殊で、CSS仕様書のこちらに説明があります。
[CSS Backgrounds and Borders Module Level 3](https://www.w3.org/TR/css-backgrounds-3/)
[2.11. Backgrounds of Special Elements](https://www.w3.org/TR/css-backgrounds-3/#special-backgrounds)
[2.11.2. The Canvas Background and the HTML <body> Element](https://www.w3.org/TR/css-backgrounds-3/#body-background)

仕様に書かれた動作を理解するため、サンプルを作りました。

サンプルのコード； [https://codepen.io/kaz_hashimoto/pen/bGYrRBm](https://codepen.io/kaz_hashimoto/pen/bGYrRBm)

### 1. &lt;body>要素にのみ背景画像が設定されている場合
まずは&lt;body>要素にのみ背景画像を設定してみます。赤い枠の矩形が&lt;html>要素、その内側の青い破線の矩形が&lt;body>要素です。このサンプルでは、&lt;html>要素自身とそのコンテンツが描画される平面 &mdash;[キャンバス](https://www.w3.org/TR/CSS2/intro.html#the-canvas)とを視覚的に区別するため、&lt;html>と&lt;body>の`width`と`height`をブラウザのウインドウ内側の寸法より小さく設定してあります。真ん中に「body」と書かれた青いタイル１個が&lt;body>要素に設定した背景画像１ピースです。
![fig3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/7fb2251e-b696-9d5a-9d13-60d5f878d3d9.png)
このケースでは背景画像が&lt;body>の矩形を越えてキャンバスの縦横方向に繰り返し配置されて拡がり、ウインドウ全体に敷き詰められました。

ここで、`background-position`は&lt;html>の矩形に対する相対位置になります。つまり、グレーの円の位置が(0%, 0%)すなわち(left, top)です。ウインドウや&lt;body>の左上からの相対ではありません。

### 2. &lt;html>要素にのみ背景画像が設定されている場合
次に、&lt;html>要素にのみ背景画像を設定してみます。真ん中に「html」と書かれたグレーのタイル１個が&lt;html>要素に設定した背景画像１ピースです。
![fig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/c129b1b0-3877-7472-5f18-8054e27b6cf0.png)

このケースも１と同様に、背景画像が&lt;html>の矩形を越えて[キャンバス](https://www.w3.org/TR/CSS2/intro.html#the-canvas)に拡がり、ウインドウ全体に敷き詰められました。`background-position`は１と同様、&lt;html>の矩形に対する相対位置になります。

### 3.  &lt;html>要素と&lt;body>要素の両方に背景画像が設定されている場合
では、&lt;html>要素にも&lt;body>要素にも背景画像を設定するとどうなるでしょうか？（下図）
![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/9864496e-0322-ff57-cd76-df354b83fb08.png)
この場合は、&lt;body>要素の背景画像は&lt;body>の矩形に閉じて敷かれ、`background-position`は&lt;body>の矩形に対する相対位置になります。一方、&lt;html>要素の背景画像はキャンバスの背景にも拡張されて、`background-position`は&lt;html>の矩形に対する相対位置です。

冒頭の図右側に示した状態は、上の説明で背景画像を`background-color`に当てはめたものに相当することがわかります。
SalesforceオーケストレータフローでレコードIdを取得する方法

ハマったのでメモ

フローではrecordIdを入力変数に指定すれば表示しているレコードのIdを取得できる。
https://help.salesforce.com/s/articleView?id=sf.flow_actions_considerations.htm&language=ja&r=https%3A%2F%2Fwww.google.com%2F&type=5

オーケストレータフローを使う場合、オーケストレータ側から画面フローへrecordIdを渡してあげる必要があるのでちょっと注意が必要。

## 操作手順
画面フローでrecordId変数を作成
その際に「入力で使用可能」「出力で使用可能」にチェックを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/57387090-fcb9-eaa7-3c52-c8861f00ac9f.png)

テスト用に画面フローにrecordIdの値を表示するためのコンポーネントを配置
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/2a43a414-a6a4-face-f454-b6a5b20a7234.png)

オーケストレータフローで上記で作成した画面フローを選択
「入力値を設定」にレコードIdのグローバル変数を渡す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/e46817ef-3bcc-4724-1142-40eabedd2ae5.png)

「レコードID」にもレコードIdのグローバル変数を渡す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/462c53e4-e065-26f3-8637-8d1123183e3d.png)

保存＆有効化

オーケストレータをレコード詳細ページに配置
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/686cff81-9e0a-75df-7bfe-d1e76d4fb0e0.png)

レコードを開く
レコードIdが画面フローに渡っていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/7e033996-e751-1a7b-0432-667451207c0f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/8f5177f6-5ca5-95f8-826d-92bf241cf290.png)

以上！
LinqPad: CSV などのテキストを読み書きする場合

# 背景
CSV や Text 系ファイルが巨大になると VS で処理したりする。
とはいえ、簡単にやるなら LinqPad ですよね、ってことでのメモ

# 環境
- LinqPad 7 (5 以降で対応）

# 概要
- ドライバー使った読み込み
- 書き込みは不可なので、Util で

# CSV/TSV/Text/Log 用ドライバー
## インストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/c3465724-e9b6-aa8c-f1cd-4257ee85d9f5.png)

## 使い方
読み込みたいファイル、若しくはフォルダを直接ドラッグ＆ドロップしてやって、OK でおしまい
色々設定はあるので、よしなに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/e1b1a714-53b2-5f43-8b58-09f1c03428ec.png)

フォルダの場合、以下のように同一形式はまとめてくれるので便利
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/4584228e-647a-5836-000b-c33912ae46a9.png)

## あとは、見たいファイルを適当に処理するだけ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/515ce2a1-acbc-fd62-08fc-829eee72acbe.png)

Linq で適当に書くだけなので、データ確認するのはすごく楽。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/c7f6afe8-7799-0c91-ba74-9952afd58657.png)

## CSV には出力されてるのに、最新が見えないんだけど
キャッシュが効いてるので、用途によってはキャッシュを殺しましょう
![2022-02-25_11h08_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/b0a318a2-aefa-3f41-689b-768a8999e5d4.png)


### InteliSence が欲しくなったら Pro を購入しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/c0e6a111-ccc5-4860-819b-3bdf694143e2.png)

https://www.linqpad.net/Purchase.aspx#Autocompletion



# 更新したくなった場合の書き込みは？
SaveChanges() は使えない。

ずっとこんな感じなので、Util.writeCsv で。
[Known Issues](https://github.com/i2van/CsvLINQPadDriver#known-issues) 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/7989517e-dfa7-59b8-4d31-d16521084beb.png)

## WriteCsv の例
> Util.WriteCsv({dataTable}, {filePath});

ってだけ。
Flush() のさせ方が不明なので、書き込まれるまで少々待つ必要がありそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/87b87bb6-6421-805a-97e0-a44e8b3ea18f.png)



# 参考
https://github.com/i2van/CsvLINQPadDriver

# あとがき
bash 系で大量に CSV 処理する場合、以下なんかも

https://www.nysol.jp/
練馬区の区内感染者数累計データ詳細のPDFをCSV変換

pdfplumberだと変換に4分ぐらいかかるが、pdftotextだと数秒で完了


# pdfplumber
```python
import pathlib
import re
from urllib.parse import urljoin

import pandas as pd
import pdfplumber
import requests
from bs4 import BeautifulSoup

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
}


def fetch_soup(url, parser="html.parser"):

    r = requests.get(url, headers=headers)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, parser)

    return soup


def fetch_file(url, dir="."):

    p = pathlib.Path(dir, pathlib.PurePath(url).name)
    p.parent.mkdir(parents=True, exist_ok=True)

    r = requests.get(url)
    r.raise_for_status()

    with p.open(mode="wb") as fw:
        fw.write(r.content)
    return p


url = "https://www.city.nerima.tokyo.jp/hokenfukushi/hoken/kansensho/2019-nCoV/ruikei.html"

soup = fetch_soup(url)

tag = soup.find("a", text=re.compile("^区内感染者数累計データ詳細"))

link = urljoin(url, tag.get("href"))

p = fetch_file(link)


with pdfplumber.open(str(p)) as pdf:

    dfs = []

    for page in pdf.pages:

        table = page.extract_table()

        df_tmp = pd.DataFrame(table)

        dfs.append(df_tmp)

data = pd.concat(dfs).values

df = pd.DataFrame(data[1:], columns=data[0]).set_index("NO.")

df.to_csv("result.csv", encoding="utf_8_sig")
```

# pdftotext

shellでのスクレイピングがわからないためPDFからCSV変換のみ
```
pdftotext -layout data.pdf - | awk 'BEGIN { OFS=","; print "No,公表日,年代,性別,退院等"; } NR>=6 { print $1, $2, $3, $4, $5 }' > result.csv
```