OmniAICreator/Qiita-1.07M huggingface dataset:
【Salesforce】変更セットのリリース注意点

# 本番環境と差異が無いか確認する

他の技術者の方のモジュールを上書きし、無駄な工数を避ける。

GitHubと連携すれば差異は確認可能。

技術者それぞれに開発環境を用意し、操作しているモジュールを共有する。

開発環境をそれぞれに用意できない場合は特に、操作しているモジュールを共有する。

# リリース後、バグ対応などの可能性を検討し、休憩やリリースの時間を確認する

午前中リリース→昼休憩→エラーメール山盛りを避ける。

定時間際リリース→バグ発生→深夜残業を避ける。

朝一やお昼休憩後が望ましい。

# ApexやVFのリリース時、本番環境でセキュリティが有効になっているか確認する

運用・保守案件でプロファイルをお客様にて操作している場合、プロファイルとモジュールを一緒にリリースできないので、モジュールのみリリースした場合、本番環境にてセキュリティのチェックをする。

モジュールの更新は大丈夫だが、新規作成した時は有効になっていない。

# データ作成、更新系のモジュールをリリース時、本番環境のレコードを更新した方がいいか確認する

例えばレコードを更新した際に条件を満たした場合、項目の値をTrueにする。などの処理を追加した場合、リリース後、レコード操作を行わないと整合性が合わない。

データローダでレコードのバックアップを取得し、本番環境用のコードを用意し、開発者コンソールから実行する。

# リリース前報告フォーマット
(GitHubのissueリンクなど)
上記について本番リリースを開始します。
※〇〇さんレビュー済

成果物は添付の〇〇件です。（キャプチャを貼る）

＜リリース後の対応＞
・新規コードのセキュリティを有効にする
・URLなどの固定テキストを本番用に切り替える
・入力規則の有効化を確認する

＜バグ時の対応＞
・Apｅｘトリガを止める。
・ルールを無効化する。

＜レコード調整＞
・リリースする処理によって既存レコードを調整する必要がある
・既存データを更新する場合、入力規則、重複ルールを考える。無効化することも視野に入れる。

# リリース後報告フォーマット
(GitHubのissueリンクなど)
上記について本番リリース完了しました。

下記、〇〇件対応後、完了とします。

・GitHubならマージなど
・仕様を書いたりなど

# リンク
[変更セットのベストプラクティス](https://help.salesforce.com/articleView?id=changesets_best_practices.htm&type=5)

[変更セットによる運用組織へのリリース時あるある](https://base.terrasky.co.jp/articles/xzxdP)

- オブジェクトに追加した項目の項目レベルセキュリティが設定されていない！
- 選択リスト項目に値を追加したのに選択リストに出てこない！
- ホーム画面に設定していたカスタムロゴが標準のSalesforceのロゴに変わってしまった！
- トランスレーションワークベンチで変更したラベル名が移行されない！
- 変更セットにコンポーネントを追加しすぎてViewStateエラーが発生してしまった！
- 運用組織の方がバージョンが低くて、変更セットのリリースが失敗した！
- 運用組織へのリリース時の全テストコード実行でテストコードが失敗しリリースできない！

[Salesforce本番リリース時に気をつけたいポイント](https://shige-mon.blogspot.com/2018/07/release.html)

- レポートを変更セットを使ってリリースする場合の落とし穴
- プロファイルを含んだ変更セット
- 参照関係、主従関係、自動採番型のデータ型変更

[Salesforce: プロファイルのリリースで気をつけたいこと](http://crmprogrammer38.hatenablog.com/entry/2018/01/30/120000)

- 変更セットでリリースする際は、プロファイル別にアクセス権が付与できるコンポーネントと一緒に変更セットを作成する
- サイトプロファイルのリリース
- 変更セットのプロファイルリリース時に、ログイン IP アドレスの制限もリリースされる

[コミュニティの変更セットリリースをスムーズに行うために](https://base.terrasky.co.jp/articles/dkBM2)

- はじめに
- ①リリース先環境に同名コミュニティサイトがあることを確認
- ②コミュニティサイト名が半角英数字であることを確認
- ③関連資材がすべて変更セットに入っているか確認
- その他のコミュニティリリース関連事項
- おわりに
Rails パンくずリストの作成

#はじめに
Railsアプリのヘッダー部分にパンくずリストを追加しました。忘れないように書き記します。

**開発環境**
ruby 2.6.5
Rails 6.0.3.4

#目次
1.Gemの導入
2.パンくずの設定
3.CSSの設定

#1.Gemの導入
gretelというGemを使用する。 下記Gemfileに追記後、ターミナルで忘れずにbundle installを実行する。

[公式GitHub](https://github.com/kzkn/gretel)

```ruby:Gemfile
gem "gretel"
```

#2.パンくずの設定
パンくずの設定を書き込むbreadcrumbs.rbファイルを作成する。作成方法は下記のようにターミナルでコマンドを実行する。

```bash:ターミナル
rails g gretel:install
```
今回下記のような4層でパンくずリストを構成する。
トップページ > 掃除提案 > 登録一覧 > 掃除箇所の登録

```ruby:config/breadcrumbs.rb
crumb :root do
  link "トップページ", root_path
end

crumb :clean_suggestions do #ページの名前
  link "掃除提案", clean_suggestions_path　#リンク名、リンク先ページ
  parent :root
end

crumb :suggestions do
  link "登録一覧", suggestions_path
  parent :clean_suggestions
end

crumb :new_suggestion do
  link "掃除箇所の登録", new_suggestion_path
  parent :suggestions
end
```

各ヘッダーのビューにパンくずリストを追記する。なお「separator: " > "」はリスト間に「>」を挿入する。これによりブラウザ上に表示される。

```ruby:トップページのヘッダー.html.erb
<%= link_to "トップページ", root_path, class: :logo %>
<% breadcrumb :root %>
```

```ruby:掃除提案のヘッダー.html.erb
<% breadcrumb :clean_suggestions  %>
<%= breadcrumbs separator: " > " , class: :logo %>
```

```ruby:登録一覧のヘッダー.html.erb
<% breadcrumb :suggestions  %>
<%= breadcrumbs separator: " > " , class: :logo %>
```

```ruby:掃除箇所の登録のヘッダー
<% breadcrumb :new_suggestion  %>
<%= breadcrumbs separator: " > " , class: :logo %>
```

#3.CSSの設定
logoクラスは「>」に適用される。現在のページを表す部分は自動的にcurrentクラスが割り当てられている。下記記述により、現在のページを太字とし、それ以外にカーソルを合わせると色が変わるようになる。

```css:header.css
.logo {
  margin-left: 3vw;
}

.logo a {
  margin-right: 0.5vw;
}

.current {
  font-weight: bold;
  margin-right: 1vw;
}

.logo:hover,.logo a:hover {
  color: Chocolate;
}
```

![4fe7bb811a01b4e77db7797b103d012f.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703987/a8160df4-b042-2788-0b1a-6c0c7b45751c.gif)

以上
Laravel 6.xでredisをセッションサーバーとして使えるようにする

Laravel 6.x でセッションサーバーとしてredisを使おうとして、インストールや設定に少し手間取ったので、備忘録としての記録です。

## 環境
ubuntu 18.04
Laravel 6.20.x

## 前提条件
php-fpm, redisはインストール済み

## インストール

まずは、peclをインストールしましょう。php-pearに含まれます。
そして、peclからphpredisのインストールです。

predisでも動作しますが、今回は公式で推奨されるphpredisをインストールしたいと思います。

[6.x 日本語ドキュメント](https://readouble.com/laravel/6.x/ja/redis.html)
>LaravelでRedis使用するには、PECLを使用してPhpRedis PHP拡張をインストールすることを推奨します。インストール方法は複雑ですが、Redisをヘビーユースするアプリケーションではより良いパフォーマンスが得られます 

```shell
## peclのインストール
sudo apt install php-pear

## phpredisのインストール
sudo pecl install redis
```
## php.iniの修正
extensionの追加。
追加後、php-fpmは**再起動**してください。

```php:/etc/php/7.x/fpm/php.ini
extension=redis
```

## Laravelの設定
各設定の変更

```config:.env
SESSION_DRIVER=redis #fileから変更
```

```php:config/database.php
# redisのクライアントがphpredisになっているか確認
'redis' => [
    'client' => env('REDIS_CLIENT', 'phpredis'),
```

## 確認
webページを開いてみると、redisがセッションサーバーとして機能してるのが分かると思います。

```shell
$ redis-cli
> keys *
1) "sample_database_cache:AIn7Io8yHuhTolvAJhk5ITLdMsqXL1FqsuOTSDBl"
> get ample_database_cache:AIn7Io8yHuhTolvAJhk5ITLdMsqXL1FqsuOTSDBl
"s:198:\"a:3:{s:6:\"_token\";s:40:\"FBn1BGQlMBUXXMQBI2SDDBuvKIr31YTAyOo4X20L\";s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}s:9:\"_previous\";a:1:{s:3:\"url\";s:40:\"https://sample.com/xxx\";}}\";"
> 
```
object-fit

# object-fit プロパティで使える値

##fill(初期値)
ボックス内を満たすように縦横比を変えながらリサイズされます。

##cover
縦横比を保持してボックスを完全に覆うようリサイズされます。縦横のうち小さい方を基準にして自動的にリサイズし、ボックスからはみ出した部分はトリミングされます。

##contain
縦横比を保持し、ボックスに収まるようにリサイズされます。幅と高さのうち大きい方のサイズに合わせて比率を保持してボックスにフィットさせます。

##none
リサイズせず、そのまま表示します

##scale-down
noneとcontainのうち、小さい方のサイズに合わせて表示します
AngularでWebAPIからblob形式で返された画像データを取得する方法

フロントエンドアプリケーションフレームワークである__Angular(Ionic)を使って、非同期通信で画像を読み込む方法__をサンプルアプリとして紹介します。動作確認用にPythonで作成したバックエンドコード付きです。

[あまりにもアクセスが少ないのでサイトを移しました💦](https://np-sys.com/general/angular%e3%81%a7webapi%e3%81%8b%e3%82%89blob%e5%bd%a2%e5%bc%8f%e3%81%a7%e8%bf%94%e3%81%95%e3%82%8c%e3%81%9f%e7%94%bb%e5%83%8f%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b/)
RubyとPythonの言語の超簡易的比較

#RubyとPythonの比較
Ruby（Rails）の学習も一通り終わり、次の学習言語としてPythonを学んでいこうと思う.
ただ、Pythonとは何か？
どちらも可読性が高いのは知っているが、具体的な違いを持って調べてみた。

##Ruby
1.Rubyは日本人が開発した言語で日本語の文献が多いので比較的、日本人が学習しやすい。
2.Webアプリケーション開発で主に使用される言語（例:twitter）
3.Ruby on RailsなどのすぐにWebアプリケーション（サイト等）を作成するためのフレームワークがあるのでベンチャー企業などに使われることが多い。

##Python
1.シンプルで覚えることが少ない構文。他の言語と比べて短く簡単にコードが書ける（Rubyとどのぐらい差があるかは学習して感じていく）
2.Webアプリケーションにも扱われることもあるが、真の実力を発揮する分野としては機械学習とAI開発にある
3.例として機械学習では大量のデータ（ビックデータ）から解析や計算をすることができるので、マーケティングに使われることもある。(YouTube)

###Pythonの学習の進め方（お金を掛けたくない自己流独学の予定）
1.Progateで基礎中の基礎を学ぶ
2.paizaで動画の閲覧（ドットインストールでも可）
3.図書館から書籍を借り、コードを記述しながら学習（どういうアプリを作成するか考えながら）
4.アイディアを浮かべたものをオリジナルアプリとして形にする（AWSアカウントは別のものでもう使っているのでherokuへデプロイ予定）
【備忘録】Swift 実践入門について　第4章

Swift 実践入門のまとめ。
分からない部分の抜粋も記載し、解決できたら随時更新していきます。
なお、ここに記載している以外でも「わけわからん…」となっている部分も多々ありますが、
今は必要ない、と言い聞かせて飛ばしています。


第4章
コレクション　let a = [1, 2, 3]など要素を複数持ちたいとき。
理解度：80％くらいか

4.2
Array型…[1, 2, 3]

4.3
Dictionary型…let dictionary = [“a” : 1, “b” : 2]　キーワードの“Key”とValue

4.4
範囲型…let range = 1..< 4

4.5
String型のコレクション
Character型…単一文字を示す
String.Index型…startIndexやendIndexなど

4.6
シーケンス…値にアクセスしていく順番。普通は左から順番にアクセスしていくが変更も可能。

・filter…複数のエレメントを持つ変数aに対してlet b = a.filter({element in element % 2 == 0})とすれば、定数bは変数aの偶数番目のエレメントを持つようになる。

・map…全エレメントに変更を加える。let b = a.map({element in element * 2})とすれば、定数bは変数aを２倍したエレメントを持つようになる。

・flatMap…let b = a.flatMap({value in [value, value + 1]})とすれば、定数bはaのエレメントとそのエレメントに1を足した値をそれぞれ持つ。

・compactMap…mapに似ているが、変更できない値があった場合は無視してコンパクトにする。

・コレクションのプロトコル
let a = [1, 2, 3, 4, 5]
a[2] //3
a.isEmpty // false
a.count //5
a.first //1
a.last //5

「.プロパティ」にまだ慣れない。本を読んでいてもSwift側で決められたプロパティなのか、こちらが個人的に決めたものなのかが曖昧。ただ4章まで進めてきて、少しづつ理解が深まってきている気はする。
rakeの使い方

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# rakeとは

rubyで処理内容を定美できるビルドツール．Rakefileにrakeあ実行する処理内容を定義する．
つまり，コマンドを実行するときに役に立つ


# 例

```ruby
task :default do
  system 'rake -T'
  exit
end

desc 'hello worldと表示'
task :hello do
   puts "Hello world!"
  exit
end
```

これをRakefileに書き込み，以下のように実行します．

    > rake -T

すると，Rakefileが用意しているタスクが表示されます．

    > rake hello                                                                  

でタスクの実行．

書き方としては，

-   desc：タスクの説明文
-   task <タスク名>
-   標準のruby言語で，動作を記述
-   end


# githubへの共有を簡単に

```ruby
desc 'git pull'
task :pull do
  p comm = "git pull origin main"
  system comm
  exit
end
```

とRakefileに書き込み，以下のように実行します．

    > rake pull                                                                        

すると， *git pull* が実行できます．

さらに，githubの共有をするためのコマンドも同じように．

```ruby
desc 'git push'
task :push do
  p comm = "git add -A"
  system comm
  p comm = "git commit -m \'hoge\'"
  system comm
  p comm = "git pull origin main"
  system comm
  p comm = "git push origin main"
  system comm
  exit
end
```

    > rake pull                                                                

**[point] p commで命令(command)が何かをpしておくこと**


# 参考

-   [Rakeの基本的な使い方まとめ](http://unageanu.hatenablog.com/entry/20100829/1283069269)



------
 - **source** ~/Desktop/grad_members_20f/members/mm-cell/post_org/rake.org
【1分でできる】aliasを使ってGitコマンドを省略する方法

## はじめに

alias（エイリアス）を使ってGitのコマンドを省略する方法を紹介します。

設定自体は<strong>1分</strong>で終わります！
Gitの設定についても簡単に解説してます。


##設定方法
さっそくですが、以下のコマンドを実行することでGitコマンドを省略することができます。

```bash
$ git config --global alias.<設定したい省略系> <元のコマンド>
```

例えば、git commitをgit ciで実行したいなら

```bash
$ git config --global alias.ci commit
```
という書き方になります。設定は以上です笑

下記はよく使うので、設定しとくと作業がスムーズになります。
どのように省略するかはお好みで！

|元のコマンド|省略系 |
|:-:|:-:|
|commit|ci|
|branch|br|
|status|st|
|checkout|co|
|switch|sw|
|restore|rs|


設定方法だけ知りたい方はここでサヨナラしてもらって大丈夫です。。。

Gitを使い始めたばかりの人や、実行したコマンドの意味がよく分からない人は下の解説を参考にしてください！

##コマンドの解説
上記で実行したコマンドの説明をしていきます！

↓コマンドの復習↓

```bash
$ git config --global alias.(設定したい省略系) (元のコマンド)
```

#### 1. configとは


`config`とはGitの設定を行うためのコマンドで、Gitの設定ファイルに記述を行ってくれます。
設定ファイルにこんな感じで記述しといてって頼むイメージです。

configの和訳は「設定」なのでそのままですね。

オプションに`--global`を使うことでパソコンのユーザー単位で設定を行うことができます。

globalオプションをつけずに設定を行うと、ディレクトリ単位での設定になります。
今、開発しているアプリだけでコマンドを省略したい場合はglobelオプションをつけずに行いましょう。ターミナルで対象のディレクトリまで移動するのを忘れずに。

<strong>なぜオプションをつけることで設定を反映させる範囲が変わるのか？</strong>

それはGitの設定ファイルがそれぞれの単位毎に存在し、オプションによってどのファイルに設定を保存するか指定しているからです。

指定なし →　(Gitで管理している各ディレクトリ)/.git/config
--global →　~/.gitconfig

ですので、最初に使用したコマンドを使わなくても上記ファイルに直接書き込むことで、
Gitの設定を行うこともできます。

ちなみに`--system`でパソコン単位で設定を行うことができます。ユーザーが複数いて同じ設定をしたい場合はこのコマンドを使うと便利です。

設定の優先順位は
1. ディレクトリ単位
2. ユーザー単位
3. パソコン単位
となります。

#### 2. alias（エイリアス）とは 

alias（エイリアス）は超簡単に言うと<strong>ニックネーム</strong>のようなものです。
山田たかし君を山ちゃんと呼んだりタカポンと呼んだりしますよね。あれと同じです。
**Gitでもaliasを登録することでコマンドにニックネームをつけることができます。**


上記で紹介したコマンド以外でもエイリアスを登録できます。
例えば僕は、ログを一行で表示してくれるコマンドのエイリアスを登録しています。

設定方法は以下のようになります。

```
$ git config --global alias.one 'log --oneline'
```
'log --oneline'という名前の友達に'one'とニックネームをつけています。
この場合は元のコマンドをシングルクオテーションで囲む必要があります。

エイリアスの使い方として、単に省略するために使うだけでなく、なかなか覚えられないコマンドを自分が覚えやすい形で登録することで、いちいちコマンドを調べる手間を省けます。


### 終わりに
本記事では初学者の方でも分かるように、Gitコマンドを省略する方法を紹介しました。

Gitに限らずいちいちコマンド打つのってかなりめんどうですよね。。。
履歴を使うのもありですがエイリアスを使えばサクッとGitを使えます。

初学者こそタイピングが遅かったり操作に時間がかかったりすると思うので、この記事が少しでも参考になれば幸いです。

また、この前までaddとcommitとpushしか知らなかった人間が書いた記事なので、ご指摘等あればコメントしていただけると喜びます。

最後まで読んでいただきありがとうございました！！！
今更 Docker - Rails アプリケーションを作りたかった

大人気 Docker を使ってのアプリケーション開発が活発化している（根拠なし）今日このごろ、実務で使っていても **実のところ細かいことについては一切何もわかっていない** という体たらくに終止符を打つべくして、 Rails の開発環境を定義してみよう、というのが本日の題である。

### 先ずはとりあえず実行したい

ということで正しい経路かどうかはわからんが、 [Docker のドキュメント](https://docs.docker.jp/engine/userguide/dockerizing.html) あたりを読み進めていく。重要そうなことが書いてある気がするのを全力で読み飛ばしつつ、まずは取り敢えず対話側での実行をしたい。

```bash
docker run -it ruby:2.6.6 bin/bash
```

~~2.6.6-alpine 使いたかったけど Rails のインストール時にコンパイルエラー食らったから一旦諦める~~
オプションについては

* `-t`: コンテナの中に擬似ターミナル（pseudo-tty）を割り当てる
* `-i`: コンテナの標準出力（STDIN）を取得する

ということらしく、つまり **この指定がないと対話型で使うことはできん** ようだ。

### Rails のアプリを発生させるぞ

コンテナに入ってさえしまえば、あとは単に `rails new` をするだけなので

```bash
gem install rails -v 6.0.3
rails new myapp
```

このままだと `Node.js not installed.` のエラーが出てたりとか、細かくは色々あるようだが、何にせよこれで開発に使えるアプリケーションソースが出来る… **訳がない** のである。

### ホスト側にファイルを置きたいんだけど

知っての通り（？）、コンテナ内のファイルはそのコンテナ内にあるものであって、そのままではホスト側から識別可能なものにならないため、開発に着手するには更に一手必要になる。
これの実現には Docker Volume の活用が必要で、コンテナの作成時に `-v` のオプションを与えると良いらしい。

```bash
# まぁ「今いるところ」なら pwd でいいかなというアレ
docker run -it -v `pwd`:/webapp ruby:2.6.6 bin/bash
```

これにより、ホスト側のカレントディレクトリがコンテナ側の /webapp ディレクトリにマウントされる（= ファイルを突っ込んだ場合はホスト側に配置される）ようになる。ホスト側の任意のディレクトリをマウントしたい場合は **左側も絶対パス指定じゃないと駄目** らしい点には留意が要る。 ~~相対パスでも構わん、と書いてあるのは多分これ別の文脈の説明だな？~~

さておき、この状況であれば /webapp にさえ配置してやれば `rails new` の生成物がホスト側でも確認できるので、

```bash
rails new webapp/myapp
```

とすることで、手元に直接的に Ruby の実行環境を持っていなくても Rails のアプリケーションが作れる。

ひとまずはここまで。実用的な開発環境の定義には Dockerfile や docker-compose の活用が前提だと思うので、遠からずそちらも書き散らしていくとしたい。
HA構成のk8sクラスタで、既存のマスターノードを再構築する

# はじめに

[以前の記事](https://qiita.com/soumi/items/ac5146f4a9ef21aa3284)で作成したHA構成のk8sクラスタの一部がサーバーの物理的な移動の際に壊れてしまい、復帰に手間取ったので記しておきます。

ただ再構築したいだけであれば対象のマスターノードで `sudo kubeadm reset` で済むようなのですが、今回はそのサーバーにアクセスできない状態になってしまったので、手動で色々と削除していきます。

この手順無しで `kubeadm join` でマスターノードを追加しようとすると、

```
[check-etcd] Checking that the etcd cluster is healthy
```

が長時間続き、その後エラーが出ます。
`etcd` に古いノードが登録されていて、それにアクセスしに行こうとしてタイムアウトしているようです。
同じIPでマスターノードを再構築しようとしていても、そのノードが立ち上がる前(`join`の段階で)にアクセスに行くのでエラーが出てしまいます。

# 参考

https://github.com/kubernetes/kubeadm/issues/1300#issuecomment-464955084

基本的にはここに書いてあるままですが、一部古い記述があったので更新していきます。

# ノードを削除する

他のマスターノードから、アクセス不可になったマスターノードを削除します。

```sh
kubectl delete node <master>
```

# etcd クラスタから対象のノードを削除する

まず `etcd` をDLしてきます。
ほぼ参照先と一緒ですが、バージョンを最新にするのと、今回の環境はARMではなくAMD上で動いているのでそこを変更しました。

```sh
mkdir /opt/tools && cd /opt/tools
wget https://github.com/etcd-io/etcd/releases/download/v3.4.14/etcd-v3.4.14-linux-amd64.tar.gz
tar xfz etcd-v3.4.14-linux-amd64.tar.gz
```

実行します。

```sh
cd /opt/tools/etcd-v3.3.12-linux-arm64
sudo ./etcdctl --endpoints https://192.168.0.11:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member list
sudo ./etcdctl --endpoints https://192.168.0.11:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member remove 86a89c4f9f2bf9f3
```

`etcdctl member list` で対象ノードのIDを取得し、 `etcdctl member remove` で削除します。

# kube-configを書き換える

`kube-config` の中にもマスターノードの情報が残っているので、削除します。

```sh
kubectl edit configmap kubeadm-config -n kube-system
```

```yml
  ClusterStatus: |
    apiEndpoints:
      master-1:
        advertiseAddress: 192.168.0.11
        bindPort: 6443
      master-2:
        advertiseAddress: 192.168.0.12
        bindPort: 6443
      master-3:
        advertiseAddress: 192.168.0.13
        bindPort: 6443
```

対象ノードの箇所を削除してください。

# 新しいマスターノードをjoinさせる

ここまで来たら、後は[この記事](https://qiita.com/soumi/items/ac5146f4a9ef21aa3284#m-%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%8E%E3%83%BC%E3%83%89%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)の手順のように `kubeadm join` を実行するだけです！

# 終わりに

`kubeadm` を使用してクラスタを構築しているので、 `etcd` という根幹を成すコマンドを触る事にびびってしまいましたが、何とか復帰できました。
そこそこな時間を悩んでしまったので、この記事が誰かの10分、1時間、半日を節約するための足掛かりになれれば幸いです。
Vue(Nuxt.js)の【Type of the default value for '〇〇' prop must be a function】エラーの対処法

Vue(Nuxt.js)の下記エラーの対処法です。

```
Type of the default value for '〇〇' prop must be a function
```

## propsのdefalutでのエラー

```vue
<script lang="ts">
export default Vue.extend({
  props: {
    items: {
      type: Object,
      default: ''
    }
  }
})
</script>
```
上記のように、propsで値を受け取る時に、出現するエラーになります。

## ObjectやArrayの場合は、関数型で指定する必要がある
`Object、Array`をdefalutに指定する場合は、関数型で指定することでエラーを解消できます。

### Object
```vue
<script lang="ts">
export default Vue.extend({
  props: {
    items: {
      type: Object,
      default: () => {}
    }
  }
})
</script>
```
### Array
```vue
<script lang="ts">
export default Vue.extend({
  props: {
    items: {
      type: Array,
      default: () => []
    }
  }
})
</script>
```

## functionを使っても書けます。
アロー関数ではなく、functionでも書くことができます。
### Object
```vue
<script lang="ts">
export default Vue.extend({
  props: {
    items: {
      type: Object,
      default: function () {
        return {}
      }
    }
  }
})
</script>
```
### Array
```vue
<script lang="ts">
export default Vue.extend({
  props: {
    items: {
      type: Array,
      default: function () {
        return []
      }
    }
  }
})
</script>
```
はじめてのnlコマンド

nlコマンドはテキストデータに行番号を付加する機能を持つ、便利なコマンドラインユーティリティです。ほとんどのUnix系環境では、特別なソフトウェアをインストールをすることなく最初から使うことができるコマンドです。この記事では、はじめて`nl`を触る人でも気軽に試せるよう基本的な使い方を説明します。

# nlコマンドができること

`nl`ができることは「テキストデータに行番号をふる」ことです。それ以上でも以下でもありません。コマンドの機能としてはそれだけですが、行番号をふることに関して様々な要求を満たすためのオプションを持っています。そして他のコマンドと組み合わせることで、その用途は「行番号をふる」という枠を越えて広がっていきます。

# nlコマンドの使い方

## 基本的な使い方

例えば、JR上野東京ライン北行（宇都宮線・高崎線）の駅名が記載された「utl-kita」という名前のテキストファイルがあるとします。ファイルの中身をそのまま標準出力に表示する`cat`を使うと次のようになります。

```console
$ cat utl-kita 
東京
上野
尾久
赤羽
浦和
さいたま新都心
大宮
```

このテキストファイル「utl-kita」に`nl`を使用した場合、以下のような出力になります。

```console
$ nl utl-kita 
     1	東京
     2	上野
     3	尾久
     4	赤羽
     5	浦和
     6	さいたま新都心
     7	大宮
```

これで`nl`によって行の先頭に行番号が付加されたことが確認できたと思います。

## 標準入出力の利用

引数を指定してファイルから読み込む以外にも、標準入力から直接データを受け取ることができます。また、標準入力から受け取ることをより明示的にするために、`-`という特殊な引数も用意されています。標準入出力と`|`（パイプ）を利用することで、様々なコマンドを組み合わせることができます。

さきほどの例は、`cat`と`nl`を組み合わせて以下のように実行しても同じ結果になります。

````console
$ cat utl-kita | nl
     1	東京
     2	上野
     3	尾久
     4	赤羽
     5	浦和
     6	さいたま新都心
     7	大宮
````

パイプを使えばいくつでもコマンドをつなげることができます。以下の例では、`yes`によって出力される「y」に`nl`が行番号を付加し、`head`が先頭3行だけを切り取って標準出力に表示しています。

```console
$ yes | nl | head -n 3
     1	y
     2	y
     3	y
```

#リダイレクトとファイル

行番号を付加したデータをファイルに保存するには、`>`（リダイレクト）を使って出力するファイルを指定します。

````console
$ nl utl-kita > numbered_utl-kita
$ cat numbered_utl-kita
     1	東京
     2	上野
     3	尾久
     4	赤羽
     5	浦和
     6	さいたま新都心
     7	大宮
````

これでファイルに保存することができました。残念ながらリダイレクトで元のファイルへの上書き保存はできません。ファイルが消失するので、試す場合は覚悟を持って試しましょう。

````console
$ nl utl-kita > utl-kita
$ cat utl-kita
$ wc utl-kita
0 0 0 utl-kita
````

リダイレクトで読み込むファイルと同じファイルに出力した結果、データが消失していることがわかります。`wc`は文字数をカウントするコマンドで、出力の3つの`0 0 0`は、左から行数、単語数、バイト数を表します。参考までに元のテキストファイルに対して`wc`を実行したときの結果は以下になります。

```console
$ wc utl-kita 
 7  7 64 utl-kita
$ wc numbered_utl-kita 
  7  14 113 numbered_utl-kita
```

詳しくは説明しませんが、上書き保存をするにはmoreutilsというコマンドユーティリティに含まれるspongeコマンドを利用する方法などがあります。

---

#補足

サンプルの`utl-kita`ファイルは、以下のテキストをプロンプトに貼り付ければ簡単に作成することができます。

```raw
cat <<EOF >utl-kita
東京
上野
尾久
赤羽
浦和
さいたま新都心
大宮
EOF
```
ファイルまたはディレクトリが壊れているため、読み取ることができません

この記事では、「にアクセスできません。<a href="https://jp.bitwar.net/howto/windows/2633.html">ファイルまたはディレクトリが壊れているため、読み取ることができません 削除</a>」という問題を修復する4つの方法を紹介します。

「ファイルまたはディレクトリが壊れているため、読み取ることができません。」は、SDカード、ハードドライブ、外部ハードドライブ、フラッシュドライブなどの外部ストレージデバイスで発生する典型的なWindowsエラーです。このエラーが発生すると、ハードドライブデバイスにアクセスできなくなり、そのデバイス上のデータを使用および処理できなくなります。したがって、この問題を解決する必要があります！


「ファイルまたはディレクトリが壊れているため、読み取ることができません」の原因


論理的問題と物理的問題の両方が原因で、ファイルまたはディレクトリが破損して読み取り不能になる可能性があります。

●ハードドライブの安全でない取り出し

●停電

   ●RAWファイルシステム
    ●ウイルスまたはマルウェアの攻撃

      ●物理的な損傷


「ファイルまたはディレクトリが壊れているため、読み取ることができません。」エラーを解決する前に、まず間違ったデバイスの正中線からすべての貴重なファイルを回復できることを知っています。次に、このエラーを修正します。


紛失または到達不能なファイルを最初に回復する


現在最も信頼性の高いファイル回復ソフトウェアであるBitwar Data Recoveryを使用してファイルをレスキューします。使いやすいウィザードインターフェイスを備えており、コンピューターの操作に慣れていない場合でも、削除、誤ったフォーマット、または失われたファイルデータを簡単に回復できます。 。以下のボタンをクリックして、この使いやすいソフトウェアをダウンロードしてインストールするか、https://jp.bitwar.net/data-recovery-software/ の公式Webサイトからダウンロードしてインストールできます。

   詳しくは、「<a href="https://jp.bitwar.net/howto/windows/2633.html">4つの修復方法「ファイルまたはディレクトリが壊れているため、読み取ることができません</a>」をご参照ください。
ES6記述　備忘録

#ES6記述一覧
##const, let
varで定義していたがES6からはconst,letで定義する。
constは変わらない変数
letは今後変わる可能性がある変数

##テンプレートリテラル
```
’今日は’ + ‘currentDay’ + ‘です’　とかいていたものが
 `今日は${currentDay}です` 　とかけるようになった。
```

##アロー関数でfunctionを省略できるようになった
```
numbers.map(function(number) {
return number + 1;
});
```
 って書いたものが

```
numbers.map((number)  => {
return number + 1;
});
```
とかけて引数が一つの場合は{}とreturnと()も省略できる	

```
numbers.map(number  => number + 1);
とかける
```
##オブジェクトリテラル

```
const fields = ['firstName', 'lastName', 'phoneNumber'];
      
const props = { fields: fields };
```
と書いていたが、keyとvalueが同じ値なら :valueを省略できる

```
const fields = ['firstName', 'lastName', 'phoneNumber'];
      
const props = { fields };
```
###関数(function)も省略
```
const color = 'red';

const Car = {
  color: color,
  drive: function() {
    return 'ブーーン!';
  },
  getColor: function() {
    return this.color;
  }
};
```
と書いていた物が

```
const color = 'red';

const Car = {
  color,
  drive() {
    return 'ブーーン!';
  },
  getColor() {
    return this.color;
  }
};
```
とかける。

##デフォルト引数

```
function addOffset(style) {
  if (!style) {
    style = {}; 
  }
  
  style.offset = '10px';
  
  return style;
}
```
と書いていた物が

```
function addOffset(style = {}) {

  style.offset = '10px';
  
  return style;
}
```
と引数に直接デフォルト値を設定できる。

##Rest,Spread演算
```
function unshift(array, a, b, c, d, e) {
  return [a, b, c, d, e].concat(array);
}
```
と書いていた物が

```
function unshift(array, ...rest) {
  return [...rest, ...array];
}
```
と書けるようになった。

```
/** スプレッド構文  */
const arr1 = [1,2,3,4,5];
const arr2 = [9,0,7,6,8];
/** 配列の残り  */
function unshift(array, ...rest) {
  return [...array, ...rest ];
}
console.log(unshift(arr1,6,7,8,9));
/** 配列をコピー */
const arr3 = [...arr1];
console.log(arr3);
/** arr6 = arr3[0]と書いてもarr1[0]が変更されない。 */
/** 配列を結合 */
const arr4 = [...arr1, ...arr2];
console.log(arr4);
```
##分割代入
```
/** 分割代入 とテンプレート文字列 */
const profile = {
  name: 'aaa',
  age: 22,
};
const message1 = `私の名前は${profile.name}です。年齢は${profile.age}`
console.log(message1);
/** profileを何回も書かなくて済む  */
const { name, age } = profile;
const message2 = `私の名前は${name}です。年齢は${age}`
console.log(message2);

```
`const { name, age } = profile;`
と一行でかけるようになった。
Float型にて、計算した際に、値に少々ズレが生じる件について

# 環境
Ruby 2.6
Rails 5.1.7


# 背景
機能実装中、数値を計算する処理が何か合わないなぁと思ったら表題の現象が起きてた。
これは初めて遭遇したので備忘録として。

# 現象
```:ruby
irb(main):005:0> 2.2 * 100
=> 220.00000000000003
irb(main):006:0> 2.3 * 100
=> 229.99999999999997
irb(main):007:0> 2.4 * 100
=> 240.0
```

Float型に100掛けると何故か100倍になっておらず少々の誤差があることに気づいた

# 対応
https://qiita.com/yusabana/items/fd4a0185c1f120403a74
こちらの記事を参考にBigDecimalを使用してあげると綺麗な数値が出る

```:ruby
irb(main):017:0> (BigDecimal(2.2.to_s) * 100).to_f
=> 220.0
irb(main):015:0> (BigDecimal(2.3.to_s) * 100).to_f
=> 230.0
irb(main):018:0> (BigDecimal(2.4.to_s) * 100).to_f
=> 240.0
```

以上
2020年 GOJAS活動報告

こんにちは！
Go Japan Splunk User Group(GOJAS)のOrganizerの山田です。

2020年は公私ともに様々なことがありました。
一番のトピックは、やはり新型コロナウイルスとその影響だと思います。

世界中に影響のある、まるで映画のようなパンデミックを経験するとは思っていなかったです。
東京オリンピックの延期、働き方改革、一部の職種のかたの業務崩壊など、計り知れないほどの影響と変化がありました。
まだ先が読めない状態ですが、1日でも早く落ち着くことを願っております。

そんなすったもんだの2020年。
コミュニティ活動も、多くの制限がある中、最大限のパフォーマンスを発揮できるよう準備と改善をしてきました。

まずはオンライン化。
GOJASのイベントに参加されるみなさま、関係者のみなさまは、ITリテラシーの高いかたが多く、オンライン化への転換はサクっとできたのかなと考えています。
どんな試行錯誤をしてきたかは、2020年11月に開催されたDevRel ASIA 2020にて発表をしておりますので、そちらをご参照ください。
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/_yiigWlU6w4/0.jpg)](https://youtu.be/_yiigWlU6w4)
補足ですが、コミュニティとはなんぞやという概要セッションもありますので、こちらのおだしょー氏のセッションを先に視聴してからのほうがシックリくると思います。
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/_uIF3KWENtE/0.jpg)](https://youtu.be/_uIF3KWENtE)

2020年のGOJASは、210名の新規参加者のかたがいらっしゃいました。
イベント開催回数は合計10回です。
そして2020年4月には、累計参加者数が1,000名を超えました!!:raised_hands:

簡単にGOJAS発足時から現在までの参加者推移を可視化してみました。
![GOJAS登録数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528751/9cc26567-7a26-b5a4-e421-25a298205acd.png)

新型コロナウイルスの影響もありましたが、熱量と勢いを保って成長できたのは、新しいカタチでのご講演を受諾いただけたご講演者のみなさま、新しい運用で事故なく実施できたGOJAS運営スタッフのみなさま、そしてなにより、暖かく寛大な気持ちでご参加いただいたゲストのみなさまのお陰です。
感謝しかありません。
引き続き2021年も変わらぬ勢いで爆速してまいりますので、よろしくお願いします!!

※運営スタッフ募集中です。
　ご興味あるかたは、最寄りのGOJASスタッフもしくはSplunk Japanのかたへお声掛けください。
【TypeScript】同じローカルファイルを読み込む

# はじめに
JavaScriptで同じローカルファイルを読み込もうとなったとき、[JavaScriptで同じローカルファイルをもう一度読み込む](https://qiita.com/te20/items/00a72535163c6d632408)に辿り着くかと思います。
ですが、TypeScriptで同じことをやろうとなった時、型に悩まされます。
本記事では[FileReader](https://developer.mozilla.org/ja/docs/Web/API/FileReader)を用いて、TypeScriptで同じローカルファイルを読み込む解決法の一つを提示していきます。
この記事のコードは[stackblitz](https://stackblitz.com/)で試しました。

# コード
## HTML

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./main.ts" async></script>
</head>
<body>
    <input type="file" id="input-file">
</body>
</html>
```

[input type="file"](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/file)を用いてファイルを取ってきます。

## TypeScript

```typescript
function main() {
    const reader = new FileReader();
    reader.addEventListener("load", e => {
        console.log(e.target.result);
    });

    const inputFile = document.getElementById("input-file");
    if (!inputFile) return;
    inputFile.addEventListener("change", e => {
        const target = e.target as HTMLInputElement;
        reader.readAsText(target.files[0]);
        target.value = "";
    });
}

main();
```

これでファイルを選択したあとconsoleにファイルの中身が表示されます。
[HTMLInputElement](https://developer.mozilla.org/ja/docs/Web/API/HTMLInputElement)に[型アサーション](https://qiita.com/irico/items/9d71060e52ffc1e79962)してあげることで、e.targetのfileやvalueにアクセスできるようになります。

また、inputのvalueを空にしてやることで、同じファイルを読み込めるようになります。
こうなると、ファイル読み込みの横に表示されていた、現在選択されているファイルは何も選択されていない状態と同じになります。最後に読み込んだファイルを表示しておきたい場合は、上記のコードの`target.value`を[innerText](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/innerText)などで表示してから`target.value = "";`すると良いかと思います。

# おわりに

DOMに関連した型は知らないと解決が難しいです。
[stackblitz](https://stackblitz.com/)は雑に便利なので使いましょう。
SeleniumでElementNotInteractableExceptionが発生した時の対処法

JavaのSeleniumでチェックボックスをクリック（チェック）しようとしたら、ElementNotInteractableExceptionが発生した。

```java:元のコード
  WebDriver driver = new ChromeDriver(driverService, options);
  // 省略
  driver.findElement(By.id("checkbox")).click();
```

```text:発生した例外
org.openqa.selenium.ElementNotInteractableException: element not interactable
```

同様の操作をJavaScriptで行なったら成功した。

```java:修正後のコード
  JavascriptExecutor executor = (JavascriptExecutor) driver;
  executor.executeScript("arguments[0].click();", driver.findElement(By.id("checkbox")));
```

何故だｗ
public変数とprivate変数のアクセス権限について

#概要
親の変数はpublicのみアクセス可能、privateはアクセスできない

```Java
/*
 * 親クラス
 */
public class Magician {
	public String Skil_rod; // 両手杖
	private String Skil_short_sord; //短剣
	private String Skil_whip; // ムチ
	public String Skil_shield; // 盾
	private String Skil_magic; // まほう 
}

/*
 * 子クラス
 */
public class Pundit extends Magician{
	Pundit(String rod,String shield){
		this.Skil_rod = rod; // 杖
		this.Skil_shield = shield; // 盾
	}
}
```

#概要
概要を書きます

#実装内容

#作成方法

#引用
>
>ここに引用する内容を記載します
>

*test
+test
-test

#参考

https://qiita.com/shizuma/items/8616bbe3ebe8ab0b6ca1
Amazon Connect Voice ID とAmazon Connect Wisdom がプレビュー公開されました！！

#はじめに
**この記事は株式会社ナレッジコミュニケーションが運営する [Amazon AI by ナレコム Advent Calendar 2020](https://qiita.com/advent-calendar/2020/knowcom-amazonai)  の 17日目にあたる記事になります。**

Amazon Connect Voice ID とAmazon Connect Wisdom がプレビュー公開されることが発表されましたね！
私もさっそくこれらのサービスを検証するべくプレビュー申請をしてきました！

#Amazon Connect Voice ID とは？
いままでコールセンターに電話をした時に、本人確認のために生年月日やお客様番号などを聞かれることが多かったのではないでしょうか？
この煩わしいプロセスがなくなればユーザーにとっても職員にとっても嬉しいですよね。
Voice ID は機械学習を利用してリアルタイムで発信者認証を行うことで、
**電話したら気づかぬうちに本人確認終わっていた**という驚異のユーザー体験を提供することができます。

#Voice ID の認証プロセス
認証プロセスは非常にシンプルかつシームレスです。

ユーザーの音声通話をもとにユーザー固有の音声認証（Voice ID）を登録
※登録には30秒程度の通話が必要です。
↓
Voice ID 登録後に再度電話すると、対話型の自動音声かエージェントとの会話中に本人確認を実施
※本人確認には10秒程度の通話が必要です。
※本人確認の結果は信頼性を示す認証スコアとして 0 〜 100 で返されます。
※認証スコアが一定以下ならエージェントが口頭で本人確認を実施といった利用が可能です。

#Amazon Connect Wisdom とは？
ユーザーのお問い合わせに回答する場合、情報の検索に時間を要することがあったのではないでしょうか？
Amazon Connect Wisdom を利用すれば、エージェントがユーザーの課題を解決するための必要な情報を機械学習によって効率的に検索することができます。

また会話から自動で課題を検出するContact Lens for Amazon Connect と併用することで、エージェントは検索操作せずとも必要な情報にアクセスすることが可能になります。

#料金
Amazon Connect Voice ID とAmazon Connect Wisdom のどちらも現時点で利用料金は公表されていません。

#プレビュー登録のやり方
![2020-12-11_09h57_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578416/e9742f61-da85-cda6-beae-f8a9275aa79c.png)
プレビューを申し込むには、
以下のサイトにある"プレビューにサインアップ"をクリックしてください。
[Amazon Connect Voice ID](https://aws.amazon.com/jp/connect/voice-id/)
[Amazon Connect Wisdom](https://aws.amazon.com/jp/connect/wisdom/)

![2020-12-11_09h58_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578416/70971a06-a4e4-3819-37e4-12d8e7072d73.png)
上記のような画面に変遷するはずです。それぞれの欄を埋めていきましょう。

![2020-12-11_10h12_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578416/3b7d68d1-9862-960b-16d3-3249d020b979.png)
登録申請が完了すると上記のメールが届きます。
結果が分かるまで時間がかかるので気長に待ちましょう。

#おわりに
今回は残念ながらプレビュー登録の結果が間に合わなかったため、実際に使用できませんでした。
プレビュー申請が通り次第、実際のレビュー記事を執筆していきたいと思います。
次回をお楽しみに！
電子署名(タイムスタンプ)のフォーマットと有効期限について

# 電子署名(タイムスタンプ)のフォーマットと有効期限について
## 長期署名フォーマット
フォーマットを重ねていくことによってより長期の有効期限で署名を検証できるようにしている
ざっくりで以下の3つになり、有効期限10年以降は`ES-A`を重ねていくことで10年、20年...と延長できる。

### ES
電子署名を付与
文書、公開鍵、ハッシュ値のセット
これだけでは有効期限1~3年

### ES-T(タイムスタンプ)
ESに署名タイムスタンプを付与する
タイムスタンプの有効期限の10年が延長される。
別途で失効リストが必要になる。

### ES-A(タイムスタンプ)
ES-Tにさらに上乗せてで署名タイムスタンプを付与することで、有効期限が10年ごと繰り返し延長できる。
タイムスタンプの付与では失効リストなど検証に必要な情報を全て含めて付与をする。

## 付与イメージ

ES <- ES-T <- ES-A <- ES-A <- ES-A ...

## 長期署名標準規格
- CAdES
- XAdES
- PAdES

## 国内での主なタイムスタンプサービス(2020年11月時点)
- アマノセキュアジャパン: [e-timing](https://www.e-timing.ne.jp/)
- セイコーサイバータイム: [セイコータイムスタンプサービス](https://www.seiko-cybertime.jp/product/time_stamp/)

# 参考
- https://www.nii.ac.jp/service/openforum2018/track/pdf/20180621PM_GN_UPKI02_Nishiyama02.pdf
- http://eswg.jnsa.org/sandbox/handson/ESig-PKI-handson-doc-v100.pdf
- https://www.itis.nssol.nipponsteel.com/blog/contracthub/hint20.html
【ServiceNow】ユーザーフィールドに直接ユーザー ID を入力して検索できるようにする方法

#概要
ServiceNow には Auto-complete という機能があり、リファレンスになっている項目に値を入力していくと、その値で検索をかけてくれます。
例えば、インシデント画面のサービスフィールドに、「SAP」と入力すると、名前が「SAP」から始まるサービスを検索してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/7144115e-e51a-fa43-bdc8-58f3d3791508.png)

この検索は、デフォルトでは Display になっている項目に対して行われますが、Auto-complete 関連の Attribute を設定することで、任意のフィールドを検索対象にすることができます。

#手順
今回は、インシデントの問い合わせユーザーフィールドに対して、「名前」だけでなく、「ユーザー ID」と「email アドレス」でも Auto-complete の検索ができるようにする手順を紹介します。

まず、問い合わせユーザーフィールドのラベル部分を右クリックし、「ディクショナリを設定」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/d2cdc822-00b8-f16c-edc8-51f6f6119d15.png)

問い合わせユーザーフィールドのディクショナリ設定画面の属性フィールドにデフォルトでなにか値が入っているかと思いますが、ここに以下の値を追加します。
,ref_ac_order_by=user_name,ref_ac_columns=user_name;email,ref_auto_completer=AJAXTableCompleter
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/446c7753-99c2-0145-07cd-81adee60fd93.png)

属性フィールドは詳細ビューでしか出てこないので、画面に出てこない場合は、ビューを切り替えてみてください。
各属性の意味については、以下のリンク先を参照ください。
https://docs.servicenow.com/bundle/paris-platform-administration/page/administer/field-administration/concept/c_AutoCompleteForReferenceFields.html


これで、設定は完了です。
インシデントの画面に戻り、ユーザーフィールドに ID を入力していくと、IDでも検索がされていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/94e22c21-0a1f-c662-f673-71dd26620cd3.png)

#補足
Auto-complete の機能は、Catalog item や Record producer でも利用でき、同じ Attribute で設定できます。
Amazon Data Lifecycle Manager (DLM) でAMIライフサクル管理

# 概要
2020/11/09のアップデートで、「Data Lifecycle Manager で AMI ライフサイクル管理が利用可能に」の発表がありました。
DLMでAMIバックアップを試してみたいと思います。

[Data Lifecycle Manager で AMI ライフサイクル管理が利用可能に](https://aws.amazon.com/jp/about-aws/whats-new/2020/11/ami-lifecycle-management-available-data-lifecycle-manager/)

# Amazon Data Lifecycle Manager とは

EBSスナップショットとAMIの作成、保存、削除を自動化してくれる機能です。

【小ネタ】
　2020/11/27時点で日本語公式サイトは更新されていませんでした。
　最新情報は英語版を確認しましょう。
　日本語
　https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/snapshot-lifecycle.html
　英語
　https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/snapshot-lifecycle.html

# やってみた

マネジメントコンソールからEC2の管理画面を開き、左メニューの「ライフサイクルマネージャー!をクリックします。

|![dlm_ami_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/6d3b1806-0320-f5d2-5937-d4403963fe7e.png)|
|:-:|

「ライフサイクルポリシーを作成」ボタンを押します。

|![dlm_ami_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/fa2a1252-7a7d-a1f7-21f8-4debeef181fe.png)|
|:-:|

ライフサイクルポリシー作成画面に移動するので、ポリシータイプを「EBS-backed AMIポリシー」を選択、説明、ターゲットとなるタグを指定します。

|![dlm_ami_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/d97999ae-b415-3f2e-2bcd-57499ecdef6a.png)|
|:-:|

IAMロールは、デフォルトロールを選択
※ 既にロールが存在する場合は、別のロールを選択でもOK

|![dlm_ami_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/e40c3a16-3e13-5e97-855e-1933aec029d7.png)|
|:-:|

ポリシースケジュール1に「スケジュール名」、「頻度」、「取得間隔」、「開始時間」、「保持タイプ」、「保持する」を設定します。
サンプルでは１時間ごとに３世代保持と設定しました。

|![dlm_ami_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/443dff08-42cb-e14a-4acb-87f730ffd6f2.png)|
|:-:|

取得したバックアップに追加で設定するタグを指定します。

|![dlm_ami_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/76f52d1c-4a7c-cdd6-37f2-027166c40595.png)|
|:-:|

クロスリージョンコピーの設定をします。
（オプション）なので指定しなくても良いが検証のため設定しました。

|![dlm_ami_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/8eb2511f-5022-5f2b-2916-f03e815a3c90.png)|
|:-:|

最後にインスタンスの再起動の実施、作成後のポリシーステータスを指定し、「ポリシーの作成」ボタンを押します。

|![dlm_ami_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/8816cd0d-d8bd-6097-5190-d95394ee5343.png)|
|:-:|

以下のような成功メッセージが表示されればライフサイクルポリシーの作成が完了です。

|![dlm_ami_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/9adbb6a9-6a9e-a6e1-ab25-fbca8d45e3e0.png)|
|:-:|

# 設定後の確認

しばらく待ちます・・・

### 東京リージョン

想定通り、１時間ごとに３世代AMIバックアップを取得できていました。

|![dlm_ami_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/128a5d2f-7be3-da34-fb0f-fafbbdda6273.png)|
|:-:|

### ソウルリージョン

クロスリージョンコピー先ですが、こちらは履歴管理はしてくれない模様です。
確かに設定はないですが、長時間放置したら、273個もAMIバックアップがコピーされていました。。。
クロスリージョンコピーを指定する場合は注意が必要そうです。

|![dlm_ami_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641560/ca449efe-55f4-cf6b-6b3e-6ccd4d9a8603.png)|
|:-:|

# 所感

数年前にEBSスナップショットのライフサイクルが取得可能となり、今回、AMIでも利用可能となりました。
以前は、Shell、Cronなど。その次にLambdaなどで自前実装していたため、機能として実装されると非常に楽になったなぁと感じました。

誰かのご参考になれば幸いです。
SteinでSpreadSheetからデータを複数条件（AND）でとって動的にメッセージを作成

#「今日飲みに行きたい人」を募るLINE Botを作っています

タイトルを汎用的なものに言い換えると、
__「DBからデータを抽出して、配列を作るよ。」__
です。

飲みに行く人を誘いにくい状態が続きますが、
もう少し落ち着いたら、対策はしたうえで飲みに行くこともありそうですね。
社内など、__知らない人もある程度混じっているコミュニティ__で、
「今日飲みたい」と思ったときに誘えるLINE Botを作っています。

<img width="300px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/f8caf70d-9175-8717-a9f1-0415053c878d.gif">

こんなサービスを実際に__誰かに動くところを見ていただきたく__て、
__使う人が「飲みに行きたい」とやったら、その人の名前（あらかじめ登録した）が出る。__
という基本部分だけとりあえず動的に動くようにしました。

今までは、固定の人に対して送るようにしていましたが、
実際に自分の名前が出たほうが楽しくなるかと思い、今回の対応をしました。

ただ、飲みに行く人数は4人一組にしたかったのですよ。そこで、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/82827b3a-b893-b1dd-6da5-f56bf202bc95.png)


このような形で、日にち・何番のグループ・何人目というデータを作りました。

```javascript

// 最後に登録した人が所属するグループに入っている名前を取得して格納
let userNameList = await store.read(tranSheet, { search: { date: today, group_no: groupNo.toString() } }).then(data => {
                        return data
                    }).catch(e => console.log(e))
```

今日、かつ、グループNoを指定して、そのグループにいる人たちを取得します。
抽出した人たちを宛先にセットして、

```javascript
let pushText;
pushText += "　グループの飲みに行くメンバーは、"
// 同じグループの人数分ループ
for(var i = 0 ; i <= userNameList.length - 1 ; i++ ){
   pushText += userNameList[i].user_name + "さん、";
}
pushText += "です！張り切っていきましょう！"
```
このような形でメッセージを作ります。そのメッセージを最終的にチャンネルに登録されている方たちに絵文字を文末につけて配信。

```javascript

let textLength = pushText.length;
pushText += "$";

// チャンネルに登録されている方たちに連絡
await client.broadcast([{
    "type": "text",
    "text": pushText,
    "emojis": [
        {
            "index": textLength,
            "productId": "5ac1bfd5040ab15980c9b435",
            "emojiId": "002"
        }
    ]
},{
    type: "sticker",
    packageId: "11537",
    stickerId: "52002745"
}]).then(data => console.log(data))
.catch(e => console.log(e))

```


#構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/562b87f4-70df-5d57-2986-016f4b7ce6bc.png)

LINEでメッセージを送ると、Node.jsで受け取って処理する。
その際、Steinを使って、SpreadSheetをDB代わりに、
　append(INSERT)　飲みに行きたい人追加や名前登録
　search(SELECT)　今日飲みに行きたい人のグループを抽出
　delete　キャンセル
　update　名前の更新


#今回つまったポイント　複数条件の設定
Steinというサービスを使って、Google Spread Sheetをテーブルとして使ってデータを入れたり出したりしています。

[参考URL　Stein](https://docs.steinhq.com/search-data)

複数条件指定したときに、なぜかデータが0件だったり、2つ目の条件が効いてないという現象が起きた。。
そもそものSteinのメソッドを呼び出すときの書き方の問題なのか、
複数条件を設定できない仕様なのか。（DBとしてそんなことはまずないだろうと思ってはいた。）

[複数条件でデータ抽出できたメモ](https://qiita.com/Sugizo50073508/items/9ef40ed0b8cf22481991)



__気を付けよう。以下のポイント__
・SpreadSheet　とってくるときは__文字列型__。数値型で入れたのにな！！SpreadSheet上も数値のよう。右寄せなので。
・Node.js　__数値型__。次のグループNoなど足し算をしたかったので数値で取り扱っています。最初、何も気にしなかったら文字列型になっていて、2+1→21になっていた。笑

#反省としてJavaScript特有？の型のあいまいさをどうするか考えていく
今回の考察として、そもそものSteinの構文で、
複数条件を指定した例がなかなか見つからなかった＋公式ドキュメントを見ると書いてあるが、推測通りなのかわからなかった。
（たぶんJSONみたいな指定だから、2つ目の条件はカンマで区切って書くよな・・・と理解はしていた。）

そのため、別の理由で間違ってても構文が間違ってる！？と思い込んでしまっていた。
__実際は、型が誤っていてデータをとれなかった。型をうまく変換できてなかったなどが理由だった。__

今後の方針として、文字列型なのか数値型なのかは、__ちゃんと都度値が取れているかで判断するか__、明示的に__型指定__してから扱おう。
と学んだ。
この考え方はif文の条件とかでも使えそう。「==」で判断するのか、「===」で判断するのかの違い。
みなさんどうやってるんだろう。



今回全体のソースは長すぎるので、ひかえておきます。。。
JUnitを学ぶために調べたサイト一覧

JUnitを学ぶために調べたサイト一覧

#検索「junit 使い方」
JUnitの使い方（初級）
https://qiita.com/YutaSaito1991/items/46707049d0a26086b443

JUnitのアサーションとMatcher API
https://qiita.com/maple_syrup/items/9b45f3a36a44682bf1fa

JUnit（techscore.com）
https://www.techscore.com/tech/Java/Others/JUnit/index/

#検索「assertequals junit」
JUnit入門（勉強メモ）
https://qiita.com/yuk0ga/items/74a0dbe36da02b358451

これだけは覚えたい、ユニットテストを書くための４つのデザイン
https://qiita.com/koduki/items/4fde43b68fe450c6a5d8
ArduinoのセンサモジュールをPythonに反映させてみた

#ArduinoのセンサモジュールをPythonに反映させてみた
授業でpythonでゲームを作ることになったので、コントローラをArduinoで自作しようと考えたのですが、細かい記事が見当たらなかったので投稿してみました。

##参考記事
https://omoroya.com/arduino-lesson13/
https://shizenkarasuzon.hatenablog.com/entry/2018/09/29/180625#5byte%E5%9E%8B%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%97%E4%BF%A1

##環境
・Arduino UNO
・Arduino IDE 1.8.13
・2軸ジョイスティックモジュール
https://akizukidenshi.com/catalog/g/gM-08763/
・python 3
・pyserial 3.5

##Arduino側

```c

const int X_PIN = A0;  // X軸方向の入力をアナログピンA0に
const int Y_PIN = A1;  // Y軸方向の入力をアナログピンA1に
const int SW_PIN = 2;  // センタースイッチの入力をデジタルピンD2に
 
byte X_POS ;   // X軸方向の読み取り値の変数をbyte型に
byte Y_POS ;   // Y軸方向の読み取り値の変数をbyte型に
byte SW_POS ;  // センタースイッチの読み取り値の変数をbyte型に
 
 void setup(){
 
   pinMode(X_PIN, INPUT);          // A0ピンを入力に(省略可)
   pinMode(Y_PIN, INPUT);          // A1ピンを入力に(省略可)
   pinMode(SW_PIN, INPUT_PULLUP);  // D2ピンをプルアップして入力に
 
   Serial.begin(115200); // シリアル通信の開始
   //Serial.begin(9600); 
  
}
 
 
 void loop(){
 
   X_POS = analogRead(X_PIN)/5;     // X軸方向のアナログ値を読み取る
   Y_POS = analogRead(Y_PIN)/5;     // Y軸方向のアナログ値を読み取る
   SW_POS = 1-digitalRead(SW_PIN);  // センタースイッチの状態を読み取る

   Serial.write('H');               //ヘッダー
   Serial.write(X_POS);
   Serial.write(Y_POS);
   Serial.write(SW_POS);

 
   delay(100);

 }
```
Arduinoとジョイスティックの接続についてはたくさん記事があるので省略します。
工夫した点は2つ。
1つ目はSerial.writeでシリアル通信にセンサー値を載せるときにbyte型にします。多くのサイトではArduino IDEのシリアルレポート機能を使うためにint型にしていますが、シリアル通信はbyte型でのやりとりが楽です。Serial.printにしてstring型で送ることも可能。
2つ目はヘッダーを付加することです。pythonでシリアル通信のデータを受け取る際、1つ目のデータはX座標、2つ目はY座標3つ目はスイッチと受け取りますが、通信ラグを考えると1つ目のデータはY座標、2つ目はスイッチ、3つ目はX座標と入れ替わった順番で送られてくる可能性があるため、ヘッダーを付加しました。


##Python側

Pyserialを使います。

```
pip install pyserial
```

ゲーム内のコードがこちら。

```python
import serial
class Game:
    def __init__(self):
        self.ser = serial.Serial('COM3', 115200, timeout = 0.1)
        self.serialheader='H'.encode('utf-8')

    def __del__(self):
        self.ser.close()

    def keyboard(self):
        while True:
            if self.ser.read() == self.serialheader:#ヘッダーを受け取った時、シリアル通信のデータを受け取る
                switchflag = False
                    joyx = int.from_bytes(self.ser.read() , 'big')#x座標を読み取ろ
                    joyy = int.from_bytes(self.ser.read() , 'big')#y座標を読み取り
                    switch=self.ser.read()                        #スイッチを読み取り
                    if  switch == b'\x01':　　　　　　　　　　　　　
                        switchflag=True
                    else:
                        switchflag=False
```

pyserialの基本的な使い方をしています。serial.Serialの引数ですが、pyserialのバージョンによってポートの書き方が異なるそうです。自分の場合は'COM+番号'(デバイスマネージャーに表示されるやつ)でした。

ヘッダーを受け取ったとき、シリアル通信を受信した順にX座標、Y座標、スイッチとデータを受け取ります。
また、繰り返し処理が重くならないように、スイッチのバイナリとヘッダーに関しては、あらかじめbyte型にencodeしたもので論理文を作成し、decodeの手間を極力省きました。

以上拙いものではございますが、Arduinoでジョイスティックの操作をpythonのゲームに反映させることができたので共有しておきます。
Shared VPC構成でサービスプロジェクトから使用することができるサブネットを限定する方法

GCPのShared VPC構成ではホストプロジェクトにあるサブネットに対してサービスプロジェクトのユーザーがVMなどを設置する権限を払い出すことができます。
このときに注意しないといけないのは、IAMによって権限を払い出す対象はプロジェクトではなくユーザーであるということです。
そのため、複数のプロジェクトでVMを設置する権限を持っているユーザーによって予期しない形でVMが建てられることがあります。

例えば、以下の構成を考えます。

```terraform
resource "google_compute_shared_vpc_service_project" "service-project-a" {
  host_project    = var.host-project
  service_project = "service-project-a"
}

resource "google_compute_subnetwork" "subnet-a" {
  name = "subnet-a"
  ...
}

data "google_iam_policy" "policy-a" {
  binding {
    role    = "roles/compute.networkUser"
    members = ["taro@example.com"]
  }
}

resource "google_compute_subnetwork_iam_policy" "policy-a" {
  project     = var.host-project
  subnetwork  = google_compute_subnetwork.subnet-a.name
  policy_data = data.google_iam_policy.policy-a.policy_data
}

resource "google_compute_shared_vpc_service_project" "service-project-b" {
  host_project    = var.host-project
  service_project = "service-project-b"
}

resource "google_compute_subnetwork" "subnet-b" {
  name = "subnet-b"
  ...
}

data "google_iam_policy" "policy-b" {
  binding {
    role    = "roles/compute.networkUser"
    members = ["taro@example.com"]
  }
}

resource "google_compute_subnetwork_iam_policy" "policy-b" {
  project     = var.host-project
  subnetwork  = google_compute_subnetwork.subnet-b.name
  policy_data = data.google_iam_policy.policy-b.policy_data
}
```

この時、service-project-aはsubnet-a、service-project-bはsubnet-bのみを利用することを意図しているとします。
しかし、両方のサブネットに対して権限を渡している `taro@example.com` はservice-project-aのVMをsubnet-bに建てることができます。
サブネット毎に権限を払い出すユーザーの重複がないようにすればこのような自体を防ぐことはできますが、複数プロジェクトにアサインされているメンバーのことを考えると現実的に厳しいケースもあります。

# 解決策
GCPのOrganization Policyを使うことでこの問題を解決することができます。

https://cloud.google.com/resource-manager/docs/organization-policy/overview

Organization Policyは特定のOrganizationやFolderやProjectに対する操作を制限することができる機能です。
aws Organizationを使ったことがある人ならば、サービスコントロールポリシー(SCP)に近しいものという説明がわかりやすいでしょう。


以下のコードを反映するとproject-aが使用できるサブネットワークがsubnet-aに限定されます。また、同様にproject-bとsubnet-bの間でも同様の設定がされます。

```terraform
resource "google_project_organization_policy" "restrict-shared-vpc-subnetworks-a" {
  project    = "service-project-a"
  constraint = "compute.restrictSharedVpcSubnetworks"

  list_policy {
    inherit_from_parent = false
    allow {
      values = [
        "projects/${var.host-project}/regions/${google_compute_subnetwork.subnet-a.region}/subnetworks/${google_compute_subnetwork.subnet-a.name}"
      ]
    }
  }
}

resource "google_project_organization_policy" "restrict-shared-vpc-subnetworks-b" {
  project    = "service-project-b"
  constraint = "compute.restrictSharedVpcSubnetworks"

  list_policy {
    inherit_from_parent = false
    allow {
      values = [
        "projects/${var.host-project}/regions/${google_compute_subnetwork.subnet-b.region}/subnetworks/${google_compute_subnetwork.subnet-b.name}"
      ]
    }
  }
}
```

なお、この時にTerraformに対して割り当てる権限はホストプロジェクトのOwner権限だけでは不十分であり、Organizationに対するroles/orgpolicy.policyAdminのRoleを割り当てる必要があります。
https://cloud.google.com/iam/docs/understanding-roles#organization-policy-roles
Unityで2つのアプリをUDPでローカル通信させる

#はじめ
デュアルモニターで2つのアプリを起動。
片方をお客様用。片方はスタッフ用のような使い方を前提にしています。

#コード
UDPマネージャー

```UdpManager.ts
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

namespace Model.UserDatagrams
{
    public class UdpManager : MonoBehaviour
    {
        public delegate void Callback(UdpData udpData);

        private Callback _callbacks;

        public void AddCallback(Callback callback)
        {
            _callbacks += callback;
        }

        private const string Host = "localHost";
        private const int ReceivePort = 10011;
        private const int SendPort = 10012;
        private const string AppType = "app01";
        private UdpClient _client;
        private Thread _thread;

        private void Start()
        {
            _client = new UdpClient();
            _client.Connect(Host, SendPort);
            _thread = new Thread(Receive) {IsBackground = true};
            _thread.Start();
        }

        /// <summary>
        /// UDPで送信
        /// </summary>
        /// <param name="text">送信コメント</param>
        public void Send(string text)
        {
            var data = new UdpData()
            {
                AppType = AppType,
                Text = text
            };
            var json = JsonUtility.ToJson(data, true);
            var dgram = Encoding.UTF8.GetBytes(json);
            _client.Send(dgram, dgram.Length);
        }

        private void Receive()
        {
            var receiver = new UdpClient(ReceivePort);
            //古い書き方のかなぁ。エラーが出る。
            //receiver.Client.ReceiveTimeout = 1000;
            while (true)
            {
                try
                {
                    IPEndPoint anyIp = null;
                    var bytesData = receiver.Receive(ref anyIp);
                    var text = Encoding.UTF8.GetString(bytesData);
                    var udpData = JsonUtility.FromJson<UdpData>(text);
                    _callbacks(udpData);
                }
                catch (Exception err)
                {
                    Debug.Log("catch :" + err);
                }
            }
            // ReSharper disable once FunctionNeverReturns
        }
        private void OnApplicationQuit()
        {
            _thread.Abort();
        }
    }
}




```
git
https://github.com/kawamurashin/UnityUDPManagerTest

#サンプルアプリ
Git https://github.com/kawamurashin/UnityUdpManagerApp1

片方だけのアプリだけでは操作できないように、両アプリ起動をコントロールします。

アプリ起動後の準備中として相手のアプリの状況を確認します。。
準備中は、文字列"ready"を受信したら、"ready"を送り返すようにします。

そしてまず、こちらから"ready"という文字列を送ります。
なにも帰ってこなければ、相手アプリは起動してないので準備中のままにします。
文字列"ready"が帰ってくれば、相手アプリは起動しているので、システム開始します。

その後の準備中に"ready"が送り返されたら、相手アプリが起動したということです。
文字列"ready"を送り、システム開始します。



#まとめ
とりあえず通信はできました。
送受信に2つのPortを用意しないでめでした。
もう少しスマートになるのかしらね。