OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】ActionMailerで作成したメールを簡単にプレビューで見る方法

## 環境
Rails 6.0.1
Ruby 2.6.3
PostgreSQL 11.16

## プレビューで見る方法

```ruby
class UserRegisterMailer < ApplicationMailer
  default from: 'info@example.com'

  def registered_email(user)
    @name = user.name
    @email = user.email

    mail to: @email, subject: 'ご登録ありがとうございます'
  end
end
```

```UserRegisterMailer```なら```UserRegisterMailerPreview```という名前で```Preview```を作成。
```Preview```では```registered_email```メソッドに引数を渡せないので注意。
```ruby
class UserRegisterMailerPreview < ActionMailer::Preview
  def registered_email
    user = User.first
    @name = user.name
    @email = user.email

    UserRegisterMailer.registered_email(user)
  end
end
```

```http://localhost:3000/rails/mailers/user_register_mailer/registered_email```
にアクセスするとプレビューが表示される。

## 参考

https://railsguides.jp/action_mailer_basics.html
requestsでアクセスできないサイトにアクセスする方法

# 結論
1. ブラウザ自動化ツール (Selenium等) を使う
2. ブロックを回避できるcliのツールを使う


# 問題
- いつものようにPythonのrequestsでアクセスしようとすると `SSLError` が発生
  - `requests.exceptions.SSLError: HTTPSConnectionPool(host='ss148.litvp.com', port=443): Max retries exceeded with url:`
- ブラウザからはアクセスできる
- cloudflareのサイトが多い


# なぜアクセスできないのか
- ボット対策
- TLSフィンガープリントなどを使ってクライアントを見分けている
- 詳細は以下の記事が参考になる
  - https://github.com/lwthiker/curl-impersonate/blob/main/README.md


# 1. ブラウザ自動化ツールを使う
- メリット
  - 実際のブラウザを動かすため、実環境と同様にアクセスできる
- デメリット
  - その分、動作速度が遅いことやメモリ使用量が多いことなどのデメリットがある


# 2. ブロックを回避できるcliのツールを使う
- メリット
  - 必要なアクセスのみを行うため、ブラウザ自動化ツールとくらべて軽量
- デメリット
  - cliのツールなのでPythonなどで使うときには、subprocessなどでコマンドを実行する必要がある
- 例
  - Windows: `Invoke-WebRequest`, wslで `curl-impersonate`
  - Mac, Linux: `curl-impersonate`


# curl-impersonateのラッパー
エスケープがあたりが怪しい。あくまで参考に
```python
import os
import subprocess

def get_from_curl_impersonate(url, headers=None):
    # -s 途中経過の非表示
    # -L リダイレクトを追跡する (Locationヘッダ)
    if os.name == 'nt':
        dirpath = '~/scripts/others/curl-impersonate/'
        replaced_url = url.replace('"', '""')
        command = f"wsl {dirpath}curl_chrome104 -s -L \"{replaced_url}\""
    elif os.name == 'posix':
        replaced_url = url.replace('"', '\\"')
        command = f'curl_chrome104 -s -L "{replaced_url}"'
    else:
        raise OSError('このOSにはまだ対応していません')

    if headers is not None:
        headers_str = ''
        for key, value in headers.items():
            if os.name == 'nt':
                formatted_key = key.replace('"', '""')
                formatted_value = value.replace('"', '""')
                headers_str += f"-H \"{formatted_key}: {formatted_value}\" "
            else:
                formatted_key = key.replace('"', '\\"')
                formatted_value = value.replace('"', '\\"')
                headers_str += f'-H "{formatted_key}: {formatted_value}" '
        command += f" {headers_str}"

    result = subprocess.run(command, shell=True, capture_output=True)
    html_str = result.stdout.decode()

    if result.stderr is not None and result.stderr != b'':
        print(result.stderr.decode(), file=sys.stderr)

    return html_str
```
【Datadog】Redis の mem.fragmentation_ratio 監視

## はじめに
Datadog での Redis の mem.fragmentation_ratio 監視について書きます。

## mem_fragmentation_ratio とは？
OSから見たメモリ使用量 (used_memory_rss) と Redis によって割り当てられたメモリ (used_memory) の比率になります。

- mem_fragmentation_ratio を求めるための式

```
mem_fragmentation_ratio = used_memory_rss / used_memory
```

## 監視について
`mem_fragmentation_ratio` は、100%〜150% の間が望ましい。

### 150% を上回った場合
- 著しいメモリの断片化を表している
- Redisインスタンスは、要求された物理メモリの150%を消費している状態

#### 対処方法
- インスタンスの再起動を実施する

### 100% を下回った場合
- Redisインスタンスは、システムで使用できるメモリよりも多くのメモリを必要としている状態
- メモリが足りずに swap が発生している状態

#### 対処方法
- インスタンスのメモリ増設
- Redisのメモリ使用量を減らす


## 参考
- [Metric to alert on: mem_fragmentation_ratio](https://www.datadoghq.com/ja/blog/how-to-monitor-redis-performance-metrics/#metric-to-alert-on-mem_fragmentation_ratio)
- [Redis](https://docs.datadoghq.com/integrations/redisdb/?tab=host)
分割された or サイズの大きいテキストファイルを扱う際に便利なコマンド

### less
- 閲覧中の行数やパーセンテージを確認したい
  - コマンド実行時にmオプション(パーセンテージのみ)またはMオプション
  - ファイル閲覧時に`:f`
- 〇行後に移動
  - 行数を入力してEnter
- 〇行目に移動 
  - 〇(行数)g
- 検索パターンに一致する行のみ表示
   - `&検索パターン` 
- 日本語が文字化けする場合は`export LESSCHARSET=utf-8`

### grep
-  行数付きで結果を出力
    - nオプション
- ワイルドカードを使用して複数ファイルをgrepする際、結果にファイル名を表示しない
    - hオプション
- ワイルドカードを使用して複数ファイルをgrepする際、ファイル名のみ表示
    - lオプション
- ワイルドカードを使用して複数ファイルをgrepする際、該当しなかったファイル名のみ表示
    - Lオプション
- 検索結果の前後数行も表示したい
    - 後の〇行 `-A 〇(行数)`
    - 前の〇行 `-B 〇(行数)`
    - 前後〇行 `-〇(行数)`
    - 前後2行  `-C`
- バイナリファイルでないのに`Binary file "ファイル名" matches`というメッセージがでてきた
  - aオプション

### その他
#### ファイルを結合して出力
```shell
cat 入力元ファイル名(複数可、ワイルドカード可) > 出力先ファイル名
```

#### 行番号を指定してファイルに切り出し
下記はファイルの10行目から20行目を切り出す例。
```shell
sed -n 10,20p 入力元ファイル名 > 出力先ファイル名
```
企業活動と組織のカタチ

# ４大資源
人、モノ、金、情報を４大資源と言う。
### 人
企業を支える人材、社員を指す。

### モノ
商品、工場、オフィス、パソコン、電話機など仕事に必要なもの

### 金
人を雇うのもモノを生み出すのもお金が必要。

### 情報
顧客情報、営業手法、市場調査の結果など企業が正確な判断を下すために必要なデータのこと。

# 代表的な組織形態と特徴
### 職能別組織
開発営業といった```仕事の種類・職能によって部門分け```する組織構成。

### 事業部制組織
```取り扱う製品や市場ごとに、独立性を持った事業部```を設ける組織構成です。
事業部単位で```必要な職能部門を保つため、各々が独立した形```で経営活動を行うことができます。

### プロジェクト組織
プロジェクトごとに、```各部門から必要な技術や経験の保有者を選抜して、適宜チーム編成```を行う組織形態

### マトリックス組織
事業部と職能別など、```２系統の所属をマス目状に組み合わせた組織```です。```命令系統が複数できてしまう```ため、混乱を生じることがある。

# CEOとCIO
## CEO（最高経営責任者）
```株主の信任により、経営の責任者として決定権を委任された存在。```
```企業戦略の策定や経営方針の決定```など、```企業経営における意思決定の責任```を負う。

## CIO（最高情報責任者）
```情報システム戦略を統括する最高責任者。```
```経営戦略に基づいた情報システム戦略の策定```と、その実現に関する責任を負う。
Python3 標準入力を辞書にする方法

先日、paizaラーニングのレベルアップ問題集で、連想配列の問題を解いていたときにでた疑問をまとめました。
https://paiza.jp/works/mondai/query_primer/query_primer__map_normal
（この練習問題の自分のコードも最後に載せてあります。）

### python3 で　標準入力を辞書の形にする方法

まず、リストを作成し、そこに要素を順に入れていきます。
```Python
list_dic = []

for i in range(N):
    list_dic.append(input().split())
```
そして、```dict()```を使って辞書にします。

```Python
dictionary = dict(list_dic)
```


例：
標準入力
```
1 Sin
2 Sakura
3 Kayo
4 Yui
```

コード
```Python
mylist=[]

for i in range(N):
    mylist.append(input().split())

mydict=dict(mylist)
```

出力
```
{'1': 'Sin', '2': 'Sakura', '3': 'Kayo', '4': 'Yui'}
```


参照:https://azuminow.com/python-dictionary


##### 練習問題の自分の解答
```Python
# coding: utf-8
# 自分の得意な言語で
# Let's チャレンジ！！
N,K = map(int,input().split())

mylist=[]

for i in range(N):
    mylist.append(input().split())
    mylist[i][0]=int(mylist[i][0])

mydict=dict(mylist)

#print(mydict)

order = []
for i in range(K):
    order.append(input().split())
    
#print(order)

for j in range(K):
    if order[j][0] == 'leave':
        mydict[int(order[j][1])] = ''
    elif order[j][0] == 'call':
        print(mydict[int(order[j][1])])
    else:
        mydict[int(order[j][1])] = order[j][2]
```
【Rails】マイグレーション時に既存データも一緒に更新する方法

## 環境
Rails 6.0.1
Ruby 2.6.3
PostgreSQL 11.16

## 前提

```Category```モデルに```code```というカラムがあったが```name```を追加したい
その際、下記の既存データの```code```の値を```name```カラムに更新したい

```ruby
Category.seed(:id,
  { id: 1, code: Category.code.ruby.value },
  { id: 2, code: Category.code.rails.value },
  { id: 3, code: Category.code.php.value },
  { id: 4, code: Category.code.laravel.value },
  { id: 5, code: Category.code.js.value },
  { id: 6, code: Category.code.java.value },
  { id: 7, code: Category.code.kotlin.value },
  { id: 8, code: Category.code.sql.value },
)
```

## migrationファイルの書き方

```name```カラムを追加する際に既存データの値を更新する処理を一緒に書く。

```ruby
class AddNameColumnToCategory < ActiveRecord::Migration[6.0]
    def up
      add_column :categories, :name, :string, null: false, default: false
    
      Category.all.each do |category|
        category.update!(name: category.code)
      end
    end
    
    def down
      remove_column :categories, :name, :string
    end
end
```
git remoteの更新方法について

# クラウド上のgit管理ツールのURLが変更になった！！

みなさまこういうときないでしょうか？？プロジェクトの名前が変更になったり、管理するgithub上のディレクトリーが変更になったり、さまざまなケースがあるかと思います。

そういう時にpushができないとなりましたのでメモ書きとして対処法を書いておきます。
## 対象方法
やることは以下の手順
1: git remote -vで現在のorigin等々のURLを確認する
2: URLだけ変更の場合は、git remote set-url origin <URL>を行い、URLだあけを変更する
3: いつも通りpushする（新たに認証をしなければいけないかも。。。）

だけです！！

簡単なのでお試しあれ！！
所有権を要求されても渡せないときの安全な対処法

# 要約

- Rustで開発している上で所有権が渡せなくて困るときに、可変参照を取れるなら安全に回避するすべがある。
- でもライブラリを作るときは使えなかった所有権を返すようなAPIが望ましい。

# 所有権で困る
Rustで開発していると所有権で困ることがあります。
自分は外部crateを使っているときに所有権を要求されて渡せなくて困りました。

[clap-serde](https://github.com/aobatact/clap-serde)なるライブラリを書いてたときにあたった問題として、
- clapは[`Command::mut_arg`](https://docs.rs/serde/latest/serde/de/trait.SeqAccess.html#tymethod.next_element_seed)で`Command`の所有権を要求される。(引数が`&mut self`でなくて`self`である)
- serdeは[`de::SeqAccess::next_element_seed`](`https://docs.rs/serde/latest/serde/de/trait.SeqAccess.html#tymethod.next_element_seed`)ではseedに所有権を渡すが残りがないと帰って来ない。
  - 残りがあれば渡した構造体が帰ってくるのでそのままそっちのリソースを握ればいいが、なければ`Option::None`が帰ってしまう。
```rust
let seed = Seed::new();
loop {
    let new_seed : Option<Seed> = seq.next_element_seed(seed)?;
    // このあとseedにnew_seedを入れて更新したいが、
    // OptionなのでNoneのときにもとのデータが消えてしまう
}
seed//返り値
```
- Seedに`Command`をラップしたものを渡してデシリアライズ中に`mut_arg`に所有権を渡したいが残りがない状態で渡してしまうと、`Command`自体の所有権が消えてしまう。

このようになり、`Command::mut_arg`に所有権を渡せなくなってしまいました。

# 安全な対処法

今回は所有権自体は渡す手前まで保持しているので簡単に解決できます。
[`mem::take`](https://doc.rust-lang.org/std/mem/fn.take.html)を使います。
可変参照として渡してやれば`take`して所有権を持った状態にできます。
もちろんその後そこに返してあげないといけませんが。

```rust
//渡すとき
let new_seed : Option<()> = seq.next_element_seed(&mut seed)?;

//受け取るとき
let value = std::mem::take(seed);//takeで中身を奪って所有権を得る。
let value_2 = value.func_take_resource();//所有権を奪って新しく返すような関数
*seed = value_2;//中身を返す
```
このようにしてもshared xor mutexのおかげでどこかでDefaultを入れただけのseedにアクセスされることはないことが保証されています。

`mem::take`は型がDefaultであることを要求していて、つまり代わりにDefault値が入ります。
例えばDefaultが実装されていなかったりdefault関数が重かったりするときは[`Option::take`](https://doc.rust-lang.org/std/option/enum.Option.html#method.take)を代わりに使えます。自分はこちらを使いました。ただこちらの場合Optionのハンドリングが余計に必要です。


# 理想的な解決法

今回は外部クレートを使っている関係で上のような実装になりましたが、理想としては所有権を奪ったリソースを使わなかったら返すほうがいいです。
例えば[`OnceCell::set`](https://docs.rs/once_cell/latest/once_cell/sync/struct.OnceCell.html#method.set)のように失敗したときに`Result<(),T>`でErrとしてもとのリソースを所有権付きで返したり、[`SyncSender::try_send`](https://doc.rust-lang.org/std/sync/mpsc/struct.SyncSender.html#method.try_send)のようにエラーの中にもとのリソースを保持した状態で返すなどのことをしてあげるといいです。
```rust
//serdeも以下のように定義してあれば問題なかった。
fn next_element_seed<T>(
    &mut self,
    seed: T
) -> Result<Result<T::Value, T>, Self::Error> 
//けど現実は Result<Option<T::Value>, Self::Error> 
```

このように所有権を消費しようとして失敗したときに返す型は`Option`ではなく`Result`にしましょう。
【入門】RubyのDateクラスについて

# はじめに
今回は、Rubyの標準ライブラリである `Dateクラス`についてまとめます。

※おことわり※
基本的に学習内容のアウトプットです。
初学者であるため、間違い等あればご指摘いただけますと嬉しいです。

# この記事の目的
- Rubyのライブラリと、Dateクラスのアウトプット

# この記事の内容
1. ライブラリについて
2. Dateクラスについて 

# 1. ライブラリについて

ライブラリとは、汎用性が高いプログラムコードを集めたファイル郡のことです。 
※フレームワークは別物

標準ライブラリと、外部ライブラリの2種類があります。（参照：画像）
[![Image from Gyazo](https://i.gyazo.com/29bfb09733f7cddaf93c17447b8cb276.png)](https://gyazo.com/29bfb09733f7cddaf93c17447b8cb276)

- ライブラリ一覧
https://docs.ruby-lang.org/ja/latest/library/index.html

- 組み込みライブラリ一覧
https://docs.ruby-lang.org/ja/latest/library/_builtin.html

# 2. Dateクラスについて 
Dateクラスは、日付を扱うことができる「標準ライブラリの組み込みではないライブラリ」です。
つまり、ライブラリから呼び出す必要があります。

- 使い方
```ruby
#ライブラリから呼び出す
require "date"

#オブジェクト生成
Date.new(年, 月, 日)

#具体的な使い方
day = Date.new(2020, 11, 3)
puts day
#返り値
2020-11-03
```

- 本日の日付を取得（todayメソッド）
```ruby
Date.today
```

- 本日の曜日を取得（wdayメソッド）
0(日曜日)から6(土曜日)の整数で取得する。
```ruby
day = Date.today.wday
puts day
#返り値
3
```
- 本日の曜日を文字列で表示
wdayメソッドで取得した整数を利用する。
```ruby
require "date"

day = Date.today.wday
week = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"]

puts " 今日は#{week[day]}です！"

#返り値
今日は水曜日です！
```
リードの取引開始時に商談のレコードタイプを設定する方法

Salesforceではデフォルトの設定として
「リードの取引開始時に商談作成をする場合、作成される商談のレコードタイプを任意に設定」という設定があります


![商談01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b4d22320-eee8-c044-c75e-f1c9beba0bc2.png)


しかしながら、通常の画面では↑のような画面なので「どこにレコードタイプの変更場所があるの？」と思う方は多いと思いますね


「＞商談」の「＞」ボタンをクリックすればレコードタイプ選択画面が現れます。

ぜひみなさん「＞」をクリックしてご確認ください！
![商談02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/cc01137c-caf7-0ac9-9cf1-33852548f649.png)
Docker環境でJitsi Meetを動かしてみる！

# 概要
Jitsi MeetをMac上で動くようにしてみます。
Dockerやdocker-composeは準備されている前提となります。

# 環境
- macOS Monterey 12.1
- Docker version 20.10.17
- Docker Compose version v1.29.2

# 手順
基本的に[Self-Hosting Guide - Docker](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker)通りに実行していきます。

## 1. ダウンロード
最新の安定版をダウンロードします。
[docker-jitsi-meet/releases](https://github.com/jitsi/docker-jitsi-meet/releases)

## 2. .env作成
```sh
cp env.example .env
```

## 3. Jitsiアプリ内で利用されるパスワードの生成

```sh
./gen-passwords.sh
```

## 4. `CONFIG`ディレクトリを作成

```sh
mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
```

## 5. Dockerの起動
```sh
docker-compose up -d
```

## 6. 確認
[https://localhost:8443](https://localhost:8443)にアクセスしてみましょう。

![スクリーンショット 2022-08-31 16.20.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290840/1c68a487-f0c0-c1bf-e4ed-c569f1df688a.png)

## 7. Dockerの終了
```sh
docker-compose down
```
WLANを管理している組織

# まえおき
最近ネットワークに関して学んでいるので、それのアウトプットをしていきます。
# 専門用語集
- RFとは、無線周波数のことです
# WLANを管理している組織
アメリカでWLAN(Wireless Local Area Network)の規制やルールを作っている４つの組織を紹介します
- Internet Engineering Task Force(IETF) - インターネットの国際規格を作る組織です
- Federal Communication Commission(FCC) - アメリカのRFスペクトラム（無線周波数帯域）を管理する組織です(ちなみにヨーロッパではETSIを使っている)。使用可能周波数と電力制限を行います。
- IEEE - 802.11規格を作った組織です。FCCが定義した無許可の周波数領域で使う規格が802.11です。（軍とかである周波数領域を使うから、被らないように許可、無許可の領域を作っているみたい）
- WiFi Alliance - 802.11規格の領域内でさらに規格を定義します。WLANの装置を作っている会社と連携していきます。

間違っていることを書いていたらコメントしていただけると嬉しいです。
以上です。
お疲れ様でした。
Azureの中の人の記事を読む「Virtual Network NAT」について その２

クラウドの中身がどのような仕組みになっているのかを知るのに、とても参考になるのが中の人が書いている記事です。
[前回](https://qiita.com/yyukawa/items/9cb5fb199fa9914b60b9)に続きて今回もAzure ネットワークのプロダクトマネージャ、Aimee Littleton氏の「Virtual Network NAT」についての投稿について紹介します。

https://azure.microsoft.com/ja-jp/blog/dive-deep-into-nat-gateway-s-snat-port-behavior/

# 前回のおさらい

前回は、Virtual Network NATがランダムなSNATポートの選択と再利用タイマーによって、同じ宛先エンドポイントで発生する接続障害を軽減することができた事例の紹介でした。

# Dive deep into NAT gateway’s SNAT port behavior

以下、画像はすべて元記事からの引用です。

## SNATポート枯渇問題

NATを利用している時の最も一般的な接続障害はSNATポートの枯渇です。接続元側がインターネット上で新しい接続を行うためのSNATポートを使い果たすことで発生します。

Virtual Network NATは、サブネット内のVMのPrivate IPとポートをVirtual Network NATのPublic IPとポートにSNATしてからアウトバウンド接続します。同じ宛先IPとポートに新たに接続するたびに、新しいソースポートが使用されます。新しいソースポートは、各接続を互いに識別できるようにするために必要です。そのためSNATのポート枯渇は同じ宛先のエンドポイントに繰り返し接続する場合に発生しやすい問題であると言えます。

## Virtual Network NATによるSNATポートの割り当て方法

Virtual Network NATによるSNATポートの割り当て方法の特徴は動的なプールからオンデマンドで割り当てを行うことです。
これによってSNATが枯渇するリスクを大幅に低減することができます。

記事の中では動的に割り当てない場合の説明がないので分かりにくいですが、動的に割り当てない場合はVM毎に固定の範囲の割り当てる方法になります。この場合、あるVMでバースト的なリクエストが発生するとSNAT枯渇が発生しやすくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/9678ae0f-50f6-675b-71bd-f251c9452a09.png)

## 割り当てるSNATポートの選択方法

まず初回ですが、前回も紹介があったようにランダムでポートが割り当てされます。
同一の宛先に対する二回目の通信の場合ですが、一度使われたポートはすぐには再利用されず、クールダウン期間経過後に再利用される動きをします。
異なる宛先エンドポイントに接続する場合は、現在使用中のSNATポートをクールダウン期間を待たずに再利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/7bc1a01f-6f82-4ee1-4882-a58d5b7eb882.png)

## 逆にいうと。。。

上記が「Dive deep into NAT gateway’s SNAT port behavior」の要約ですが、やはりこれも逆にいうと、Azure Load balancerを使っている場合はこのような問題が発生するということです。

SNATポート枯渇問題についてはコネクションプールを利用するなど、ここでは紹介されなかった、アプリケーションとして実施可能な対策も重要ですが、Virtual Network NATがこうした動きをするということは理解しておくべきでしょう。
転ばぬ先のバックアップ

# バックアップのルール
### 定期的にバックアップを行う。
```適切な周期```でバックアップを行うこと。

### バックアップする媒体は分けること
その```媒体が壊れた時にはバックアップごとデータが失われてしまう```から。

### 業務処理中にバックアップしないこと
```データの一貫性が損なわれる。```

# バックアップの方法
バックアップ方法には種類がある。
以下紹介する。

### フルバックアップ
```保存されているすべてのデータ```をバックアップする。
```前回のバックアップを含めてすべて```の内容を含む。
```直前の一回のバックアップで元の状態に戻る。```

### 差分バックアップ
* フルバックアップ以降に作成のあと、```変更されたファイルだけ```をバックアップする。
```フルバックアップと差分のバックアップ```で元の状態に戻す。

* 初回行ったフルバックアップからの変更や追加されたデータを複製
   出典 https://www.infraexpert.com/study/networking10.html
#### 気づき
前回の差分のバックアップを含みながらバックアップするのか。

### 増分バックアップ
* フルバックアップの後に```変更されたファイルだけ```をバックアップする
```直近のフルバックアップ以降のバックアップがすべて必要```になる。

* 前回行われたバックアップからの変更や追加されたデータのみ複製するバックアップ。
    出典 https://www.infraexpert.com/study/networking10.html
#### 気づき
バックアップを小分けにしているのか。

# 差分バックアップと増分バックアップの違いとは？
* 差分と増分で違うのは、```2回目以降にバックアップするデータの量```です。
差分では、```初回フルバックアップから変更・追加のあった箇所を毎回バックアップ```します。
対して増分は、```前回行われたバックアップから変更・追加のあった箇所をバックアップ```します。
   出典 https://www.backstore.jp/blog/2016/08/17/differential_and_increment_backup/

## メリット・デメリット
### 差分バックアップのメリット‥
復元時には```初回分＋差分の2データのみを繋ぎ合わせれば良い```ので、サービス側の処理が簡易

### 差分バックアップのデメリット‥
1回あたりの```バックアップ時間が長い```。
世代を複数残す場合、```容量を圧迫```する
 

### 増分バックアップのメリット‥
1回あたりの```バックアップ量を少なく```できる。
世代を```複数残しても容量を圧迫しない```。

### 増分のバックアップのデメリット‥
復元時、```複数のデータブロックをつなぎ合わせる```必要があるため、```作業が複雑```になる

## それぞれの用途
### 差分バックアップが望ましい場合‥
仮にテープや HDD にバックアップを取っていて、```世代などを担当者が手動で管理している場合```、差分バックアップの方が望ましいでしょう。増分バックアップだと、```世代の管理が煩雑になる上に、1回分のバックアップが失われただけで、それ以降のデータを復元できなくなる```可能性があるからです。

### 増分バックアップが望ましい場合‥
クラウドなどで```自動化されたバックアップ・復元の場合```、使い勝手は増分バックアップの方が優れています。1日に1回以上バックアップを取る場合も同様です。
この増分バックアップは、```時間が少なく済む上に回線への圧迫も最小限に抑えられます```。さらに、```多くの世代を残しても容量は圧迫されません```。
復元も、ユーザからすれば戻したい時点の日付を選択するだけなので、簡単です。

#### 世代とは？
* 世代管理とは
バックアップにおいては、```最新のものだけでなく、その前にバックアップしたデータも保存する```ことです。1日1回バックアップを取っている環境で「3世代保存」といえば、3日前のデータにまで遡ることができます。昨今では特にランサムウェア対策として、```複数の世代を保存することが求められています```。
出典 https://www.backstore.jp/crashplan/generation.html#:~:text=%E4%B8%96%E4%BB%A3%E7%AE%A1%E7%90%86%E3%81%A8%E3%81%AF,%E3%81%8C%E6%B1%82%E3%82%81%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82

* バックアップにおける世代数とは、```バックアップデータのセット数```を指します。
差分・増分バックアップ時には、基本となる```日曜日のフルバックアップのデータおよび、月～土曜の6日間の増分または差分バックアップのデータを1セットにして「1世代」```とする場合が多いです。
出典 https://www.fujitsu.com/jp/products/computing/storage/lib-f/tech/backup/generation/
##### 気づき
一つの区切りで世代に分けるのか。

イメージ図は出典元に
出典 https://www.backstore.jp/blog/2016/08/17/differential_and_increment_backup/

出典　

https://gihyo.jp/book/2020/978-4-297-11781-8
Accessで問題が無いはずのレポートを印刷プレビューすると『イベントプロパティに指定した式…』で例外の時

# 現象

昨日まで正常に開けていて、問題が無いはずのレポートについて、今日印刷プレビューすると下記例外。

> イベントプロパティに指定した式 フォーマット時 でエラーが発生しました:
オブジェクトまたはクラスがこのイベント セットをサポートしていません。
>マクロ名、ユーザー定義関数名、[イベントプロシージャ]以外の式が設定されています。
関数、イベント、マクロの評価でエラーが発生しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/16a3322a-8eef-1127-c1e6-e4e96aeee7e6.png)

> このレポート内のカスタム マクロの実行が失敗したため、レポートを表示できません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/98ea8934-bcf8-b669-1b6b-bc24c3f223b6.png)

レポートをデザインビューで開くことはできる。

Windows10とMicrosoft365（Access）のバージョンアップは起きていない。
（ソフトのアップデートが原因とは考えにくい）

# 対応（オブジェクト再作成）

根本の原因は不明だけど、こうすると直った…。

1. Accessファイルを複製。（『原本』と『コピー』の2ファイル）
1. 『原本』から問題のレポートを削除してファイル閉じる。
1. 『コピー』から『原本』へ問題のレポートを移植（コピペ）。

要は一旦オブジェクトを削除して、全く同じオブジェクトを再作成。
はぁ…(´·ω·`)

# 対応（イベント設定の修正）

オブジェクト再作成ではなく、イベント設定の修正で直ったこともあった。
（こちらの方がより根本の原因に近い対応と思われる）

下記のようにイベントが設定されている箇所について、一つ一つ『…』を開いて、関数を見ていく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/67aa9ab0-02b3-6d2a-03a0-6468d7d8b87c.png)

それを行っていく中で、中身が空の関数が新規作成されたら、その関数とイベント設定を削除。
おそらくそれは不必要なイベント（作成した覚えが無いイベント）である可能性が高い。

要は『イベント設定だけが存在して、それに紐づく関数が無い』という不一致状態を解消。

オブジェクト再作成だけでなく、『イベント設定におかしな点が無いか』の確認も合わせてやっておいた方がいい。


# 蛇足

> イベントプロパティに指定した式

で始まる例外はオブジェクト再作成で直ることが多い…。
はぁ…(´·ω·`)

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1889
Microsoft Access for Microsoft 365 MSO (バージョン 2207 ビルド 16.0.15427.20166) 32 ビット
【Unity】編集モード中にスクリプトを実行する方法

# 結論
スクリプトに[ExcuteAlways]を追加するだけ



## 実装例 こんな感じ↓

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteAlways]
public class Test : MonoBehaviour {
    [SerializeField] private Transform target;

    // Update is called once per frame
    void Update () {
        transform.LookAt (target);
    }
}
```




# 8秒で動画で確認できます。

[手順を8秒の動画にしてます](http://qiita.com "手順を8秒の動画にしてます")

https://www.tiktok.com/@tobiya_gamecreate/video/7137658755679915265?is_copy_url=1&is_from_webapp=v1

[<img width = 500 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821482/928e60c5-0132-2dcf-210a-f461ebab5bf7.png">](https://www.tiktok.com/@tobiya_gamecreate/video/7137658755679915265?is_copy_url=1&is_from_webapp=v1
)




# 補足
・Start関数は、Play終わりとか、Prefabモードなどで走ります。
・hierarchyのオブジェクトに張り付けないと動かないです。

・不明点あればコメントにお願いします。
【VSCode】ターミナルの配色を変更する

## ターミナルの配色を変更する方法
`setting.json`に以下のように記述することでターミナルの配色が変更できます。

```~/Library/Application Support/Code/User/settings.json
  "workbench.colorCustomizations": {
    "terminal.foreground": "#c6c8d1",
    "terminal.background": "#161821",
    "terminal.ansiBlack": "#1e2132",
    "terminal.ansiBlue": "#84a0c6",
    "terminal.ansiCyan": "#89b8c2",
    "terminal.ansiGreen": "#b4be82",
    "terminal.ansiMagenta": "#a093c7",
    "terminal.ansiRed": "#e27878",
    "terminal.ansiWhite": "#c6c8d1",
    "terminal.ansiYellow": "#e2a478",
    "terminal.ansiBrightBlack": "#6b7089",
    "terminal.ansiBrightBlue": "#91acd1",
    "terminal.ansiBrightCyan": "#95c4ce",
    "terminal.ansiBrightGreen": "#c0ca8e",
    "terminal.ansiBrightMagenta": "#ada0d3",
    "terminal.ansiBrightRed": "#e98989",
    "terminal.ansiBrightWhite": "#d2d4de",
    "terminal.ansiBrightYellow": "#e9b189",
    "terminal.selectionBackground": "#272C42",
    "terminalCursor.foreground": "#c6c8d1"
  },
```

以下のページからカラーテーマを探しGitHubの同名のファイルのコードをコピーして貼り付けると簡単に変更できます。

https://iterm2colorschemes.com/

https://github.com/mbadolato/iTerm2-Color-Schemes/tree/master/vscode
Salesforceでフローを作成しよう～リードの取引開始済み後、商談カスタム参照項目（取引先責任者）に取引先責任者を自動更新する

こんにちは。本橋孝昭です


今回はSalesforceでフロー作成する方法を解説します

今回の作成するフローはこちらです！


### 前提条件
今回のフローは「取引開始済み」の挙動にかかわるため、ちょっと整理させてください。

みなさんはリードから「取引開始済み」をしたことはありますか？
![開始01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/71e14e85-2886-cdad-008b-9bd528dd4155.png)

この場合、作成された取引先責任者は商談の
「取引榊責任者の役割」に紐づくのがデフォルトの設定ですね
![開始02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b2e9e30d-ef7b-21dc-1335-9e4d53277df8.png)

しかしながら、多くの会社には（「取引榊責任者の役割」は使わずに）商談にカスタム項目の参照関係（取引先責任者）を作成し、商談に紐づく取引先責任者を管理してたりするかもしれませんね

![開始03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/3f9697ef-ee08-7777-7c3f-87723fc04a5b.png)

もちろん通常ではこのカスタム項目は空欄のまま商談は作成されます


### 今回やりたいフロー

今回やりたいフローとして
「リードの取引開始時に商談カスタム参照項目（取引先責任者）に取引先責任者を自動更新する」という内容です
先ほどの例でいうと、取引先責任者の「田中さん」を商談「株式会社A-」に自動更新したいよ。という話です

![開始01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/71e14e85-2886-cdad-008b-9bd528dd4155.png)

### 注意事項！
今回の記事はフローの解説のための記事にしようと思います
この記事を見た方は
「いやいや、オブジェクト構成おかしいだろ」
とか
「取引先責任者の役割を活用したほうがいい」とか思ってる方はいらっしゃるかと思いますが、あくまでフロー作成の１例なんだな。と思ってスルーしていただければ嬉しいです！


さあ、フロー作成に進みます

## フローを作成しよう

フロー全体像は以下となります

![uro-.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9e89c39b-dacb-e0d5-1679-2d096aeae08d.png)

開始条件とレコードの更新のみのシンプルな作りですね（安心ですね！）




### フロー開始条件

開始条件は以下となります
IsConverted　がTrueである
![フロー02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/69f42a31-99ad-3887-b443-acd7694d76bb.png)



### フロー　レコードの更新

更新条件は以下となります
（今回商談カスタム参照項目（取引先責任者）のAPI参照名はContact＿c　としております。このAPI参照名を貴社カスタム項目ＡＰＩ参照名に変更してみてください）
![finish.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/894ee0c1-d125-8ea6-8944-d80184c73051.png)


以上でフロー作成はおしまいです。あとはフローの有効化を忘れずに！




### おまけ

取引開始済みの際に取引先責任者を「既存を選択」として既存の取引先責任者にすることができますね。

この「既存を選択」を選択して取引開始済みをすると、商談カスタム参照項目（取引先責任者）に取引先責任者を自動更新する値は「既存を選択」を選択したレコードになります

（以下の画像で言うと（鈴木次郎ではなく）田中太郎が商談カスタム参照項目（取引先責任者）に更新されます）

![開発03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c3233900-58f2-7c11-9976-49eff8b50b19.png)
Canvasについて

Canvasの扱い方。

⓪canvasタグを使いオブジェクトを生成
```<canvas id = "myCanvas" width = "150" height = "150"></canvas>```

①getElementByIdでキャンバスオブジェクトを取得
```const canvas = document.getElementById("myCanvas");```


②キャンバスのプロパティを操作できるように設定
```const ctx = canvas.getContext('2d');```

③ctx.〇〇 = ** でプロパティの値を編集
```
ctx.fillStyle = 'rgb(200, 0, 0)';
ctx.fillRect(10, 10, 50, 50);
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';
ctx.fillRect(30, 30, 50, 50);
```
オブジェクト生成
↓
オブジェクト取得
↓
オブジェクトのプロパティ設定
↓
オブジェクトのプロパティ操作
Windows Server 2019 に ssh 接続する

Linux から AWS EC2 上の Windows Server 2019 に接続する方法です。

## Windows Server 2019 での設定

OpenSSH SSH Server を有効にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/3bbbf5a6-f2f3-7426-114e-c45fc9b1f16a.png)

ローカルユーザーを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f014f3b8-bd31-9010-1f9a-12a88a4dbb89.png)

ssh で localhost にログインする

```text
ssh uchida@localhost
```

## AWS Console での設定

ポート 22 を開ける

EC2 -> セキュリティグループ
　インバウンドのルールを編集
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/1890452c-e3f1-b8f8-2784-65aa9729a45c.png)



## ssh で接続

```text
ssh 13.114.78.154
```

または、

```text
ssh uchida@13.114.78.154
```

## パスワードなしでログインにできるように設定

```text
mkdir .ssh
```

public key を、authorized_keys に追加する

authorized_keys の権限を変更

```text
icacls authorized_keys /remove Everyone
```

## powershell に切り替える

```text
uchida@EC2AMAZ-UHBD0H4 C:\Users\uchida>powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Users\uchida>
```
【入門】必ず覚えておきたいRubyの基礎

## はじめに

今回は、Rubyの基礎についてまとめます。

※おことわり※
基本的に学習内容のアウトプットです。
初学者であるため、間違い等あればご指摘いただけますと嬉しいです。

## この記事の目的
Ruby基礎内容のアウトプット

## この記事の内容
1. ハッシュの基礎
2. 二重ハッシュ 
3. クラスとインスタンス 

## 1. ハッシュの基礎

ハッシュとは、複数のオブジェクトをキーとバリューのセットで、まとめて管理することがきるオブジェクトです。
**ハッシュは、`キー` で要素を管理している**ことがポイントです。
キーとバリューのセットを、 `キーバリューストア` と言います。

- ハッシュの書き方
```ruby
#書き方① シンボル
hash = { キー: 値}

#書き方② ロケットハッシュ
hash = {:キー=>　値}
```

- キーの取得方法（keysメソッド）
```ruby
#オブジェクト.keys
hash.keys
```

- バリューの取得方法（valuesメソッド）
```ruby
#オブジェクト.values
hash.values
```

- 指定の値の取得方法
```ruby
#オブジェクト[：キー]
hash[:key]
```

### なぜシンボルを使って記述をするのか？
コード上は文字列のように見えるが、数値として処理されるため、処理速度が早くなる。

### 具体的なハッシュの書き方と値の取得
```ruby
hash = {one: 1, two: 2, three: 3}
=> {:one=>1, :two=>2, :three=>3}

puts hash.keys
#返り値
one
two
three

puts hash.values
#返り値
1
2
3

puts hash[:one]
#返り値
1
```

## 2. 二重ハッシュ 
- 二重ハッシュの書き方
```ruby
user_date = {user: {profile: {name: '一郎'}}}
```

- 値の取得方法
取得したい値までのキーを連続で指定する。
```ruby
puts user_date[:user][:profile]
#返り値
{:name=>"一郎"}
```

### 配列の中に二重ハッシュが格納されている場合

変数 `user_data` は、複数のユーザーの情報をハッシュとして持つ。
```ruby
user_data = [
 {user: {profile: {name: '一郎'}}},
 {user: {profile: {name: '二郎'}}},
 {user: {profile: {name: '三郎'}}},
]
```

- 値の取得方法
配列に格納されている値を`eachメソッド`で1つずつ取り出す。
取り出された値はハッシュなので、取得したい値(name)までのキーを連続で指定する。
```ruby
#全ユーザーの名前を取得する
user_data.each do |name|
 puts name[:user][:profile][:name]
end
#返り値
一郎
二郎
三郎

#特定のユーザー情報を取得する
puts user_data[0]
#返り値
{:user=>{:profile=>{:name=>"一郎"}}}
```

## 3. クラスとインスタンス 
クラスとは、「もの」を作るための設計図やルールのようなものです。
インスタンスとは、その設計図(クラス)を元に作られるデータのことです。
例えば、「車」を作るための設計図がクラスであり、設計図から作成された「パトカー」や「消防車」等がインスタンスです。

- クラスの定義
    - インスタンスの生成
    - インスタンスメソッドの実行

```ruby
class Car
  def initialize(type, color)
    @type = type
    @color = color
  end

  def type
    @type
  end

  def color
    puts "この車は#{@color}です。"
  end
end

#クラスを生成
car = Car.new("消防車", "赤色")

#書き方①
puts "この車は、#{car.type}です。"
#返り値
この車は、消防車です。

#書き方②
puts car.color
#返り値
この車は赤色です。
```
[個人用備忘録] iPadOSのSafariでの開発者ツールの表示方法

MacOS, iPadOS, iOSのそれぞれのSafariでデバッグする必要があり，特にモバイルデバイスのブラウザでの開発経験がなかったので調べまわった記録。
EdgeやChromeならF12キーで出るあのウィンドウの出し方について，ひとまずiPadOSの方法だけ

## iPadOS
### Macと接続して確認する場合
自分の環境だとMacが古いせいかもしれないが微妙に安定しないのであまり使わなくなった（MacBook (Retina, 12-inch, Early 2016) ）
1. iPadでSettings ＞ Safari ＞ Advanced ＞ Web Inspectorをオン 
2. MacのSafariでSettings(cmd + ,) ＞ Advanced＞Show Develop menu in menu barにチェック
2. iPadとMacを有線接続した状態でMacのSafariのメニューバーのDevelop ＞ [接続しているiPadの名前] ＞ 開発者ツールを表示したいタブをクリック。iPadでもSafariを開いていないと表示されないで注意

### Web Inspectorの導入
外部アプリのWeb Inspectorを使用してiPadに開発者ツールを表示する。
Macと接続するときより表示・使用できる機能は限られるがコンソールさえ見れればよかったため主に使用した。

1. App StoreでWeb Inspectorをダウンロード・インストール
1. Settings ＞ Advanced ＞ Extentions ＞ Web Inspectorをオン
1. 開発者ツールを表示したいページでタブバー右のアイコンからWeb Inspectorを起動
【Go】Go言語の入門ーコメント、変数

# はじめ
　　Go言語を勉強しはじめました。
　　ポイントをメモします。

# コメント
インラインコメント
```go
// コメント
```
複数行コメント
```go
/*　
　　コメント
　　コメント
　　コメント
*/
```

# 自動整形

goファイルを自動整形してくれる

```go
$ gofmt [file-name]

```

# 実行する時の入り口
実行する時、最初に呼び出す関数はmain関数である。

```go
package main

func main(){
    //main関数内に処理内容を記入する
}

```

# 変数

## 変数宣言と代入

```go
var 変数名 データ型 // 変数宣言
変数名 = 値  // 変数に値を代入

//例
var num int
num = 10
```

注意点

- 変数を宣言した時点に、デフォルト値を代入される。　intとfloatの場合、デフォルト値は０である。
- データ型が自動推測されることができる。
  
  ```go
  var num = 10  //numのデータ型はint型と推測される
  ```

- 「**:=**」を使用すれば、**var** を省略して、宣言代入することができる。(この前に、宣言されたことない変数名のみ対応)
  
  ```go
  int := 100
  ```

## 複数変数宣言
同じデータ型の場合
```go
var 変数名1, 変数名2, ... データ型
// 例
var n1, n2, n3 int
```

異なるデータ型の場合

```go
//方法１
var n1, name, n2 = 100, "Tom", 888

//方法２
n3, name1, n4 := 200, "Lucy", 666

//方法３
var (
    n5 = 600
    n6 = 700
    name2 = "Lily"
)

```

注意点：

- 変数は同じスコープ内に同じデータ型の値を代入するしかない。
```go
func main() {
  var i int
  i = 10  // OK
  i = 20  // OK
  i = 30.5  // NG int型ではない
}
```
- 同じスコープ内に、同じ変数名を宣言することができない。
```go
func main() {
  var i int
  i = 10  // OK
  i := "Lucy"  // NG この変数名は使用された
}
```
bigobject memo

Big Object で許可されない SOQL 操作

1.インデックス項目のみしか検索できない
インデックス順序が後の項目を検索する場合はそれより前のインデックス項目についても検索条件を指定しなくてはならない。
~~~
⭐只能用index检索
⭐index检索顺序的限制
    假设你有三个检索index，分别是index1 ，index2， index3
    那么在你写检索条件的时候，你可以这样写
             where index1 = condition1 and index2 = condition2 
    但是你不能这么写
             where index1 = condition1 and index3 = condition3 
    你需要这么写
             where index1 = condition1 and index2 = condition2 and index3 = condition3
⭐无法在检索条件中使用参照項目

SELECT Contact__c,Product_Code__c,Purchase_DateTime__c FROM Purchase_History__b WHERE Contact__r.Name = 'Tanaka'

需要使用二次查询

SELECT Contact__c,Product_Code__c,Purchase_DateTime__c FROM Purchase_History__b WHERE Contact__c IN (SELECT ID FROM Contact WHERE Name = 'Tanaka')
~~~
2.検索条件としてつかえる比較演算子は=、IN 、<、>、<=、>=に限られ、またIN 、<、>、<=、>=の演算子が使えるのは指定された検索条件のインデックス項目のうち、順序がもっとも後の項目のみ
~~~
!=、LIKE、NOT IN、EXCLUDES、INCLUDES 全部不能使用，IN是可以使用的
~~~
3.結果のリストを取得するには、クエリに Id 項目は使用しないでください。クエリに Id を含めると、空の ID (000000000000000 または 000000000000000AAA) の結果のみが返されます。
~~~
id不能出现在检索项目里
~~~
4.クエリ結果の集計や並び替えのSOQLサブコマンドは使用できない
~~~
所有的集計，排序都用不了
~~~
5　もしbigobjectのレコードを削除したい場合は、consoleのqueryではできないため、
apex code（deleteImmediateを使って）を実行してやりましょう

~~~
例：
List<Customer_Interaction__b> cBO = new List<Customer_Interaction__b>();
cBO.addAll([SELECT Account__c, Game_Platform__c, Play_Date__c FROM Customer_Interaction__b WHERE Account__c = '001d000000Ky3xIAB']);

Database.deleteImmediate(cBO);


~~~

6.Big Object does not support sharing rules, trigger, flows, processes, and Salesforce Apps
这说明了你无法对bigobject的数据进行共享。说的是record level的sharing。同时也不能在sf内部数据变形。

唯一可以做到的，就是插入bigobject数据之后，在画面上修改，或者是另外写apex进行处理。
PREP法とは

# PREP法とは?

P=　Point(結論)
R=Reason(理由)
E=Example(具体例)
P=Point(結論)

結論を最初に伝え、その後に理由、事例で理由を修飾し、最後に結論を述べる方式です。

# 具体例


**PREP法を使った例文**

Point：豆腐はダイエットに最適です。
Reason：なぜなら、高タンパク質・低糖質・低カロリーだからです。豆腐はさまざまなレシピに対応可能で、無理せずにダイエットが続けられます。
Example：実際に、晩ごはんダイエットの著書である美波紀子さんは12kgのダイエットに成功しました。
Point：このように、おいしくて栄養価の高い豆腐はダイエットに最適な食材です。

**PREP法を使っていない例文**

豆腐は高タンパク質・低糖質・低カロリーな食材です。 さまざまなレシピにも使えるのでとても便利。ダイエットを考えている方にもぴったりです。 しかし、本当にダイエットに効果があるのか気になる方もいらっしゃるでしょう。 実際に、晩ごはんダイエットの著書である美波紀子さんは、なんと12kgのダイエットに成功したという実績があります。 このように、豆腐はおいしいだけではなく、ダイエットにも最適な食材です。

> わかりやすい文章構成にはPREP法がおすすめ！伝わる文章の書き方も解説
> https://tech-camp.in/note/careerchange/53916/
【JavaScript】Ajaxでメソッドを呼び出せない！【MVC】

# はじめに
どうも、ATLのヴィリアスです。

ある日、 JavaScript から MVC のコントローラーのメソッドを呼び出そうとしたところ…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2124150/c2d214cf-5828-eebf-edd5-7c0bd7ba1cd0.png)
「**メソッドが見つからない**から、404エラーだよー！！」と怒られてしまいました。

それに対して、私は該当のコードを確認しましたが…

```C#: HomeController.cs
    public class HomeController : Controller
    {
        public async Task<string> GetNewTokenAsync()
        {
            .
            .
            .
        }
    }
```

```JavaScript: スニペット.js
async function updateToken() {
    $.ajax({
        type: 'POST',
        url: location.origin + '/Home/GetNewTokenAsync',
        .
        .
        .
    })
}
```

「ん？**メソッド名**あってね？？」となり、一悶着してしまいました。

そこでいろいろ調べた結果、最終的に**私が悪かった**ことが判明したので、
戒めと反省と謝罪として、そのときの解決策をここに記します。

**※免責事項(必ず、ご一読ください)**
　　本記事の情報により生じた、いかなる損害や損失についても、当社は一切の責任を負いかねます。
　　また、誤情報が入り込んだり、情報が古くなったりすることもありますので、
　　必ずしも正確性を保証するものではありません。ご了承ください。

# まずは結論

こちらが正しい書き方でした。

```JavaScript: スニペット.js
async function updateToken() {
    $.ajax({
        type: 'POST',
        // url: location.origin + '/Home/GetNewTokenAsync',
        url: location.origin + '/Home/GetNewToken'
        .
        .
        .
    })
}
```

**Ajaxで指定するメソッド名 (アクション名) に```Async```はいらなかったのです！**

# なぜ```Async```が必要ないのか？

以下によると、MVC 3.0以降では
**コントローラーのメソッド名の後ろに付随する```Async```は内部で削除される仕様**になっているとのこと。

https://github.com/dotnet/docs/issues/14716

これに気が付かず、
「**```GetNewTokenAsync```が見つからないよ！**」ということで404エラーが出てしまっていたんですね。

## 補足1: ```Async```が削除されないようにするには

MVC のスタートアップ設定で、以下のコードを記述します。

```C#:Program.cs
services.AddMvc(options =>
{
   options.SuppressAsyncSuffixInActionNames = false; 
});
```

```SuppressAsyncSuffixInActionNames```は直訳すると、
「アクション名の```Async```サフィックスを抑える」です。

つまり、「**アクション名の後ろに付随する```Async```を削除する**」かどうかを設定できます。
それを```false```に設定することで、```Async```の削除を無効化できるということですね。

## 補足2: なぜこの仕様になったのか？

> Asynchronous .NET methods, by convention, end with the Async suffix. However, when a method defines an MVC action, it is generally not desirable to have the Async suffix.

「慣習的には、非同期 .NET メソッドは```Async```サフィックスをつけます。
ですが、**MVC アクション名としては```Async```サフィックスは望ましくないのです。**」

とのことでした。

# おわりに

うーん、これは初見殺しの罠ですね。さすがに許せない。

……

冗談はさておき、
「**JavaScript などの外部からメソッドを呼び出す時、```Async```には要注意！**」ですね。

それではまた、次の記事で。
Power Automate で Dataverse の選択肢のラベルを取得する

こんにちは。日本マイクロソフトの向井です。

こちらの記事では、Power Automate でDataverse の選択肢（オプションセット）のラベルを取得する方法をご紹介します。

Power Automate で選択肢型のデータを取得して表示させたいとき、内部の値（数字）は簡単に取得できますが、ラベル（テキスト）の部分を取得して表示するのは意外と難しかったので、こちらに方法をまとめておきます。


# 1. 下準備
今回のフローはDataverseのレコードが作成・更新・削除された時をトリガーにしています。
トリガーに使う申請というテーブルの中に承認ステータスという選択肢型の列があります。

表示させたい選択肢のラベルが格納されている場所を探すために、一度フローを実行します。

フローには必ず1つ以上のアクションが必要なので、今回はTeamsコネクターの「チャットまたはチャネルでメッセージを投稿する」を使用しました。※アクションは何でも大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/9d7e0255-d92c-dd9b-3ac8-8d0eeadeca99.png)

このフローを保存し、実行します。


フローの実行履歴を確認します。
先ほど実行したものの詳細を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/575b51b4-d5ab-cb4a-e8cd-15b594e167df.png)

トリガーの出力のところの、未加工出力の表示をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/27102a2f-ff78-1b86-d57a-2713d8a1418a.png)

承認ステータスのラベルが格納されている場所を確認し、メモ帳などにコピーしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/935257b9-e9a8-c9e0-ac2d-1d5656ceb77c.png)

コピーしたら右上の編集ボタンからフローの編集画面に戻ります。
ちなみに今回作成したフローのように、動的なコンテンツから選択肢型の列を選択すると、画像のように内部の値が取得されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/c7d116f5-a18d-cc5b-a1da-9403c170c608.png)


# 2. 「作成」アクションを使用し、選択肢のラベルを取得する
トリガーの後に新しいアクションを追加します。
組み込み＞データ操作＞作成　を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/b44cff88-c9a4-8b55-6b15-416af9cb11dd.png)

一度、入力欄に、使用したい選択肢列を動的コンテンツから選択し、入力します。
この動的コンテンツをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/90a78e40-6f46-1f9d-6532-92abbf985b29.png)

今コピーした動的コンテンツを、式に貼り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/60576b14-b75d-c6db-4537-8e173c417680.png)

張り付けたものはこのようなコードになっていると思います。
@{triggerOutputs()?['body/cr30e_status']}

ここから先頭の @{ と最後の } を消します。

そうすると、こんな感じになっていると思います。
triggerOutputs()?['body/cr30e_status']
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/15861122-482c-a956-3196-a8f6d374e197.png)

['body/○○']
となっているところの○○を 1. でメモ帳にコピーしておいた値に変更します。

すると、こんな感じになると思います。
triggerOutputs()?['body/_cr30e_status_label']
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/55fd1da4-3c68-3bfe-c149-2ea39153e6e5.png)

この状態でOKを押します。

作成のところに関数が入りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/e7f2a704-4e76-4d62-6422-deabb087857a.png)

すると、これ以降のアクションで動的コンテンツから「出力」というものが選べるようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/f8236309-63c6-0467-11e1-6e805fab4422.png)

この「出力」に選択肢のラベル（テキスト部分）が入っています。

# 3. テスト
最初に作成したフローのTeamsアクションのMessageを出力に変更し、テストしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/41438b52-85e9-e555-61c1-6577e2dfe53f.png)

保存し、フローを実行します。

このように、選択肢のラベルを取得することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/3e80361f-278b-9a9a-40ae-4de84ef6cbb2.png)
【Blue Prism】書き込みステージを使用してWeb上のテキストボックスに値を入力できない場合の対処方法例


## はじめに
書き込みステージを使用してブラウザに値が反映されず困り果て、[こちら](https://qiita.com/ta-hashimoto/items/97a2ff79422c8bb4e267)の記事を参考にして問題解決！と思いきやこちらでも反映されなかったため、その時の対処方法を書いていこうと思います。

## 書き込みステージを使用したときのブラウザの状態
以下の画像の「案件名」に値を入力していきます。
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/f8dfc025-6167-bf5d-fe08-2bee6ba08b24.png)

書き込みステージを使用して値を入力してみます。
![画像_書き込みステージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/6b7a8ee6-b8c0-97e0-be0e-7563b9ad0cc7.png)


結果は以下のようになりました。
![画像_失敗.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/f9a308c0-2d35-db07-29cc-59367e825fcb.png)
このように正しく入力することができず、ブラウザ上では「未入力」とされてしまいました。

そこで参考元の記事に倣って実装し直してみましたが今度はテキストボックス内に何も表示されてないという事態となってしまい、別の方法を考えなくてはならなくなりました。

記事を参考に実装を修正したときのオブジェクトは以下になります。
![画像_記事参考.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/650cb4a3-0ad3-ae17-19bb-2a1e159cdfa5.png)



## 対処方法
さっそく対処方法をご紹介していきます。

手順は以下になります。

1.案件名をクリップボードに貼り付ける
2.ブラウザをアクティブ化する
3.「案件名」のテキストボックスをクリックする
4.コピーした文字を貼り付ける

手順は参考元の記事と変わりありませんが、問題解決の決め手は**スパイした要素**にありました。
手順4では、UIオートメーションナビゲーターを使って要素をスパイし実装します。次の項目から詳しく説明していきます。

#### UIオートメーションナビゲーターによる要素取得
通常のスパイモード(ブラウザモード)でスパイした要素では、手順4「コピーした文字を貼り付ける」のアクションが画面上に反映されませんでした。

そのため、手順3のアクションで使用する通常のスパイモードでスパイした要素と手順4のアクションで使用する**UIオートメーションナビゲーター**でスパイした要素を用意します。

通常のスパイモードでスパイした要素(要素の名前は、text_案件名(ブラウザ)としました)
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/a94afc00-208f-9df1-7c70-16714828fee8.png)



UIオートメーションナビゲーターでスパイした要素(要素の名前は、案件名入力項目ラベル(UIA)としました)
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/dc207d80-1d51-038f-ba91-19c4def715b3.png)

UIオートメーションナビゲーターは、
アプリケーションモデラーをクリックし、識別の▼をクリック、「UIオートメーションナビゲーターを開く」で選択できます。
使用すると非表示の要素を含め、ページ上の要素を全て確認、取得することができます。
![画像_説明1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/fdc09aab-8675-1d75-02dc-b4fb51916513.png)
![画像_説明2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/3cb234ad-dd72-4a80-0582-a195202c4c02.png)


#### 実装
手順をもとに実装していきます。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/8356003f-b151-7ac5-76b5-7bca0b92c755.png)


アクションステージ「クリップボードに張り付け」の詳細は以下になります。(手順1)
![画像_クリップボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/25d08a01-2a25-0ab4-1a05-762a008bdf11.png)




操作ステージ「案件名入力」の詳細は以下になります。(手順2～4)
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/4c991f17-8fc0-21a3-4480-35f323a62541.png)


実行してみます。
![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820916/8bd21173-48cb-5d3e-5341-43190c9d71f1.png)


値が入力できました！


## まとめ
[参考記事](https://qiita.com/ta-hashimoto/items/97a2ff79422c8bb4e267)との違いは、通常のスパイモードでは取得できない要素が原因で値を入力することができなかったということでした。
通常のスパイで上手くいかない場合には、アプリケーションモデラーの識別のから「UIオートメーションナビゲーターを開く」を選択し、要素を取得するのがおすすめです。ぜひ、試してみたください。

本記事が参考になれば幸いです。
【Rails】生SQLを書きそうになったらsanitize_sql_for_orderを検討しよう

## 環境
Rails 6.0.1
Ruby 2.6.3
PostgreSQL 11.16


## 
UserモデルにPost作成日でnilが最後に来るようにソートするスコープがあったとき、
```created_at_sort```に入ってきた値が```desc```か```asc```で降順か昇順にソートしている。
```order```の中で生のSQLを書くことになってしまいセキュリティとしてあまり良くない。
あと美しくない。
```models/user.rb
scope :sort_by_created_at, ->(created_at_sort) do
    if created_at_sort == 'desc'
        eager_load(:posts)
            .order('posts.created_at DESC NULLS LAST')
            .select('users.*', 'posts.created_at AS posts_created_at')
    else
        eager_load(:posts)
            .order('posts.created_at ASC NULLS LAST')
            .select('users.*', 'posts.created_at AS posts_created_at')
    end
end
```

## sanitize_sql_for_orderを使おう

```sanitize_sql_for_order```を使うことでSQLインジェクション対策ができる。
```created_at_sort```に```desc```か```asc```のどちらが渡ってきてもちゃんとソートできるので条件分岐が必要ない。
あとすっきりして美しい！

```models/user.rb
scope :sort_by_created_at, ->(created_at_sort) do
    sort_sql = sanitize_sql_for_order("posts.created_at #{created_at_sort}")

    eager_load(:posts)
        .order("#{sort_sql} NULLS LAST")
        .select('users.*', 'posts.created_at AS posts_created_at')
end
```

今回の場合、```sanitize_sql_for_order```は結果だけ見るとただ文字列に変換してるだけのように見えるが、

```ruby
created_at_sort = 'asc'
sanitize_sql_for_order("posts.created_at #{created_at_sort}")
#=> "customer_support_plans.start_date asc"
```

引数の値が配列だったりすると内部でしっかりサニタイズしてくれる。

https://github.com/rails/rails/blob/04972d9b9ef60796dc8f0917817b5392d61fcf09/activerecord/lib/active_record/sanitization.rb#L62

```ruby
sanitize_sql_for_order([Arel.sql("field(id, ?)"), [1,3,2]])
# => "field(id, 1,3,2)"

sanitize_sql_for_order("id ASC")
# => "id ASC"
```


## 参考

https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_for_order

https://qiita.com/kat0/items/e3c7eb5184b0b6fd5d72
iPerfのクライアントとサーバーをバッチファイルからワンクリックで起動 

## PowerShellとBatchを使って、コマンドを叩くことなく1クリックでiPerfを実行する

### ユースケース
+ 5Gのトラフィック性能を見せる簡易デモでiPerfを使用
+ デモの**セットアップが完了**したら、あとは説明員さんがクリックするだけで動くようにしたい
+ 社内ITの事情によりiPerfの実行端末はWindows PCしかない
+ デモPCのメンテを続けるのは面倒なので、あえてPowerShell 7系を使わず、デフォルトで入っているWindows Powershell 5.1で対応
+ フリーソフトのTCP Monitor Plusを使わせて頂いてトラフィックの状態をグラフィカルに表示
+ PowerShellでiPerf3を実行し、そのPSスクリプトとTCP Monitorをバッチファイルからクリックで実行できるようにした
※[TCP Monitor](https://dns-plus.net/)

### 5Gネットワークデモ構成
![5ge2e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699739/2accb7e6-be1a-3950-3517-d35625485916.png)


### 実行環境
+ Windows10 英語版
+ Windows PowerShell 5.1 
+ iPerf 3.1.3

### iPerf3設定

```plantuml
iPerf3_Client -> iPerf3_Server: Upstream traffic
iPerf3_Client <- iPerf3_Server: Downstream traffic
```
+ iPerf3クライアントはCPEの下に接続
+ iPerf3サーバーはUPF(N6)の後ろで接続

### クライアント側 ( ファイル )

| ファイル名 | 用途 |
|:-----------------|:----------------|
| iPerf3_clnt_1.ps1 | アップストリームのパフォーマンスチェック |
| iPerf3_clnt_2.ps1 | ダウンストリームのパフォーマンスチェック |
| configClient.ps1 | 設定用ファイル（インターフェース、ポートを指定、インターバル、タイム、パラレルなどのコマンドオプションパラメータ）|
| start_iPerf3_client.bat | Windowsバッチファイル。クリックすることで2つのiPerf3クライアントとTCPモニターを起動 |

### サーバー側 ( ファイル )

| ファイル名 | 用途 |
|:-----------------|:----------------|
| iPerf3_svr_1.ps1 | アップストリームのパフォーマンスチェック |
| iPerf3_svr_2.ps1 | ダウンストリームのパフォーマンスチェック |
| configServer.ps1 | 設定用ファイル（インターフェース、ポートを指定）|
| start_iPerf3_server.bat | Windowsバッチファイル。クリックすることで2つのiPerf3サーバを起動 |


### リポジトリ

今回作成したファイルは以下のリポジトリに置いてます。

[MashCannu - Github](https://github.com/MashCannu/Performance_Demo.git)
【いろいろよく知らない私が困った】make initで作られたはずのDBが無い！

dockerで環境構築したら、migrateもseederもされているのに
```$ mysql -u root -p```で```>show tables;```するとDBがないと表示される


### １. DBブラウザを開く
```
"localhost:3306". The error is: "Cancelled load from 'localhost:3306' because it is using HTTP/0.9." (:0)

「HTTP/0.9を使用しているため、「localhost:3306」からのロードをキャンセルしました(:0)」
```
### ２. １.を受け、```.env```のportを変えて再度```$ make init```

１.と同様。。


### ３. phpMyAdminが```docker-compose.yml```になかったので、勝手に作成することに。
　　（ ※私は他プロジェクトからのコピペしました💪 ）
###### その後① dockerからphpmyadminのブラウザを開く。
###### その後② ```docker-compose.yml```の```db:environment:```記載のあったuser_name,pass_wordを入力。

これでmigrate,seederされたDBが確認できました！🙆‍♀️
Next.jsの本番環境で効率的にリビルドする（Linux/Shell）


こんにちは。先日[ブログSaaSアプリの報告記事（Qiita）](https://qiita.com/yuipapps/items/62d638ca06e06c5693f0)を挙げてから、
マイナーチェンジやバグ修正なりで、時々Next.jsのリビルド・再ビルドを行う必要性が出てきました。

件のNext.jsアプリは[Conoha VPS](https://www.conoha.jp/)の2GBメモリ・3コアCPUのプランで動かしています。

（※ 実際、この程度のアプリだと、動かすだけならこれほどのスペックはあまり要りませんが、
僕の場合VPS上でVSCodeを立ち上げデバッグしてしまうので、割りと1.8GBくらいまで行ってしまいます）

このスペックでNext.jsのビルド `npx next build` を行うと、

```sh
$ time NEXT_PUBLIC_APP_MODE=production NEXT_PUBLIC_APP_DIST=.next/prod.tmp npm run build

real    1m13.301s
user    2m11.505s
sys     0m6.562s
```

1分以上も掛かってしまい、
これを、`next start`を一度停止して行っていると、その間に訪問したユーザに不便となってしまいます。

そのため、他のディレクトリに一度ビルドをして、それをコピー/名前変更して、再度`next start`を行えば、サービスのダウンタイムが最小に抑えられます。

ビルド先のディレクトリを変更するには、`distDir`を指定します。

`next.config.js`に以下の例のように`distDir`を指定し、
コマンドラインから`NEXT_PUBLIC_APP_DIST`を渡して出力先ディレクトリを動的に変更できるようにします。

```js 
// ./next.config.js
..
const app__mode = process.env.NEXT_PUBLIC_APP_MODE === 'production' ? 'production' : 'development';
const app__dist = process.env.NEXT_PUBLIC_APP_DIST;

module.exports = withPWA({
  pwa: {
    ..
  },
  distDir: app__dist || ( app__mode === "production" ? '.next/prod' : '.next/dev' ), // <-- 追加 
  ..
})
```

ファイルを変更してリビルドしたい場合に、`NEXT_PUBLIC_APP_DIST`に`.next/prod.new`のように指定をします。

```sh
$ NEXT_PUBLIC_APP_MODE=production NEXT_PUBLIC_APP_DIST=.next/prod.new npm run build
```

ビルドが完了すると、以下のようなディレクトリ構造になります。

```sh
$ tree -L 1 .next
.next
├── dev
├── prod
└── prod.new
```

`prod`ディレクトリを`prod.old`に名前変更し、
`prod.new`ディレクトリを`prod`ディレクトリに名前変更します。

```sh
mv .next/{prod,prod.old}
mv .next/{prod.new,prod}
```

なお、上記の作業は素早く行わないと、Next.jsが`prod`ディレクトリを作成してしまいます。
また、そのまま放置すると、アプリもコードが不完全なため不安定になります。

そのため、上記の作業を.shファイルなどからバッチ処理で行うか、一度`next start`を停止してから行うとよいと思います。

上記の作業を完了すると、以下のようなディレクトリ構造になります。

```
$ tree -L 1 .next
.next
├── dev
├── prod
└── prod.old
```

この時点で、Next.jsサーバーを一度停止、再スタートさせます。

```sh
$ NEXT_PUBLIC_APP_MODE=production npx next start --port 3001
```

アプリが正常に動くか確認し、確認できれば完了です。

アプリがバグってしまったら、`prod.old`ディレクトリを`prod`に戻してロールバックを行います。

```
mv .next/{prod,prod.new}
mv .next/{prod.old,prod}
```

以上です。

--- 

PS. よいやり方の提案・間違い修正etcぜひお伝え下さい。
ありがとうございました。
【Angular】IPアドレスを取得する

# はじめに
今回はAngularでIPアドレスの取得を試してみました。
意外と簡単に実装することができました。
ただ、また実装するときのために備忘録として残すことにします。
他の方の参考にもなればと思います。

# バージョン
- Angular: 9.1.11
バージョンの確認方法については過去記事に記載しております。

https://qiita.com/Shogongon/items/81c8a26028c82892a5c4#%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3

# 結論の前に
IPアドレスを取得するにはAngularの機能だけではなく「[ipinfo.io](http://ipinfo.io/)」というサービスを使っています。
こちらのサービスを使うだけで簡単にIPアドレスを得ることができます。
無料でもかなり使えるのでおすすめです。

# 結論
※moduleの設定は[Angular:サーバーとの通信の設定](https://angular.jp/guide/http#%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%A8%E3%81%AE%E9%80%9A%E4%BF%A1%E3%81%AE%E8%A8%AD%E5%AE%9A)が参考になります。

```tsx:test.module.ts
// 前略
import { HttpClientModule } from '@angular/common/http';

// 中略
@NgModule({
  imports: [
    HttpClientModule,

// 後略
```

```tsx:test.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html'
})
export class TestComponent implements OnInit
{

  constructor(
    private httpClient: HttpClient
  ) {}

  async ngOnInit(): Promise<void> {
    try {
      const ipAddress = await new Promise((resolve, reject) => {
        this.httpClient.get("https://ipinfo.io")
          .subscribe(data => {
            return resolve(data['ip']);
          }, error => {
            return reject(error);
          });
      });
      console.log(ipAddress);
    } catch(error) {
      console.log(error);
    }
  }
}
```

# 参考文献
[ipinfo.io](http://ipinfo.io/)
[Angular:サーバーとの通信の設定](https://angular.jp/guide/http#%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%A8%E3%81%AE%E9%80%9A%E4%BF%A1%E3%81%AE%E8%A8%AD%E5%AE%9A)