OmniAICreator/Qiita-1.07M huggingface dataset:
ArduinoNano の互換機を使ってみた

今回安価に購入できるArduino Nanoの互換機を使用してみました。
ELEGOO Arduino Nano
https://www.amazon.co.jp/ELEGOO-Arduino-Nano%E3%83%9C%E3%83%BC%E3%83%89-ATmega328P%E3%80%81Arduino-V3-0%E4%BA%92%E6%8F%9B/dp/B072F5NS4X/qid=1637816845

<h1>セットアップ</h1>
本製品の接続ケーブルはMini-Bとなっており、最近はこれ系のケーブルは
あまりないので探すのに苦労しました。。。
家を漁っているとPS3のコントローラケーブルがこの形状になっていたので
それを使用することに！！

<h3>１、ドライバインストール</h3>
そのままでは使えないので以下のサイトからドライバをダウンロードし、インストールします。
http://www.wch.cn/download/CH341SER_ZIP.html

インストール後はArduinoIDEでボードを「Arduino Nano」に選択すれば
通常通り使用できます。
macに変えると躓くキーボードの困りごと一覧

支給されたM1 macが開発に不向きすぎるが使っていかなきゃいけないので、
使いやすいようにカスタマイズしていく。


## Vim で delete キーを押したら ^? になる

https://qiita.com/rild/items/ccbf7c7ac9cecd1fc32d
(delete キーを押すと、 `^?` と出た)

# 対策
vim 操作でdeleteキー文字消しをしたくても出来ない場合は代わりに
「x」キーを使うことで一文字づつの削除は出来る。

その他、delete キーで削除できるようにカスタマイズすることも可能。

vimrc/bashrc どちらの方法でも問題は解決できた

## vimrc の設定を変える

`~/.vimrc` に、 

```bash:.vimrc

noremap! <C-?> <C-h>
```
を追加する

## bashrc の設定を変える
または、

`~/.bashrc` に

```bash:.bashrc

 stty erase '^?'
```
を追加する

# 終わりに
当初、bashrc の設定を変える方法で問題解決を図ったが、
「vim の問題は vim で解決するべきだろう」
と思い、 vimrc の設定を変える方法に変えた

```bash:.vimrc
set compatible "nocompatible だったのを変更"
:fixdel
set backspace=indent,eol,start
```
これも試してみたものの、自分の環境ではキーマッピングの問題だったみたい...



# 参考
[vim backspace leaves ^?](https://stackoverflow.com/questions/9701366/vim-backspace-leaves/47152541#47152541)
[Mapping control-H in insert mode doesn't work; it always works like backspace](https://vi.stackexchange.com/questions/3119/mapping-control-h-in-insert-mode-doesnt-work-it-always-works-like-backspace)
[VimTip, Todo
Backspace and delete problems](http://vim.wikia.com/wiki/Backspace_and_delete_problems)
[【図解Vim】mapとnoremap](http://cocopon.me/blog/?p=3871)


backspace押してもそうなる。

対策としては、
viで文字を消したいときは uキーで文字を消す
uキーの操作をキャンセルするときはxキーを押す
[MFC] CMFCToolBarのツールボタンのドラッグが出来ない問題

MFC (Microsoft Foundation Class) でツール作ってたらカスタマイズ機能が上手くいかない問題を見つけたのでメモ。

# 症状
* ツールバーのカスタマイズ画面で、コマンドの D&D による出し入れが出来ない。
  * ドラッグ開始した一瞬だけドラッグ中を示すカーソルアイコンに変わる。
* Alt を押しながらドラッグでツールボタンの入れ替えが出来ない。(Quick Customization 有効時)

(※カスタマイズ画面)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233982/1d918361-1535-039c-c202-abfe2130bed6.png)

# 対処
`CWinApp` または `CWinAppEx` の `InitInstance()` を継承したメンバ関数内の頭らへんに

```
AfxOleInit();
```

を挿入し、`ExitInstance()` を継承したメンバ関数内に

```
AfxOleTerm();
```
を挿入する。

## 対処例
```diff_cpp
BOOL CMFCApp::InitInstance() {
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

+	AfxOleInit();
	CWinAppEx::InitInstance();
```

```diff_cpp
int CMFCApp::ExitInstance() {
+	AfxOleTerm();
	return CWinAppEx::ExitInstance();
}
```


# 参考
* [Feature Pack 2008 - Customise toolbars problem](https://microsoft.public.vc.mfc.narkive.com/2fXTwnHx/feature-pack-2008-customise-toolbars-problem) (2021-11-25)
ゲームテスト終了後の「振り返り」と「品質分析」は大切

#1.はじめに
ゲームテストを行っていますと、
新規リリース時も大変ですが、運営に入るともっと大変になったご経験はありませんでしょうか？
運営タイトルも運営期間が長くなってくると、
「施策のたび、不具合の数がどんどん増えてきてるな」
「ここ同じような不具合前にもあったよな」
というようなことを思われたこともあるのではないかと思います。
今回、そのような点についてテスト後の振り返りや品質分析がいかに大切であるかを
お話できればと思います。

#2.振り返りは何のために行うのか
まずは、<b>「振り返りは何のためにやるんだろう」</b>というところですが、
一般的には
<b>【言動や傾向を客観的に捉えて、次回に向けた改善点の洗い出しを行い、その改善点を実行する】</b>
とされています。

ゲーム開発のプロジェクトの振り返りとしては、
KPIやDAUなどの情報から次回どうしていけばいいのか等を客観的に改善点を洗い出し、
実行に移していくことが行われるかと思います。

では、テストの振り返りはどういうことを行うのかですが、
以下の点などを話し合い、次回に繋げていくことになります。
<b>・テスト中に発生した問題点について
　-問題が発生した際にどのように行動をして対策を打ったか
　-テストにどのような影響が出たか
　-次回以降の対策</b>

例えば、
<b>実装が遅れ、テストスケジュールがひっ迫した</b>
という問題が発生したとします。
事象が発生した際は、臨時対応を行う必要があり、
<b>・増員対応
・スケジュール調整</b>
などの対応が取られる可能性があると思います。
ただ、<b>こちらは発生してしまった後にどう対応するか</b>であって
このようなことが<b>発生しないための対策</b>ではないということです。

この<b>発生しないための対策</b>を話し合うのが振り返りの場として有効なものになります。
問題によっては<b>発生させない</b>ということは難しい課題になるかと思います。
その場合は、<b>発生頻度を落とすためにはどうするか</b>というポイントを当てて、
取り組んでいく必要があります。

このような例のもので、
振り返りを行わず、毎回同じような問題が発生するとなると、
工数がひっ迫し、焦りからテストのミスにつながる可能性も出てきます。
また、増員・残業等も発生しますと、余計なコストもかかることになるので、
結果として負の連鎖が生まれてしまうため、
振り返りを行う必要があると考えます。

ただし、問題点のみ話題を上げるのではなく、
どういう点が良かったのかという点も話し合う必要があります。
その良かったことを次回どのように伸ばしていくかなどの話が行えれば、
より良いサイクルを生み出していく可能性があります。

#3.品質分析は何のために行い、何に活用できるのか
次に、品質分析についてです。
こちらは、振り返りとイコールになる部分もありますが、
品質分析を用いて、各施策の不具合傾向をつかみ、
テストスコープの見直しやQA側で改善すべき点なのか、開発側で改善すべき点なのかを洗い出します。

品質分析は以下の情報等を用いていきます。
<b>・テスト中に発生した不具合数（ランク別、機能別）
・不具合が発生した原因（不具合種別）</b>

例えば、
<b>不具合が合計100件発生したとします。</b>
ただこの情報のみですと、前回比で不具合数が多い・少ないの判別が付きますが、
今後に活かすための数値としては弱い状態です。

では、不具合ランク別に以下のように数値が出た場合はどうでしょうか？
![ランク別.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286509/d8de0e46-8a2c-e7ed-e7db-5df0f4cd2e7c.png)
先程より、重要度の不具合の数が分かるようになりましたが、
どの機能に対して、どういう不具合原因が発生していたのかが分からなため、
情報が足りないように感じるかと思います。

上記情報に加え、以下のように不具合種別の情報も合わせてみるとどうでしょうか？
![ランク別＋不具合種別.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286509/1ac4ebfe-4a15-81e9-9bdd-c28221d74d31.png)
ランク別にどういう不具合原因があったかと言うのがこれで分かるようになり、
傾向がつかみやすくなったかと思います。

もう1つ、
![機能別＋不具合種別.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286509/33c3a1c5-692a-1108-81d3-68f79e246636.png)
上記のように機能毎に不具合種別で集計することにより、
どのような不具合原因がどのような機能で多く発生しているのか等が確認できるようになり、
改善に向けての振り返りが行えるようになります。

上記例の件を分析を行っていくと、
・マスタ設定ミスが全体の3割以上を占めている
・マスタ設定ミスの中で、大きな問題に発展する可能性がある課金に関わる
　【ガチャ機能】【ショップ機能】で不具合が多く発生している状態
・不具合ランクとしては【B】となっている可能性があるが、
　課金に絡む部分のため、テストの粒度としては引き続き細かく確認すべき
・同じような不具合傾向が毎回発生している場合、開発の運用フローに問題点が潜んでいる可能性がある
などが大きく挙げられるかと思います。

この内容から、振り返り同様、次回このようなリスクを軽減させるために、どういうことが行えるかなどを検討し、
実際に行動をしていくことで、初期品質の向上を目指せるのではないかと思います。

#4.QA担当者内の振り返りのみではなく、担当開発者との振り返りも大切
前項まではQA内での振り返り、品質分析などを用いて、
<b>QA内でどのように次行動を起こして、改善に努めるのか</b>という内容になってきました。
では、それだけで、QA中の問題の洗い出しや改善対策が行えているかというと、<b>【そうではない】</b>と考えます。

QA担当者のみで話し合うと、QA側の視点のみで話が進んでしまう可能性があるため、
客観性がかけてしまう可能性があります。
また、開発担当者がどう思っていて、またどういう問題を抱えていたのかというのが、わからない状態になってしまうため、
QA担当者と開発担当者との振り返りも必要になります。

双方が対応することによって、問題点に対してより改善内容に踏み込んで対応を行うことができ、
同じ問題が発生しないためにも、お互いに協力していく必要があります。

#5.最後に
一概に振り返りや品質分析を行うと言いましても、
何のために行うべきなのか目的を明確にして行う必要があると思います。
目的等を定め、何のためにこのような取り組みを行うのかはプロジェクト毎に変わってくるかと思われますが、
その中で、本記事で皆様の中で共感いただけるもの、
また、参考になるものが少しでもありましたら幸いです。
Sync Gateway機能解説：拡張属性（XATTRS）の利用

## はじめに

### Sync Gatewayで拡張属性を使用する理由
XATTRSは、ドキュメントのルーティングとアクセス制御に使用されるデータをドキュメント内に安全に保持するために使用できます。保持された情報を、Sync関数内で利用することにより、データを使用してアクセス許可を駆動できます。このアプローチには、次の利点があります。

- 追加レベルのセキュリティを提供する。例えば、チャネルを追加し、ユーザーに対するドキュメントのアクセスコントロールを行う。
- 情報はメタデータに含まれているため、ドキュメントのコンテンツから分離される。
- 拡張属性の更新は、新しいリビジョンを作成しない。そのため、アクセス制御情報のみを変更し、ドキュメント全体をクライアントにプッシュする必要性がない。

Sync Gatewayは、この目的のために単一のユーザー定義可能な拡張属性`user_xattr_key`を持ちます。

### Couchbase Serverの拡張属性についての復習

Couchbase Serverでは、拡張属性（XATTR）を使って、開発者は、アプリケーション固有のメタデータを定義できます。このメタデータは、その存在を把握した上で、明示的にリクエスト、または変更を行おうとするアプリケーションにのみ表示されます。
たとえば、プログラミングフレームワークに固有のメタデータとして利用し、他のアプリケーションやフレームワーク、ないし同じフレームワークの別のバージョンに対して非表示にするということが考えられます。
拡張属性（XATTR）は、基本的に一般的なアプリケーションでの使用を目的としておらず、ライブラリーやフレームワークで利用することが想定されています。

拡張属性（XATTR）に保存されているデータには、通常のCouchbase Serverのデータへアクセスする方法では、簡単にアクセスできないようになっています。
Couchbase Server SDKは、サブドキュメントAPIの拡張機能によって拡張属性をサポートしていおり、拡張属性の定義、検索、編集、削除などを行うことができます。ただし、サブドキュメント操作を通常の属性ではなく拡張属性で実行するように指定するには、アプリケーションで`xattr`フラグを`true`に設定する必要があります。

Couchbase Serverに保存されているドキュメントの最大サイズは20MBであり、拡張属性（XATTR）は、ユーザー利用領域としてこのコンテンツサイズを消費します。

## Sync Gatewayで拡張属性を利用する方法

### 構成

Sync Gatewayは、構成プロパティの一部として、ユーザー定義による拡張属性の名前`user_xattr_key`を持ちます。


拡張属性（XATTR）は、値として、文字列、配列、オブジェクトなど、JSONとして有効な要素を取ることができます。


次の例では、Admin REST APIを使用して、データベース`hotels`に、XATTR名「channelXattr」を指定しています。


```shell
curl -X PUT 'http://localhost:4985/hotels/_config' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
    "user_xattr_key": "channelXattr" 
    }
}'
```

ここで、「channelXattr」が、チャネルルーティング情報を保持するように指定された拡張属性の名前として設定されます。

### 設定
Couchbase Server SDK APIを使用して、XATTRの値を設定および維持できます。Sync Gateway REST APIを使用して設定することはできません。ドキュメントの作成時および更新時に、SDK APIを使用してxattrの値を設定します。

Couchbase Serverドキュメントのメタデータの例について、以下示します。

```JSON
{
  "meta": { ①
    "id": "1000",
    "rev": "7-1680c88cbce700000000000002000006",
    "expiration": 0,
    "flags": 33554438,
    "type": "json"
  },
  "xattrs": { ②
    "channelXattr": [ ③
      "channel1",
      "channel3",
      "useradmin"
    ]
  }
}
```

① システムメタデータ
② ユーザーメタデータとしての拡張属性
③ ここで、`channelXattr`は、Sync関数に渡されるチャネルルーティング情報を保持する指定されたxattrの名前です。値は、ドキュメントの作成時および更新時に、SDK APIを使用して設定されたものです。


### 利用
Sync Gateway構成プロパティ`user_xattr_key`で指定された拡張属性（XATTR）は、Sync関数の引数`meta`を使って、`meta.xattrs.<拡張属性名>`の形で、利用できます

```JAVASCRIPT
function (doc, oldDoc, meta) { ①

  if (meta.xattrs.channelXattr == "undefined") ②
    {
      console.log("no user_xattr_key defined")
      channel(null)
    } else {
      channel(meta.xattrs.channelXattr) ③
    }

  // Further processing as required ../
```

① sync関数の引数に、`meta`を含めます。
② `meta`オブジェクトにアクセスして、対象の拡張属性がこのドキュメントに存在することを確認します。
③ 拡張属性のコンテンツを使用し、チャネルを定義します。



## 関連情報

https://docs.couchbase.com/sync-gateway/3.0/access-control-how-use-xattrs-for-access-grants.html#ex-cbs-metadata


https://docs.couchbase.com/java-sdk/current/concept-docs/xattr.html
スケーラブルとコスト効率向上の災害対策【AWS】

#はじめに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543340/cc697aa3-444b-4118-8394-14254935b746.png)

災害が発生した場合、ビジネスを継続するために、必要になるサービス
『AWS Elastic Disaster Recovery (DRS)』についてAWSがブログを投稿されていたので
このブログでさらに読みやすくなるように解説していきたいと思います。

#想定される考慮事項
- 定期的なデータバックアップ以上のことが必要
- ビジネスの目標復旧時間 (RTO) を満たす完全なリカバリ
- データの処理に使用されるインフラストラクチャ、オペレーティングシステム、アプリケーション、および構成も含める
- ランサムウェアの脅威の増大に伴い、完全なポイントインタイムリカバリを実行できる環境の必要性

ランサムウェア攻撃の影響を受けた企業では、手動のバックアップからデータを復元するだけでは不十分です。

#過去の対策での問題点
これまで、企業は物理的災害対策 (DR) インフラストラクチャを個別にプロビジョニングすることを選択していました。

- 要求されるまで、アイドル状態のままであるハードウェアや設備への投資
- スペースとコストの両方が法外になる可能性がある
- インフラストラクチャは、要求があった場合、現在のビジネス負荷は最初のプロビジョニング以降に大幅に増加している可能性がある
- これに対応できる状態にあることを確認するため、通常手動で行われる定期的な検査とメンテナンスに関するオーバーヘッドも発生
- テストが困難になり、コストも高い

#AWS Elastic Disaster Recovery (DRS) について
AWS災害対策に基づく、物理的サーバー、仮想サーバー、およびクラウドサーバー向けの、完全にスケーラブルで費用対効果に優れたサービス 

- 必要になるまでアイドル状態で、オンプレミスの DR インフラストラクチャに投資する必要がない
- AWS で弾力性のあるリカバリサイトとして使用
- オペレーティングシステム、アプリケーション、データベースのレプリケーションを常時維持
- 企業は、災害発生後、数秒の目標復旧時点 (RPO)、数分の RTO を達成
- 例えば、ランサムウェア攻撃の場合、DRS は以前の時点へのリカバリも可能にします
- 現在のセットアップに合わせて必要に応じて拡張できるリカバリを提供
- 準備状態を維持するために時間のかかる手動プロセスがいらない
- 災害対策読み取り演習を実施する機能

#サービス機能について

- 物理的サーバー、仮想サーバー、またはクラウドベースのサーバーからブロックストレージボリュームを継続的に複製
- 数秒で測定されるビジネス RPO をサポートできる
- リカバリには、物理的インフラストラクチャ、VMware vSphere、Microsoft Hyper-V、および AWS へのクラウドインフラストラクチャで実行されているアプリケーションが含まれる
- サポートされている Windows および Linux オペレーティングシステムで実行される、すべてのアプリケーションとデータベースをリカバリ
- AWS 上のサーバーのリカバリプロセスを調整し、数分で測定される RTO をサポートします

#仕組みについて
- サーバーにインストールしたエージェントを使用
- AWS アカウント内の選択したリージョンのステージングエリアサブネットに、データを安全にレプリケート
- ステージングエリアサブネットは、手頃な価格のストレージと最小限のコンピューティングリソースを使用、コストを削減
- DRS コンソール内では、必要に応じて、別のAWS リージョンにある Amazon EC2 インスタンスをリカバリ
- DRS のレプリケーションとリカバリの手順を自動化してくれる
- 特別なスキルセットを必要とせずに、1 つのプロセスで災害対策機能をセットアップ、テスト、運用できます

#コストについて
- 長期契約や一定数のサーバーを契約する必要がない
- オンプレミスまたはデータセンターのリカバリソリューションよりもメリットがある
- 従量制料金制で時間単位で課金されます。


#さいごに
バックアップからの、データのリストアをテストすることが重要であるのと同様に、
継続的な複製やお客様のサービス利用に影響を与えることなく、コストパフォーマンスに優れた方法でリカバリ演習を実施できると
リカバリを依頼する必要がある場合に、目標とお客様の期待に応えることができますので積極的に使うべきサービスだと思います。
次回は軽くチュートリアルを実践していきますので、合わせてお読みいただければ幸いです。
Herokuへseedデータを流したら詰まった

#概要

heroku run rails db:seedを実行したらエラーが起きた。

#結論

古い本番環境のデータが残っていたのが原因。

##それまでの過程
➀Herokuへログイン

```
$ heroku login --interactive
```
➁Herokuへデプロイして、本番環境でのマイグレーションファイルを生成

```
$ git push heroku master
$ heroku run rails db:migrate
```

➂初期データ（seed）を流し込む

```
$ heroku run rails :seed
```
##はい、ここで詰まります。
ActiveModel::UnknownAttributeError: unknown attribute 'user_area' for User.

Userテーブルにuser_areaのカラムがないんだと。
ここでschema.rbを確認。すると…

```
 create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.integer "user_area"
    t.integer "user_job"
    t.integer "school_year"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "password_digest"
    t.string "remember_digest"
    t.boolean "admin", default: false
    t.string "activation_digest"
    t.boolean "activated", default: false
    t.datetime "activated_at"
    t.string "avatar"
    t.string "reset_digest"
    t.datetime "reset_sent_at"
    t.string "profile"
    t.index ["email"], name: "index_users_on_email", unique: true
  end
```
はあ？あるやん！
じゃあ今の本番環境のUserテーブルどうなってんの？
ってことで

```
heroku run rails c
```
すると、Railsチュートリアルを走らせていた時の古いデータが。。
そこにはuser_areaのカラムがない。
なので、$ heroku run rails db:resetを実行。
データをすっきりさせてからもう一度$ heroku run rails db:seedを実行。
そしたらseedが通りました。

でもこれだとアプリをアップデートしてカラムを増やしたときにまた同じことが起こる。
それまでに登録していたユーザーが消えてしまう。。
他にも良い方法があればコメントで教えてください。
InDesign JavaScript XML 要素に文字を挿入もしくは要素を文字に変換

要素に文字を挿入もしくは要素を文字に変換するスクリプトは、これで良いのかな・・・？

~~~JavaScript
/*
このスクリプトを利用して起こった不具合の責任は取れません。
ご了承下さい。

更新 2021/11/25
*/

// アプリ指定
#target "indesign";

// スクリプト名
var scriptName = "要素に文字を挿入もしくは要素を文字に変換";

// 挿入対象の要素
var afterElementInsertTextAsContentElementArray = ["p"];

// 挿入文字
var afterElementInsertTextAsContentArray = ["\r"];

// 挿入文字の読み
var afterElementInsertTextAsContentReadingArray = ["段落の終わり"];

// 変換対象の要素
var escapeSpecialCharacterElementArray = ["CR","LF"];

// 変換文字
var escapeSpecialCharacterArray = ["\r","\n"];

// 変換文字の読み
var escapeSpecialCharacterReadingArray = ["段落の終わり","強制改行"];

// ダイアログのテキスト
var daialogTextArray = [];

/* 文字を入れる */
daialogTextArray.push("要素の後が「Storyの終わり」もしくは「段落の終わり」の場合は「段落の終わり」は挿入されません。" + "\r");

for(var i = 0; i < afterElementInsertTextAsContentElementArray.length; i++){

    daialogTextArray.push("「" + afterElementInsertTextAsContentElementArray[i] +"」要素の後に「" +afterElementInsertTextAsContentReadingArray[i] +"」を挿入します。");
}

daialogTextArray.push("");

for(var i = 0; i < escapeSpecialCharacterElementArray.length; i++){

    daialogTextArray.push("「" + escapeSpecialCharacterElementArray[i] +"」要素を「" +escapeSpecialCharacterReadingArray[i] +"」に変換します。");
}
/* 文字を入れる */

// ダイアログ
var dialogueFlg = confirm(daialogTextArray.join("\r"),"", scriptName);

// Noの場合
if(dialogueFlg == false){

    // 終了
    exit();
}

// エラー処理
try {

    // glue code.jsxを取り込み
    $.evalFile(app.filePath + "/Scripts/XML Rules/glue code.jsx");

// エラーの場合
}catch(e){

    // 警告
    alert("「glue code.jsx」が見つかりませんでした。");

    // 終了
    exit();
}

/* ルールセット */
var myRuleSet = [];

for(var i = 0; i < afterElementInsertTextAsContentElementArray.length; i++){

    myRuleSet.push(new afterElementInsertTextAsContent("//" + afterElementInsertTextAsContentElementArray[i], afterElementInsertTextAsContentArray[i]));
}

for(var i = 0; i < escapeSpecialCharacterElementArray.length; i++){

    myRuleSet.push(new escapeSpecialCharacters("//" + escapeSpecialCharacterElementArray[i], escapeSpecialCharacterArray[i]));
}
/* ルールセット */

// スクリプトを実行
app.doScript(function(){

    // 処理するxmlRule
    __processRuleSet(app.activeDocument.xmlElements.firstItem(),myRuleSet);

// 一つのアンドゥ履歴にする
}, ScriptLanguage.JAVASCRIPT,[], UndoModes.ENTIRE_SCRIPT, scriptName);
/* スクリプトを実行 */

// 要素の後に文字を挿入するXmlRule
function afterElementInsertTextAsContent(myXpath, myContents){
    this.name = "afterElementInsertTextAsContent" ;
    this.xpath = myXpath;
    this.apply = function(myElement, myRuleProcessor){

        // 要素に挿入
        myElement.insertTextAsContent(myContents, XMLElementPosition.AFTER_ELEMENT);
        return true;
    }
}

// 要素を文字に変えるXmlRule
function escapeSpecialCharacters(myXpath, myContents){
    this.name = "escapeSpecialCharacters" ;
    this.xpath = myXpath;
    this.apply = function(myElement, myRuleProcessor){

        // 要素の内容に入れる
        myElement.contents = myContents;

        // 子要素をスキップ
        __skipChildren(myRuleProcessor);

        // タグを外す
        myElement.untag();
        return true;
    }
}
~~~
【rails】ログインユーザーに一回だけ回答させる (サンプル例)

ログイン、質問投稿、投稿に対する回答ができるアプリがある。
各ユーザーが各質問に対して一回だけ回答できるように設定したい

# 1.モデル

ユーザーを表すmemberモデル、投稿した質問に関するpostモデル、
質問に対する回答を表すanswerモデルがそれぞれある。
各モデルの関係は以下

```app/models/answer.rb
class Answer < ApplicationRecord
  belongs_to :member
  belongs_to :post
end
```

```app/models/post.rb
class Post < ApplicationRecord
  has_many :answers, dependent: :destroy
  belongs_to :member
end

```

```app/models/member.rb
class Member < ApplicationRecord
  has_many :answers, dependent: :destroy
  has_many :posts, dependent: :destroy
end
```

# 2. コントローラーファイル
post,answerのコントローラーについては以下

```app/controllers/posts_controller.rb
class PostsController < ApplicationController

  def index # 質問一覧を表示する画面 
    @posts = Post.all
  end

  def show # 投稿内容、と回答内容をまとめて見れる画面
    @post = Post.find(params[:id])
    # 現ログインユーザーが一回既に回答してたらそれ以上回答できなくする
    @answer = Answer.find_by(post_id: params[:id], member_id: current_member.id)
    @answers = @post.answers # postに紐づくanswerを表示させる
  end

  def new
    @newpost = Post.new
  end

  def create
    @newpost = current_member.posts.build(post_params)
    redirect_to  public_posts_path
  end
 ....
end
```

```app/controllers/answers_controller.rb
class AnswersController < ApplicationController

  def new # 新規回答画面
    @newanswer = Answer.new
  end

  def create # 新規回答作成
    @newanswer = Answer.new(answer_params)
    @newanswer.member = current_member
    redirect_to public_post_path(@newanswer.post_id)
  end
  ....
end
```

# 3.viewファイル

　以下については割愛

  ・posts/index.html.erb(質問投稿一覧画面)
  ・posts/new.html.erb(新規質問投稿作成画面)
  ・answers/new.html.erb(新規回答作成画面)

以下のようなposts/show.html.erb ファイルを作成することでpostの内容とそれに紐づくanswer内容、answers/new.html.erbへ行くリンクを表示可能
　※answer内のanswerbody等、具体的なカラムについては割愛

```app/views/posts/show.html.erb

 <%= link_to ' 新規回答投稿する', new_post_answer_path(@post) %>

<table>

   (~質問内容表示~)
<%= @post.posttitle %>
<%= @post.postbody %>
....

  (~~回答内容を表示~~)
<% @answers.each do |answer| %>
 <%= answer.answerbody %>
 <%= answer.updated_at %>
 ....
<% end %>

</table>

```
上記ファイルの冒頭に以下のような条件分岐を設けることで
現ログインユーザー(current_member)が既に回答した場合、
新規回答作成画面へのリンクを表示できなくさせることができる。

```
<% if @answer.blank? %>
 <%= link_to ' 新規回答投稿する', new_post_answer_path(@post) %>
<% end %>
```

さらに以下を付け加えれば、「そもそも非ログイン状態だと回答できない」

```
<% if member_signed_in? %>
 
<% end %>
```
「質問を作成したユーザーだと回答できない」

```
<% if @post.member.id != current_member.id %>
 
<% end %>
```

等細かい条件を設定可能
Varnish Grace Mode非同期キャッシュ更新

###本項はLumen Edge Application DeliveryでのVarnishについての記述です
https://lumen-28.hubspotpagebuilder.com/lumen-technologies-japan/lumen-edge-cloud-app-delivery

https://varnish-cache.org/docs/trunk/users-guide/vcl-grace.html

#Grace Modeとは
キャッシュ有効期間(TTLで設定された期間)が過ぎた場合に置いても、 grace期間はキャッシュからレスポンスを返し、バックグラウンドでフェッチし、キャッシュオブジェクトを更新します。

これにより、クライアントにはなるべくキャッシュからレスポンスを返すとともに、キャッシュのオブジェクトを最新化できます。


![Untitled-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264348/4c559b59-de99-5f91-98b3-031d7314d052.gif)



```ruby:vcl
sub vcl_backend_response {
  set beresp.ttl = 30s;
  set beresp.grace = 30s;
}
```

##Grace mode
複数のクライアントが同じページを要求している場合、Varnishは1つの要求をバックエンドに送信し、バックエンドから1つのリクエストをフェッチしている間他のユーザからの要求を保留にします。これはリクエストのアグリゲーションとしてRequest CoalescingまたはRequest Collapsingと呼ばれ、Varnishはこれを自動的に行います。

https://qiita.com/yoshitaka_nakahara/items/59b6ffa225dd6d308f96

例えば1秒あたり数千ものリクエストを処理している場合、待機中のリクエストのキューが膨大になる可能性があります。ここには2つの潜在的な問題があります-1つ目はRequest Collapsingで最終的にフェッチしたコンテンツを、キューに待たせたユーザに一気にレスポンスするためサーバ負荷が高くなる可能性があります。2つ目にそもそも待機キューとなってしまう事での遅延が発生する可能性もあります。

そこでGrace　modeを設定する事で、VarnishはコンテンツTTLの期限が切れた後しばらくの間、既存キャッシュしたオブジェクトをクライアントに提供しつつオブジェクトの新しいバージョンをオリジンサーバよりフェッチします。デフォルト値は、パラメータdefault_graceによって制御されます。

##Keep
オブジェクトに対してKeep設定すると、Varnishはオブジェクトをキャッシュに保持しつつ、更新確認条件付きのGETバックエンドリクエストを作成します（If-Modified-Since：および/またはÌf-None-Match：ヘッダーを使用）、この場合バックエンドでのオリジンサーバが304 Not　Modified(コンテンツ更新無し)を応答をレスポンス返却した場合は、再度コンテンツBODYを取得することなく既存のキャッシュ済コンテンツを利用します。

上記のGraceとKeepを併用する場合はキャッシュTTLは両機能の加算値になります。

```ruby:vcl
sub vcl_backend_response {
     set beresp.grace = 2m;
     set beresp.keep = 8m;
}
```

上記の場合、合計のTTL値は10Munitesになります。

![object_lifetime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264348/0d4fa424-b2c5-4ad6-565f-abb2fd2e996f.png)

##5XX時のGrace mode
![backend-down.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264348/784833b0-6e2d-1854-7818-5c3dd70814fb.png)
HDRPのライトを点滅させる

HDRPでも動きます。
Mathfだとうまく動かなったのでRandom.Rangeで

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

public class RandomLight : MonoBehaviour
{
    Light myLight;  //LIghtクラスのmyLight変数を宣言
    public float low = 0.0f;
    public float high = 0.0f;

    void Start()
    {
        myLight = GetComponent<Light>();  //myLightにオブジェクトのLightコンポーネント情報を代入
    }

    void Update()
    {
        myLight.intensity = Random.Range(low,high);　　//RandomクラスRangeメソッドで2値間の値を返す
        //Debug.Log(myLight.intensity);
    }
}
NuxtとRailsで構築したアプリにローカルでスマホからアクセスする

# はじめに
NuxtとRails APIで開発してる時にスマホで動作確認したい時ありますよね。
わざわざステージング環境にデプロイして動作確認するのは一手間。
そこでローカルでスマホからアクセスして動作確認する方法をメモしておきます。
Dockerを使って環境構築しており、PCとスマホを同じWiFiに接続していることが前提です。
僕はMacとiPhoneを利用するので端末がこれらと異なる場合はご自身で対応してください。
# 注意事項
同じネットワークを利用している端末だったらアクセスできてしまうため、カフェなどFree Wi-Fiなどでは避けること。
# 設定していく

## 1.IPアドレスを確認する
システム環境設定→ネットワークを開きます。
すると以下の画像の青線のようにプライベートIPアドレスがわかるのでコピーしておきましょう。
この例では`192.168.11.9`です。
![スクリーンショット 2021-11-25 10.56.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631045/b525ae8f-285c-a7fc-cb9c-d422e5d87c12.png)

## 2.Nuxtの設定

package.jsonの`"dev": "nuxt"`以下に変更します。
僕は8080番ポートを使っているのでご自身のポート番号に置き換えてください。
IPアドレスも先ほどメモしたご自身のものに置き換えましょう。

```package.json
"scripts": {
   "dev": "NUXT_HOST=192.168.11.9 NUXT_PORT=8080 nuxt"
}
```

続いてaxiosの設定です。
僕の場合はbaseURLがlocalhostになっています。
このままだとスマホでアクセスしてRails側にリクエストを投げる際、スマホ自身の3000番ポートを参照してしまいます。
なので先ほどメモしたIPアドレスとRails側のポート番号に変更します。
僕はRailsのデフォルトである3000番ポートを使っていますが、ご自身のものに置き換えてください。

```js:front/plugins/axios.js
//削除
config.baseURL = 'http://localhost:3000'
//追加
config.baseURL = 'http://192.168.11.9:3000'
```
## 3.Railsの設定
corsで`http://192.168.11.9:8080`を許可します。
corsの設定は他にもやり方もあるので下記通りではうまくいかないかもしれませんが、許可するオリジンに`http://192.168.11.9:8080`を追加すればOKです。

```rb:development.rb
# 削除
config.allow_origins = ['http://localhost:8080']
# 追加
config.allow_origins = ['http://localhost:8080', 'http://192.168.11.9:8080']
```

これで`http://192.168.11.9:8080`（自分のIPアドレスとポート番号に変更する）にスマホでアクセスできると思います。
動作確認が終わったらファイルの変更を元に戻しましょう。
flutter doctor で Got socket error が発生

# エラー内容
Windows PowerShellで`flutter doctor -v`を実行したら以下のエラーが発生した。

```
Got socket error trying to find package test at https://pub.dartlang.org.
pub get failed (server unavailable) -- attempting retry 1 in 1 second...
```

## 環境
 * Windows 10 Pro
 * Flutter SDK Version 2.2.0


# 対処内容
PowerShellのproxy設定ができてなかったので、proxy環境にあわせて以下の設定を行い解決した。

```
$Env:http_proxy="username:password@hostname:port"
$Env:https_proxy="username:password@hostname:port"
```

# 参考サイト
https://dart.dev/tools/pub/troubleshoot#pub-get-fails-from-behind-a-corporate-firewall
.gitignore の記載を変更しても反映されない

# 目的

- すでにgit管理されているファイルをgitignoreファイルに登録したが反映されなかったので自分用のメモとして残す。

# 概要

- gitignoreファイルと同じ階層にある`s3`ディレクトリ配下をすべてgit管理から外したい。

# 方法

1. .gitignoreファイルへの記載
    1. .gitignoreファイルに下記のように記載を行った。

        ```.gitignore
        /s3/
        ```
1. キャッシュの削除
    1. 下記コマンドを実行してgit管理から除外したファイルキャッシュを削除した。

        ```terminal
        $ git rm -r --cached s3/*
        ```

    1. 後は差分が出ているファイルをaddしてcommitしたら作業完了

# 参考文献

- [https://qiita.com/fuwamaki/items/3ed021163e50beab7154](https://qiita.com/fuwamaki/items/3ed021163e50beab7154)
GvizでCRPの周囲のゲノムブラウザの図を描いてみる

## はじめに

GvisはRのパッケージで、ゲノムブラウザのような図を生成することができます。
この記事は基本的には下記の記事の焼き直しで新しい内容は特にありません。

* [UCSC Genome Browser をRのplotで再現する](https://qiita.com/wakuteka/items/a99d5fb9f24367f55461)

ここでは、血液検査の結果で馴染み深い [CRP（C反応性蛋白）](https://ja.wikipedia.org/wiki/C%E5%8F%8D%E5%BF%9C%E6%80%A7%E8%9B%8B%E7%99%BD)の周囲の領域について、ゲノムブラウザのような画面を作成してみます。

ライブラリの読み込み

```r
library(gviz)
```

染色体の番号と、リファレンスゲノムの指定。ここでは `chr1:159,681,503-159,684,954` を表示します。

```r
chr <- "chr1"
gen <- "hg19"
from <- 159681503
to   <- 159684954
```

イデオグラムを追加する

```r
itrack <- IdeogramTrack(genome = gen, chromosome = chr)
```

```r
plotTracks(list(itrack), from = from, to = to)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/89f9863b-a0dd-2755-fb46-027cd29b6c5b.png)

Gトラックを追加する

```r
gtrack <- GenomeAxisTrack()
```

```r
plotTracks(list(itrack, gtrack), from = from, to = to)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/30885049-ac2b-929a-1c58-d5352cd4a72d.png)

UCSCにアクセスして各種トラックを取得する

```r
knownGenes <- UcscTrack(genome=gen, chromosome=chr, track="knownGene", from=from, to=to,
                        trackType="GeneRegionTrack", rstarts="exonStarts", rends="exonEnds",
                        gene="name", symbol="name", transcript="name", strand="strand", 
                        fill="#8282d2", name="UCSC Genes")

refGenes <- UcscTrack(genome=gen, chromosome=chr, track="xenoRefGene", from=from, to=to,
                      trackType="GeneRegionTrack", rstarts="exonStarts", rends="exonEnds", 
                      gene="name", symbol="name2", transcript="name", strand="strand", 
                      fill="#8282d2", stacking="dense", name="Other RefSeq")

ensGenes <- UcscTrack(genome=gen, chromosome=chr, track="ensGene", from=from, to=to,
                      trackType="GeneRegionTrack", rstarts="exonStarts", rends="exonEnds", 
                      gene="name", symbol="name2", transcript="name", strand="strand", 
                      fill="#960000", stacking="dense", name="Ensembl Genes")
```

```r
plotTracks(list(idxTrack, axTrack, knownGenes,refGenes,ensGenes), from=from, to=to, showTitle=TRUE)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/c0336d6c-f1c1-7c9b-c55d-12e5812b751e.png)

気になったのは、同じように書いたつもりなのに成功したり失敗したりする場合もあるみたいで、UCSCのサーバーにアクセスしているので、サーバの調子によってうまくいったり失敗するのかもしれません。

## Biomartを使う

BioMartは接続が不安定なので、mirrorにはできるだけasiaを指定した方がいい

```r
library(biomaRt)

bm <- useEnsembl(host = "grch37.ensembl.org", 
                 biomart = "ENSEMBL_MART_ENSEMBL", 
                 dataset = "hsapiens_gene_ensembl",
                 mirror="asia")
```

```r
biomTrack <- BiomartGeneRegionTrack(genome = gen, chromosome = chr, 
                                    start = from, end = to,
                                    name = "ENSEMBL", biomart = bm)
```

```r
plotTracks(list(idxTrack, axTrack, knownGenes,refGenes,ensGenes, biomTrack), from=from, to=to, showTitle=TRUE)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/d9010c3d-7ad4-7516-7104-262c0fd99a0a.png)
実行ディレクトリパスを取得

```path.sh
#二つのパターンを載せた意味
#echoで変数に格納している記載をしていた方がいた。
#理由は不明

SCRIPT_DIR=$(cd $(dirname $0); pwd)
SCRIPT_DIR2=`echo $(cd $(dirname $0); pwd)`
echo $SCRIPT_DIR
echo $SCRIPT_DIR2
```

参考
https://ex1.m-yabe.com/archives/3948
CXL (Compute Express Link) その2 - CXLのバージョンとCPUによる対応

メモリデバイスの不揮発性メモリ制御やホストIFなどを扱うソフト屋です。
仕事でCXL(Compute Express Link)まわりの技術に関わっています。
CXL技術に関連するメモ書きを残していこうと思います。
ホストまわりのこと経験・知識共に乏しいので、詳しい親切な方は教えて下さると幸いです。現在、まずはQEMUで、CXLが接続された環境を立ち上げようとしているので、教えて頂けると非常に有難いです。
また、間違い、アドバイス、その他、ご意見やご要望ありましたらお気軽にどうぞ。

#1. CXLのバージョンによる違い
一般的な仕様書と同様に、CXLの仕様にはリリース時期により、バージョン番号がついています。個人的な大まかな印象ですが、CXLのそれぞれのバージョンでは、以下の対応を考慮したアップデートになっているように見えます。

- CXL 1.1  
Type3デバイス揮発性メモリへの対応
- CXL 2.0  
Type3デバイス不揮発性メモリへの対応
- CXL 3.0  
Type1/Type2デバイスへの対応

それぞれの違いに関する詳細は、追々書くとしますが、CXL3.0の仕様書は、まだリリースされていないので、CXL2.0の範囲内での話をします。

#2. CPUベンダーによるのCXLへの対応
CPUベンダーのCXLへの対応予定(2021/11/25時点)は以下の通りになると予想されます。

- Intel  
2022年から「Sapphire Rapids」で、CXL1.1に対応。既に特定顧客にはサンプルが配られているようです。

https://download.intel.com/newsroom/2021/client-computing/intel-architecture-day-2021-fact-sheet.pdf

https://www.anandtech.com/show/16921/intel-sapphire-rapids-nextgen-xeon-scalable-gets-a-tiling-upgrade

- AMD  
2022年から「Epyc Genoa」で、CXL1.1に対応。

https://www.amd.com/en/press-releases/2021-11-08-amd-unveils-workload-tailored-innovations-and-products-the-accelerated

https://www.anandtech.com/show/17055/amd-gives-details-on-epyc-zen4-genoa-and-bergamo-up-to-96-and-128-cores

- ARM  
2022年から「Neoverse N2」で、CXL2.0に対応。  
(Neoverse N2 Core + CMN700の組み合わせでCXL2.0デバイスに繋がるデザインになるかと思われます)  
ARMは、既に「Neoverse N1 + CMN600」の組み合わせで、CCIX(CXL同様のCache Coherencyを実現するInterconnect技術)で、不揮発性メモリ搭載のType2に相当するデバイスの接続を試作で実現しているため、IntelやAMDよりCXL2.0対応には一日の長があるのかもしれません。

https://www.arm.com/ja/products/silicon-ip-cpu/neoverse/neoverse-n2

https://www.anandtech.com/show/16640/arm-announces-neoverse-v1-n2-platforms-cpus-cmn700-mesh

https://armkeil.blob.core.windows.net/developer/Files/pdf/solution_overview-corelink-cmn-700.pdf

#3. CXLデバイス
CPUに接続されるデバイスとして以下の製品が発表されています。

- Samsung  
DRAMが搭載されたCXLモジュールが発売されます。恐らく、CPUに合わせてCXL1.1対応で、2022年の発売になると予想されます。既に特定顧客にはサンプルが配られているようです。

https://news.samsung.com/global/samsung-unveils-industry-first-memory-module-incorporating-new-cxl-interconnect-standard

---
次回以降CXLの仕様の詳細について書いていこうと思っています。
initStoryshotsを２回呼び出したら console.warn Unexpected loaded state. Did you call load` twice? と怒られたことの対策

initStoryshotsを２回呼び出したら以下のように怒られた。GitHubのissueのコメ欄とかみててもよくわからなかった。

```
console.warn Unexpected loaded state. Did you call load` twice?
```

## エラーとなったファイル
やりたかったことはビジュアルリグレッションテストとスナップショットテストを怒られずにそれぞれで実行すること。

```snapshot.test.js
import initStoryshots from '@storybook/addon-storyshots';
import { imageSnapshot } from '@storybook/addon-storyshots-puppeteer';

initStoryshots({ suite: 'Storyshots' });
initStoryshots({
  suite: 'Image storyshots',
  test: imageSnapshot({ storybookUrl: 'http://localhost:6006/' }),
});

```

非同期処理に変えたところ別のエラーが発生して別の方法を模索。

## ファイルを分けたら怒られなくなった
分割すればいけました。

```imageSnap.test.js
import initStoryshots from '@storybook/addon-storyshots';
import { imageSnapshot } from '@storybook/addon-storyshots-puppeteer';

initStoryshots({
  suite: 'Image storyshots',
  test: imageSnapshot({ storybookUrl: 'http://localhost:6006/' }),
});

```

```snapshot.test.js
import initStoryshots from '@storybook/addon-storyshots';

initStoryshots({ suite: 'Storyshots' });

```

実機別に確認したいとかでループ処理を噛ませたい場合などはどうやるんだろう。。
AVAudioPlayer の再生。

このAVAudioPlayerは、簡単にPlayersのインターバルが取得できる特徴がある。

```
class ViewController: UIViewController {
var player = AVAudioPlayer()
var url = NSUNL()
var slider = UISlider()
var Tim = Timer() 
  override func viewDidLoad(){
    url = URL(string: “https://url/audio_file.m4a”)! as NSURL
    player = try! AVAudioPlayer(contentsOf: url as URL)
    PlayMusic()
    slider.frame = CGRect(x: 10, y: self.view.frame.size.height-44, width: self.view.frame.size.width-20, 44)
    self.view.addSubview(slider)
    let btn1 = UIButton()
    btn1.frame = CGRect(x: 0, y: 300, width: 320, height: 40)
    btn1.addTarget(self, action: #selector(playing(playing:)), for: .touchUpInside)
    self.view.addSubview(btn1)
  }
  func PlayMusic(){
    let t = player.duration
    let t2 = player.currentTime
    slider.maximumValue = Float(t)
    slider.minimumValue = 0.0
    slider.value = Float(t2) 
    Tim = Timer.scheduledTimer(interval: 0.1, target: self, selector: #selector(tim(tim:)), userInfo: nil, repeats: true)
  }
  @objc func playing(playing: UIButton){
    plsyer.play()
    PlayMusic()
  }
  @objc tim(tim: Timer){
    let t = player.duration
    let t2 = player.currentTime
    slider.maximumValue = Float(t)
    slider.minimumValue = 0.0
    slider.value = Float(t2) 
  }
}
```
URLは独自のものを使ってください。
AVAudioPlayerはiOSのデバイス内の音声出力は確認できていますが、外部URLはどうか？
ボタンタップからの再生で、スライダーだけの　UIの実装です。
1行野郎でSSHの秘密鍵のパスフレーズがあるかないかを暴く

#ノーパスフレーズはノー

ということで、SSHの秘密鍵がノーパスフレーズかどうか確認する方法を編み出しました。

```:bash
$ ssh-keygen -y -f 秘密鍵ファイル > /dev/null 2>&1 ;echo $?
```

戻り値が0：パスフレーズが設定されていません
パスフレーズを聞いてくる、：パスフレーズが一応ある。

ってことです。

もう少し工夫すれば自動化できそう。

ということで工夫してみました。

```:bash
$ ssh-keygen -y -f ./パスフレーズのない秘密鍵 -P 1 > /dev/null 2>&1 ; echo $?
0
$ ssh-keygen -y -f ./パスフレーズのない秘密鍵 -P ""  > /dev/null 2>&1 ; echo $?
0
```

そう、ノーパスフレーズに何入れても0が返ってきます。
なのでこうします

```:bash
$ ssh-keygen -y -f ./パスフレーズのない秘密鍵 -P 1 > /dev/null 2>&1 && ssh-keygen -y -f ./パスフレーズのない秘密鍵 -P "" >/dev/null 2>&1 ; echo $?
0
```

二回やっているのは、もしパスフレーズが入っているときに0で返らない様にするためです。
こうしなくっても良いかもしれませんが...。

```:bash
$ ssh-keygen -y -f ./パスフレーズのある秘密鍵 -P 1 > /dev/null 2>&1 && ssh-keygen -y -f ./パスフレーズのある秘密鍵 -P "" >/dev/null 2>&1 ; echo $?
255
```

こんな感じ。

以上!!
同じSalesforce組織内で異なる商談フェーズを使い分ける方法

こんにちは。本橋です。
今回は「同じSalesforce組織内で異なる商談フェーズを使い分ける方法」について説明します。


基本的な設定では、１つの商談オブジェクトには１つのフェーズの種類しか表示できません
このフェーズを２つに使い分けたい　という要望があった場合どうするか　について説明します。

そもそもフェーズとは何かというと
画像のように一般的に矢羽のように表示されている部分です。
![商談フェーズ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/2f08ad7e-b178-e42a-f90c-77f72a17ac9e.png)

デフォルトでは
Prospecting→Qualification→Needs Analysis→Value Proposition
と続いていき、最後に受注or失注になります
一般的に左のフェーズからどんどん右に進んでいくように表示させます。

しかしながら、
・同じ会社でも営業部隊が複数いて、必ずしもその営業部隊は同じように商談が進まない
・会社合併などで同じ会社に在籍する営業部が必ずしも同じ商談フェーズの動きをとらない

ということがあり、
Prospecting→Qualification→Needs Analysis→Value Proposition
の動きがある部隊もあるが、
Prospecting→Needs Analysis→Value Proposition
とQualificationを飛ばしたり、また「上司にヒアリング」という追加の選択リストも必要なはずです。

さて、では「同じSalesforce組織内で異なる商談フェーズを使い分ける方法」について設定を説明します

ステップ１　フェーズに追加する選択リストを作成
まずは今回追加する必要のあるフェーズの選択リストの値の追加を行います
オブジェクトマネージャー＞商談＞フェーズ＞新規ボタンをクリック
です
![フェーズ新規.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/0993cfeb-373a-69f7-2cc7-4406fe85aeac.png)

新規フェーズ作成画面は下記となります
![上司にヒアリング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/bd1722e6-51f7-5521-a76f-f1c4397d0baa.png)


ステップ２　セールスプロセスを作成、編集
新規フェーズ作成後、セールスプロセスの設定を行います。
セールスプロセスで設定したフェーズの選択リストのみがフェーズ選択が可能です
![セールスプロセス編集.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/3b6f599e-4fc8-8f02-3ce3-2f53f3563e60.png)

ステップ３　レコードタイプ作成
レコードタイプを作成することにより、商談の「新規」ボタン作成時に複数の選択をして、どのフェーズを使用するかの選択が可能になります。
レコードタイプ作成時は、必ずセールスプロセスの選択が必要です
![新規レコードタイプ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/8b17b557-0b1f-ec78-1038-505872551b46.png)


さて、これで作業は完了です。
まずは商談の「新規」ボタンをクリックすると、２つの選択肢が表示されます
![レコードタイプ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/98030922-ea2c-c6c9-a512-b5f2b1a8e1ee.png)


このように、フェーズが異なる商談の作成が可能となります
![最後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/54169e07-41a2-f56e-3f4d-d74a1d5786d8.png)



まとめ
複数の商談フェーズを使い分けるには
・セールスプロセスの作成
・レコードタイプの作成
が必要。
もしも新規のフェーズの選択肢を追加したいなら、フェーズの選択リストの値の新規作成が必要です
【TeachableMachine】画像プロジェクトの操作方法

TeachableMachineの操作方法のみを記載するもの。


#サイト

https://teachablemachine.withgoogle.com/

#使い始めるまで
「使ってみる」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/25392c85-ae3c-c28c-ba26-77490ceb3cad.png)

「画像プロジェクト」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/cd1b02d6-b3d9-79b9-9d38-df2d01a87700.png)

「標準の画像モデル」を選択する。
※小さいカメラを使う場合は「埋め込み型の画像モデル」を選択する。今回は使用しない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/2b608dee-ba32-6f2a-127f-4dc7f03ce295.png)

#設定方法
以下画面に移行するので、それぞれ設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/9674d5b9-913d-2406-02c1-6e02a3798c2e.png)

##クラス
クラス名を変更する。鉛筆マークを押すと変更できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/6d10b984-1b2e-9966-d79b-b69f3889efa2.png)

クラスが足りなければクラスを追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/7b834026-0617-2f39-f054-57a960148acc.png)

各クラスに画像サンプルを追加する。
・ウェブカメラを利用する場合は、自分のパソコンのメインカメラで撮影する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/9c5bd748-548a-695f-ee39-7e34a4155a77.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/17109e0c-ecfd-d3ca-7b24-0d1d68347fba.png)

・アップロードする場合は、画像ファイルを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/25de4153-d107-4762-51b0-f4df854b2aeb.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/1d1db829-2c02-a24e-4cba-fa14979473f4.png)

##トレーニング
<font color="#ff0000">**トレーニングしている間はタブの切り替えをしてはいけない。**</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/e5537228-df4f-048c-f966-9d389dff398c.png)

##プレビュー
トレーニングが終わるとプレビューができるようになる。
Webアプリで使う学習データができるので、ちょっと試してみるのも良い。

学習データを使うために「モデルをエクスポートする」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/f699e2b5-f3f6-a10d-557d-37fd65bfa5d6.png)

「アップロード（共有可能なリンク）」を選択すると、共有可能なリンクが出来上がるので、それをコピーする。
右側にリンクをコピーするボタンが出現するので、押すと良い。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122199/e6f2167f-c44a-5ac9-e90d-c8a8d24c6be5.png)

Webアプリのデータとして使用することが可能となる。
開発効率を上げる為にcommit時に自動でprettierとlintを走らせる

#huskyとは？
Git hooksを簡単にできるツールです。
**commit、push**時にscriptを走らせることができます。
Github: https://github.com/typicode/husky

##lint-stagetとは？
ステージング済みのファイルに対して、特定の処理が走らせることができるツールです。
Github： https://github.com/okonet/lint-staged

#実装 

まず、開発プロジェクトを用意しましょう。
今回はReactで行います。

```
npx create-react-app プロジェクト名
```
プロジェクトを立ち上げた後、最低限必要なpackageをインストールします。
（他のlintなど必要な場合プロジェクトによって変更してください。今回はprettierとeslintの設定に関しては触れません。）

・ Eslint
・ prettier
・ husky
・ lint-staged

```
npm i -D eslint prettier husky lint-staged
```

必要な設定を行っていきます。

```
"lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix \"src/**/*.{ts,tsx}\"",
      "prettier --write \"src/**/*.{ts,tsx,css}\""
    ]
  },
```
※設定内容に関しては、プロジェクトごとに対応した変更をしてください。

Git hooksを有効化していきます。

```
npx husky install
```
.huskyディレクトリが作成されます。

Githubのリポジトリからcloneする際にGithooksを有効化する為に以下のスクリプトを作成します。

```
"scripts": {
  "prepare": "husky install"
  "lint-staged":"lint-staged"
}
```

コミットした時に実行されるhooksを用意します。

```
npx husky add .husky/pre-commit "npm run lint-staged"
```

実行後に.huskyフォルダ内に.husky/pre-commitファイルが生成されます。（このファイルに記述している内容が走ります。必要があれば他のscriptも追加してください。）

あとは、commitした時に実行されていれば完了です。
Explore - "Blender Tutorial - Create a Wormhole Animation In Blender"

https://www.youtube.com/watch?v=v2146WbGYME

# 製作工程

# 新しく知ったこと・途中で調べたこと
+ カメラのFallowPathという機能。
+ WireFrameモデファイア
+ Emissionマテリアル
+ ColorRamp

# 感想
動画内でやっている通りにやったが全然違うものになってしまった...
壁面が真っ黒。why?
日を開けてしまったのでできるだけ開けないようにしたい。

# 成果物
![wormhole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2316614/d64fde88-27ef-0a68-9e1f-3a5c5e757cd7.png)
ps ho pid p プロセスID

プロセス確認方法に以下の方法がある

#ps ho pid p プロセスID

まぁ、その実行ユーザのプロセス実行が確認できる。
echo $?が「0」の時はそのプロセスIDでの実行がされており
echo $?が「1」の時はそのプロセスIDでの実行がされていない。

実にわかりにくい記載方法であまり好きではない。

ps ・・・実行ユーザのプロセス表示
h　・・・ヘッダなしオプション（上のPID等の項目が消える）
o　・・・オプション。次のpidを使用するためのもの
pid ・・・pidだけ出力してほしい
p　　・・・プロセスIDを入れますよっていうオプション？
プロセスID　そのままプロセスID

用途としては、プロセスIDが出力しているファイルからプロセスIDを取ってきて
そのプロセスIDをこのコマンドの最後に代入して
戻り値でプロセスIDを確認する技。。。

※スクリプトに記載があったときは、説明書いておけよって思った。
なんでもナイトコアにする

# ナイトコアとは

>　原曲のテンポを高速化させ、場合によっては意図的にピッチも上げて作られた、リミックスを指す音楽ジャンルである

[ナイトコア 出典: フリー百科事典『ウィキペディア（Wikipedia）』](https://ja.wikipedia.org/wiki/%E3%83%8A%E3%82%A4%E3%83%88%E3%82%B3%E3%82%A2)

# ナイトコアにする
とりあえず早くする

```python:
import pydub
from pydub import AudioSegment

path = "xxxxxxx.mp3"

base_sound = AudioSegment.from_file(path, format="mp3") 
base_sound = base_sound.speedup(playback_speed=1.5, crossfade=0)

base_sound.export("nightcore.mp3", format="mp3")

```

おしまい

音を高くするとかも多分すぐできるでしょ

# 今後の展開
- youtubeのURLを貼ると音源がナイトコアになるようなやつ作る
- もっとBPM上げてGainも上げてガバキックを乗せてなんでもガバにする

# 目指すは
ボタン一つで君もアニクラDJになれるセットを作る
Mac+React+Jestで、watchmanが動かない場合の対応

# はじめに

Mac + React + Jestでテストが動作しない場合の対応方法。

## 現象

`npm test`
でテストを実行しようとすると以下のようなメッセージが表示される。

```sh
Watchman crawl failed. Retrying once with node crawler.
Usually this happens when watchman isn't running. Create an empty `.watchmanconfig` file 
in your project's root folder or initialize a git or hg repository in your project.
Error: Watchman error: std::__1::system_error: open: /Users/xxxxx/Documents/xxxxx/src: Operation not permitted. Make sure watchman is running for this project. See https://facebook.github.io/watchman/docs/troubleshooting.
```

## 対策

メッセージにあるように、プロジェクトディレクトリに`.watchmanconfig`を作成する。

**→改善せず**

ネットで調べると、どうやらwatchmanがプロジェクトディレクトリにアクセスできないことが原因のようす。

まずは、watchmanがインストールされているかを確認。

```sh
brew list watchman
/usr/local/Cellar/watchman/2021.10.04.00/bin/watchman
/usr/local/Cellar/watchman/2021.10.04.00/bin/watchman-diag
/usr/local/Cellar/watchman/2021.10.04.00/bin/watchman-make
/usr/local/Cellar/watchman/2021.10.04.00/bin/watchman-replicate-subscription
/usr/local/Cellar/watchman/2021.10.04.00/bin/watchman-wait
/usr/local/Cellar/watchman/2021.10.04.00/bin/watchmanctl
/usr/local/Cellar/watchman/2021.10.04.00/lib/python3.9/ (13 files)
```

うん。インストールはされている。

次のMacのシステム環境設定を変更する。

- システム環境設定を起動し、「セキュリティとプライバシー」を選択。
- 左側のメニューから「フルディスクアクセス」を選択。
- 左下の鍵アイコンをクリックして、パスワードを入力。
- 右側のリストの「＋」アイコンを押す。
- ダイヤログが開く。
![スクリーンショット 2021-11-25 10.37.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b234adde-e31c-a928-857a-28038b10bafd.png)

- 右上の検索ウィンドウで、command + shift + .（ピリオド）を入力。←このオペレーションがわからず、すごい苦労した
- 先程のbrewの結果を確認し、watchmanを探す（私は/usr/local/Cellar/watchman/2021.10.04.00/binにあった）。
- 「開く」を押して選択
![スクリーンショット 2021-11-25 10.40.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/ae24b5bc-f0e8-7f34-5c63-6c7a47f1dc76.png)

- チェックが入っていることを確認して、左下のロックをクリック。

では再び`npm test`を実行。

```sh
No tests found related to files changed since last commit.
Press `a` to run all tests, or run Jest with `--watchAll`.

Watch Usage
 › Press a to run all tests.
 › Press f to run only failed tests.
 › Press q to quit watch mode.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press Enter to trigger a test run.
```

解決ー！
【初心者必見！】BizRoboのDAのComponentに変数を設定する　～Part2～

#はじめに
記事をご覧いただきありがとうございます。
今回はBizRoboのComponentの設定のPart2を紹介したいと思います。
使用するタイミングがあればぜひ使用してみてください。

あ、気になる方もいらっしゃると思いますがPart1については下記リンクの記事をご覧ください。
https://qiita.com/t_k9006/items/ab5b253d11ea7089681c
では、早速見ていきましょう！

#本題
Part1では、変数に変えたい箇所が文字列の1番最後にあります。
今回は、変数に変えたい箇所が文字列と文字列の間にある場合についての紹介です。
Part1の設定方法とは少し変わった部分もあります。

予め、フォルダ内に複数のExcelファイルを用意しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/06241b98-90ea-b54b-3ec2-071862accaa2.png)


基本的にこの処理が使用できるのは、ファイルループでファイルを開く必要があった際の「Guarded Choice」ステップで使用できます。

例えばなんですが、
①「ファイルループ」ステップを置いて、ディレクトリを設定し、ファイルパスを変数に格納します。
②ファイルパスが格納された変数から、正規表現でファイル名のみを抽出します。
③そのファイル名が格納された変数とファイルパスが格納された変数をDA側に渡します。
④Openステップを置いて、URIを設定します。
URIには「replaceall(ファイルパスが格納された変数,"￥（バックスラッシュ）4つ","/")」を設定すると開けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/1f7597ac-c1c3-972f-2b24-a461f19cd893.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/2cbf8b79-a735-faa3-b552-31d719f72dc6.png)
※「ファイル名」はファイルパスが格納されている変数です。

⑤これを開いて、要素があるかの確認の際に今回のものが使用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/e7b3a06c-a499-0bf8-0d3d-c7ce8b380e68.png)
⑥「Guarded Choice」ステップを置いて、要素を取得します。
恐らく、「EXCEL.EXE」か「EXCEL.EXE[title="A.xlsx - Excel"」という要素が取得されます。
しかし、これでは、「A.xlsx」のみでしか要素が取得できないため、2周目のループの際にエラーになります。
「EXCEL.EXE」だと他のExcelファイルが開いた際にどのExcelかを認識できずにエラーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/5fd2fece-ccb7-3769-fc4a-7724d7f1d83e.png)

⑦Componentを設定することで対象のExcelの要素を取得できるようにします。
変数「ファイル名」はファイル名が格納された変数です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/458ae3e0-2bbd-f0f1-0b6a-aa5495e44d26.png)

⑧このような設定を行うことで、ファイルループした際にもファイル名のみが格納されているので
どの要素を読み込んでいるのかを判断させることができます。
以下が2周目と３周目の結果です。

２周目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/6d32bdcd-9323-c987-2163-3792f523a616.png)

３周目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/0194f444-f6fe-426b-502e-27cfcd6d2355.png)

#最後に
最後までご覧頂きありがとうございました。
あくまで参考です。個人個人でやりやすい方法は違ってくるので、自分のやりやすい方を選んでください。
もっと良いやり方がある場合はそちらを優先してください。
使用する機会があれば、ぜひ使用してみてください。
会計freee APIでできること を読んでの備忘録

#取引を作成 / 取得する

取引を作成 / 取得を行うことができます。一般的な仕訳にはお金の動きが伴うものと、お金の動きが伴わないものがあります。freeeではお金の動きが伴うものを取引、お金の動きが伴わないものを振替伝票と呼んでいます。

部門はご利用中のプランに応じて1階層〜5階層まで作成することが可能です。取引作成時に部門タグを付与することで部門別の集計が可能になり、より便利にfreeeをご利用頂けます。


取引作成時に品目タグを付与することで商品別の集計が可能になり、より便利にfreeeをご利用頂けます。

取引作成時にメモタグを付与することでメモタグ別の集計が可能になります。メモタグは1つの取引に対して複数紐付けることが可能です。

#明細を作成 / 取得する

明細とはインターネットバンキングなどから情報を取得したそのままのデータで、この段階では取引(仕訳)は作成されていません。
明細としてfreeeへデータを渡すことで「自動で経理」の機能を通すことが可能になります。


#SFA、CRM、販売管理との連携ニーズ

freeeではインターネットバンキングと連携して自動で入金消込を行う機能があり、債権管理を効率化することができます。
自動で消込を行うためには事前に入金予定(売掛)を登録しておく必要があり、SFA/CRM/販売管理との連携によって入金消込をよりスムーズに行うことが可能です。

#マスタ連携

初回同期時のマッチングは別途考慮する必要があることもご留意ください。
freeeが正：勘定科目、税区分、部門
連携サービスが正：取引先、品目


#消込結果の連携

freeeAPIを利用して請求書(取引)の入金消込状況を取得することが可能です。消込状況をフロント側のサービスに連携することで債権状況を適切に把握し、回収活動に活かすことが可能です。
従来、債権督促は経理部門が未入金リスト作成 → 営業部門が取引先へ債権督促を分担しており、部門間のやりとりに時間がかかっていました。
freeeと各サービスとの連携によって部門を超えた情報のやりとりが整理され、スムーズに情報共有を行うことが可能です。
ServiceNow - テーブルをお気に入りにする

ServiceNowではナビゲータに「テーブル名+.list」を入力すると該当するテーブルが表示される。
よく利用されるテーブルをお気に入りに追加すると毎回テーブル名を入力する手間を省くことができる。

手順：
テーブルを表示した後にブレッドクラムをお気に入りにドラッグ＆ドロップする。
![servicenow_list_favorites_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/28e4b20d-31bf-3c84-2f6d-55d78e1eb25e.png)

以上
Couchbase Mobile機能解説：データ同期における競合解決①（概要）

## ドキュメントの競合(Conflict)

データ同期をサポートする分散環境では、ドキュメントの競合が発生する可能性があります。したがって、こうしたドキュメントの競合を解決する必要があります。 

## 自動競合解決 / コンフリクト・フリー・モード
Couchbase Mobileでは、「自動競合解決」、言い換えると、 「コンフリクト・フリー」モードが導入されています。このモードでは、競合が自動的に処理されます。
この場合、システムのデフォルトのコンフリクト・リゾルバーが自動的に処理するため、アプリ開発者が、競合に対処するためにアプリ側で特定のことを行う必要は基本的にありません。ただし、競合について通知を受けるオプションがあり、必要に応じて、適切なアクションを実行することが可能です。

この投稿では、自動競合解決 / コンフリクト・フリー・モードを使用して、Couchbase Mobileでドキュメントの競合が自動的に処理される方法の基本について説明します。

## ドキュメントリビジョン(改訂)ツリー

競合解決プロセスを理解するには、ドキュメントの管理方法の基本を理解する必要があります。Couchbase Mobileでは、すべてのドキュメントに、システムで生成された一意のリビジョンID（revID）が割り当てられます。このIDは、ドキュメントを一意に示すIDであるドキュメントIDとは別に管理されます。ドキュメントへのすべての変更は（削除の場合を含め）、ドキュメントの新しいリビジョンとして扱われ、リビジョンIDが割り当てられます。


既存のドキュメントに変更（編集または削除）を行うたびに、ドキュメントを更新するアプリケーション（ライター）は、更新されるドキュメントの現在のリビジョンIDを含める必要があります。変更に対して新しいリビジョンが作成され、更新されていた現在のリビジョンに子ノードとして追加され、ドキュメントのリビジョンツリーが作成されます。

注：「revID」はアプリに対して不透明な（透過的な）オブジェクトとして扱われる必要があります。アプリは「revID」を生成しようとしてはなりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/ce22adc4-bf30-52f4-ef42-038547a277a5.png)

## 競合発生のメカニズム
端的に言えば、複数のライターがドキュメントの同じ親リビジョンに変更を加えると、競合が発生します。

## Couchbase Liteでの（プルレプリケーションによる）競合
次の図は、プルレプリケーションの結果として、モバイルデバイスのドキュメントが更新されるときに、既にアプリがローカルのドキュメントの同じリビジョンを更新しているシナリオを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/c26095be-31be-3c74-7c26-c4566ca9078b.png)

## Sync Gatewayでの（プッシュレプリケーションによる）競合
次の図は、2つのクライアントがドキュメントの同じリビジョンへの変更をプッシュするシナリオを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/248c334a-bd50-4c75-22bc-030ee7826d68.png)

## 競合の解決
コンフリクトフリーモードでは、競合は、自動的に解決されます。
つまり、データベースに競合するドキュメントが保存されると言うことは起こりえず、事実上「競合がない（コンフリクトフリー）」ということです。

## 最後に
詳細について、稿を改めて解説します。







# 関連情報

https://blog.couchbase.com/document-conflicts-couchbase-mobile/

以前のバージョン
[Demystifying Conflict Resolution in Couchbase Mobile](https://blog.couchbase.com/conflict-resolution-couchbase-mobile/)