OmniAICreator/Qiita-1.07M huggingface dataset:
【PowerAutomate】Teamsからチームまたはチャネル宛のメンションをする方法

#概要
PowerAutomateからGraphAPIを使い､チームまたはチャネル宛のメンションを行います｡
\<at>~\</at>で囲む方法ではチームまたはチャネルへのメンションができません｡(2020年9月現在)
恐らくですが､GraphAPIにある｢mentions｣プロパティを使うしかないと思います｡
あと残念なことにWebhookではメンションに関するプロパティはありません｡

#事前準備
・AzureADでAPIのアクセス許可を追加
　参考:(https://qiita.com/kaitomate/items/606f103f34dfcadd31dd)

・ブラウザ版のTeamsにログインし対象のチームIDとチャネルIDを取得
　こちらの方の記事をご確認ください。分かりやすいです。
　参考:(https://qiita.com/yamad365/items/e480f77e9102b132d258)

#フロー作成
今回はインスタント(手動)フローでチャネル宛にメンションするフロー作成します｡
トリガーについては用途に応じて設定してください｡
> ![eee.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/362e707d-c5e2-0385-34a8-46f9a61b635a.png)

####１．チームIDとチャネルIDを変数に格納
URLが長くなるのとコピペがめんどくさいので変数作っちゃいます｡
いらない方は飛ばしてもOKです。
>![bbb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/33a9fb10-f1af-1aa8-4bfc-351081c7791f.png)

####２．HTTP要求の作成
ここからAzureADに接続してAPIを設定していきます。
> ![ccc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/24a1bc8a-c317-6d66-f3d6-b85e567082b3.png)

最初は下記が表示されると思うのでそれぞれ入力してください。
・Base Resource URL　→　https://graph.microsoft.com
・Azure AD Resource URI　→　https://graph.microsoft.com
> ![ddd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/8002d95e-47eb-d448-d96c-df61f777df18.png)

次に設定部分です。
方法：POST
URL：https://graph.microsoft.com/v1.0/teams/チームID/channels/チャネルID/messages
ヘッダー：Content-type　application/json
> ![fff.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/76b31077-89f5-30bb-46a4-c1544bb8a093.png)

本文です｡(下記にコード書いてます)
黒塗りのところはチャネルの名前してください。
チーム宛にメンションする場合は黒塗りの部分をチーム名にして
赤枠で囲ってるchannelIDをチームID､｢channel｣を｢team｣に変更してください。
> ![ggg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/3f07e1c5-df38-7703-699c-e333abd8b611.png)

> ```
{
    "body": {
    "content": "This is Flow mention channel test, <at id=\"0\">チャネル名</at>",
    "contentType": "html"
            },
    "mentions": [
                {
                "id": 0,
                "mentionText": "チャネル名",
                "mentioned": {
                                "conversation": {
                                                    "id": "チャネルID",
                                                    "displayName": "チャネル名",
                                                    "conversationIdentityType@odata.type": "#Microsoft.Teams.GraphSvc.conversationIdentityType",
                                                    "conversationIdentityType": "channel"
                                                }
                            }
                }
                ]
}
```

####３．結果
画像のようになっていればOKです。
 ※すいません、teamsの見た目変えてるので見づらいかも…
赤塗のところにチャネル(チーム)名が表示され、赤枠にこのマークがついていればメンションされてます。
> ![hhh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/190ab87a-acd6-89c6-36c6-62a008a605d0.png)

#最後に
ググッても個人にメンションする方法しか出てこなくて嫌になりましたね笑
ぜひLGTM頂ければ日々を生きる気力が湧いてきますのでお手数ですが、ポチッとお願いします。
多くの方に見て頂ければ多分ググッた時に上位の方に来ると思うので…
【Azure】AzureADにGraphAPIの許可を追加する方法

#注意
注意事項ですが､本記事が唯一絶対の方法とは限りません｡
また記載に間違いがあるかもしれません､何卒ご了承くださいませ｡

#概要
今回はTeamsにメッセージを投稿するために必要なAPI許可を追加していきます。
Graphという特化した内容になりますが、応用も聞くと思います(てへ)

#設定
１．Azureにログイン
　　https://portal.azure.com/

２．左メニューから｢AzureActiveDirectory｣を選択
> ![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/38e61183-602f-e3d0-136f-a64701ad6fdf.png)

３．左メニューから｢アプリの登録｣を選択
>![iii.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/642d5414-aaac-0abe-aa0c-8cb5f5ab8905.png)

４．新規作成
上部の新規作成ボタンを押下
>![jjj.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/f49788b6-0869-f0ee-ad09-ab502d84ba8b.png)

任意の名前をつけて､アクセス許可を制限したら保存
>![kkk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/27ffb106-205e-2e85-6633-7c39501fbe7c.png)

５．APIの登録
APIアクセス許可の表示を押下
>![lll.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/95e33b75-a128-b513-40dc-5023ccdc4b4b.png)

アクセス許可の追加を押下
>![mmm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/78da9826-b967-05cb-7144-e4f9c87deec2.png)

Microsoft Graphを選択
>![nnn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/463dc323-0b35-3a6d-343c-b69a57186d8e.png)

委任されたアクセス許可→channelで検索→channelMessageの｢ChannelMessage.Send｣にチェックし
アクセス許可の追加を押下
>![ooo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700727/7d934c48-03b2-937c-0f8e-61f3f98cd525.png)

これで完了です。

#最後に
Graphを使ってTeamsにチームまたはチャネル宛にメンションするために必要な設定になるともいます。
むしろこのためだけに設定したまであります。
PHP-SQL

<p>学習でのアウトプット<br>
間違っている部分もあるかも・・・</p>


<h3>データベースへの接続</h3>

```php

$host='';
$username='mysqlのユーザ名';
$password='mysqlのパスワード';
$dbname='';
$charset='utf8';

//mysql用のDSN文字列
$dsn = 'mysql:dbname='.$dbname.';host='.$host.';charset='.$charset;
```

```php

try{
       $dbh=new PDO($dsn, $username, $password, array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'));
       $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
       $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      
                           処理を行う

 } catch (PDOException $e){
     echo 'データベース処理でエラーが発生しました。理由：'.$e->getMessage();
 }
```

<h4>DBに接続しテーブルにデータを登録する</h4>
```php

```
MySQLWorkbenchでER図を作ってそのままデータベースにDDLで流し込む

# やりたこと
MySQLWorkbenchでER図を作ってそのままデータベースにDDLで流し込みたい。

# 経緯
今までER図を書くときはとっかかりが簡単だったのでCacooを使っていたが、その後DDLを書き起こすのが面倒くさいなと思ったので、MySQLWorkbenchで描いてみたらとても良かった。

さらにDDLを実行するところで、MySQLとMySQLWorkbenchのバージョン違いによって少しハマったので、備忘として記載。

# 環境
* MySQL5.7.26
* MySQLWorkbentch8.0.13

# 手順
基本的なDDL流し込みは以下の手順通り、フォワードエンジニアリングを行えば良い。
https://ti-tomo-knowledge.hatenablog.com/entry/2018/05/21/172936

ただし、最後のDDL実行で、以下のエラーが出てしまった。

```
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VISIBLE,   INDEX `fk_xxx1_idx` (`xxx_id` ASC) VISIBLE,   INDEX `fk' at line 9;
```

原因は生成されたINDEXを作る箇所の`VISIBLE`だった。

```
INDEX `fk_xxx1_idx` (`xxx_id` ASC) VISIBLE,
```

これはMySQL8.0からの仕様のため、対象のMySQLが5.7のためエラーとなった。

こちらを発生させないためには
`MySQLWorkbench > Preferences > Modeling > Default Target MySQL Version`を該当のバージョンにしてから再実行すると、そのバージョンとして動作するDDLが生成される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691945/789b6880-8a68-e9d7-f232-e21173068fa1.png)

上記で解決して無事にDDL実行が完了した。

# 感想
MySQLを利用するなら、ER図はMySQLWorkbenchでの作成が一番便利だと思う。

# 参照
https://stackoverflow.com/questions/52785125/mysql-workbench-error-in-query-1064-syntax-error-near-visible-at-line-1
【Python】openCVで日本語の文字を扱う方法

毎回使う時に調べているので
備忘録として残します。


```ruby:
image = cv2.puttext(image,"ハローワールド", (0, 0), '<フォントのパス>', 10, (0, 0, 0),2,False)
```
引数
　　画像、文字列、描写する座標、フォントのパス、文字のサイズ、文字の色、文字の太さ、画像の原点の位置（Trueが左下Falseが左上）

そのままでは日本語が表示出来ない理由は、
CV2にはデフォルトではマルチバイト文字に対応していないため。

つまり、日本語のフォントを指定してやる事により画像に日本語を描画する事が出来ます。
条件のある数値の計算

今回の条件は、
・配列の数値を全て合計する
・ただし同じ数値だった場合には計算しない

（例）
array1 = [1, 2, 3]
sum1 = 1 + 2 + 3 = 6

array2 = [2, 4, 2]
sum2 = 4

array3 = [3, 3, 3]
sum3 = 0

というもの。

1.合計できる数値を配列にするため、空の配列を定義する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/a764159f-f967-b2cd-59f3-5408da7c40ab.png)

2.メソッドの引数（配列）をそれぞれブロック変数iに代入する。
　※countは後ほど使用するため数値0を代入。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/b1dac8c4-4ffe-62b0-547b-d8268463d03c.png)

3.２内でさらにメソッドの引数（配列）をそれぞれブロック変数nに代入する。
　そして「i = n」となった場合には２で定義していたcountに1を加える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/0a9e5434-046a-237f-6821-9264baceadcf.png)

4.countが２未満、つまり１の時のみ変数iを配列uniq_numsに加えていく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/c9923b80-b1cc-24b7-e3ea-b8e90e42254c.png)

5.配列uniq_numsをそれぞれブロック変数uniq_numに代入して行き、sum=0に加算していく。
　そして最後にsumを出力してメソッドの完成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/9c29be22-e111-b4b5-7a28-b68c9d26a737.png)

6.コード全体
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/d4bbd6db-eef3-96ff-f145-265228c1f399.png)

例えば配列[1,2,3]だった場合、
i = 1の時、n = 1,2,3と比較され、数値が1の時のみcountが1加算される。
2、3も同様。
それぞれ条件を通過して配列uniq_numsに代入されていったので、上記5の通り計算され6となる。

以上。

何に応用できるかはわからない。
【Ruby on Rails】投稿の編集機能（更新、削除）

# 目標
- 編集、更新
![編集.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/2c3b24ff-0987-1816-9e35-13d62b65647f.gif)

- 削除
![削除.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/eb079063-19e3-bef4-90e4-811868000298.gif)



# 開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

# 前提
- [deviseでログイン環境構築](https://qiita.com/japwork/items/275110b810965fbdf72f)
- [ログインユーザーのみができる投稿機能](https://qiita.com/japwork/items/8dfb52121036791ac4fb)



# １，ルーティングの変更

```rb:config/routes.rb
resources :posts, only: [:create, :new]
``` 
上記記述に下記を追加することで、edit,update,destroy　のルート設定。

```rb:config/routes.rb
resources :posts, only: [:create, :new, :edit, :update, :destroy]
``` 
下記の結果になればOKです。

```:ターミナル
$ rails routes

...

posts     POST     /posts(.:format)           posts#create
new_post  GET      /posts/new(.:format)       posts#new
edit_post GET      /posts/:id/edit(.:format)  posts#edit
post      PATCH    /posts/:id(.:format)       posts#update
          PUT      /posts/:id(.:format)       posts#update
          DELETE   /posts/:id(.:format)       posts#destroy
````

# ２，コントローラーの変更
下記を追加

```rb:app/controllers/posts_controller.rb

...

  def edit
   @post = Post.find(params[:id])
  end

  def update
    @post = Post.find(params[:id])
    if @post.update(post_params)
      redirect_to request.referer
    else
      render :new
    end
  end

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to request.referer
  end
```

# ３，ビューの変更
app/views/posts 配下にedit.html.erb ファイルを新規作成

```erb:app/views/posts/edit.html.erb
<h1>Posts#edit</h1>
<span>現在ログイン中のユーザー：<%= current_user.name %></span>
<%= form_for(@post, url: post_path(@post)) do |f| %>
	<div>
		<%= f.label :タイトル %><br>
		<%= f.text_field :title, autofocus: true, :placeholder =>"#{@post.title}" %>
	</div>
	<div>
		<%= f.label :中身 %><br>
		<%= f.text_area :body, :placeholder =>"#{@post.body}" %>
	</div>
	<div><%= f.submit "更新する" %></div>
<% end %>
```

```erb:app/views/posts/new.html.erb
<table>
	<thead>
		<tr>
			<th>投稿者名</th>
			<th>タイトル</th>
			<th>本文</th>
		</tr>
	</thead>
	<tbody>
		<% @posts.each do |post| %>
			<tr>
				<td><%= post.user.name %></td>
				<td><%= post.title %></td>
				<td><%= post.body %></td>
				<td><%= link_to "編集", edit_post_path(post) %></td>　　　　　　　  ←追加
				<td><%= link_to "削除", post_path(post), method: :delete %></td>  ←追加
			</tr>
		<% end %>
	</tbody>
</table>
```
再帰関数を掴んだ気がする(競プロ)

再帰関数、どう動いているか頭の中で追うのが苦手なのは自分だけですか。

[ABC114-C](https://atcoder.jp/contests/abc114/tasks/abc114_c)を解いてて、再帰使えそう！とは思ったものの実装はできなかったのでけんちょんさんの解説記事を見ながら実装。

ついでにその記事で、「全ての数字を使っているか」をbitで管理していて上手いと思った。
以下が自分のACコード

```cpp
#include<bits/stdc++.h>
using ll = long long;
using namespace std;
/*........................................DEFINE FUNCTIONS.........................................*/
int N;
int ans;
/*....................................DEFINE GLOBAL VARIABLES .....................................*/
void func(ll cur, int use) {
	if (cur > N)return;
	if (use == 0b111)ans++;
	func(cur * 10 + 3, use | 0b001);
	func(cur * 10 + 5, use | 0b010);
	func(cur * 10 + 7, use | 0b100);
}
/*.........................................kemkemG0................................................*/
int main() {
	cin >> N;
	func(0, 0);
	cout << ans << endl;
	return 0;
}

```


いや〜上手い。
macでpythonの仮想環境をする【めっちゃ簡単】

macでpythonの仮想環境の手順をメモがてら投稿します。

##必要な環境
■ Homebrew
必要なものをインストールするためのツール。

■ pyenv
Pythonのバージョンを簡単に切り替えるためのツール。

■ venv
Python標準の仮想環境ツール

##仮想環境の作り方

フォルダを作成。名前は何でもいいので今回はわかりやすく「python」にする。

```
cd /Users/※ユーザー名/python
```

上記で作成したフォルダ内に移動して下記を入力。
「pyenv」の所は任意なので何でもok。仮想環境なので「pyenv」にする。
ちなみにここが仮想環境になる

```
python -m venv pyenv
```
上記を入力すると「pyenv」フォルダができるのでフォルダの中に入る。


```
cd /Users/※ユーザー名/python/pyenv
```

「pyenv」フォルダ内で

```
. bin/activate
```
を入力すると

```
(pyenv) なんとかかんとか:pyenv ※ユーザー名$ 
```
みたいになるのでここがいわゆる仮想環境になる。
ここなら色々インストールしたりしても本体に影響なし。
ちなみに

```
. bin/activate
```
を入力してもうまくいかない時は

```
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
```
これをやってみてから

```
. bin/activate
```
をやってみてください。

仮想環境を無効化する時は

```
deactivate
```
これで出てこれます。
1つのリポジトリに複数のDockerfileを置かなければならなくなったときのディレクトリ構成

1つのリポジトリで1つのDockerfileなことが多いと思うので、だいたいルートディレクトリにDockefileを置くことになると思いますが、2つ以上のDockerfileを起きたくなる場合もあるでしょう。そんな場合にどういうディレクトリ構成にして、どういうファイル名にするか悩んだこと（そして失敗したこと）があるので書いておきます。

## 失敗パターン: Dockerfileという名前ではなく、別の名前でDockerfileを配置した

例えばrailsを動かすDockerfileと、nginxを動かすDockerfileがあった場合に、それぞれDockerfile.railsとDockerfile.nginxとするようなイメージ。

```
dockerfiles
├── Dockerfile.rails
├── Dockerfile.nginx
```

dockerのbuildを行う際に、オプションを指定することで特定のDockerfileを指定できるので、この方法でも大きな問題はありません。
しかしこのDockerfileを再びいじるようになって気づいたのですが、そのままだとエディタのシンタックスハイライトが効かないということに気づきました。


## 成功かもしれないパターン: ディレクトリを切ってDockerfileを配置する

```
docker
├── rails
│   └── Dockerfile
└── nginx
    └── Dockerfile
```

こんな感じ。
これだとシンタックスハイライトが効きますし、docker buildの際に（カレントディレクトリを移動すれば）オプションも不要になり便利です。

## まとめ

当たり前っちゃ当たり前なことですが、なぜ今のプロジェクトがこのディレクトリ構成にしているかの理由を後世に伝えるためのメモとして残しておきます。
【メモ】flashtextを用いたpandas dataframe内のテキストマッチング

## 概要
- pandasを用いて、容量の大きいcsv内のテキストマッチングを行う際に以下の点からflashtextというライブラリを導入。
  - 独自のアルゴリズムで、容量の大きいデータでも高速な正規表現処理が可能。
      - 容量によっては、pythonの[reモジュール](https://docs.python.org/ja/3/library/re.html)の方が速い。
  - 記法が簡易的。
  - テキスト処理が豊富。
- [Github](https://github.com/vi3k6i5/flashtext)
- 今回は、備忘録として基本記法を記述
    - **※そのため、各種apiは[公式ドキュメント](https://flashtext.readthedocs.io/)を確認する。**

## インストール
- 下記のコマンドで、導入。

```zsh
pip install flashtext
```

## サンプルコード
- 以下、サンプルCSVをdataframeに読み込んで、簡単なcount数を出す処理。

```python
import pandas as pd
from flashtext import KeywordProcessor

# keyword指定
keyword_dict = {
'front': ['html', 'javascript','css'],
'back': ['php','python','ruby'],
'db': ['mysql','postgress','mongo']
}

# init
keyword_processor = KeywordProcessor()

# keyword追加
keyword_processor.add_keywords_from_dict(keyword_dict)

# サンプルcsv読み込み
df = pd.read_csv("sample.csv")

# カウント処理。各カウントした数を表示するカラム追加。
# 例 : sample.csv内の「contents」カラム内にあるデータに対して、各マッチング。
df['all_count'] = df['contents'].apply(lambda x: len(keyword_processor.extract_keywords(x)))

# 最初の3行出力
df.head(3)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336499/fb04a46e-a895-516a-f3e9-38601ed3dadb.png)

## 参考
- [ドキュメント](https://flashtext.readthedocs.io/)
- https://medium.com/better-programming/using-pythons-flashtext-library-to-find-keywords-in-text-data-f6cdf9c018ee
React

こちらの記事は以下の書籍を参考にアウトプットとして執筆しました
[React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで](https://www.amazon.co.jp/React%E5%85%A5%E9%96%80-React%E3%83%BBRedux%E3%81%AE%E5%B0%8E%E5%85%A5%E3%81%8B%E3%82%89%E3%82%B5%E3%83%BC%E3%83%90%E3%82%B5%E3%82%A4%E3%83%89%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AB%E3%82%88%E3%82%8BUX%E3%81%AE%E5%90%91%E4%B8%8A%E3%81%BE%E3%81%A7-%E7%A9%B4%E4%BA%95%E5%AE%8F%E5%B9%B8-ebook/dp/B078XDLL2J/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=&sr=)

#ライフサイクル
##マウントに関するライフサイクルメソッド

|単語|説明|
|---|---|
|マイント|新たにReactコンポを配置すること|
コンポのrenderが初めて呼ばれたとき
→コンポーネントがマウントされた状態

2回目以降でrenderが呼ばれたら
→コンポがアップデートされた

###componentWillMount
コンポがマウント直**前**に呼ばれる
renderよりも先に呼ばれる
通常はコンストラクタで代用できる

###componentDidMount
コンポがマウント直**後**に呼ばれる
マウントされているためDOMに直接アクセスできる。

DOMに対してイベントリスナーを登録するならこのタイミング
####ライフサイクルでsetStateは使わないように
stateが変更されるとrenderメソッドが実行される
`render→componentDidMount→setState→rendre`
のように**renderが2回実行される。**

###componentWillUnMount
コンポがアンマウントされる直**前**に呼ばれる

このライフサイクルは、各コンポに紐付いた処理の掃除をする
どこかでsetIntervalを使っていたらここでclearIntervalを実行するなど。

##データアップデートに関するライフサイクルメソッド
コンポのアップデートと関連で呼ばれる
アップデートはpropsかstateが変更されたときに行われる。

###componentWillReceiveProps
引数に受け取る予定のpropsをとる

```
componentWillReceiveProps(nextProps)
```
参考：[React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで](https://www.amazon.co.jp/React%E5%85%A5%E9%96%80-React%E3%83%BBRedux%E3%81%AE%E5%B0%8E%E5%85%A5%E3%81%8B%E3%82%89%E3%82%B5%E3%83%BC%E3%83%90%E3%82%B5%E3%82%A4%E3%83%89%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AB%E3%82%88%E3%82%8BUX%E3%81%AE%E5%90%91%E4%B8%8A%E3%81%BE%E3%81%A7-%E7%A9%B4%E4%BA%95%E5%AE%8F%E5%B9%B8-ebook/dp/B078XDLL2J/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=&sr=)

この時点ではthis.propsには以前音値が入っている。
propsの比較結果をstateとして扱いたいときに。
cluster用アイテムの配布方法

Unity: Unity 2019.4.1f1
ClusterCretorKit: ClusterCreatorKit v1.6.2
を想定しています。

---

1．ClusterCreatorKitを導入したUnityでアイテムやそのギミックのセットアップをする。

2．Unity上でそれらのアイテムをPrefab化する。
ヒエラルキーウィンドウからプロジェクトウィンドウにドラッグアンドドロップでPrefab化できる。

3．Unityのうえの方のAssets→Export Packageで、2．で作ったPrefabにチェックを入れて保存。

4．いろいろな人に配布したい場合は、boothが便利。zip形式でまとめればUnityPackageやVRM、Blenderファイルなども配布可能。

---

アイテムをPrefab化せずにUnityPackageでまとめただけだと他の人がそのまますぐに使うことはできないみたいです。Prefab化してからパッケージを出力しましょう。



【2021年4月30日追記】
cluster公式さんがよりわかりやすい記事を作成してくださいました。そちらも参考にしてみてください。
https://creator.cluster.mu/2020/11/11/export-unitypackage
Docker-compose.ymlの記載について 


##version
docker-composeで使用するバージョンを定義する
#####バージョンによって,docker-compose.ymlの書き方が変わる

##service
アプリケーションを動かすためのそれぞれの要素のこと
webやdbはアプリケーションを動かす一つの要素であると定義される

##depends_on
コンテナの作成順序と依存関係を決める

##tty: true
docker-compose upしたコンテナを起動させ続ける。

##environment
環境変数を追加する

##volumes
マウントする設定ファイルのパスを指定する
[「PATH を通す」の意味をできるだけわかりやすく説明する試み](https://qiita.com/sta/items/63e1048025d1830d12fd #)

##参考
[docker-compose.ymlの書き方について解説してみた](https://qiita.com/yuta-ushijima/items/d3d98177e1b28f736f04#version%E3%81%A3%E3%81%A6 #)
Mysqlについて


```
# Mysqlを起動させる
$ mysql.server start


# Mysqlを停止させる
$ mysql.server stop

# Mysqlを起動させて以下のエラーが出たら、一旦停止させる
> mysqld_safe A mysqld process already exists


# ログイン
$ mysql -uroot


# ユーザー一覧の取得
$ mysql> SELECT Host, User FROM mysql.user;

# ユーザー作成
$ mysql> create user '[user_name]@localhost' indentified by '[password]';

# ユーザーにall権限を与える
$ mysql> grant all on *.* to '[user_name]@localhost';
```
Vue.jsのSPAでログインセッション切れの後、ログインをして、元の画面に戻す方法

# 課題

ログイン後の画面をSPAで作成しています。
ログインセッションが切れた場合、ログインからやり直します。
ログイン完了後は、元の画面に戻したい。

SPAは、ブラウザで動作しているので、ブラウザ側でなんとかしたい

# 回答

SessionStorageを利用する。

（重要）SessionStorageはタブ/ウィンドウごとにある。

1. ログインセッション切れを検知
2. sessionStorageに、現在のURLをログイン後の遷移先として保存する
3. ログイン画面に遷移
4. ログイン成功後、SessionStorageを参照して、遷移先の画面が指定されていれば、読み出し後削除して、その画面に遷移する。なければデフォルトの画面に遷移する。


# 参考文献
* [JavaScriptでブラウザタブを識別する方法はありますか？](https://www.it-swarm.dev/ja/javascript/javascript%E3%81%A7%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%82%BF%E3%83%96%E3%82%92%E8%AD%98%E5%88%A5%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B%EF%BC%9F/1068123532/)
kabuステーション®APIをPythonから使う

# 概要

auカブコム証券が個人に提供するkabuステーションAPIをPythonから利用する。
なお、kabuステーションはインストール済みのものとする。

# 環境

- Windows 10
- Python 3.8.5 ( Microsoft Store からインストール )

# 追加パッケージ

- requests
- pyyaml

# コード

以下では、取引余力の取得、残高の表示、注文の表示を行っている。

```python
import json
import requests
import yaml

# ---

def get_token():  # トークンを取得する。取得する度・またはkabuステーション再起動の度に変わる。
    with open('auth.yaml', 'r') as yml:
        auth = yaml.safe_load(yml)

    url = 'http://localhost:18080/kabusapi/token'
    headers = {'content-type': 'application/json'}
    payload = json.dumps(
        {'APIPassword': auth['PASS'],}
        ).encode('utf8')

    response = requests.post(url, data=payload, headers=headers)

    return json.loads(response.text)['Token']

# ---

token = get_token()

url = 'http://localhost:18080/kabusapi/wallet/cash'
response = requests.get(url, headers={'X-API-KEY': token,})
cash = json.loads(response.text)

print("取引余力\t{}".format(cash['StockAccountWallet']))

url = 'http://localhost:18080/kabusapi/positions'
response = requests.get(url, headers={'X-API-KEY': token,})
positions = json.loads(response.text)

print('コード　銘柄　平均取得価格　保有数　現在値　損益')
for position in positions:
    print("{}\t{}\t{}\t{}\t{}\t{}".format(
        position['Symbol'],
        position['SymbolName'],
        position['Price'],
        position['LeavesQty'],
        position['CurrentPrice'],
        position['ProfitLoss']))

url = 'http://localhost:18080/kabusapi/orders'
response = requests.get(url, headers={'X-API-KEY': token,})
orders = json.loads(response.text)

print('コード　銘柄　注文価格　注文数　期限')
for order in orders:
    if order['State'] == 1:
        print("{}\t{}\t{}\t{}\t{}".format(
            order['Symbol'],
            order['SymbolName'],
            order['Price'],
            order['OrderQty'],
            order['ExpireDay'],))

```

# その他

本番環境ポートが 18080 、検証環境ポートが 18081 である。
また localhost 以外の接続は不可。

【要望】localhost以外からのAPIアクセスについて
　　Issue#34 https://github.com/kabucom/kabusapi/issues/34

試しに PowerShell で

```
netsh http add urlacl url=http://[ IP ADDRESS ]:18080/ user=Everyone
```

でバインドしたところ、503 エラーで Reject された。

# 関連記事

- 次回：[kabuステーション®APIのWebsocketをPythonで受ける](https://qiita.com/shirasublue/items/222c2bc7dbf284d24878)
keydownとkeyupの違いに気をつけて！IME入力時に順番が違う！

### はじめに
フロントエンド開発していると、日本語入力確定時のEnterキーが、確定時のEnterキー打鍵と判別がつかず更新されてしまう事象に悩むことは誰しも遭遇したことあることかと思います。

![ workload.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/daef4129-beb7-e2b4-a32b-16e17a1dc9ce.gif)
↑↑例）調査という文字を打って、漢字変換を確定Enterを押したらそのまま更新になっちゃう

そんな時は、[compositionイベント](https://developer.mozilla.org/ja/docs/Web/API/Element/compositionstart_event)を利用すれば良いのですが、不可解な事象に少しハマってしまい数時間溶けてしまいました。

同じ事象でハマる人が減りますように :pray: 

### compositionイベントの使い方
一般的には以下のように、`data`に`composing`のような変数を用意し、`compositionstart`, `compositionend`でそれぞれ`composing`を更新することで、状態のチェックができると思います。

```vue.js
<template>
  ...
  <input
    v-model="name"
    type="text"
    @compositionstart="composing = true"
    @compositionend="composing = false"
    @keyup.enter="onChangeName"
  >
  ...
</template>

<script>
export default {
  data() {
    return {
      composing: false // IME入力中かどうか
    }
  },
  methods: {
    onChangeName () {
      if(this.composing) return
      // 更新処理を書く
    }
  }
}
<script>
...
```
（普段はTS入れてますが、わかりやすいように省略）

そして上記のように`methods`で`this.composing`を判定して後続処理を止めてたりします。これで日本語入力確定時に更新処理を走らないようにしたりします。

### しかし問題は起きた
上記のようにやっていて、問題なく`composing`値も更新され問題なかったのですが、おや？日本語入力確定時にも更新処理が走ってしまうぞ？！という状況に遭遇したのが今回のケースです。

試しにconsoleを仕込んでデベロッパーツールを見てみると、「composing値が先に終わって、更新処理時の判定時には使えていない！？」状態となっていたのでした。


```vue.js
// 省略

<script>
export default {
  data() {
    return {
      composing: false
    }
  },
  watch: {
    composing(val) {
      console.info(val, 'watch') // ←追加！
    }
  }
  methods: {
    onChangeName () {
      console.info(val, 'methods') // ←追加！
      if(this.composing) return
      // 更新処理を書く
    }
  }
}
<script>
...
```

<img width="150" alt="mojikyo45_640-2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/7db8814b-98f2-15b3-d6fe-1c5c2939c866.png">

もう発狂ものです。

### どうしたらよいのか？
結論から行くと、メソッドを呼び出している`keyup`イベントを`keydown`イベントに変更してください。

```vue.js
<template>
  ...
  <input
    v-model="name"
    type="text"
    @compositionstart="composing = true"
    @compositionend="composing = false"
    @keydown.enter="onChangeName" // ←keyupからkeydownに変更
  >
  ...
</template>
// 省略
```

<img width="150" alt="mojikyo45_640-2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252687/efe9dd8e-25a0-7844-218f-7dc070b3f512.png">

そうすると見事に、`methods`での判定箇所で`composing`が`false`になる箇所が後になってくれてます

### なんでkeydownで回避できるの？
`keydown`イベントは文字通り、キーが押された時に発火し、`keyup`イベントはキーを押して話した時に発火します。また今回これで事象を回避できたことから、`keyup`イベントは`compositionend`と同時に呼び出すと`compositionend`が優先されることがわかりました。また、`keydown`を利用することで明示的に`compositionend`イベントよりも先に発火させることができるものだと思います。

### さいごに
`keyCode`プロパティや`keyPress`イベントがDeprecatedになっていくので、日本語IME入力時には`composition`イベントを利用していくことになると思いますが、こういうケースもあるのでご注意ください〜

ちょくちょく詰まったネタは記事にしていきたいと思います！
Rubyの構文まとめ


#三項演算子(条件演算子)

```
? trueの時の処理:falseの時の処理
```

#Case構文
```
case 対象のオブジェクトや式
when 値1
 #値1の場合の処理 then 
when 値2 then #値2が真だった場合の処理(thenを使うと一行で済む)  
else
 #どれにも一致しない場合の処理
end
```
・最後に評価された式が戻り値になるので、結果を変数にいれることも可能
・whenの後の値には、:japanなどのハッシュでも可。

#クラス

```
class クラス名(最初の文字は大文字。キャメルケース)
end
```
・Rubyでは単一継承を採用しているため、一つのクラスは一つのスーパークラスしか持てない。
・クラスでモジュールをincludeすると、モジュールで定義したメソッドがインスタンスメソッドとして呼び出せるようになる。
・モジュールをクラスにincludeやextendして機能追加することをミックスインといい、これで多重継承と似た仕組みを実現できる。includeはインスタンスメソッド、extendは特異メソッド(クラスメソッド)として呼び出しが可能なので、クラス構文直下で呼び出したい時はextend。
・クラスはclassクラスのインスタンス(オブジェクト)。Objectクラスを継承するModuleクラスを継承している。

#####・includeしたモジュールの確認方法
```
> User.include?(モジュール名) 
 => #true or falseが返る
> User.included_module 
 => [Kernel] #includeされているモジュールが配列で返る
> User.ancestors
 => [Bank, Object, Kernel, BasicObject] #モジュールとスーパークラスが返る
```

#モジュール

```
module モジュール名
　モジュールの定義。メソッドや定数など
end
```
・クラスと違いモジュールからインスタンスは作成不可。(user = User.newでエラーが出る)
・他のモジュールやクラスは継承不可。is-aの関係が成り立たないので継承はできないが、共通機能はもたせたい..という時に使用する。
・クラスでミックスインする場合は、publicにする必要がない場合は、モジュール側でprivateにしておくと良き。
・モジュールのselfはinclude先のインスタンスになる為、includeされた先のクラスにpriceメソッドがあればモジュール側でもpriceが呼び出せる
・Rubyでいつでもputsやloopメソッドなどが使えるのは、実質全クラス頂点のObjectクラスがKarnelモジュールをincludeしている為。([Karnelモジュールの中身](https://docs.ruby-lang.org/ja/latest/class/Kernel.html))
・モジュールはmoduleクラスのインスタンス。Objectクラスを継承している。


#例外処理

```一番basicな構文.
begin
 #例外が起き得る処理
rescue
 #例外が発生した場合の処理
end

```

```ensure&else.
begin
 #例外が起き得る処理
 (#例外が発生しなかった場合の処理をここに書いてもいいのでelseは不要な場合が多い)
(rescue)
 (#例外が発生した場合の処理。)
(else)
 #例外が発生しなかった場合の処理
(ensure)
 #例外の有無に関わらず必ず実行する処理
end

```
・rescueは必須ではない。異常終了してもいいが、終了する前にやりたい処理がある場合などはensureだけでも可
・ただし、openメソッドにブロックを渡したりなど、「使用したら必ずソースを解放する」などの場合はブロック付きメソッドを使うことで自動処理できる場合が多い為、ensureメソッドの出番は少ないかも。


```
def メソッド名
 case object
 when :japan
  'yen'
 when :us 
  'dollar'
 else
  raise "エラーメッセージ" 
  #=> RuntimeError: "エラーメッセージ"
  #特に何も指定しないとRuntimeErrorが呼び出される。
 end
end
```
・RuntimeError以外を呼び出したい場合は、以下参照
① `raise ArgumentError, "エラーメッセージ"`
② `raise ArgumentError.new("エラーメッセージ")`


#ブロック
処理の塊。Procでブロックをオブジェクト化できる
Rubyではメソッドを呼び出す際にブロックを使用できる。

#メソッドまとめ

| 1 | 2 |
|:-:|:-:|
| chomp  | 改行文字を削除  |
| scan  |   |
|  message |   |
| size(length)  |   |
| open  |   |
| inject  |   |
|  reject |   |
|  brock.given? |  ブロックが渡されている場合にtrueを返す |
|   |   |
|   |   |
Python初心者によるタイピング自動化メモ

#初めての自動化

コピペライティングしないために
**説明できないコードは使わない**
を自分の心に刻み込みコードを書いています。
そのためプログラム内のコメントを多く入れるようにしてます。

ある有名タイピングゲームによる自動化です。
(タイトルは、利用規約うんぬんがあるので控えさせてもらいます。)

#実行環境
windows
python3.6
anaconda3


#コード全体
```
from selenium import webdriver
from time import sleep
import time
from selenium.webdriver.common.action_chains import ActionChains #アクションするために必要
import pyautogui as pa
import pyocr
import pyocr.builders
import cv2
from PIL import Image
#driver開く#
driver = webdriver.Chrome()

#windowサイズ#
driver.set_window_size(800, 800)

#サイトを開く#
driver.get("http://hogehoge")

#サイトが開くまで待機#
sleep(10)

#スタートボタンの座標#
#>>> pyautogui.position()#
'''
start_x = 400
start_y = 523
'''

#スタートボタンクリック#
pa.click(400, 523)
sleep(3)
#コースクリック#
pa.click(400, 523)
sleep(3)
pa.press(" ")
sleep(3)

i = 0
while True:
    if i > 350:
        break
    print(i)
    #スクリーンショット#
    pa.screenshot(imageFilename="sumple.png", region=(282, 498, 200, 20))
    im = cv2.imread('sumple.png')#画像読み込み
    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)#グレースケール

    #2値化
    im_gray = cv2.imread('sumple.png', 0)#グレースケールとして読み込み
    threshold_val = 100
    ret, thres_im = cv2.threshold(im_gray, threshold_val, 255,cv2.THRESH_BINARY)#2値化
    cv2.imwrite('sumple.png', thres_im)#2値化された画像保存
    im_bw = Image.open('sumple.png')

    #文字認識#
    tool = pyocr.get_available_tools()[0]
    text = tool.image_to_string(im_bw, lang='eng', builder=pyocr.builders.TextBuilder())

    #文字入力#
    print(text)
    pa.typewrite(text, interval = 0.1)

    i += 1

#終了#
input("何か入力")
driver.close()
driver.quit()
```
#終わりに
初めてのコードだったので１つ１つ調べるのに時間が掛かりました。
小さな事でもどんどんアウトプットしていこうと思います。
期間同士が重なっているかを判定するコード

期間同士が重なっているか判定するのって以外とミスを入れ込みやすい印象。間違えないように書いとく。

ちなみにコードはKotlinだけど、他の言語でもあまり変わらないはず。

## 前提

任意の日時が期間内にあるかは以下の式で判定する。

```kotlin
date >= start && date < end
```

要は[区間](https://ja.wikipedia.org/wiki/%E5%8C%BA%E9%96%93_(%E6%95%B0%E5%AD%A6))における半開区間（左閉右開）ってことです。閉区間にしちゃうと、任意の日時がどちらの期間にも属する可能性が出て来ちゃいますからね。

## 「重なっている」の捉え方その1: そのまんま重なっているかを見てやる

言葉の通りに判定する方法です。まず2つの期間から重なっている部分を取り出します。

下記の図のような期間1および期間2があるとします。この2つの期間が重なっている部分は期間2の開始から期間1の終了までとなります。

![スクリーンショット 2020-09-03 15.36.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6934/ab345127-38d5-1b18-f738-9b61cab73854.png)

これは以下の式で求められます。期間1と期間2の位置関係が逆転しても大丈夫なように、maxOf関数やminOf関数を用いています。

```kotlin
val start = maxOf(start1, start2)
val end = minOf(end1, end2)
```

あとはこれが空の期間でなければ良いので、以下の式で判定できます。

```kotlin
start < end
```

閉区間だと `start <= end` ですが、半開区間（以上未満）なので `start < end` であることに注意。

期間を表すクラスを定義し、そこにisEmptyメソッド（isNotEmptyメソッド）を生やしてあげるのも良いですね。KotlinのビルトインクラスであるClosedRangeなどがちょうどそのような形になっているので、参考にしてみると良さそう。

## 「重なっている」の捉え方その2: 「重なっていない」に注目する

「重なっていない」の否定が「重なっている」なので、「重なっていない」が分かれば良いだろう、という話。

重なっていないのは2つのケースしかありません。これと:

![スクリーンショット 2020-09-03 15.42.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6934/55c0be5f-c5c1-5420-7a61-8819d2979379.png)

これだけ。

![スクリーンショット 2020-09-03 15.43.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6934/c0489697-7131-ad8f-fcef-0357feb24eee.png)

なので、以下の式で判定できます。

```kotlin
!(end1 <= start2 || end2 <= start1)
```

ド・モルガンの法則を適用するとこう。

```kotlin
end1 > start2 && end2 > start1
```

SQLとかだとこっちの方が書き易いかもしれない（LEAST関数とか使えばその1でも出来るけど）。
JSONのkeyが数字の時

#扱うJSONデータ
[こちら](
https://qiita.com/next1ka2u/items/1d7e63c37d9a205219b6)のデータを扱わせてもらいました。

```json:qiita.json

[
  {
    "01": {
      "id": "01",
      "name": "北海道",
      "short": "北海道",
      "kana": "ホッカイドウ",
      "en": "hokkaido",
      "city": [
        { "citycode": "0010001", "city": "札幌市中央区" },
        { "citycode": "0010002", "city": "札幌市北区" },
        { "citycode": "0010003", "city": "札幌市東区" }, ...
```

#なかなかデータを取り出せなかった原因

**ブランケット記法を忘れていた**

この書き方しか頭になくわけもわからず時間を浪費した。


```javascript:qiita.js
import Jsondata from "./qiita.json";

  const data = Jsondata[0];
  console.log(data.01.id);//エラー
  // ドット記法は識別子の命名規則を満たす必要がある

```



ドット記法は簡単に言うと数字やハイフンが入ったものは扱えないからブラケット記法という[]の間に式を描く方法でないと変なエラーが出てくる

#解決した書き方

ほかの言語ではこの書き方をよくするのになぜ思いつかなかったのか、

```javascript:qiita.js
import Jsondata from "./qiita.json";

  const data = Jsondata[0];
  console.log(data["01"].id);//01
//ブランケット記法これが正解

```
[React + Firestore] 最もシンプルな投稿機能 Hooks対応

React + Firestoreでつくる最もシンプルな投稿機能を書いておきます。
テンプレートデータとしてご利用ください。

### 環境
- create-react-app
- Firestore

### 下準備
※各モジュールを`npm install`で入れる
- react-hook-form `npm install react-hook-form`
- react-firebase-hooks `npm install --save react-firebase-hooks`
- firebase `npm install --save firebase`

```js:Firebase.js
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

const firebaseConfig = {
    // 自分のFirebase Keyを入れる
    apiKey: "YourCode",
    authDomain: "YourCode",
    databaseURL: "YourCode",
    projectId: "YourCode",
    storageBucket: "YourCode",
    messagingSenderId: "YourCode",
    appId: "YourCode",
    measurementId: "YourCode"
};

firebase.initializeApp(firebaseConfig);

export const providerFacebook = new firebase.auth.FacebookAuthProvider();
export const providerGoogle = new firebase.auth.GoogleAuthProvider();
export const providerTwitter = new firebase.auth.TwitterAuthProvider();
export const db = firebase.firestore();
export default firebase;
```

### 実装（投稿テンプレート）

```jsx:Post.js
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { useCollectionData } from 'react-firebase-hooks/firestore';
import firebase, { db } from '../../Firebase'; // 階層により異なる

const Post = () => {
    const { register, handleSubmit, errors } = useForm();
    
    // Create
    const [msg, setMsg] = useState('');
    const [pending,setPending] = useState(false);
    const createdAt = firebase.firestore.FieldValue.serverTimestamp();
    
    const OnSubmit = async () => {
        setMsg('');
        setPending(true);
        try {
            await firebase
                .firestore()
                .collection('posts')
                .add({
                    msg,
                    createdAt,
                });
        } finally {
            setPending(false);
        }
    }
    
    // Render
    const [ list, loading, error ] = useCollectionData(db.collection('posts').orderBy('createdAt', 'desc'), { idField: 'docId' });
    console.log(list);

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error...</div>;
    
    return (
        <>
            <form onSubmit={handleSubmit(OnSubmit)}>
                <div>
                    <input
                        value={ msg }
                        onChange={ e => setMsg(e.target.value) }
                        placeholder="msg"
                        name="msg"
                        ref={register({ required: true })}
                    />
                </div>
                <div className="error">{errors.msg && 'コメントが入力されていません'}</div>
                <button type="submit">送信</button>
                { pending && 'Pendeing...' }  
            </form>
        </>
    );
}

export default Post;
```
GravioでChromecastに動画を流す: Windows編


# 背景
[前回](https://qiita.com/zrock/items/5ff126bf64d2716299a4)はラズパイ上のGravioからCATTコマンドを使ってChromecastに動画を流してみました。
PythonなんでLinuxの方が簡単ですが、Windowsでも同じようにCATTは使えますので、Gravioから動画をキャストすることが可能です。ただし、Pythonのインストールでちょっとだけコツがあるのでそこだけ注意。

# 使用環境
今回はWindowsなのでちょっとだけPythonのバージョンが違います。

- Windows 10 1909 (18363.1049)
- Python 3.8.5
- CATT v0.11.3
- Gravio HubKit v3.8.4550.0
- Gravio Studio v3.8.3606.0

# ポイント

GravioはWindowsサービスで動作しています。Pythonをそのまま何も考えずにインストールしたりするとユーザー領域にコマンドがインストールされちゃったりするので、管理者権限を使いましょう。
あと、RunScriptで実行するのはシェルではなくバッチファイルで。

# 手順

## Pythonのインストール
Pythonをインストールします。ダウンロードはこちらから。 → https://www.python.org/downloads/
今回は3.8.5のインストーラーを使います。

![pyinstall.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/241bbd84-8432-cdb0-fc82-d80032e0db8a.png)

最初の画面では、「**Add Python 3.8 to PATH**」をチェックしてPythonにパスを通しておきます。それから、デフォルトインストールだと書いてあるとおりユーザー領域にインストールされるので「**Customize installation**」を選んでクリックします。

![pyinstall2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/a6f46445-911c-08de-601a-daaab9d6080d.png)

この画面はデフォルトのままでOK。

![pyinstall3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/4a3fa234-26a0-7613-58ec-10de53e82770.png)

ここで「**install for all users**」にチェック。するとインストールパスが `C:\Program Files\Python38`になります。まぁ、自分で変えてもいいかもしれないですが、できるだけ素直にインストールしておきましょう。
あとは「Install」をクリックしてインストールです。

## CATTのインストール
CATTのインストールはLinuxとほぼ同じです。ポイントはコマンドプロンプトを管理者モードで起動すること。すると先程のインストールパスにインストールされます。ここで通常モードでインストールしちゃうとCATTがユーザー領域にインストールされちゃって痛い目にあいます。
というわけで、 `pip install catt` でインストールしましょう。
![cattnistall.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/b43187d6-5664-ad67-d318-c47f85def176.png)

ここまで来たら準備完了。パスの変更がGravioには伝わってないので、Gravio Toolsを使って**Gravioを再起動**しておきましょう。

## Gravioの設定
あとはほぼ[Linux](https://qiita.com/zrock/items/5ff126bf64d2716299a4)のときと同じです。バッチファイルにするのと、引数を `%1` とするくらいですね。Windowsの場合、権限もないので、このファイルを配置するだけです。

```play-video.bat
catt -d "Chromecast 4K" cast "%1"
``` 

![cattgravio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/78426aee-4555-a383-23dc-7acc7fede184.png)

ざわわーざわわーと波の音が聞こえ始めるでしょうｗ

# 最後に
GravioとCATTを使ってChromecastに動画を流すシリーズ、なかなか楽しかったです。Castデバイスはいろいろあるので、アイデア次第でいろんな事できちゃいますね。プロジェクタにChromecastをつないで、画面のないところにプロジェクションマッピング！なんてのもありですしね。
firestoreでcollectionGroupを使ってorderByしたい。

``collection``に対しては特に何もしなくてもindexが作成されているみたいなので``orderBy``が使える。
だけど``collectionGroup``になるとindexは自動では作られないとの事

#collection
コレクションの取得

```javascript

const db = firebase.firestore()

db.collection("images").orderBy("timeStamp", "desc").limit(5).get()
```
これはちゃんと降順に取得できる

#collectionGroup
コレクション内にあるサブコレクションの取得

####フィールド
```
  message: "テスト"
  displayName: "testUser"
  timeStamp: 2020年9月3日 14:10:46 UTC+9
```

```javascript

db.collectionGroup("comment").orderBy("timeStamp", "desc").limit(10).get()
```
これを実行すると下記のエラーが出て取得できない

```
Uncaught (in promise) FirebaseError: The query requires a COLLECTION_GROUP_DESC index for collection comment and field timeStamp. You can create it here
```

__``index``__がないからできませんよ
といっているらしい
#設定
firebaseコンソール>firestore>インデックス>単一フィールド

``collection group scope``と書いてあるところがすべて無効になっています。

``除外を追加``を選択


![設定前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605079/c0aeb74c-1d31-cf86-05fb-d64017f66b7e.png)

今回の場合だと``collectionGroup("comment")``なので``コレクションID``に``comment``
``フィールドのパス``は``timeStamp``を使いたいので``timeStamp``と入力して
コレクショングループにチェックを入れて``Next``

 ![設定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605079/bf5165ed-98d8-f8b1-96a8-a255ac115b31.png)

``昇順``と``降順``を使用したいので``有効``にして保存

![設定3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605079/b6afd7dc-8132-2bea-dc03-cb1c23b8670d.png)
除外のところに新しく設定したものが表示されます

![設定4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605079/54f7445d-def0-a0b1-358e-92d75e84eb45.png)

これで先ほどと同じ

```javascript
db.collectionGroup("comment").orderBy("timeStamp", "desc").limit(10).get()
```
を実行してみます。

ちゃんと降順で取得することができました。
コンパクトレイアウトに動的にアクションボタンを配置する

Add Dynamic Actions to the Highlights Panel for Custom Objects (Beta)
https://releasenotes.docs.salesforce.com/en-us/summer20/release-notes/rn_lex_dynamic_actions.htm

まだ、日本語版のリリースノートはないです。
今のところ(2020/09/03)ベータ版でかつ、カスタムオブジェクトだけの対応です。
ゆくゆくは標準オブジェクトにもできるようになるらしい。


こちらは、英語版ですがブログ
https://admin.salesforce.com/blog/2020/try-dynamic-actions-in-app-builder-with-the-summer-20-release



以下のようにアクションに条件を設定できます。

例では受注確定フラグがfalseの時だけ　受注確定ボタンを表示するようになります。

![dynamic-actions-in-app-builder.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ce5fed29-5660-de01-0ea5-cf7121b9711f.png)
micropythonとPython3の相違点

## 概要
少しずつ更新。
Python3とmicropythonでプログラミングする上で
困った点・解決した点を下記に記載。

### 比較前提
- Python 3.7
- micropython 1.1.2

### 相違点
- FTPライブラリが使えない
    - micropythonではFTPLibが標準では使えない。
        - SpotlightKid氏の[micropython-ftplib](https://github.com/SpotlightKid/micropython-ftplib)を使用する
- zfillが使えない
    - 0パディングでよく使用するzfillがmicropythonでは使用できない
        - zfill関数を実装する

        ```
        def zfill(s, width):
            if len(s) < width:
                return ("0" * (width - len(s))) + s
            else:
                return s
        ```

### 参考ページ
- [help adding string module to mu or any other ide](https://forum.micropython.org/viewtopic.php?t=3201)
WEBカメラ取り込み Ver 2

Raspberry Piを使用した撮影をする上で
まず通る所が、キーボード操作による撮影が多いと思います。
しかしながら、大量の画像を取るとなると
高〇名人ばりの連射が必要なので一般人には到底無理。
なので自動で撮影して楽が出来ないかと思い作成。

今回は部下(生贄1号)が出来たので一緒に作成しました

##環境
Raspberry Pi 3 Model B+
os Raspbian(Bastar)
Python 3.7.3
opencv 4.1.0.25
使用カメラ　ELECOM UCAM-C750FBBK

##ライブラリ
```python:cap_save.py
import cv2
import os
import sys
import datetime  
import RPi.GPIO as GPIO
from time import sleep
import time
```
今回はGPIOを使用するので
撮影基本セットに追加したのと
タイマー使うので＋しています。

##基本設定
```python:cap_save.py
GPIO.setmode(GPIO.BCM)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(25, GPIO.OUT)
```
今回はブレッドボードにタクトスイッチをつけて
撮影開始・終了の使い方をするのでそれが出来る様な設定にしています。

##撮影プログラム
```python:cap_save.py
def save_frame_camera_cycle(device_num, dir_path, basename, cycle, ext='jpg', delay=1, window_name='frame'):
    cap = cv2.VideoCapture(0)

    if not cap.isOpened():
        return

    os.makedirs(dir_path, exist_ok=True)
    base_path = os.path.join(dir_path, basename)
    
　　n = 0
    while True:
        ret, frame = cap.read()
        cv2.imshow(window_name, frame)
        
        if GPIO.input(24) == GPIO.HIGH:
            GPIO.output(25, GPIO.HIGH)
            
            while True:   
                
                ret,frame = cap.read()
                cv2.imshow(window_name, frame)
                key = cv2.waitKey(1) & 0xFF
                if n == cycle:
                    n = 0
                    GPIO.output(25, GPIO.HIGH)
                    cv2.imwrite('{}_{}.{}'.format(base_path, datetime.datetime.now().strftime('%F %T'), ext), frame)
                    print("shoot")
                n += 1
    
                if GPIO.input(22) == GPIO.HIGH:
                    GPIO.output(25, GPIO.LOW)
                    print ("stop")
                    time.sleep(1)
                    break                
        else:
            GPIO.output(25, GPIO.LOW)
            
        if GPIO.input(22) == GPIO.HIGH:
            GPIO.output(25, GPIO.LOW)
            print ("end")
            break
        
    cv2.destroyWindow(window_name)
    GPIO.cleanup()

save_frame_camera_cycle(0,'/home/pi/Desktop/GPIO/test/photo', 'test', 20) 
```
タクトスイッチ(24)を押すと1秒ごとに撮影します。
タクトスイッチ(22)を押すと撮影停止。
停止状態でタクトスイッチ(24)を押すと撮影再開。
停止状態でタクトスイッチ(22)を押すと撮影終了。
撮影中はLED(25)が点灯。

色々と調べながら作成したので細かな部分までは理解していませんが
撮影出来ているのでＯＫとしています。

##実配線
ブレッドボードへの配線は様々な資料を元に配線してこんな感じ。

![2020-09-03 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607764/28823f2d-e8cb-ff42-88ce-a83f948c5a04.png)


##まとめ
4時間ほど動作させましたが、止まることなく動きました。
ただ、枚数指定で自動停止とまではいかなかったので
現在作成中です。

色々とWEB上を巡回して知らべていますがなかなかどうしてうまくいかない今日この頃

以上です。
React Hook で管理する値の更新について

# はじめに
ReactHooksで配列などで管理している値を変更したい際の方法をまとめました。

# 配列の更新
配列をHooksで管理している際は以下のように変更できます。

### 配列の最後に要素をプッシュ part1

```sample.js
const [sampleArray, setSampleArray] = useState(initialArray);

const newArray = Array.from(initialArray);
newArray.push(newValue);
setSampleArray(newArray);
```

### 配列の最後に要素をプッシュ part2

```sample.js
const [sampleArray, setSampleArray] = useState(initialArray);

setSampleArray(oldArray => [...oldArray, newValue]);
```

# オブジェクトの更新
オブジェクトをHooksで管理している際は以下のように変更できます。

### オブジェクトの最後に要素をプッシュ/更新する part1

```sample.js
const [sampleArray, setSampleArray] = useState(initialArray);

const newObj = Object.assign({}, initialArray);
newObj[currentOrNewKey] = newValue;
setSampleObject(newObj);
```

### オブジェクトの最後に要素をプッシュ/更新する part2

```sample.js
const [sampleArray, setSampleArray] = useState(initialArray);

setSampleObject(oldState => ({ ...oldState, currentOrNewKey: newValue}));
```

### オブジェクトの最初に要素をプッシュ/更新する

```sample.js
const [sampleArray, setSampleArray] = useState(initialArray);

setSampleObject(oldState => ({currentOrNewKey: newValue}, ...oldState));
```

### オブジェクトの配列の最後に要素をプッシュ/更新する

```sample.js
const [sampleArray, setSampleArray] = useState(initialArray);

setSampleArray(oldState => [...oldState, {currentOrNewKey: newValue}]);
```
CakePHP2で論理削除を実装する方法

#論理削除とは
論理削除とは、ユーザーがブラウザで見た場合は、削除しているように見えるが、実際のデータは別に用意したカラムに保存されている。そのため、削除したデーターを管理者側から復活させることなどが可能。

#物理削除とは
データーベースのデーターも削除すること。データーの復旧は不可。
通常のdeleteメソッドを用いた削除方法などはコレ。

#さっそく解説
SoftDeleteBehaviorをダウンロードして設置する。

https://github.com/CakeDC/utils/blob/master/Model/Behavior/SoftDeleteBehavior.php

ダウンロードしたファイルをapp/Model/Behaviorのフォルダ内に置く。

#テーブルに論理削除用のカラムを作成
削除フラグ
名前：deleted
型：tinyint(1)
※デフォルト値：0

削除日
名前：deleted_date
型：datetime

DBでdeletedカラムをデフォルトで0に設定して、
delete関数が走った時に、deletedカラムに１が立つように実装すれば良い。


#論理削除したいモデルで以下のように呼び出します

```php

class 使いたいモデル名 extends AppModel{
    // 論理削除用ビヘイビア
    public $actsAs = array( 'SoftDelete' );
```

#AppModelには以下のように記述しておきます。
```php

class AppModel extends Model {

    public function exists($id = null) {
        if ($this->Behaviors->loaded('SoftDelete')) {
            return $this->existsAndNotDeleted($id);
        } else {
            return parent::exists($id);
        }
    }

    public function delete($id = null, $cascade = true) {
        $result = parent::delete($id, $cascade);
        if ($result === false && $this->Behaviors->enabled('SoftDelete')) {
            return (bool)$this->field('deleted', array('deleted' => 1));
        }
        return $result;
    }
}
```
上記の、delete()はsoftdeleteで上書きされていて、消去ではなくupdate（更新）という形になっている。
また、deletedというカラム名があればそこに１を立ててくれるようになっている。

#コントローラーはこんな感じ

```php

  public function delete($id) {
    $this->autoRender = false;
    if($this->request->is('get')) {
      throw new MethodNotAllowedException();
    }
    
    if($this->User->delete($id)) {
      $this->Session->setFlash('Delete!');
      $this->redirect(array('action'=>'index'));
    }else{
      debug(__LINE__);
    }
  }
```

はい、これだけでオーケーです。
十の位と一の位の求め方について

表題について、解決に想像以上に悩んだので備忘録として。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678246/64511968-210c-6aa0-fcb2-6b39d13fa4ce.png)

（例）
input == 69だった場合
tens = (69 / 10) % 10 == 6
ones = (69 / 10) % 10 == 9
となります。
databricks公式ドキュメントやってみた~Secure access to S3 buckets using instance profiles(後編)~

#はじめに
公式ドキュメントやってみたシリーズ第2弾です。
今回のテーマは
「Secure access to S3 buckets using instance profiles」です。
インスタンスプロファイルを使用してセキュアにS3バケットにアクセスする方法をdatabricks公式ドキュメントの手順に従ってやってみたいと思います。

#今回の作業内容
今回行う作業は以下の8項目です。

※0.ターゲットS3バケットの作成

1. S3バケットにアクセスするためのインスタンスプロファイルを作成

2. ターゲットのS3バケットのバケットポリシーの作成

3. databricks on AWSデプロイ時のIAMロールの確認

4. ターゲットS3バケットにアクセスするためのIAMロールをEC2に付与

5. インスタンスプロファイルをdatabricksにアタッチ

6. インスタンスプロファイルを使用してクラスタを立ち上げる

7. ノートブックから今回設定したS3へのアクセスを確認する

作業自体がやや長いのと、
細かいロールやポリシーの設定があるため

- 前編(0~3)→AWS側の設定
- 後編(4~7)→databricks側の設定

に分けてやっていきたいと思います。

#本題
では、本題に入っていきましょう。

###5. インスタンスプロファイルをdatabricksにアタッチ
前編.1で作成したIAMロールを選択し、インスタンスプロファイルARNをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/2520589e-7af9-9f62-3471-d0ce024de1cd.png)


databricksにログインして
右側の人間マークからdatabricks adminコンソールに入る、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/ad5e86e8-9e79-c07e-bbe6-4fd66455791f.png)

Instance Profileに移動、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/71e6ae83-df71-60ad-1811-e7ca45d5cb99.png)

Add Instance Profileをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/f011b2d9-03e6-0d12-3b1f-9d70c4ae8051.png)

Instance Profile ARNに先ほどコピーしたIAMロールインスタンスプロファイルARNを貼り付けてAddをクリック。
その下の２つの項目に関しては今回はチェックしないで進めたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/f0b73c90-c602-77f1-86ef-8e96016590c5.png)



###6. インスタンスプロファイルを使用してクラスタを立ち上げる
先ほど作成したインスタンスプロファイルを使用してクラスターの立ち上げを行います。
すでに作成済みもしくは新しいクラスタのページに移動します。
Advanced Optionsをクリックして項目を表示させると、一番下にInstance Profileを記入する欄がありますのでクリック
先ほど設定したInstance Profileがあると思うので、それを設定してクラスターを立ち上げます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/fd98c24f-e8b7-c2ba-3248-b54140e9da67.png)

###7. ノートブックから今回設定したS3へのアクセスを確認する
新しくノートブックを開きます。
名前はなんでもOKで、言語はPython、クラスタはインスタンスプロファイルを設定したものを選択してください。
ノートブックの画面を開いたら下記を実行します。s3-bucket-nameは今回のターゲットS3バケット名を記入します。

```
dbutils.fs.ls("s3a://s3-bucket-name/")
```


このようにターゲットS3バケットの中身が表示されたら無事今回の作業がうまくいっていることになります。
(この例ではターゲットS3バケット内にsampleとsample2という2つのフォルダを入れているのでこのような結果表示になっています。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/174081bb-9ac7-278d-9fab-5ee9a682ae1b.png)

**注)ターゲットS3バケットが空の状態でスクリプトを実行すると対象のディレクトリがありませんという内容のエラーを吐くので、必ずフォルダもしくはファイルを最低1つ入れた状態にしてください。**

#終わりに
以上がdatabricks公式ドキュメントやってみた~Secure access to S3 buckets using instance profiles(後編)~でした。
今回の内容を活用して、ぜひご自身の目的に合ったセキュアなdatabricks環境構築に取り組んでみてください。
最後までお読みいただきありがとうございました。
本記事がどなたかのお役に立てていれば幸いです。

※本内容はこちらの公式ドキュメントを参考にしております。
https://docs.databricks.com/administration-guide/cloud-configurations/aws/instance-profiles.html
GoF Factory系個人まとめ

## (Simple) Factory

単に何かを生成するやつ。Factoryに生成のロジックをまとめて、クライアントから分離する

## Factory Method

同じ系統のオブジェクトの生成に対して、それぞれクラスを作成し、生成のロジックを閉じ込める。

例えば、ドアという系統のオブジェクトを作ると考えた時、「木のドア」、「鉄のドア」の様な違う製品が考えられる。
この時に、「木のドア」に対してFactoryを、「鉄のドア」に対してFactoryを作成して、それぞれの生成のロジックをまとめる。
この時、「ドア」と「ドアのFactory」の抽象クラスを作成し、それぞれ継承させる。作成するクラスを整理するとこんな感じ

### 抽象群
- DoorFactory (ドア工場抽象クラス)
- Door (ドア抽象クラス)

### 具体群
- WoodDoor
- IronDoor
- WoodDoorFactory
- IronDoorFactory

## Abstract Factory

「関連するオブジェクト郡をまとめて生成するための手順」の抽象化をします。

たとえば、家を作るみたいなことを考える。この時、「木造住宅」、「ウチッパ住宅」の2種類あると考える。
この時、例えば、「柱」、「壁」、「ドア」などのパーツに何を使うかの判定が必要なことがある。
この時例えば、木造住宅なら、「木の柱、木の壁、木のドア」、ウチッパ住宅なら、「鉄筋の柱、コンクリートの壁、金属のドア」みたいな、パーツごとの場合分けが必要になる。この関連するオブジェクト群を整合性を持って生成することを目標をしています。この時、ドア、壁、柱の抽象クラスとそれぞれのFactoryの抽象クラスを必要とします。

### 抽象群
- HouseFactory
- Door
- Hashira
- Wall

### 具体群
- WoodHouseFactory (extend HouseFactory or implement HouseFactory)
- ConcreteHouseFactory (extend HouseFactory)
- WoodHashira (extend Hashira)
- IronHashira (extend Hashira)
- WoodWall (extend Wall)
- ConcreteWall (extend Wall)
- WoodDoor (extend Door)
- IronDoor (extend Door)

HouseFactoryが、DoorとHashiraとWallが必要であることを定義して、その実装をConcreteHouseFactory、WoodHouseFactoryが担っています。
(HouseFactoryとWoodHouseFactory、ConcreteHouseFactoryがTemplateMethodパターンになっています。)

## Factory MethodとAbstract Factoryの違い


Factory Methodは、１つのFactoryが1つのオブジェクト生成を担っているのに対して、
WoodHouseFactoryが木造住宅というドメインの周辺オブジェクトの生成を全て担っている様に、AbstractFactoryは、複数のオブジェクト生成を担っています。

ここからわかる様に、
Factory Methodは、「オブジェクトの生成についての抽象化」を目指していて、
Abstract Factoryは、「特定ドメインの周辺オブジェクト生成を整合性を担保する」を目指しているというところで違うのかなと思います。

## 多分
Factory MethodとAbstract Factoryはそれぞれ目的が違うので、共存がありえるのかなと思います。
Abstract Factoryで、パーツ全体で整合性をとりながら、それぞれのパーツの生成は、FactoryMethodで、生成の抽象化をする様なことがありえそうです