OmniAICreator/Qiita-1.07M huggingface dataset:
日本語でエラー文章

<h2>gemを入れる</h2>
```ruby:GEM
gem 'rails-i18n'
```

```ターミナル
bundle install
```
<h2>config/application.rbに追記</h2>
```config/application.rb
module Stoma
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2
    config.i18n.default_locale = :ja    ここ追加する
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end

```
<h2>3点未入力がありますのエラー部分テンプレート作成</h2>
```html:layouts/_errors.html.erb
<% if obj.errors.any? %>
  <div id="error_explanation">
    <h3><%= pluralize(obj.errors.count, "点") %> 未入力があります</h3>
    <ul>
      <% obj.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

```
<h2>obj：＠エラー文の対象とし、部分テンプレートを呼び出す</h2>
```html:html
<%= render 'layouts/errors', obj: @ostomy%>
```


<h2>config/locales/models/ja.ymlで日本語化する</h2>
<p>インデントずれると翻訳できないので注意</p>

```config/locales/models/ja.yml
ja:
  activerecord:
    errors:
      messages:
        record_invalid: 'バリデーションに失敗しました: %{errors}'
        restrict_dependent_destroy:
          has_one: "%{record}が存在しているので削除できません"
          has_many: "%{record}が存在しているので削除できません"
    attributes:
      ostomy:
        color: ストーマの色
        edema: むくみ
        skin: 皮膚の状態

##########この順序でかく##################################

attributes:  　　　　　　　# attributes:の直下
  post:  　　　　　　　　　 # モデル名
    title: 名前   　　　　　   #カラム
　　   content:ブログ本文　　　　#カラム名
############enumsの訳も以下############################
enums:　　#enum
    ostomy: #モデル名
      color:　　#カラム
        pink: ピンク  #訳
        red: あか    #訳
        brown: ちゃいろ #訳
        black: くろ　　　　　　#訳
```
git clone --depth 1 したリポジトリの履歴をやっぱりすべて取得する

ビルドで過去のコミット数を参照している部分があり、`--depth 1`でクローンしたリポジトリのすべての履歴が後から必要になりました。
以下のコマンドですべての過去のコミット数が取得できるようになりました。

```
git fetch --unshallow
```

参考
https://stackoverflow.com/questions/6802145/how-to-convert-a-git-shallow-clone-to-a-full-clone
AWSでEC2にEIPを付与→関連解除すると、パブリックIPがEC2に残ってしまう

## これは何

AWSでEC2にEIPを付与→関連解除すると、パブリックIPがEC2に残ってしまった(!)の記録です。

## 記録

自動割り当てパブリックIPを無効にします。

![スクリーンショット 2021-09-10 17.52.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/ddcb6cdd-c0bc-575f-217c-981104413ff7.png)

![スクリーンショット 2021-09-10 17.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/df4a7a13-82eb-3477-2b53-eb546a6d3530.png)

EIPを付与します。

![スクリーンショット 2021-09-10 17.55.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/c915e71d-ecec-553c-4715-6a37d577158a.png)

EIPの関連を解除します。

![スクリーンショット 2021-09-10 17.56.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/8864985b-d98b-3820-b1b5-1714921ec724.png)

残ってしまっている(!)
(インスタンス削除済みなのでIP載せてます)

![スクリーンショット 2021-09-10 17.56.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/f6e2fb8f-ea29-af45-7a26-ad99a34d463b.png)

## 総括

EIPをアタッチしたら、パブリックIPは取り除けないんですね。
ネットワーク周りは構築初期から本当に気をつけて見ないとですね。
仮に外したいとなったら、AMIコピーからやらないといけなそう。（https://cloudpack.media/29286）

## 参考

```
https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-recover-ip-address/
https://josys-memo.com/ec2-public-kaijo/
https://cloudpack.media/29286
```

参考にさせていただきました。ありがとうございます。
[備忘録]STSの起動ができなったときの対処法

##目的
読書記録のアプリケーションを作成しようとSTSで新規プロジェクトを立ち上げたが、アプリケーションの起動ができなかった。
すぐに解決ができずにいたため、その対処法を備忘録として残したい。

*エラー文*
[selection does not contain a main type]

##結果
<b>結論：HelloWorldApplication.javaを誤って消してしまっていた。</b>

SpringBootで開発したアプリケーションを起動するクラスを削除していたため、起動ができなかった。

内容は以下の通り。

```HelloWorldApplication.java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloWorldApplication {
	public static void main(String[] args) {
		SpringApplication.run(HelloWorldApplication.class, args);
	}
}
```

GitHubで削除前のデータは残っていたが、折角なので自分で作成したところ、うまく起動した。


##感想
[HelloWorldApplication.java]を消したらアプリケーションが起動しないこと自体は覚えていたが、実際に消したときのエラーに遭遇してみて、すぐに[HelloWorldApplication.java]にたどり着けなかった。比較的簡単に解決したが、注意を払ってSTSの操作をしたい。
エンジニアスポット採用のすゝめ

知見の獲得方法として、スポットでエンジニアを採用することについて書いてみました。
マネジメントコストが上がりがちなど、採用方法としては敬遠されがちですが実は企業にとっても大きなメリットがあると思います。
僕の体験から共有できることを書いてみようと思います。


## 実務レベルで新しい分野の知見を獲得するにはお金と時間がかかる
実務レベルの技術獲得には以下の工程が必要だと思います。設計から始まり、実際に運用してみて改善を繰り返し、はじめて知見と呼べるものになると思います。
ですので、自社内で知見と呼べるものにするには**数ヶ月**かかってしまうのが現状です。
![スクリーンショット 2021-09-11 14.56.04（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410824/ff438557-3e30-1c1c-64ca-22e31756fd66.png)

例えばElasticsearchへの移行を例にとってみます。
既存の検索ツールではalgoliaを使っていたのですが、サービスが大きくなるにつれて従量課金による費用の増大が問題になってきました。
そこで費用を抑えるため、サーバーでの運用ができるElasticsearchを導入することにしました。

ただ問題がありました。
それはElasticsearchへの知見を持つ人が社内にいなかったことです。
迂闊に導入してデータモデルの設計が甘かったりすると、データ更新の頻度が増えるなど運用コストが高くなってしまう可能性があります。

そんな時に**スポット知見輸入**が役立つのです！


## スポット(タスクor issue単位)で知見を獲得する

例えば、今回で言うとElasticsearchの設計や運用までを経験しているエンジニアをスポットで獲得することになります。
スポットで獲得した場合のメリットには以下のようなものがあります。
<dl>
  <dt>採用スピードがはやい</dt>
  <dd>issueやタスク単位だと内容が明確で応募しやすいのでエンジニアが集まりやすい→すぐにエンジニアを確保できる</dd>
  <dt>ミスマッチが少ない</dt>
  <dd>issueの詳細な内容を理解してくるエンジニアはそもそもマッチしている確率が高い:sunglasses:</dd>
  <dt>費用を節約できる</dt>
  <dd>正社員として入社してもらった場合にかかるもの。毎月の基本給、福利厚生費、社会保険料、健康保険料...:scream:</dd>
</dl>

## 緊急度は低いが一定のインパクト見込めそうなものをお願いする

ポイントとしては、緊急度が低く重要度の高いものをお願いしましょう。
あくまで業務委託の副業社員なので、スピード勝負のissueは不向きです。

![スクリーンショット 2021-09-11 15.25.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410824/7255a98f-9108-1238-4d8a-f0aa707f2d52.png)


## (例)ページパフォーマンス改善やOGP画像サーバーの作成

実際に過去、スポット依頼で開発依頼をお願いした案件に以下のようなものがありました。


### ページパフォーマンス改善
![images.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410824/2d460a68-81c1-21a5-0fc7-e2a92740808c.png)



表示まで2秒かかるページがあり、ユーザーから速度改善の要望がありました。
速度改善が得意なフロントエンジニアに修正をお願いして、なんと0.6秒(3倍以上)まで速くしてもらいました！


### OGP画像サーバーの作成

SPAでもユーザー詳細ページの情報をもとに動的にOGP画像を生成する実装をしてもらいました。
UGCコンテンツにもなるのでC向けサービスを展開されているところにはとても相性が良かったです！

※イメージ
![スクリーンショット 2021-09-11 15.35.15（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410824/2a7a8a7a-7637-2d4c-17ea-63ecb92837c3.png)


## スポット採用についての疑問

しかし一方でスポットエンジニア採用は浸透していません。それは企業にとってマイナスなイメージが強いからだと思います。
そういった声に少しお答えさせていただきました。

###Q.マネジメントコストが高くなるのではないか
スポット獲得したエンジニアに対してマネジメントする必要はほとんどありません。なぜなら要件が固まっていれば、後は知見を持つエンジニアがよしなに実装してくれるからです。マネジャーは**成果物を確認するだけ**になります。

###Q.知見が社内にたまりにくいのではないか
スポット参画した知見のあるエンジニアに敷いてもらったコードを**見本**に、社内のエンジニアがキャッチアップすることで解消できると思います。後はスポットで参加いただいたエンジニアにドキュメント作成などの依頼するなどの対応をしていました。

###Q.新規で参画したエンジニアのキャッチアップコストが高くならないか
スポット採用において特定の分野に深い知見をもち、かつ新規で実装できるようなもの(例えばリポジトリを分けたり、既存システムはいじらない、もしくはちょっと繋ぎこむだけ)に関しては**実はあまりキャッチアップはかかりません**。あくまで自分の持つ知見をアウトプットすることがメインになります。
それでも環境構築は大変じゃないか、というお声もあると思います。それには「オンボーディングファイル」と言うものを用意して、新規で参画したエンジニアのキャッチアップを自動化しています。詳しくは続編で...

### 採用に繋がる確率が一定ないと費用対効果合わないのではないか
こちらも別のソリューションがあります。詳しくは続編で...

## まとめ
無駄な費用をカットして、効率的に知見を社内に積み重ねていきましょう！
副業の浸透が始まったばかりでまだまだ認知の薄い、スポット採用ですが今後盛り上がっていくことを目標にしています！

## おまけ
スポット採用については下記のアカウントでも情報発信してるので、ぜひフォローお願いします！
https://twitter.com/twinsdevelopper
一覧画面でテーブルの集計値をjsワンライナー計算

さすがに、すべてをワンライナーで書くと長いので計算部分のみ、

```js:total.js
(() => {
    'use strict';
    kintone.events.on('app.record.index.show', (event) => {
        console.log(`(合計)  ${event.records.reduce((total, record) => total += record['テーブル'].value.reduce((value, row) => value += Number(row.value['数値'].value), 0), 0)}`);
    });
})();
```

**注意**:
一覧画面で表示中のレコードのみの計算になるので、
最高で100件まで。
MySQL 片仮名/平仮名 濁点/半濁点を区別する	

##３つの collation (照合順序) を調べて全て変更
データベース/テーブル/列
→それぞれ別々なので全て変更すること。

【検索用：定義 設定 】
###Collationについて
MySQLは<b>文字コード(Character Set)</b>と<b>ソート順(Collation)</b>を持っている。
比較するときには文字コード(Character Set)だけでなくてソート順(Collation)が一致するかどうかを比較する								

##データベースのcollationの確認
```
SELECT @@character_set_database, @@collation_database;
```
データベースをuse した状態でコマンドを実行すること。

##データベースのcollationの変更	
```
ALTER DATABASE COLLATE utf8_general_ci;
```
「utf8_general_ci」の部分はcollation


##テーブルのcollationの確認
```
 SHOW TABLE status FROM データベース名;
```

##テーブルのcollationの変更
```	
 ALTER TABLE テーブル名 COLLATE utf8_general_ci;	
```
「utf8_general_ci」の部分はcollation	

##カラムのcollationの確認
```
 SHOW FULL COLUMNS FROM テーブル名;
```

##カラムのcollationの変更
```
ALTER TABLE テーブル名MODIFY COLUMN カラム名 varchar(50) COLLATE utf8_general_ci;
```

「varchar(50)」はデータ型と文字数
「utf8_general_ci」の部分はcollation
【VSCode】.tsxファイルにユーザースニペットが登録されない際の解決方法

## 使用環境

・MacOS BigSur（11.5.2）
・VScode（1.59.1）
・Node.js   (16.1.1）
・React（17.0.2）
・Next.js（11.1.0）

## はじめに

エンジニアなら誰しも、開発効率化のためにVS Codeのユーザースニペット（入力補完ツール）を登録したいですよね。

自分もそう思って記事を参考に手を出してみたのですが、登録したはずのスニペットがtsxファイルになぜか現れてくれません・・・涙

そこで自分が使ってるVS Codeの拡張機能が原因かもしれないといろいろ探っていましたがいい方法が見つからず。。

しばらく放置してまたやってみようと思った今日、とってもシンプルな方法を見つけたのでそれを紹介します。（前提としてスニペットの登録方法は調べておいてください。）
参考までに↓
[VsCodeのスニペットのススメ][2]
[2]:https://qiita.com/xx2xyyy/items/fd333368db548167f15a

## 結論/解決策

もったいぶらずにやり方を説明します。

ReactとTypeScriptを使用している.tsxファイルにスニペットを適用させるには、スニペット登録ようのJSONファイル内のscopeに`typescriptreact` を記述します。以上。

`"scope": "javascript, typescript, typescriptreact"`

例としてclassName=''をスニペットとして登録する場合の記述方法をあげておきます

```tsx
{
	"className": {
		"scope": "javascript,typescript,typescriptreact", //ここに記述
		"prefix": ["cla", "class"],
		"body": ["className=''"],
		"description": "className input"
	}
}
```
tsxファイルは別物なのですね。おそらくjsxファイルも同様に`javascriptreact`とか必要になるのかもしれません。

ちなみに設定を反映するのにVS Codeの再起動とかは必要ありません。
これで入力されることを確認してみてください。

## 参考資料

StackOverflow [Visual Studio Code user snippets not working][1]

[1]:https://stackoverflow.com/questions/44321000/visual-studio-code-user-snippets-not-working/46574024
WSLにてapt update時の『Temporary failure resolving ~』を解決する方法

# 問題

wslで `sudo apt update` するときに、名前解決ができない問題がある。

具体的には

```sh
sudo apt update
```

を実行すると

```
Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
  Temporary failure resolving 'archive.ubuntu.com'
```

というエラーが出る。
この記事では、これを解決する。

# 解決方法指針

書いてあるとおりに、名前解決ができていないので自分の環境にあったDNSサーバを `/etc/resolv.conf` に指定する。
いろいろな記事に記載されているのはDNSサーバとして `8.8.8.8` を指定するように書いてある。
私の環境ではこれでは解決しなかった。

これを解決するために自分の環境にあったDNSサーバを調べ、それを `/etc/resolv.conf` に記載する手順を書いておく。

# 前提

wslのネットワークの自動で生成機能は切っておきましょう。
`/etc/wsl.conf` をこんな感じにしておく。

```
username@hostname:/etc$ cat /etc/wsl.conf
[network]
generateResolvConf = false
```

# やり方

## 自分の環境のDNSサーバを調べる

コマンドプロンプトで DNSサーバを調べるために以下のコマンドを叩く。

```powershell
PS C:\Users\username> ipconfig.exe /all
```

するとDNSサーバを含む全てのネットワークが表示される。

```
Wireless LAN adapter Wi-Fi:

   接続固有の DNS サフィックス . . . . .:
   説明. . . . . . . . . . . . . . . . .: Intel(R) Dual Band Wireless-AC 8265
   物理アドレス. . . . . . . . . . . . .: D0-AB-D5-E3-41-D0
   DHCP 有効 . . . . . . . . . . . . . .: はい
   自動構成有効. . . . . . . . . . . . .: はい
   IPv4 アドレス . . . . . . . . . . . .: 192.168.11.10(優先)
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   リース取得. . . . . . . . . . . . . .: 2021年9月13日 0:39:37
   リースの有効期限. . . . . . . . . . .: 2021年9月15日 8:29:58
   デフォルト ゲートウェイ . . . . . . .: 192.168.11.1
   DHCP サーバー . . . . . . . . . . . .: 192.168.11.1
   DNS サーバー. . . . . . . . . . . . .: 192.168.11.1
   NetBIOS over TCP/IP . . . . . . . . .: 有効
```

この中でDNSサーバと書いてある箇所をメモする。
上記の表示例だと `192.168.11.1` がDNSサーバのIPアドレス。

## /etc/resolv.conf に書き込む

```
sudo sh -c "echo 'nameserver 192.168.11.1' > /etc/resolv.conf"
```

## apt updateを実行する

ここまでやると名前解決のエラーが無くなり、解決できるはず。
具体的には以下のような表示になり、解決する。

```sh
username@hostname:/etc$ sudo apt update
Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
Hit:2 http://archive.ubuntu.com/ubuntu focal InRelease
Get:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
Get:4 http://security.ubuntu.com/ubuntu focal-security/main amd64 Packages [861 kB]
Get:5 http://archive.ubuntu.com/ubuntu focal-backports InRelease [101 kB]
Get:6 http://archive.ubuntu.com/ubuntu focal/universe amd64 Packages [8628 kB]
Get:7 http://security.ubuntu.com/ubuntu focal-security/main Translation-en [166 kB]
Get:8 http://security.ubuntu.com/ubuntu focal-security/main amd64 c-n-f Metadata [8692 B]
Get:9 http://security.ubuntu.com/ubuntu focal-security/restricted amd64 Packages [405 kB]
（以下略）
```
【学習メモ】覚えやすいPublic DNS

# はじめに
覚えやすいPublic DNS

# 一覧
## 覚えやすい
安全かどうかは各自判断してください。

|IPv4|DoT|DoH|提供元|備考|
|:--:|:--:|:--:|:--:|:--:|
|1.1.1.1|○|○|Cloudflare||
|8.8.8.8|○|○|Google||
|9.9.9.9||○|IBM|Quad9。フィッシングをブロックするらしい。|

## まあまあ覚えやすい
|IPv4|提供元|備考|
|:--:|:--:|:--:|
|233.5.5.5|[Alibaba cloud](https://www.alibabacloud.com/help/ja/doc-detail/171502.htm)||
|216.146.35.35|[Dyn(Oracle)](https://help.dyn.com/dyn-internet-guide/)||
|64.6.64.6|Vedrisign||
## 番外
|IPv4|提供元|備考|
|:--:|:--:|:--:|
|80.80.80.80|freenom World|DNSSEC対応していますがDNSSECに対応していないtkなどのドメインを提供しています。|
|114.114.114.114|[114dns](https://www.114dns.com/)|中国なのでわざわざ使う理由がありません。|
|180.76.76.76|Baidu|怖くて使えません。|
|-|Azure|大手ですが提供しているドキュメントを見つけられていません。|

# 個別
## Cloudflare
参考:https://1.1.1.1/ja-jp/

|IP|備考|
|:--:|:--:|
|1.1.1.1||
|1.0.0.1|セカンダリ|

## Google
Google Public DNS
参考:https://developers.google.com/speed/public-dns/

|IP|備考|
|:--:|:--:|
|8.8.8.8||
|8.8.4.4|セカンダリ|

## IBM
Quad9
参考:https://www.quad9.net/support/faq/

|IP|備考|
|:--:|:--:|
|9.9.9.9||
|9.9.9.10|セキュリティブロックリストなし、DNSSECなし、EDNSなし|
|9.9.9.11|セキュリティブロックリスト、DNSSEC、EDNS クライアント|

Memo
いずれのセカンダリも覚えやすいIPv4ではないため記載しません。
【初心者向け雑記】SaaSの発展とSaaS/PaaS/IaaSの概念まとめ

#■はじめに
##`ワークスタイルの変化`
新型コロナ対策としてテレワークやペーパーレス化の需要が増加したことで、
場所を選ばず業務を行えるようなワークスタイルが求められている。
このニーズに応えるため近年のIT業界で台頭してきたのが、SaaS型のサービスである。

#■SaaSとは
##`「サービスとしてのソフトウェア」`
クラウドサーバーにあるソフトウェアを、インターネットを経由して利用できるサービスのこと。
ベンダーがサービスを稼働・運営、ユーザーはクラウド経由でそれらを利用し、
データ量等に応じて月額料金を支払う取引形態で成り立っている。

例えば、メジャーなものでは以下がある。
（見覚えのあるサービスが多いが、全てSaaSの仲間）
・ビジネスチャット
　　- Slack、Chatworks、LINEWORKS
・Web会議
　　- Zoom、Webex Meetings、Microsoft Teams
・会計管理／名刺管理など
　　- freee（クラウド会計ソフト）、Sansan（クラウド名刺管理サービス）

##`関連ワード`
>PaaS（Platform as a Service）
　　- ソフトウェアの構築・稼働に必要なプラットフォームをサービスとして提供すること。
　　　Amazon Web Services（AWS）、Google App Engineなど。
>IaaS（Infrastructure as a Service）
　　- システムの稼働に必要な基盤をサービスとして提供すること。
　　　Amazon EC2、IBM Cloudなど。

#■SaaS導入のメリット／デメリット
##`メリット`
・導入スピードの早さ。環境構築が不要で、アカウント登録さえ行えばすぐにサービスを利用できる。
・システム管理/運用の負担軽減。これらはサービス提供側が行うため、ユーザ側が人員を割く必要がなくなる。
・イニシャルコストの節約。自前でサーバやソフトウェアを用意する必要がなく、初期費用を抑えられる。
　また、SaaSは主に従量課金制を採用している為、データ利用量に応じた適切な費用で運用することが出来る。

##`デメリット`
・カスタマイズ性が低い。自社開発の製品と比較して、痒いところに手が届かない可能性がある。
・不正アクセスのリスク。インターネットから手軽にアクセスしてサービスを利用できるため、徹底したセキュリティ対策が必要。

#■余談
基本情報技術者試験でも出題されがち。

https://www.fe-siken.com/kakomon/28_haru/q41.html

https://www.fe-siken.com/kakomon/24_aki/q63.html


#■参考文献

https://tech-camp.in/note/pickup/100763/

https://www.tramsystem.jp/voice/voice-2484/

https://digital-shift.jp/flash_news/s_210518_4
Slack API に自分のアプリ専用の Webhook を作る

Slack のチャネルに自分のアプリから何かメッセージを送りたい時、Slack API の Webhookが必要になります。そのために作られた Thirdparty提供の汎用的 Incoming Webhook サービスもありますが、最近これを使ってみようとしたら Slackの画面にこれはLegacyだから使わないでという旨の警告が表示されたので、直接自分のアプリをSlackに登録してWebhookを作ることにしました。今回はその設定手順を紹介(メモ）します。

### 前提
- Slack Workspaceの管理者権限を持っていること
- 自分のアプリからSlackにメッセージを飛ばすチャネルを準備しておくこと（今回は #cdev というチャネルを作っておきました）

### 設定手順

1. Slack Desktop アプリからManage appsを開く
![slack01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/e6bb3dfe-36e4-4def-9040-80c4abd49a94.png)

2. Slack Apps 画面が表示される
![slack02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/aa6f792b-de9d-a19b-3add-3876c7b1d17b.png)

3. 画面右上の「Build」をクリックする
![slack03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/55a49d98-5695-a57a-446f-047d83684f62.png)

4. 「Your Apps」に自分のアプリ一覧が表示される
![slack04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/7f0dc7db-0bc5-48bf-7a64-3afdd40ef7db.png)

5. 「Create an app」をクリックする
![slack05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/14c26038-293d-9714-a6f7-e8660f76da1f.png)

6. 「Create an app」のメニューが表示される
![slack06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/e2a06ea5-433c-0aa3-7901-eeee561b7c2a.png)

7. 「From scratch」を選択する
![slack07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/ac1e9bed-b2f3-01f1-aa96-7c15f6e2bf07.png)

8. App Nameを入れて(今回はQUALITIA-App)、Workspaceを選択し(今回はQUALITIA CO., LTD.)、「Create App」をクリックする
![slack08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/3b1d5eec-c35c-454c-fc8d-4f175b693e64.png)

9. 「Add features and functionality」が表示されたら「Incoming Webhooks」をクリックする
![slack10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/20e40385-be08-06d2-0490-5e5f2add579d.png)

10. Incoming Webhooksが表示される
![slack11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/4aea8dd7-4d37-550e-51de-12ceca446a9e.png)

11. Activate Incoming Webhooks を On にする
![slack12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/03125810-8595-cea3-fd2f-026fb75f9332.png)

12. アプリからSlack チャネルへの承認を求める画面に遷移する。メッセージを飛ばしたいチャネルを選択する
![slack14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/60b20446-9029-302b-acc5-a4256061fd6a.png)

13. Allow をクリックする
![slack15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/13c001d1-b96e-ed64-d43b-aab16b7ccada.png)

### Webhook URL 確認

手順13まで行うと、少し時間が経って(1~2秒)から　Incoming Webhooks画面に戻ります。
その画面の下のほうに、 Webhook URL for Your Workspaceに　Webhook URLと設定したチャネルが表示されています。

![slack16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326401/16ccb1af-1bde-0335-ed3d-8902006c44a3.png)


これで完了です。
osを作る その12

#概要

osを作る。
インラインアセンブラで、シリアルを送信してみた。

#サンプルコード

```

void send(void) {
	asm(
	"ldi 	r16, 0x55				\n\t"
	"sts 	0x00C6, r16				\n\t"//UDR0
	);
}

void setup(void) {
	Serial.begin(9600);
	while (!Serial)
		continue;
	Serial.println("ok0");
	Serial.println("ok1");
}

void loop(void) {
  delay(100);
  send();
}



```

#結果


```
ok0
ok1
UUUUUUUUUUUUUUUUUUUU
```

以上。
AWS IoT CoreをRaspberry Piで使ってみた その3

## 概要
* AWSにはIoT機器と接続、管理するためのAWS IoT Coreというサービスがある
* 公式にもハンズオンがあるが、最小限の手順、構成で動作を確かめてみる  
https://aws-iot-core-for-beginners.workshop.aws/phase2/step2.html
* 前回に引き続き温湿度センサーDHT22のデータを送信することを試みる

![aws-iot-core.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/5b2e455f-a8b2-e09b-ba52-9fdeb020073d.png)

前回の記事
https://qiita.com/cami_oshimo/items/8e9c45230fccfac4ff4c

![スクリーンショット 2021-09-12 11.35.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/54dca80b-5125-2074-e23f-b8a67b3f827b.png)

![IMG_2332.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/1428f5a4-2ac4-a3dd-b591-8841bca03a00.jpeg)


## Raspberry Piの操作
ライブラリseeed-python-dhtをインストールする

```
# pip3 install seeed-python-dht
```

まずセンサー、ライブラリの動作を確認するコードを書いてみる

```dht22.py
import RPi.GPIO as GPIO
import seeed_dht

GPIO.setup(4, GPIO.IN)

sensor = seeed_dht.DHT("22", 4)

humi, temp = sensor.read()

humidity = '{:.1f}'.format(humi)
temperature = '{:.1f}'.format(temp)

print(humidity)
print(temp)
```

動作を確認してみる（温度、湿度が順番に表示される）

```
# python3 dht22.py
26.3
78.1
```

前回使用したサンプルプログラムに組み込んでみる

```basicPubSub.py
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import logging
import time
import argparse
import json

import RPi.GPIO as GPIO          // 追加
import seeed_dht                 // 追加


GPIO.setup(4, GPIO.IN)           // 追加
sensor = seeed_dht.DHT("22", 4)  // 追加

AllowedActions = ['both', 'publish', 'subscribe']
```

```basicPubSub.py
while True:
    if args.mode == 'both' or args.mode == 'publish':
        humi, temp = sensor.read()          // 追加
        humidity = '{:.1f}'.format(humi)    // 追加
        temperature = '{:.1f}'.format(temp) // 追加
        message = {}
        message['message'] = args.message
        message['sequence'] = loopCount
        message['temp'] = temp              // 追加
        message['humi'] = humi              // 追加
        messageJson = json.dumps(message)
        myAWSIoTMQTTClient.publish(topic, messageJson, 1)
        if args.mode == 'publish':
            print('Published topic %s: %s\n' % (topic, messageJson))
        loopCount += 1
    time.sleep(1)
```

修正したサンプルプログラムのbasicPubSub.pyを実行する

```
pi@raspberrypi:~/aws-iot-device-sdk-python/samples/basicPubSub $ python3 basicPubSub.py  --endpoint abc123abc123abc123-ats.iot.ap-northeast-1.amazonaws.com --rootCA ../certs/AmazonRootCA1.pem --cert ../certs/abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123-certificate.pem.crt --key  ../certs/abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123-private.pem.key
```

トピック sdk/test/Python にPublishされていることを確認する
![スクリーンショット 2021-09-12 11.27.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/eb2dde8d-94a7-1fe9-5eff-9c4b7e5371a3.png)

## AWS IoT Coreの操作
テスト→MQTTクライアントでJSON形式のデータが到着していることを確認する
![スクリーンショット 2021-09-12 11.29.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/930d2728-64fd-7b22-91a1-6336dea86315.png)

## 課題  
* seeed-python-dht から読みだした値を小数点以下1桁で送信したかったが、  
  Pythonで '{:.1f}'.format(temp) としても反映されない。  
  テスト用のコードでは再現しない。原因不明。時間のある際に調査する。
systemctlでエラーになったときの詳細確認方法

systemctlで以下のようなエラーがでることがある。例はsidkiq。

---

Job for sidekiq.service failed because the control process exited with error code. See "systemctl status sidekiq.service" and "journalctl -xe" for details.

---


でも statusを見てもjournalctlをしてもさっぱり原因がわからない..

そんなときは以下の流れで詳細が確認できる。


1. "systemctl cat サービス名" コマンドを実行してUnitファイルを見る。
*  [Service]以下の「WorkingDirectory」と「ExecStart」を取得。
*  WorkingDirectoryに移動してExecStartの中身を実行。ここで実行時のエラー内容が直接確認できる！！



[参考]
https://kazuminkun.hatenablog.com/entry/2016/08/30/234458
[Swift] バージョン番号文字列の新旧比較をする。


##やりたいこと

x.y.z 形式のバージョン番号について、2つのバージョン番号間でどちらが新しいバージョンかをSwiftのコードで判定したい。

```text:バージョン番号の比較例
2.0 > 1.5.1
1.6 > 1.5.24
1.10.1 > 1.7.55
1.5.3 < 1.5.11
```

ここでの前提として、バージョン番号はString型で定義されているものとします。

##よくある間違い

検索してよく出てくる方法は、単純にcompareメソッドを使って文字列比較する方法です。

```swift
let result = ver1.compare(ver2)

switch result {
case .orderedAscending:
    print("ascending")
case .orderedSame:
    print("same")
case .orderedDescending:
    print("descending")
}
```

この方法はよく見かけるのですが、問題があります。
問題がある場合の例を以下に示します。

ver1 = "1.6"　ver2 = "1.5.1"　の場合
　descending 　正しい結果！

ver1 = "1.10.1"　ver2 = "1.7.55"　の場合　
　ascending 　★間違った結果★
　(1.10.1 は 1.7.55より新しいので、 decendingと出力されるべき。)

単純にcompareメソッドを使う比較方法では、各レベルの数字で比較する際に桁数が違うと正しい結果になりません。
上記の例では、文字列として比較されて 10 が 7 よりも先だと判定されてしまうため、上記のような誤った結果となってしまいます。


##正しい方法

ではどうすればよいか。
「数字として比較する」オプションをつければ良いです。

```swift
let result = ver1.compare(ver2, options: [.numeric])

switch result {
case .orderedAscending:
    print("ascending")
case .orderedSame:
    print("same")
case .orderedDescending:
    print("descending")
}
```

ver1 = "1.6" ver2 = "1.5.1" の場合
　→ descending　正しい結果！

ver1 = "1.10.1"　ver2 = "1.7.55"　の場合　
　→ descending　正しい結果！


というわけで、compareでの比較時に .numeric オプションを忘れずにつけるようにしましょう。

##動作確認環境

Xcode: 12.5
iOS: 14.7.1
Swiftバージョン: Swift 5.4


以上
build.gradleに依存関係を追加したのにインポートが追加されない

## 概要
JdbcTemplateを使ってDAOクラスを実装するケースを例にして、build.gradleに依存関係を追加したのにインポートが追加されない場合の原因および解決策を記載する。

## 環境
Eclipse IDE：2021-06 (4.20.0)


## 事象
JdbcTemplateを使ってDAOクラスを実装する。

```gradle:build.gradle
・・・
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	runtimeOnly 'com.h2database:h2'
	implementation 'org.springframework.boot:spring-boot-devtools'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
・・・

```

```java:SampleDaoImpl.java
package com.example.sample.dao

public class SampleDaoImpl implements SampleDao {
	private final JdbcTemplate jdbcTemplate;
	・・・
}
```

この状態だと、`SampleDaoImpl.java`のソースビューに

>JdbcTemplateを型解決できません

というエラーが表示される。
これは、`build.gradle`の依存関係にJdbcTemplateのライブラリが定義されていないためである。

そこで、`build.gradle`の依存関係にJdbcTemplateのライブラリ`` 'org.springframework.boot:spring-boot-starter-jdbc'``を追加する。

```gradle:build.gradle
・・・
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	runtimeOnly 'com.h2database:h2'
	implementation 'org.springframework.boot:spring-boot-devtools'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
}
・・・

```

ファイルを保存して、インポートの編成を実行する。
しかしながら、`SampleDaoImpl.java`にJdbcTemplateのインポートが追加されない。

>JdbcTemplateを型解決できません

というエラーが変わらず表示される。

## 原因

原因は、**build.gradleを編集後、Eclipseに変更が反映されていないこと**だった。


## 解決策
解決策としては、build.gradleを編集後、**gradleプロジェクトをリフレッシュ**する。

gradleプロジェクトをリフレッシュする方法は、パッケージエクスプローラーの右クリックメニューから`Gradle＞Gradleプロジェクトのリフレッシュ`を実行する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879666/755a4793-f2ed-4c8b-044d-f5def2da20bc.png)


F5キーでプロジェクトをリフレッシュしても解消しないので注意。
Python で Azure の サブスクリプション毎 に リソースグループの一覧 を取得してみました


## 概要
Azure SDK for Python を利用して、接続しているテナントのサブスクリプション一覧を取得し、そのサブスクリプション毎にリソースグループの一覧を取得するための Python プログラムです。

### 実行環境
macOS Big Sur 11.1 
python 3.8.3

### 実行プログラム

```python:GetSubscriptionResourceGroup.py

import time
import argparse
from azure.mgmt.resource import SubscriptionClient, ResourceManagementClient
from azure.identity import AzureCliCredential


# 接続しているテナントのサブスクリプションを操作するオブジェクトを取得
def GetSubscriptionObject():
    subscription_client = SubscriptionClient(
        credential=AzureCliCredential()
    )
    return subscription_client


# 特定のサブスクリプションIDのリソースグループを操作するオブジェクトを取得
def GetResourceGroupObject(subs_id):
    resource_client = ResourceManagementClient(
        credential=AzureCliCredential(),
        subscription_id=subs_id
    )
    return resource_client


# サブスクリプション毎のリソースグループ一覧を取得
def GetSubscriptionResourceGroupList():

    # サブスクリプションを操作するオブジェクトの取得
    subscription_list = GetSubscriptionObject()

    # サブスクリプション毎の処理
    for n, subs in enumerate(subscription_list.subscriptions.list()):
        print("\n    サブスクリプション ：　{} {}".format(subs.subscription_id, subs.display_name))

        # リソースグループ一覧の取得
        resource_client = GetResourceGroupObject(subs.subscription_id)
        for i, rg in enumerate(resource_client.resource_groups.list()):
            print("{} {}".format(rg.name, rg.location))
        
        resource_client.close()
        print("    リソースグループ数:{0} \n".format(i+1))
    
    subscription_list.close()
    print("サブスクリプション数:{0} \n".format(n+1))


if __name__ == '__main__':    
    parser = argparse.ArgumentParser(description='Subscription 一覧の取得')
    args = parser.parse_args()

    start = time.time()
    GetSubscriptionResourceGroupList()
    generate_time = time.time() - start

    print("\n 取得時間:{0}".format(generate_time) + " [sec] \n")
```

### プログラムの実行
 
```
$ python GetSubscriptionResourceGroup.py 

    サブスクリプション ：　xxxxxxxx-nnnn-mmmm-ffff-yyyyyyyyyyyy APP-01
rg-test01 japaneast
rg-lab099 japaneast
rg-backup westus2
    リソースグループ数:3 

     ：
    中略
     ：

    サブスクリプション ：　zzzzzzzz-pppp-qqqq-rrrr-aaaaaaaaaaaa LAB-01
rg-blob japaneast
rg-DataExplorer japaneast
rg-powerapps japaneast
rg-adlsG2 japaneast
    リソースグループ数:4 

サブスクリプション数:15 

 取得時間:9.154601812362671 [sec] 
```

### まとめ
Azure CLI で取得するのもよいですが、プログラムでゴリゴリしたいときはこちらですね。
Python で Azure の サブスクリプション一覧 を取得してみました


## 概要
Azure SDK for Python を利用して、接続しているテナントのサブスクリプション一覧を取得するための Python プログラムです。

### 実行環境
macOS Big Sur 11.1 
python 3.8.3

### 実行プログラム

```python:GetSubscriptionList.py

import time
import argparse
from azure.mgmt.resource import SubscriptionClient
from azure.identity import AzureCliCredential


# 接続しているテナントのサブスクリプションを操作するオブジェクトを取得
def GetSubscriptionObject():
    subscription_client = SubscriptionClient(
        credential=AzureCliCredential()
    )
    return subscription_client


if __name__ == '__main__':    
    parser = argparse.ArgumentParser(description='Subscription 一覧の取得')
    args = parser.parse_args()

    start = time.time()
    subscription_list = GetSubscriptionObject()
    generate_time = time.time() - start

    print("\n 取得時間:{0}".format(generate_time) + " [sec]")
    print("\n サブスクリプション一覧：")
    
    # 接続しているテナントのサブスクリプション一覧を取得
    for num, subs in enumerate(subscription_list.subscriptions.list()):
        print("{} {}".format(subs.subscription_id, subs.display_name))

    subscription_list.close()
    print("\n サブスクリプション数:{0} \n".format(num+1))
```

### プログラムの実行
 
```
$ python GetSubscriptionList.py

 取得時間:0.000293731689453125 [sec]

 サブスクリプション一覧：
xxxxxxxx-nnnn-mmmm-ffff-yyyyyyyyyyyy APP-01
     ：
    中略
     ：
zzzzzzzz-pppp-qqqq-rrrr-aaaaaaaaaaaa LAB-01

 サブスクリプション数:15 
```

### まとめ
Azure CLI で取得するのもよいですが、プログラムでゴリゴリしたいときはこちらですね。
Python で Azure の リソースグループ一覧 を取得してみました


## 概要
Azure SDK for Python を利用して、特定のサブスクリプションにあるリソースグループ一覧を取得するための Python プログラムです。

### 実行環境
macOS Big Sur 11.1 
python 3.8.3

### 実行プログラム

```python:GetResourceGroup.py

import os
import time
import argparse
from azure.mgmt.resource import ResourceManagementClient
from azure.identity import AzureCliCredential

SUBSCRIPTION_ID = os.environ['ARM_SUBSCRIPTION_ID']

# 特定のサブスクリプションIDのリソースグループを操作するオブジェクトを取得
def GetResourceGroupObject(subs_id):
    resource_client = ResourceManagementClient(
        credential=AzureCliCredential(),
        subscription_id=subs_id
    )
    return resource_client


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Subscription の ResourceGroup 一覧の取得')
    args = parser.parse_args()

    start = time.time()
    resource_client = GetResourceGroupObject(SUBSCRIPTION_ID)
    generate_time = time.time() - start

    print("\n 取得時間:{0}".format(generate_time) + " [sec]")
    print("\n リソースグループ一覧：")

    # リソースグループ一覧を取得
    for num, rg in enumerate(resource_client.resource_groups.list()):
        print("{} {}".format(rg.name, rg.location))

    resource_client.close()
    print("\n リソースグループ数:{0} \n".format(num+1))
```

### プログラムの実行
 
```
$ python GetResourceGroup.py

 取得時間:0.0002779960632324219 [sec]

 リソースグループ一覧：
rg-yas-01 japaneast
rg-yas-02 japaneast
rg_koumu japaneast
rg_c4th japaneast
     ：
    中略
     ：
rg_azstackhci japaneast
rg-lab-01 japaneast
rg-lab-02 southeastasia

 リソースグループ数:22 
```

### まとめ
Azure CLI で取得するのもよいですが、プログラムでゴリゴリしたいときはこちらですね。
Swift で Edit Distance (編集距離)


Edit Distance を Swift で書いたのでメモ

## NOTE

- 実装：DP
- 問題：[Edit Distance - LeetCode](https://leetcode.com/problems/edit-distance/)

## 解法

ロジックの詳しい解説はけんちょん本の下記項目を参照

- https://www.amazon.co.jp/dp/B08PV83L3N/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
- 5.5動的計画法の例(2)：編集距離


## コード

```swift
func minDistance(_ word1: String, _ word2: String) -> Int {
        let w1 = word1.map({ String($0) })
        let w2 = word2.map({ String($0) })
        var dp = [[Int]](repeating: [Int](repeating: Int.max, count: w2.count+1), count: w1.count+1)
        dp[0][0] = 0
        
        for i in 0..<w1.count+1 {
            for j in 0..<w2.count+1 {
                if i-1 >= 0 && j-1 >= 0 {
                    // noop
                    if w1[i-1] == w2[j-1] {
                        dp[i][j] = min(dp[i][j], dp[i-1][j-1])
                    }
                    // replace
                    else {
                        dp[i][j] = min(dp[i][j], dp[i-1][j-1]+1)
                    }
                }
                                
                // delete
                if i-1 >= 0 {
                    dp[i][j] = min(dp[i][j], dp[i-1][j]+1)
                }
                
                // insert
                if j-1 >= 0 {
                    dp[i][j] = min(dp[i][j], dp[i][j-1]+1)
                }
            }
        }
        
        return dp[w1.count][w2.count]
    }
```
トランザクションとは。

# はじめに
本記事では、トランザクションについて記述しました。
トランザクションとはなんですか?
と聞かれた際に、私は何も答えることができませんでした。
悔しかったので調べました。

# トランザクションとは
`レコードの更新を行う複数の処理を1つにまとめて行うこと`を指します。

トランザクションを利用することにより、
「処理の一部は成功し、一部は失敗した」という事象は発生せず、
`すべての処理の成功または失敗のみの状態`を作ることができます。

### Railsではこのような利用

```ruby
ActiveRecord::Base.transaction do
  処理1
  処理2
  処理3
  ...
end
```
ここに処理１、処理２...を１つのまとまりとして記述することで、
処理が１つでも失敗すれば、全体としての処理は失敗ということになります。

# トランザクションのACIDプロパティー
以下を参照しています。
トランザクションは、銀行のATMに例えることが多いみたいです。
かなりわかりやすいので勝手にオススメです。
[トランザクションの ACID プロパティー](https://www.ibm.com/docs/ja/cics-ts/5.4?topic=processing-acid-properties-transactions)

> トランザクション処理における ACID という頭字語は、原子性 (A)、一貫性 (C)、独立性 (I)、および耐久性 (D) というトランザクションの 4つの重要なプロパティーを表しています。

`A`
`原子性`を表す`Atomicity`
トランザクションが終わった時に、
そこに含まれていた更新処理が全て実行されるか、
全て実行されない状態で終わることを保証する性質。
> ある口座から別の口座に資金を移動するアプリケーションで、原子性プロパティーは、ある口座から引き落としが正常に行われると、対応する入金が別の口座に行われることを保証します。

`C`
`一貫性`の`Consistency`
トランザクションに含まれる処理はそれぞれの制約を満たすという性質。
> ある口座から別の口座に資金を移動するアプリケーションで、一貫性プロパティーは、各トランザクションの開始時と終了時で、両方の口座の資金の合計金額が同じになることを保証します。

`I`
`独立性`の`Isolation`
トランザクションが実行中の場合、
もう一方のその他のトランザクションの影響を受けないという性質。
> ある口座から別の口座に資金を移動するアプリケーションで、独立性プロパティーは、別のトランザクションから見て移動資金がいずれかの口座に存在していて、両方に存在していたりどちらにも存在しなかったりすることはないことを保証します。

`D`
`耐久性`の`Durability`
トランザクションが完了した後、そのデータ状態が保存され失われることは無いという性質。
> ある口座から別の口座に資金を移動するアプリケーションで、耐久性プロパティーは、それぞれの口座に対して行われた変更が元に戻されることはないことを保証します。

以上です。

# 終わりに
今回もスマッシュブラザーズで例えてやろうと考えており、
`ファルコンパンチ`ってトランザクションじゃないかなとか思ったんですが、
ファルコンパンチってBボタンを押したら、モーションはあるものの、
`複数の処理を１つにまとめているかと言われたら違うような気がした`ので、やめました。

自分の知らなかった言葉を
何か身近なものに例えて理解するのはとてもいいなと感じております。

以下参考サイトです。
[「トランザクションのACID特性」を理解する](https://atmarkit.itmedia.co.jp/ait/articles/1703/01/news194.html)
[トランザクションの ACID プロパティー](https://www.ibm.com/docs/ja/cics-ts/5.4?topic=processing-acid-properties-transactions)

明日も頑張ります！
float配列をpngとして保存する

#はじめに
　processingで画像処理をしていると、時々、RGB各8bitでは足りなくなる時があります。byteでなくてintで計算したいとか、floatで計算したいとか。フォーマットとしては、exrとかhdrがありますが、簡単に使い始められそうなライブラリがなく、二の足を踏んでしまいます。
　そういうわけで、とりあえず、自分で読み書きできれば、十分という場合に、サンプルを書いたメモです。

#概要
　戦略としては、createImage( ,ARGB)でImage作って、その中に、色情報に見せかけた、float情報を書き込んでpngとして保存。loadImageでpngを読み込んで、色情報からfloat値を読み込むという手順。
　ここで、colorとintは同じであリ、floatを含めて全て32bit変数であることを前提に書く。
　32bit変数である、intとfloatを中身のbit情報を変えずに、見かけ状の型だけ変えたい。c言語だとポインタ使って楽勝だが、javaだとそうはいかず。
　javaで動いているprocessingには、便利な命令があって、floatToIntBits/intBitsToFloatの二つを使えば、簡単に実装できました。

#環境
processing 3.5.4

#プログラムの概要
①noise命令で適当なfloat配列を生成
②グレースケール画像として表示確認
③PImageを作り、float配列をint配列と見なして、１ピクセルずつ書き込み、pngとして保存。
④そのpngをloadImageして、ピクセル値を読み込み、floatに変換して、間違いがないかチェック

#備考
　64bitのデータを扱いたいときは、doubleToLongBits/longBitsToDouble命令がある。しかし、1ピクセルに64bitは入らないので、32bitずつ書き込む工夫が必要である。

#実行結果
　実行すると、下記noise画像が表示されるが、保存したい元データはfloat配列であり、0~1の小数である。255倍して表示しただけ。
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/f39f4b0f-eca2-db6b-3555-d34dcbb0dddb.png)
この、float値をint値(color値)と解釈して保存した画像が下記。ぐちゃぐちゃだが、なんとなく面影が残っている。
![float.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/df29f5bb-3046-0dda-3fd1-03cb61b560dd.png)
float配列の最初が0.6852823で、読み書き結果が同じだから大丈夫でしょう。

#コード

```java:floatArraySaveAsPng.pde
size(256, 256);
float[][] f;
f = new float[256][256];

//generate random float array
noiseSeed(0);
for (int y=0; y<256; y++) {
  for (int x=0; x<256; x++) {
    f[x][y] = noise(x*0.01, y*0.01);
  }
}
println(f[0][0]);

//display x255
for (int y=0; y<256; y++) {
  for (int x=0; x<256; x++) {
    stroke(f[x][y]*255);
    point(x, y);
  }
}

//save as png
PImage img = createImage(256, 256, ARGB);
img.loadPixels();
for (int y=0; y<256; y++) {
  for (int x=0; x<256; x++) {
    int i = Float.floatToIntBits(f[x][y]);
    img.pixels[x+y*256] = i;
  }
}
img.updatePixels();
img.save("float.png");

//load check
PImage img2 = loadImage("float.png");
img2.loadPixels();
color c = img2.pixels[0];
float f2 = Float.intBitsToFloat(c);
println(f2);
```
Ruby 入門 [インスタンス変数を簡単に操作]

● インスタンス変数を簡単に操作する

```rb
class Drink
    def name ———#①attr_reader :name
        @name
    end
    def name=(text) ———#②attr_write :name
        @name = text
    end
end

drink = Drink.new
drink.name="カフェラテ"
puts drink.name
↪️カフェラテ
```




```rb:①と②の省略できる書き方
class Drink
    attr_reader :name ———#①
    attr_writer :name ————#②
end

drink = Drink.new
drink.name="カフェラテ"
puts drink.name
↪️カフェラテ
```

```rb:①と②を合体させたattr_accessor
class Drink
    attr_accessor :name
end

drink = Drink.new
drink.name="カフェラテ"
puts drink.name
↪️カフェラテ
```
Ruby 入門 [例外の詳しい情報を得る]

● 例外の詳しい情報を得る

```rb:例外オブジェクトの代入
begin
　#例外が発生する可能性がある処理
rescue 例外クラス => e　#変数eに例外オブジェクトが代入される
　#例外が発生する可能性がある処理(rescue節)
end
```

```rb
def cat(filename)
    #ファイルの内容を表示する
    File.open(filename) do |file| —————①ファイルを開く
        file.each_line {|line| puts line} ————②ファイルの内容を表示する
end ————③ファイルを閉じる

resucue SystemCallError => e ————④例外処理 : 例外オブジェクトを変数eに代入
    puts "--- 例外が発生しました ---"
    puts "例外クラス: #{e.class}" ———⑤e.classで例外オブジェクトのクラス名を表示
    puts "例外メッセージ: #{e.message}” ————⑥e.messageで例外メッセージを表示
end

filename = ARGV.first ———⑦コマンドプロントの引数を読み込み
cat(filename)
↪️>ruby cat.rb menu.txt -menu.txtテキストファイルを用意して”カフェラテ””カプチーノ”を入力
      カフェラテ
      カプチーノ
```
存在しない適当なファイル名を指定してプログラムを実行すると

```
↪️>ruby cat.rb not found.txt
       —例外が発生しました—
       例外クラス: Errno::ENOENT
       例外メッセージ: No such file or directory @ rb_sysopen - not found.text
```
●Fileクラス —ファイル操作に組み込みライブラリのFileクラスを使う

●File.open —引数filenameで指定したファイルを開きファイル操作のためのFileオブジェクトを作ってfile変数に代入する

●each_line —配列のeachに似たメソッドで、ファイルの先頭から1行ずつ読み込み、繰り返しline変数     に代入する。読み込んだ各行は、putsメソッドで画面に表示する。

●SystemCallError => —ファイル操作などに失敗した時に発生する例外クラスです。例外クラスの後ろの=> eのeは変数。受け取った例外オブジェクトが変数eに代入される。

●e.class —例外オブジェクトのクラス名を表示

●e.message —例外のメッセージを表示

●classとmessage —例外クラスで使えるメソッド

●ARGV —Rubyが用意した特別な定数で、コマンドプロントで指定した引数を要素として持つ配列。AVGRで先頭の要素を取得する。
Ruby 入門 [例外を処理]

● 例外を処理する


```rb:例外処理
begin
　#例外が発生する可能性がある処理
rescue
　#例外が発生した時に実行する処置(rescue節)
end
```

```rb
puts "金額を入力してください"
bill = gets.to_i
puts "割り勘する人数を入力してください"
number = gets.to_i

begin
    warikan = bill / number
    puts "1人あたり#{warikan}円です"
rescue ZeroDivisionError
    # ZeroDivisionError例外が発生したらメッセージを表示する
    puts "おっと、0人では割り切れません"
end
↪️金額を入力してください
 100
 割り勘する人数を入力してください
 0
 おっと、0人では割り切れません ——#例外がなければ発生しない
↪️金額を入力してください
 100
 割り勘する人数を入力してください
 4
 1人あたり25円です
```
例外がなければrescue節は発生しない。
0で割り算した時に発生するZeroDivisionError例外を処理する時はrescue ZeroDivisionErrorと書く。

メソッド内で例外処理を書く場合は、beginとrescueを省略できる。メソッドの初めからrescueまでの処理で発生した例外を、rescue節で受け入れる。

```rb
def warikan(bill, number)
    warikan = bill/number
    puts "1人あたり#{warikan}円です"
rescue ZeroDivisionError
    # ZeroDivisionError例外が発生したらメッセージを表示する
    puts "おっと、0人では割り勘できません"    
end

warikan(100,0)
warikan(100,1)
warikan(100,2)
↪️おっと、0人では割り勘できません
 1人あたり100円です
 1人あたり50円です
```
Ruby2.5以降ではブロック内でもbeginとendを省略できる。

```rb
bill = 100
numbers = [0,1,2]

numbers.each do |number|
    warikan = bill/number
    puts "1人あたり#{warikan}円です"
rescue ZeroDivisionError
    puts "おっと、0人では割り勘できません"
end   
↪️おっと、0人では割り勘できません
 1人あたり100円です
 1人あたり50円です
```
Gomega エラーメッセージが分かりやすいEqual Matcherを作った

## 作ったもの

https://github.com/KamikazeZirou/equal-cmp

## 動機

仕事でGoのテストライブラリとしてGinkgo/Gomegaを使っているのだが、Gomegaに組み込まれているEqual Matcherは、エラーメッセージが分かりづらい。

以下のようなテストコードがあるとする。gomegaのEqual Matcherにより２つの構造体を比較し、結果が同じになるか検証している。

```go
var _ = Describe("Example", func() {
	It("Example", func() {
		actual := Object{ID: 1, Name: "actual", Tel: "Tel", Email: "Email"}
		expected := Object{ID: 1, Name: "expected", Tel: "Tel", Email: "Email"}
		Expect(actual).Should(Equal(expected))
	})
})
```

比較対象のNameの値に差異があるのでエラーになる。このときのエラーメッセージは以下の通り。

```
  Expected
      <equalcmp_test.Object>: {ID: 1, Name: "actual", Tel: "Tel", Email: "Email"}
  to equal
      <equalcmp_test.Object>: {ID: 1, Name: "expected", Tel: "Tel", Email: "Email"}
```

Nameが違うことが分かりづらい。

## このモジュールが提供するEqual Matcher

EqualCmpという名前でEqual Matcherを提供している。EqualCmpを使ったサンプルコードを示す。
gomegaのEqual()をEqualCmpに置き換えるだけ。

```go
import (
	"testing"

	. "github.com/kamikazezirou/equal-cmp"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

...

var _ = Describe("Example", func() {
	It("Example", func() {
		actual := Object{ID: 1, Name: "actual", Tel: "Tel", Email: "Email"}
		expected := Object{ID: 1, Name: "expected", Tel: "Tel", Email: "Email"}
		Expect(actual).Should(EqualCmp(expected))
	})
})
```

EqualCmpのエラーメッセージは以下のとおり。

```go
  Mismatch(-actual +expected):
    equalcmp_test.Object{
    	ID:    1,
  - 	Name:  "actual",
  + 	Name:  "expected",
    	Tel:   "Tel",
    	Email: "Email",
    }
```

差分箇所が分かりやすくなった。

## 備考：実現方法

実際値と期待値の比較にgo-cmpを使うことで、このモジュールは実現している。

元ネタはこちら。このコードのエラーメッセージを調整して、module化しただけ。

https://gist.github.com/jaslong/8852fb0ae5367484957dc9b6c33924d3
Djangoで初期データをfixtureで登録・dump

# DjangoでDBにfixtureでデータ初期登録
初期データやテストで使うデータをデータベースに最初から用意しておきたいということがあります。
そんなときに使うのが`fixture`です。Djangoで初期データを登録する方法を書きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/bf15666a-caf9-6231-2322-884b6ba4e1aa.png)


```django_docker/accounts/models.py
from django.db import models


class Customer(models.Model):
    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=20)
    email = models.CharField(max_length=255)
    age = models.IntegerField()
    created_at = models.DateTimeField(auto_now_add=True)

```

# fixtureファイル準備

今回は`JSON`を使います。`XML`や`YAML`でも記述できます。
アプリ(今回の場合は`accounts`というアプリ名で作ってます)の中に`fixtures`というディレクトリを作成してその中に`customer_init.json`を作成

```django_docker/accounts/fixtures/customer_init.json
[
  {
    "model": "accounts.customer",
    "pk": 1,
    "fields": {
      "name": "Tanaka Tarou",
      "phone": "09011111111",
      "email": "tanaka@gmail.com",
      "age": 35,
      "created_at": "2021-09-13 00:00:05"
    }
  },
  {
    "model": "accounts.customer",
    "pk": 2,
    "fields": {
      "name": "Satoh Jirou",
      "phone": "09022222222",
      "email": "satoh@gmail.com",
      "age": 25,
      "created_at": "2021-09-13 00:00:10"
    }
  }
]
```

# コマンドでDBに入れる
データを入れるのは簡単で、コマンドをたたけば完了です。

```
python manage.py loaddata customer_init.json
```

## 入れたデータを確認
データを入れたので、Django shellで確認してみます。

```
>>> Customer.objects.all()
<QuerySet [<Customer: Customer object (1)>, <Customer: Customer object (2)>]>
>>> for c in Customer.objects.all():
...     print(c.name, c.phone, c.email, c.age, c.created_at)
... 
Tanaka Tarou 09011111111 tanaka@gmail.com 35 2021-09-12 15:00:05+00:00
Satoh Jirou 09022222222 satoh@gmail.com 25 2021-09-12 15:00:10+00:0
```

DBの設定やってなくて、DBのタイムゾーンの問題でUTCになっていますが想定したデータが投入されていますね。

# DBデータをdump
jsonファイルで手書きで作っても良いですが、データ数多くなると間違いも増えるし、手間がかかって仕方ありません。そんなときはデータをダンプしましょう。

`python manage.py dumpdata <アプリ名> > ファイル名`でダンプできます。

```
python manage.py dumpdata accounts > accounts.json
```

改行されていないですが、ダンプできました。

```accounts.json
[{"model": "accounts.customer", "pk": 1, "fields": {"name": "Tanaka Tarou", "phone": "09011111111", "email": "tanaka@gmail.com", "age": 35, "created_at": "2021-09-12T15:00:05Z"}}, {"model": "accounts.customer", "pk": 2, "fields": {"name": "Satoh Jirou", "phone": "09022222222", "email": "satoh@gmail.com", "age": 25, "created_at": "2021-09-12T15:00:10Z"}}]
```

もしくは特定のmodel(テーブル)のデータだけ取り出したいということもあると思います。
そんな時は

`python manage.py dumpdata <アプリ名>.<model> > ファイル名`でダンプできます。

```
python manage.py dumpdata accounts.customer > accounts_customer.json
```

今回はmodel一つしかないので同じですが:sweat_smile:、場合によってはバックアップにも使えますね。
【Python3】M1 Mac(Docker)で分散並列処理フレームワークRayのサンプルコードを動かす

## Rayとは
RayはPythonにおける分散並列処理を高速かつシンプルに書けるフレームワークで、既存のコードを並列化することも容易な設計となっています。

https://docs.ray.io/en/latest/index.html

Rayを使うことでmultiprocessingなどに比べ簡単にプロセスレベルの並列処理を記述することができます。Rayは2021年9月現在MacOSとLinuxをサポートしています。Windowsのサポートは実験段階であり、開発中です。

ローカル環境を構築する予定でしたが、既知のバグがあるらしく動かなかったので、仕方なくDocker環境を構築します。

## 環境

```
macOS Big Sur 11.5.2
docker 20.10.7
python 3.7.7 (dockerコンテナ内)
```

## M1MacにDockerDesktopをインストール

https://docs.docker.com/desktop/mac/install/

M1MacにDockerDesktopをインストールするには、上のリンクを踏んでダウンロードする必要があります。

さらに、Rosetta2もインストールしなければならないため、公式ページの指示に従って以下のコマンドをターミナルで叩きます。

```{sh:Rosetta2 install}
softwareupdate --install-rosetta
```

これでDockerが使用可能になります。

ちなみに、2021年8月31日にDocker社がDocker Desktopを有料化することを発表したようですね。個人開発なら無料で使えますが、面倒なことになりました。

https://qiita.com/autotaker1984/items/284e28f82fc1828da44e

## RayのDocker ImageをPullする
DockerHubから公式のImageをローカルにPullします。

```sh
docker pull rayproject/ray
```

## コンテナ内でjupyter notebookを実行する
まず、Docker Imageからコンテナを作成し、中に入ります。

```sh
docker run --shm-size=512M -p 8888:8888 -it  rayproject/ray
```

[公式ページ](https://docs.ray.io/en/latest/installation.html#docker-source-images)によると、shm-sizeには512M~2G程度の値を設定するようです。
また、jupyter notebookを使用する関係でポートを公開しています。
コンテナ上のポートとローカルのポートを接続するルールは、-p [ローカルのポート]:[コンテナのポート]　です。
コンテナ内に入ったら、jupyter をインストール後、サーバを立てます。

```sh
pip install jupyter
jupyter notebook --ip=0.0.0.0 --allow-root
```

Docker上でjupyter notebookを実行する方法は以下を参考にしました。

https://qiita.com/ricrowl/items/bc178a184a300b22e5e5

## ブラウザでnotebookにアクセス
ローカルPCのブラウザでコンテナで起動したnotebookにアクセスします。
ブラウザに下記URLを打ち込みます。

```
localhost:8888
```
するとJupyter Notebookの画面に遷移して`Password or token:`と入力が求められます。

入力するためのtokenはコンテナ上でnotebookを起動したときに以下のようなURLが出るのでそこから取得します。

```
    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://5217807fea51:8888/?token=601c330c097e59cd7b69dcaa6ea336218583a492e4684bde&token=601c330c097e59cd7b69dcaa6ea336218583a492e4684bde
```
上の場合、`601c330c097e59cd7b69dcaa6ea336218583a492e4684bde`を`Password or token:`に入力すればいつものnotebookの画面に遷移します。

## サンプルコードを動かし動作確認を行う

チュートリアルの解説に関しては以下のページが神です。

https://qiita.com/waffoo/items/603bb3df25163fa461e9

サンプルコードがエラーなく実行できれば成功です。

```py
import ray
import time
# ray.init() のように明示的に指定しなかった場合自動的にリソース数が決定されます
ray.init(num_cpus=4)

# 時間計測をより正確にする都合上Rayの起動を少し待つ
time.sleep(1)

@ray.remote
def func(x):
    time.sleep(5)
    return x

begin_time = time.time()
res1, res2 = func.remote(1), func.remote(2)

print(ray.get(res1), ray.get(res2)) # 出力: 1 2

# ray.getはreturnをリストで受けとることもできる
print(ray.get([res1, res2])) # 出力: [1, 2]

end_time = time.time()
print(end_time - begin_time) # 5秒ぐらい
```

実行結果例

```py
1 2
[1, 2]
5.051432132720947
```

## 終わりに
標準モジュールのmultiprocessingと比べるとコードが非常に簡単です。まだまだ発展途上のフレームワークですが、いずれ「マルチプロセスといえばRay」というようになっていくでしょう。

なお、コードを速くするという意味では、マルチプロセス化するのは最後の手段です。まずは既存のコードを整理し、充分にリファクタリングしたいところです。
【Unity】Unity始めてみた（エディタ編）

# プロジェクトを作成する
Unityを起動し、『プロジェクト』の『新規作成』から、プロジェクトを作成可能。
作成時に『テンプレート』（2D/3D/ARなど）と『設定』（プロジェクト名、保存先）をそれぞれ選択。


#エディタを開く
Unityエディタの画面構造はこんな感じ
![スクリーンショット 2021-09-13 0.39.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379501/4495065b-d4d6-c9e7-106f-3eb285fbb2a6.png)

### ① シーンビュー
- 作成しているゲーム世界に相互作用できるビュー
- 風景、キャラクター、カメラ、ライト、その他全ての種類のゲームオブジェクトを選択し配置する

### ② ゲームビュー
ゲーム内のカメラから見た絵をレンダリングしているビュー

### ③ ゲームオブジェクト
- キャラクター、小道具、背景などを表すUnityの基礎となるオブジェクト
- 実際に機能を実装するComponentのコンテナのように扱える

### ④ ヒエラルキーウィンドウ
- 現在のシーンにおける各ゲームオブジェクトのリストが表示される
- デフォルトでは、オブジェクトは作成された順にリスト化される
- オブジェクトをドラッグすることで、順番を替えたり、親子オブジェクトを作成することが可能

### ⑤ プロジェクトウィンドウ
プロジェクトに属するアセットにアクセスし、管理することが出来るウィンドウ

### ⑥ インスペクタ
- 現在選択されているゲームオブジェクトに関する詳細な情報を表示する
- 表示される情報には、ゲームオブジェクトにアタッチされたコンポーネントやそのプロパティーなども含む

### ⑦ ツールバー
エディタの各所に関連する7つの基本コントロールを含むバー

# 基本操作
- **回り込み**： Option + 左クリック + ドラッグ
- **ズームイン・ズームアウト**： ホイールを前後に回転
- **視点の平行移動**： ホイールを押し込む + ドラッグ
- **視点の注目**： ヒエラルキーウィンドウでゲームオブジェクトをダブルクリック
ブラウザゲームを作ってみよう(その1)

#はじめに
今までは基本的にサーバサイドの記事が多かったのですが、今回はゲームということでクライアントサイドになります。
ここではJavaScriptを使って作っていきたいと思います。

#Webシステムとゲームの違いについて
今まで記事にしていたWeb系のシステムとゲームですが少し作り方が違います。
それぞれの動き方ですが、概ね以下のようになっています。

[Webシステム]
1.ページアクセス
2.サーバプログラム実行(セッション、データベースから値取得など)
3.クライアントプログラム実行(画面表示)
※ここで終了、別ページへのリンクをクリックするとまた1から実行される

[ゲーム]
1.プログラム実行
2.タイマー起動
3.タイトル画面、ゲーム画面など(タイマーの中で画面遷移)
※2のタイマーがずっと実行されていて終了することがない

主にこのような違いがあります。

#JavaScriptで作れるのか？
冒頭でJavaScriptで作ると書いているのですが、そもそも作れるのか？と思う方もいるかもしれませんので、どういったことが実現出来ればゲームが作れるのか簡単に整理したいと思います。
皆さんはゲームと言われてどういったものを思い浮かべるでしょうか？

■画面に絵や文字が表示される
■コントローラ操作で画面のキャラクターが操作出来る
■タイマーで繰り返し処理が出来る(プレイしているユーザは意識しませんが)

これらの要素をJavaScriptで実現出来るかですが

|要素|結果|
|---|---|
|画面に絵や文字が表示される|表示出来るので○|
|コントローラ操作で画面のキャラクターが操作出来る|キーボードやマウス入力が出来るので○|
|タイマーで繰り返し処理が出来る|タイマー処理(setIntervalなど)が出来るので○|
実現出来そうですね。

#サンプル
タイマー処理が確認出来るサンプルを作ったので以下にコードと実行結果を記載します。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="rNwwVpR" data-user="noji505" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/rNwwVpR">
  </a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#最後に
とりあえず一回目ということで、Webシステムとゲームの作り方の違いを中心に解説しました。
次回は文字表示処理を作ってみたいと思います。