OmniAICreator/Qiita-1.07M huggingface dataset:
Power Automateでチームメンバーにウェルカムメッセージを送る

プロジェクトや部署などのチーム単位で作成されるTeamsのチームですが、メンバーが流動的なプロジェクトだと、『入ったらここ見ておいてください』みたいな連携があったりしますよね。
あるいはTeamsのWikiにプロジェクトのガイド・紹介を書いておくといった使い方もあるかと思います。

そんな新規メンバーへのウェルカムメッセージを自動的にTeamsに投稿するFlowをご紹介します。

## Acknowledge
This work is supported by [John Liu 劉](https://twitter.com/johnnliu).  Thank you!
You can find his awesome work in his blog posts, See [JOHN LIU.NET](http://johnliu.net/)

# Flowの全体
Flow自体は非常にシンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/e05d49ab-32c0-3281-c3e7-9b9b03fcd5da.png)

1. Office 365 Groupsコネクターの「グループにメンバーが追加または削除されたとき」のトリガーを利用
2. 1の結果のidから、Office 365 Usersコネクターでユーザー情報を取得
3. **(ここがポイント！)** 1.の結果のReason を利用。deletedかどうかで分岐
4. YesならTeamsに歓迎メッセージ
5. Noならメンバーにメールを送信する（ここではFormsのアンケートを送っています）

重要なのは3.です。トリガーはメンバーの出入りどちらも発火するので、どちらも同じように歓迎メッセージを送るとおかしなことになります。
これを回避するために、条件を追加し、トリガーの"Reason"を利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/554513ac-80a9-a3ad-8952-c5d222e03ad5.png)

以上でFlowは完成です。追加時にはこんな風にメッセージが送られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/3c0cefb7-96f3-f837-712a-f47d520b614b.png)

脱退するとこのようにメールが送信されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/c64c7061-d380-4ec5-494b-913c07d61c1b.png)

#まとめ
Power Automateを利用するとTeamsを少し便利に活用することができます。ぜひ活用してみてください。

この内容はOffice 365勉強会のLTでご紹介したのですが、当日参加されていた [廣澤みなみさん](https://twitter.com/hirosawa373)の手により、すぐに活用いただけました！ありがとうございます！！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">一昨日 (2020/1/25) の Office 365 勉強会、Hiro さん (<a href="https://twitter.com/mofumofu_dance?ref_src=twsrc%5Etfw">@mofumofu_dance</a>) の LT の Power Automate フローをマネさせていただきました(*´ω｀*)<br>流れるような ライブ作成、Power Automate の簡単さと効果がとても分かりやすく伝わり、素敵な LT でした！ <a href="https://t.co/gJ4azvklcq">pic.twitter.com/gJ4azvklcq</a></p>&mdash; 廣澤みなみ (@hirosawa373) <a href="https://twitter.com/hirosawa373/status/1221785871067672576?ref_src=twsrc%5Etfw">January 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Python2でCSVからRedmineのチケットを登録する

### 環境
OS：windows10
Redmine：ver 3.4
Python：2.7
読込対象：CSV(shift-jis)

```csv:csv
"project","title","subject"
"test","テスト","テスト"
```

```python:sample.py
# -*- coding: utf-8 -*-

import csv
import urllib2

API_KEY = 'XXXXXXXXXXXXXXXXXXXXX'
URL = 'http://host_name/redmine//issues.xml'

def requests(xml):
    request = urllib2.Request(URL, data=xml)
    request.add_header('Content-Type', 'text/xml')
    request.add_header('X-Redmine-API-Key', API_KEY)
    request.get_method = lambda: 'POST'
        
    # 登録実行
    response = urllib2.urlopen(request)
    ret = response.read()
    print 'Response:', ret.decode('utf-8')

def main():
    csv_filename = r'.\test.csv'
    
    with open(csv_filename) as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            xml = """<?xml version="1.0"?>
            <issue>
            <project_id>""" + row['project'] + """</project_id>
            <subject>""" + row['title'] + """</subject>
            <description>""" + row['subject'] + """</description>
            </issue>"""
            
            xml = xml.decode('shift-jis').encode('utf-8')
            requests(xml)

if __name__ == '__main__':
    main()
```

Python2でのRedmine APIの使い方でハマったのでメモ
Mac作業効率化（Alfredを使ってみた）

# はじめに
Mac を購入してから数週間が経過したのですが、ファイル検索やアプリの起動など
まだまだ不慣れな点が多くもっと効率的にしていきたいと思い、あれこれググっていると
`Alfred`が魅力的だと目にし、実際に導入してみたのでまとめてみようと思います。

## Alfredとは
一言でいうならランチャーアプリという種類のアプリの一つです。

ランチャーアプリとはアプリやファイルを素早く起動してくれるようなものです。
この Alfred はそれ以外にも便利な機能を兼ね備えています。

実際に Alfred に触れてみたいと思います。

## インストール
まずは[こちら](https://www.alfredapp.com/)からインストールしてみましょう。
現在はバージョン４になっています。

下記の`Download`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/0681ee88-dea5-06f7-ca5c-3998e675b716.png)

インストールが完了するとすぐに使用できます。

## Alfred 起動方法
`option`+`space`で起動することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/5b99ffed-e0f9-2326-1979-9f39aa841601.png)

デフォルトでは`option`+`space`ですが
下記の画面からショートカットキーの変更も可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/562475c6-6ff5-51ff-83bf-5b681f627b0a.png)

## アプリを起動させる
使用したいアプリ名の文字を打ち込むだけで
簡単に対象アプリを起動させることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/a631cbe4-e6ee-4697-a7c8-6c18cd18183b.png)

## Webサイト検索
アプリだけでなく Google などのWebサイト検索も Alfred 上で行えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/75b9c5b3-1b02-efea-aa96-cdb1c439c94a.png)

## ファイル、フォルダ検索
Alfred 上で`space`を入力すると`'`と表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/4768a5fd-1486-9cd6-5ebc-f71ae2a40a88.png)

`'`の後ろに検索したファイル名やフォルダ名の文字を入力することで開くことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/7236bd06-59a0-8066-4686-ce86a16b0ea6.png)

## 画面ロックやシャットダウンなど
アプリやファイル以外にもシステム機能を操作できます。


`lock`で画面のロックを行うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/2189f6dd-6d21-b4f0-b66e-7202462c58cb.png)

`shutdown`でMacをシャットダウンさせることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/dea5310f-5289-205a-b168-5171675bda9a.png)

上記以外にも便利なシステム機能のショートカットが存在するので調べてみてください。

## お気に入りのWebサイトを呼び出す
最後によく使用するサイトを Alfred に登録する方法を説明します。
今回は Qiita を登録して呼び出そうと思います。

1. `option`+`space`で Alfred を呼び出します。

2. `al`などを入力して Alfred を呼び出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/8af95e2f-6a6c-0695-d91d-140c70075ba5.png)


3. 左の欄の`Features`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/73a371ca-76c8-1d19-9fda-85555183884a.png)

4. `Web Search`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/0c2fc5fb-eb05-8dd1-434b-43cafb89abb7.png)

5. 画面右下の'Add Custom Search'をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/fe3236f7-4833-54de-0257-2405207f341e.png)

6. URL、タイトル、検索キーワードを入力します。（`Drop icon`はGoogleで検索したアイコンをドラックアンドドロップで貼り付けることが可能です。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/9863ac25-6bc1-fd13-ab53-dc46257a9633.png)

7. これで`Save`をクリックして完了です。

Alfred 上でキーワードを入力すると登録したタイトルとアイコンで表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/062fcd83-a1e0-7262-44fd-d9e38b122c12.png)

無事 Qiita にアクセスすること確認できたので
これから色んなサイトを登録してみようと思います。
python2でRedmien

```python:redmine.py
# coding: utf-8

import csv
import urllib2

csv_filename = r'fullpath'
with open(csv_filename) as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print row['project'], row['title'], row['subject']

api_key = 'api-key'
url = 'http://ip/redmine/issues.xml'
xml = """<?xml version="1.0"?>
<issue>
<project_id>""" + str(row['project']) + """</project_id>
<subject>""" + str(row['title']) + """</subject>
<description>""" + str(row['subject']) + """</description>
</issue>"""

print xml

request = urllib2.Request(url, data=xml)
request.add_header('Content-Type', 'text/xml')
request.add_header('X-Redmine-API-Key', api_key)
request.get_method = lambda: 'POST'

# 登録実行
response = urllib2.urlopen(request)
ret = response.read()
print 'Response:', ret
```
[RuboCop] UnknownEnvironment 警告の解決方法

対象 ver: rubocop (0.71.0)

## テストで Rubocop が警告を吐く [ C: Rails/UnknownEnv: Unknown environment staging?. ]
Rails アプリに staging 等の環境を追加して `Rails.env.staging?` といった処理を書くと、RuboCop に警告されます

出力されたログ ※一部を省略しています

```
$ rails rubocop

Inspecting 50 files
.....................C............................

Offenses:
app/controllers/hoge_controller.rb:51:60: C: Rails/UnknownEnv: Unknown environment staging?.
        if Rails.env.production? && Rails.env.staging?
                                              ^^^^^^^^
50 files inspected, 1 offense detected
```
どうやらデフォルト以外の環境を自動で認識してくれない模様


## 解決策
.rubocop.yml に以下を追加

```
Rails/UnknownEnv:
  Environments:
    - production
    - development
    - test
    - staging
```
※上記のオプションを追加する場合、デフォルトの環境( test, development, production )も併せて記述する必要があるので注意してください


## いきさつ
※以下は興味のある人向け

現在作成している Rails アプリには、デフォルトで定義されている

- test
- development
- production

に加えて

- staging

環境を定義しており、AWS 上で問題なく稼働していました。
しかし、コード中に

```
if Rails.env.production? && Rails.env.staging?
```
という一行を追加したところ例の警告が...

(staging 環境が正しく定義できていないのか?でも環境動いてるし...)
などと思いながら調べていたところ、[Issue](https://github.com/rubocop-hq/rubocop/issues/4956) を発見。

Issue の情報をもとに yml に例の設定を追加したところ、無事にテストが通りました。

以上

内容に間違い等ありましたらコメントでご指摘ください。
この記事が参考になりましたら幸いです。


## 参考
- [見つけた Issue](https://github.com/rubocop-hq/rubocop/issues/4956)
- [RuboCopのドキュメント](https://www.rubocop.org/en/stable/)
- [RubyDoc.info](https://www.rubydoc.info/github/rubocop-hq/rubocop/master/RuboCop/Cop/Rails/UnknownEnv)
Apache Commons BeanUtils はまりポイント

[Apache Commons BeanUtils](http://commons.apache.org/proper/commons-beanutils/)を使ったときにはまったことのメモ

##### 確認したバージョン

* Java 8
* Apache Common BeanUtils 1.8.3～1.9.4

##### 検証コード

Bean.java

```java
public class Bean {
	private Timestamp timestamp;

	public Timestamp getTimestamp() {
		return timestamp;
	}
	public void setTimestamp(Timestamp timestamp) {
		this.timestamp = timestamp;
	}
}
```

Main.java

```java
public class Main {
	public static void main(String[] args) throws Exception {
		Bean bean = new Bean();

		// 1.9.3以前では、Object.getClass()をアクセサと解釈して"class"がプロパティ一覧に含まれる。
		BeanUtils.describe(bean);
		// => 1.9.3以前：{class=class test.Bean, timestamp=null}
		//    1.9.4：{timestamp=null}
		// ※ PropertyUtils.describe(bean) も同様の結果となる。

		// 1.9.3以前では、setPropertyとcopyPropertyでアクセスできないプロパティを設定したときの挙動が異なる。
		BeanUtils.setProperty(bean, "class", Bean.class);
		// => 何も実行されない。
		BeanUtils.copyProperty(bean, "class", Bean.class);
		// => 1.9.3以前：java.lang.reflect.InvocationTargetException: Cannot set class が発生する。
		//    1.9.4：何も実行されない。(BEANUTILS-520の影響で振る舞いが変わった？）

		// setPropertyとcopyPropertyで一部の型のプロパティにnullを設定しようとしたときの挙動が異なる。
		BeanUtils.setProperty(bean, "timestamp", null);
		// => org.apache.commons.beanutils.ConversionException: No value specified for 'java.sql.Timestamp' が発生する。
		BeanUtils.copyProperty(bean, "timestamp", null);
		// => 1.8.3以前：copyProperty同様にConversionExceptionが発生していた。
		//    1.9.0以降：何も実行されない。(BEANUTILS-454にて修正)
	}
}
```

##### 参考

* https://issues.apache.org/jira/browse/BEANUTILS-454
* https://issues.apache.org/jira/browse/BEANUTILS-520
AzureVM にssh公開キーで接続【Mac】

AzureVM へのssh公開キーでの接続の方法です。
毎回パスワードを入力しなくても、この設定をすれば公開キーでのssh接続が出来るようになります。

## 環境

今回の私の環境は以下の通りです。

* macOS Catalina バージョン10.15.2
* iTerm2 Build 3.3.4

AzureVM はcentOSですが、特に関係ないです。またiTerm2ではなくても、標準搭載のterminalでも可能だと思います。

## 公開鍵の作成

ディレクトリは`~/.ssh`で鍵をつくるほうが良いです。

```bash
$ cd ~/.ssh
```

`.ssh`にパーミッションを割り当てます

```bash
$ chmod 700 ~/.ssh
```

ディレクトリが移動できたら、以下のコマンドを入力して、キーペアを作成します。

```bash
$ ssh-keygen -m PEM -t rsa -b 4096
``

このコマンドで4096ビット長の鍵を作ることができます。

次に以下のように聞かれるので、任意の値を入力します。
今回は`test-rsa`という鍵名の鍵を生成します。

```bash
Generating public/private rsa key pair.
Enter file in which to save the key : test-rsa
Enter passphrase (empty for no passphrase):(ここに任意のパスフレーズ。後で使うので忘れないように)
Enter same passphrase again:(パスフレーズを再入力)
Your identification has been saved in test-rsa.
Your public key has been saved in test-rsa.pub.
```

`test-rsa.pub` が公開鍵です
以下の２つのファイルが生成されました

* test-rsa
* test-rsa.pub

## AzureVMの設定

今回はすでに作成済みのVMをssh公開キー認証に変更します。
新規作成する際は、作成時にssh公開キーを選択するだけです。

Azureから仮想マシンを開き、左側のタブの `サポート + トラブルシューティング` から`パスワードのリセットを`選択します。

![スクリーンショット 2020-01-28 22.06.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492847/bd1911db-8c52-c69d-2111-e2767cf47683.png)


ssh公開キーのリセットを選択して、ユーザー名を入力します。
ssh公開キーには先程作成した`test-rsa.pub`を入力します

```bash
$ cat ~/.ssh/test-rsa.pub

ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxxxx(略)xxxxxxxxxxxxxxxxxxxx yourname@MacBook-Air.local
```
上記のように表示されます(xの部分に鍵が入ります)`ssh-rsa`から自分のMacのユーザー名(yourname@MacBook-Air.local)より手前をコピーしてAzureのssh公開キーの欄に入力します。

## SSH configの設定

`~/.ssh/`に`config`を作成し、以下のように入力します

```bash
$ vim config

Host test(VMの名前)
   HostName (VMのipアドレス または DNS名)
   User (VM作成時のユーザー名)
   IdentityFile ~/.ssh/test-rsa
   Port 22
```

## ssh-agentの設定

SSHサインインのたびに秘密キーファイルのパスフレーズを入力しなくてすむように、`ssh-agent`を利用します。

```bash
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/test-rsa

Enter passphrase for /Users/yourname/.ssh/test-rsa: (先程設定したパスフレーズ)
```

## SSHログイン

これでssh公開キーを使ってログイン出来るようになりました。
以下のコマンドです。

```bash
ssh (VMのユーザー名)@(VMのip または DNS名)

Are you sure you want to continue connecting (yes/no)? yes
(VMのユーザー名)@(VMのip または DNS名)'s password:
```

初回のみ、接続しても良いですか？と聞かれるので`yes`
これも初回のみ先程設定したパスフレーズを聞かれるので入力

Done!!!!
My First Attempt to Post a Note / Qiita初投稿に挑戦！

# My First Attempt to Post a Note
I'm gonna get used to markdown notation.
btw, if you wanna write a header, you can add # in front of the line,
# and it's gonna be like this.
...was that too big? lol

well, you can also add more ###,
## and you can see your line,
### gets smaller and smaller
#### if you like it, just try and see how it works :)
##### Thanks for reading this
###### (okay, this is the smallest size, I suppose.)



# 初投稿の記事です。

Markdownの記法に慣れていきたいと思います。

おさらいですが、タイトルにあるように、大きい字を書きたいときは、パウンド記号「#」とスペースの後に続けて、書きたいことを書いてやると、
# 見出しのように大きな字になってくれます。
・・・馬鹿みたいに大きいですね（笑）

流石に大きすぎるかな、ともし思ったら、パウンド記号「#」を続けて
## 「###」と書いていくと、
### 書いた分だけ字が小さくなります。

#### みなさん、もしよかったら、
##### Qiitaの投稿やGitHubのREADMEを書くときに使ってみてください！
###### 読んでくれて、ありがとうございます！（このくらい小さくなりました）
Railsでシンプルな検索機能を実装する

RailsでGem等を使わず、余計なメソッドを作ったりもせずにとにかくシンプルに検索機能を実装する方法です。

今回はtitleというカラムを持つpostsテーブルを検索するという状況設定で話をします。


#フォームを作る
index.htmlに検索フォームを作ります。
検索はテーブルに変更を与えないため、form_tagを使用します。

```erb:view/index.html.erb
<%= form_tag('/search', :method => "get") do %>
 <input type="text" name="keyword">
 <input type="submit" value="検索">
<% end %>
}
```

#コントローラーに検索用のアクションを定義する
２行目で検索フォームから送信された値をkeywordというパラーメーターで受け取っています。
３行目ではtitleに@keywordを含む列を検索し、@postsに代入します。

```ruby:posts_controller.rb
def search
 @keyword = params[:keyword] 
 @posts = Post.where("title LIKE ?", "%#{@keyword}%")
end
```

#検索結果の表示
まず検索結果を表示するためのページをルーティングで設定します。

```ruby:routes.rb
get 'search' => 'posts#search'
```

最後に検索結果を表示するためのhtml.erbファイルを作成します。
今回は適当に検索結果のtitleだけ表示します。

```erb:view/search.html.erb
<% @posts.each do |post| %>
 <%= post.title %> 
<% end %>
```
vscodeでpythonを保存時に実行するマクロを使う

適当なマクロエクステンションをインストールする
https://marketplace.visualstudio.com/items?itemName=geddski.macros

settings.jsonにマクロを設定する

```
		"macros":{
			"redirectTextFileAndRunPython":[
				"workbench.action.files.save",
        {
					"command": "workbench.action.terminal.sendSequence", 
					"args": { "text": "python app.py < input.txt\n" }
				},
				],
		},
```

keybindings.jsonにマクロ名を記述する

```
{
		"key":"ctrl+q",
		"command":"macros.redirectTextFileAndRunPython"
}
```

#追記
エクステンションなど入れなくてもkeybindできました！お恥ずかしい！

```:これだけ！
	{
		"key":"ctrl+q",
		"command": "workbench.action.terminal.sendSequence", 
		"args": { "text": "python app.py < input.txt\n"}
	}
```
パラメータなしのPOSTリクエストをPHPUnitでテストする

朝からPRONTOに行って、個人開発アプリTranderの開発を進めた。前回から課題になっていた`SettingApiTest`の実装を進めた。内容は、`/api/setting`への`POST`リクエストが成功することを確かめるものだ。

しかし、リクエスト時にパラメータを送信しない実装であるため、ログインユーザーとしてどのようにテストするかを課題にしていた。

結論としては、ログイン（`/api/login`への`POST`リクエスト）→セッティング（`/api/setting`への`POST`リクエスト）という流れで実装できた。以下に全体の流れを示す。

- ①テストユーザ作成
- ②作成したテストユーザ検索
- ③ログイン
- ④setting_APIにリクエストして成功する

# 前提
- Laravel 5.7
- PHP 7.2
- PHPUnit 7.5.18

# ①テストユーザ作成
`factory`を使ってテーブルにデータを挿入している。
 
```src/tests/Feature/SettingApiTest.php
$this->setting = factory(Setting::class)->states('register user and safe distance')->create();
```

基になる`Setting::class`を用意しておいて、`state`で値を差し替える形にした。テストケースに応じて柔軟にテストデータを用意できるひとつの方法だと判断したからだ。以下は作成した`SettingFactory.php`である。

```src/database/factories/SettingFactory.php
<?php
    
use Illuminate\Support\Str;
use Faker\Generator as Faker;
    
/**
 * setting登録
 */
$factory->define(App\Setting::class, function (Faker $faker) {
    return [
        'user_id' => null,
        'min_distance' => null,
        'max_distance' => null,
    ];
});
    
/**
 * setting登録（ユーザー登録・範囲内の距離）
 */
$factory->state(App\Setting::class, 'register user and safe distance', function (Faker $faker) {
    return [
        'user_id' => function () {
            return factory(App\User::class)->create()->id;
        },
        'min_distance' => 15,
        'max_distance' => 78,
    ];
});
```

なお、`user_id`は`users`テーブルの`id`と紐付ける形にしている。

# ②作成したテストユーザ検索
作成したテストユーザを取得している

```src/database/factories/SettingFactory.php
$user = DB::table('users')->where('id', $this->setting->user_id)->first();
```

# ③ログイン
`$user`を使い、`/api/login`に`POST`リクエストを送信してログインする。

```src/database/factories/SettingFactory.php
$response_test = $this->json('POST', route('login'), [
  'email' => $user->email,
  'password' => 'secret',
]);
```

# ④setting_APIにリクエストして成功する

`/api/setting`に`POST`リクエストを送信し、正しくレスポンスが返ってくるか確認している。

```src/database/factories/SettingFactory.php
$response = $this->post(route('setting'));
$response
    ->assertStatus(200)
    ->assertJson([
        'user_id' => $this->setting->user_id,
        'min_distance' => $this->setting->min_distance,
        'max_distance' => $this->setting->max_distance
    ]);
```

# 結論
パラメータなしで、かつログインユーザとしてある機能に`POST`リクエストを送る必要がある場合、PHPUnitでのテストはまず`/api/login`に`POST`リクエストを送信してログインしてから実施する必要がある。

他に良い方法、ベターな書き方があればコメント欄でお知らせください。
vuexのgetters,state,mutations,actionsについて自分用メモ

#vuexのgetters,state,mutations,actionsについて自分用メモ
最近vue.jsとvuexを使ったAPIのつなぎ部分を作成する機会があり、
vuexについて自分用メモを残すために書きます。

##actions
actionsはAPIとのデータのやり取りをする場合に使う。
例えば、DBからデータを取ってくる。
なんてときに使うAPIを叩くときにactionsを使うようにする。

##mutations
例えば、actionsで取ってきたデータをstateに入れる役割を持っている。
stateのデータを唯一変更することを許されている。
したがって、mutation以外でstateのデータを変更することは基本的にやらないほうが良い
mutation以外でデータを変更してしまうと、データの信頼性が損なわれてしまう。
あとわかりにくいソースになっちゃう。

##state
actionsでAPIから取ってきたデータを保存しておくオブジェクトです。

##getters
stateにあるデータを取ってくる処理を書く。
gettersがAPIを叩いてデータを取ってくる処理は書かないようにする。

自分用メモとして書いています。
間違った認識しているところがあれば、コメントいただけると幸いです。

##参考資料
vuex公式ドキュメント
https://vuex.vuejs.org/ja/
streamでFizzBuzzを出力する

#導入
こんにちは。けちょんです。
**皆さん、stream使ってますか？**
私は数日前に学んだのですが、めっちゃはまってます。
業務中も隙あらばいじってます。
今回はstreamを使ってFizzBuzzを出力してみます。

#やってみる
##なにはともあれ、1~100までを生成
```java
IntStream.range(1,101);
```
rangeClosedではなく、rangeの理由はショートコードを意識しました。
（最終的にそんなに短くならない）

##mapToObjを使って、FizzBuzzを作成

```java
IntStream.range(1,101).mapToObj(i->i%3==0&&i%5==0?"FizzBuzz":i%3==0?"Fizz":i%5==0?"Buzz":i).forEach(i->System.out.println(i));
```
はい、書いてて辛いし、きっと皆さんも辛い。

```java
i->i%3==0&&i%5==0?"FizzBuzz":i%3==0?"Fizz":i%5==0?"Buzz":i
```
この部分でFizzBuzzを実装してます。
3項演算子で、以下の順に文字列に変換してます。
1. 3でも5でも割り切れるならFizzBuzzに変換
2. 3で割り切れるならFizzに変換
3. 5で割り切れるならBuzzに変換
4. そのまま

出力結果

```java
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
・・・
```
よさげですね。

#短くしてみる
現在129byteですが、もう少し短くできますね。

##メソッド参照を使う
メソッド参照を使うと、引数を省略できます。
```i->System.out.println(i)```を```System.out::println```と表記できます。


```java
IntStream.range(1,101).mapToObj(i->(i%3==0&&i%5==0)?"FizzBuzz":i%3==0?"Fizz":i%5==0?"Buzz":i).forEach(System.out::println);
```
これで124byteです

##==を>で書く
その方が一文字短いですね。

```java
IntStream.range(1,101).mapToObj(i->(i%3>0&&i%5>0)?i:i%3>0?"Buzz":i%5>0?"Fizz":"FizzBuzz").forEach(System.out::println);
```
これで120byteになりました。
**さらに短くする方法を募集中です**

#まとめ
stream楽しい

#追記
コメント欄にてより短いコードを書いてくださりました。

```java
IntStream.range(1,101).forEach(i->System.out.println((i%3<1?"Fizz":"")+(i%5<1?"Buzz":i%3<1?"":i)));
```
FizzBuzzの文字列の冗長さを取り除いています。
mapToObjを使わず、そのまま出力。
なんと100byte!!
シールド言語var0.1

#シールド言語var 0.1
この言語はPython,C#,Kotlin,vの良いなと思ったところを取り込んだ自作言語です。拡張性が高く速度もJava並みJitのようにメモリ使用は多くなく並列化も難しくありません。

```ex.shie
using Sys
using Os <-Os.ptr,Os.Pointer.Nullptr,Os.Pointer.thisptr,Os.Pointer.ID,Os.Pointer.Out,Os.Environment.Exit等
using Collection #<- class Enumerable,class Range,class Array,class List(デフォルト),class Dict,class...
from Sys using static Console
from Sys using Environment <-Exit,
from Sys using static Math
delegate file as files //関数別名

static class ex():
    def do_File() ():
        opt var t = 1
        opt f float = Null
        lst = new int [[1,2,3],[6,7,2,4],[7,10,24,66,13]] #リスト
        lst1 = new int [10,30]
        lst2 = new [[val = for(x in Range(10)) if(x == 4 and y == 6) break] for(y in Range(10))]
        itg := 1 #イミュータブル ERROR itg = 3
        string := "VVAN.png"
        opt fstring str = Os.File.Is_Pass(string) #パスがない場合None Unit
        if (not fstring):
            return #自動でNone Unit
        else:
            WriteLine(string+"は" + fstring"に存在します")
            return 

    pub def Main(Matual_Girls str):
        WriteLine(ex.do_File()) #staticオブジェクト参照はオブジェクト名.でアクセス。普通の場合はthis.でアクセス out->None
        ex.mycls = cls() 
        ex.mycls.show()

struct stl:
    pub def _init():
        pub self.x = 500
        pub self.y = 400
        pub self.z = 0

class cls():
    pub def _init():
        get set del this.mylist = [for(i in Range(10)) if(i%3 is _Nothing()) 1 elif(i%2 is _Nothing()) 2 else Null] //elseの時はNull
    
    pub def show():
        WriteLine(for(l in this.mylist))
        get set del opt this.stl_s stl = Null

if(_name == "__main__"):
    ex.Main()

(*
    変数は オプション 変数名 型 = 変数
    メンバーオブジェクトアクセスはself.~,this.~
    Unit型(C++でいうnullptr_t型)はNoneとNullのみ。普通のメソッドはNoneを返す。ジェネリクス等でWhere selfと書くと値型で非staticなものWhere struct と書くと全ての値型が取り出される。Unit型は特殊で、Unit classと書くとNoneのみUnit struct と書くとNullのみ。Where t is false と書くと_Nothing()値が選ばれる。
    ジャンプ命令はbreak(##<T>),continue(##<T>),return,yield,yield break,yield continueがある。
*)
```
#シールド言語の仕組み
事前コンパイル(スタティックリンク)->jcpファイル生成(コンテナで動くファイル)->コンテナ(ダイナミックリンク/GC/プラットフォーム間の特異点を吸収)->Jitコンパイル->実行で動く言語VMと比べてCPU/メモリ使用量が少ないので良い。**速度は*Java*程度の能力**があるようにしたて出ししたいので**後悔しませんね？**って言われても**はい**と答えましょうか。
bootstrapでサイドバーの設定

bootstrapのグリッドを使用してサイドバーの設置をしようとした時にはまったため、共有します。
(コードは読みやすさ重視にしているため簡単に書いています。)

##やりたいこと
左側のサイドバーは固定し、右側のサイドバーはページによってつける。

##はまったところ
・`<div class="col-sm-2">`と左側のサイドバーの範囲指定。・・・①
・`<div class="col-sm-10">`の中でそれ以外の内容を表示。・・・②
・`index.html.erb`の`<div class="col-sm-8">`でメインの表示。・・・③
・`<div class="col-sm-2">`と右側のサイドバー・・・④

このままでは①②③は思うようにできるのですが、
④の右側のサイドバーにしたいところが③の下に表示されてしまいます。

```erb:application.html.erb
<!DOCTYPE html>
<html lang="ja">
  <head>
    #(省略)
  </head>

  <body>
    <div class="row">
      <div class="col-sm-2">
        ①左側のサイドバー
      </div>
      <div class="col-sm-10">
        ②<%= yield %>
      </div>
    </div>
  </div>
    #(省略)
  </body>
</html>
```

```erb:index.html.erb
<div class="col-sm-8">
  ③メインのコード
</div>

<div class="col-sm-2">
  ④右側のサイドバー
</div>
```

##解決方法
グリッドの中でさらにグリッドを使って横並びにしたい時には`<div class="row">`と
例全体を囲むと、③と④を横並びに配置することができます。

```erb:index.html.erb
<div class="row"> #追加部分
  <div class="col-sm-8">
    ③メインのコード
  </div>

  <div class="col-sm-2">
    ④右側のサイドバー
  </div>
</div>
```
チェックボックスでチェックされている値を全て取得するワンライナー

```javascript
const values = [...document.getElementsByName('checkBoxName')].filter(elm => elm.checked).map(elm => elm.value);
if (values.length === 0) {
  alert('チェックボックスをチェックしてください。')
}
```

ES2015じゃないと動かないですが、新しいブラウザなら動くと思います。

domの配列だと機能が足りないので、一旦、jsの配列に変換しているところがポイントかと思います。
テスト実行者が漏れなく、ダブりなく、結合テストを進めるには

## はじめに
今度、結合テスト手伝ってもらうから～！
プロジェクトで突然、そんな場面に出会うこともチラホラ。
テスト仕様書見ながらひたすら項目こなせばいいだけでしょ？
・・いえいえそんなことありません。

やり方を間違えれば、

- 期間内に終わらない
- 重要な観点を見落として、後の工程 or リリース後に障害発生（→ テスト実行者誰や～?ってなるやつ）

などなど、いろいろと問題になりかねないので、心して臨む必要があります。

自身の経験も踏まえ、漏れなく、ダブりなく、結合テストを進める手順をまとめてみました。

※様々なテストがありますが、今回は結合テストにのみフォーカスしています。


## 結合テスト実行手順
### 1. スケジュール、制約事項の確認
まずはスケジュール、制約事項の確認をします。

- 期間、ボリュームはどのくらいか?
- どのような環境、ツールを使うのか?
- 不具合が見つかったらどうするのか?（エスカレーションの方法、頻度など）

などなど。テストを進めるにあたって必要な情報を把握しておきましょう。

### 2. 実行環境の準備
次に、テスト実行に必要な環境やツールの準備を行います。
テスト実行時に不足のないよう、この段階で一通り整えておきましょう。

### 3. 設計書、テスト仕様書の確認
続いて、設計書、テスト仕様書に目を通しておきましょう。
ありがちのが、テスト仕様書は見るけれども、設計書は見ないケース。
テスト仕様書の内容がわかりやすく的確であればかまわないのですが、必ずしもそうとは限りません。

例えば、次のようなケース。

機能概要：試験問題を解き終え、終了ボタンを押す。70点以上の場合は「合格」、70点未満の場合は「不合格」と表示される。

そして、結合テスト仕様書が以下のようになっていたとします。

| 画面 |操作|期待値|備考|
|:------------|:------------|:------------|:------------|
|結果画面|終了ボタンを押下すること|結果が合格であること|正答率70%で試験を終了すること|

この場合、確認すべきなのは、画面の表示でしょうか? テーブルの値でしょうか? それとも、両方?
・・正解は、設計書の内容によります。

期待値の内容が、

- 結果画面に合格と表示されていること
- scoreテーブルの合否フラグの値が1（合格）であること

のように詳細に書いてあればいいのですが、上の表のように曖昧な書き方をされている場合は何をもって合格とすればいいのか、ハッキリしません。
独断と偏見で進めると、後々富んだ大事故になりかねないので、設計書も一通り読んで、テスト実行時に具体的に何を確認できればよいのか？把握しておきます。

・・実際に上のような結合テスト仕様書に出くわして不具合を見逃してしまい、後の工程で発覚、手戻りが発生してたいへんなことになりかけたことがあります。
（テスト設計レビューの段階で修正しておいてほしいところではありましたが、、）


何らかの問題が起こったことによる再テストの場合は、不具合チケットなどを確認し、問題とそれに対する対応内容も把握しておきます。

また、この段階で必要に応じて、実装者やテスト設計者に確認をとり、疑問点を払拭しておきましょう。
（不具合や手戻りを最小限にとどめるためにも、この後のプロセスでも、疑問点があれば適宜確認を。）

### 4. テスト実行順序の決定
例えばWEBサイトの場合、テスト項目はたいてい画面単位で順に並んでいるため、そのまま順番通りやると非効率です。
どの順序でやるとスムーズか考え、必要なデータや条件などでパターンわけしておきましょう。

例えば、次のようなケース。

機能概要：ユーザーIDでログイン → 結果画面に合否を表示 → 詳細画面に得点を表示する。
備考：70点以上の場合は「合格」、70点未満の場合は「不合格」

そして、テスト仕様書が以下のように書かれていたとします。

|No|画面|操作|期待値|
|:------------:|:------------|:------------|:------------|
|1|結果|得点が70点以上のユーザーでログイン|・合格と表示されること|
|2||得点が70点未満のユーザーでログイン|・不合格と表示されること|
|3||詳細ボタンを押下|・詳細画面に遷移すること|
|4|詳細|得点が70点以上のユーザーで詳細画面に遷移|・DBに登録されている得点が表示されること<br>・得点が70点以上であること|
|5||得点が70点未満のユーザーで詳細画面に遷移|・DBに登録されている得点が表示されること<br>・得点が70点未満であること|

この場合はどうでしょうか?
上から順に進めるよりも、

- 1 → 3 → 4
- 2 → (3) → 5

のように進めたほうがスムーズですよね。

テストのボリュームが多くなればなるほど、パターン分けも複雑になるので、無理しすぎない範囲で（このプロセスに時間を取りすぎるのもよくないので、、）やっておきましょう。


### 5. テストデータの準備
続けて、4でわけたパターンに対応したデータを準備します。
このパターンの場合はこのデータを使う、と一覧にまとめておくと実行時に楽です。

手順4であげたテストケースの場合、以下のような感じ。
（実行順序も併せて書いています。）

||パターン1|パターン2|備考|
|:------------|:------------|:------------|:------------|
||合格|不合格||
|ユーザーID|0001|0002|userテーブル|
|得点|70|69|scoreテーブル|
|実行順序|No|No||
||1|2||
||3|(3)||
||4|5||

### 6. テスト実行、報告
いよいよテスト実行です。
手順4, 5で決めた順序とデータを使って進めていきましょう！
不具合が出た場合は、不具合チケットの起票等を行うなどして、都度報告していきます。
（この辺りの対応はプロジェクトによって異なるので、手順1でぬかりなく確認しておきましょう。）

テストを実行し終えたら、実行結果や画面キャプチャなど、成果物の提出も忘れずに！

### 7. 振り返りの実施
プロジェクト全体で振り返りを行うところもあると思いますが、個人でも振り返りを行い、よかった点、改善点をピックアップして、次回、よりスムーズに進められるようにしておきましょう。
PDCAサイクルをまわしていけば、最強のテスト実行者になれること間違いなし！

## 終わりに

いかがだったでしょうか?
結合テストはじめ、テスト工程はシステムの品質に重要な役割を担っています。
経験を積みつつ、書籍や勉強会などで学んで、よりスピーディーに、より質の良いテストを実施できるようにしていきたいですね。


## 参考
日頃のテスト、そして、本記事の執筆に、以下の書籍を参考にさせていただきました。

- この1冊でよくわかるソフトウェアテストの教科書 | SB Creative
- 駄目パターンに学ぶ失敗しないソフトウエアテスト実践ノウハウ | 日経SYSTEMS

前者ではテスト手法メインに必要な知識を一通り、後者ではテスターに必要な考え方を学べます。
いずれも比較的読みやすいので、オススメです！
結婚式の写真共有アプリを作って参列者経験を向上させた

本記事は [個人開発 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/private-development) 22日目の記事[結婚式の受付システムを作って参列者経験を向上させた](https://qiita.com/07JP27/items/8f687a7eb906e624f659)のリンク記事です。

# つくろうとしたもの
またまたN番煎じの結婚式での写真共有アプリです。
独自機能として二次会での上映用にアップロードされた写真をスライドショーで流す機能をつけようと思いました！（ダイレクトアクセスのみの隠し機能)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/c2a42b8e-72bd-3d02-3090-7af103ce0084.png)
上の絵は[zoom](https://zoom.us/)の[ホワイトボード機能](https://zoom-shukyaku.com/zoom-%E4%BD%BF%E3%81%84%E6%96%B9-%E7%94%BB%E9%9D%A2%E5%85%B1%E6%9C%89-%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88%E3%83%9C%E3%83%BC%E3%83%89/)を使って新郎新婦とWeb通話をしながら描きました。今後の要件定義や顧客との打ち合わせはこんな感じにすると結構楽かもと思ったり・・・。


# 作ったもの
## 案内カード
アプリを使うための認証コードと使い方を記載したカードを作成しました。式場にフリーWi-FiがあったのでそのSSIDも記載。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/b533895e-f02c-c71f-4af6-fef9c97d76a4.png)



## 写真共有アプリ
###システム仕様
- Webアプリ
- 機能
 - 認証コードを使ったログイン
 - 写真一覧→タップでちょい大きめの写真
 - 写真を一度に最大１０枚までアップロード
 - 管理者用認証コードでログインした時のみオリジナル画質をダウンロードできる（新郎新婦&親族用）
 - アップロードされた画像をスライドショー上映

###言語・フレームワーク
- HTML, CSS, JavaScript 
- Vue.js

###ライブラリ
- buefy : CSSライブラリ「Bluma」のVue.js用ラッパー

###インフラ
- Firebase Hosting: ホスティングサービス
- Cloud Firestore: DB
- Cloud Storage: 写真保存用
- Firebase Authentication: ユーザー認証基盤
- Google analytics：ロギング

###構成&フロー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/e6288add-272d-37dc-fda4-a8e3518b305b.png)


###画面構成
||||
|----|---|---|
|ログイン画面|Firebase Authenticationを使って認証コードログインを実装しました。具体的な方法については[こちら](https://qiita.com/07JP27/items/47787ad757c23a2b1295)| ![IMG_9649.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/3a7c757f-9e98-c549-0a8d-719a69211421.png) |
|ホーム画面| 写真一覧が表示されます。 | ![IMG_9650.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/173779a9-52db-9e0b-1440-e229808975fd.png) |
|詳細画面| 写真一覧でサムネをタップするとモーダルが表示されます。 | <img width="375" alt="IMG_9657.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/c7d8d7ac-0e5b-d624-9304-4a3e1da6498b.jpeg">
 |
|アップロード画面| アップロードエリアをタップするとスマホのフォトライブラリが開いて写真を選択できます。 | ![IMG_9651.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/2d489c34-9ff2-e14a-ed2c-9a991c5eec39.png) |
|スライドショー画面| アップロードされた写真からランダムで15秒間隔でスライドショーが表示されます。Firestoreのリアルタイムリスナーを使うことでスライドショー中に追加される写真も表示対象になります。Fullscreen APIを使うことでフルスクリーンでモニタに投影できるようにしました。 | ![wedding-photo-share 2020-01-28 20-52-51.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/11e8f60e-d99b-c963-6f94-aac895c1ea3c.jpeg)
 |

###画面遷移図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/5c7264bd-d8bc-9bcf-4cac-acedf3d77d38.png)

# 結果
アップロードされた写真の総数は**472枚**でした！
そして、Firebaseの利用料金は**¥0**！

# 今後の展望
- 動画対応：数人のユーザから「動画はあげれないの？」と聞かれて気づきました。確かに結婚式ってケーキ入刀などムービーポイントが多いんですよね。
- AIで人物分類&自動タグ付け：この人が写ってる写真とかシチュエーションでフィルタできればいいな〜。
xamppでmysql利用時のトラブル(PHPからのmysql接続時の認証エラー原因)

###1.phpからmysql接続テスト(突然の認証エラー)

mariadb(mysql)にはrootで入れるの(というかDB作成、テーブル作成まで完了)に、
テストプログラムの接続で失敗。下記のようなエラー画面(caching_sha2_password)
が表示される。

この画面で何のプログラムかわかる人は、きっと天才だ。


![php_auth_err.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494408/c45fe43d-68cd-73f8-1316-2fc09104d7f7.jpeg)

###2．解決法(ホスト名の後ろに何かを指定)

ググって修正した結果が下記のプログラム。

```php:test_dino2_mysql.php
<!DOCTYPE html>
<html lang="ja">
<meta charset="utf-8">
<title>恐竜登録テスト</title>
<h1>開始</h1>

<?php 
	require 'common_dino2.php';
	$select_all = "select count(*) from tbl_dino";

	$dsn = 'mysql:dbname=db_dino;host=localhost:3308;charset=utf8mb4';
	$user = 'root';
	$password = 'root123';

    $dbh = new PDO($dsn, $user, $password);
	
	$ret0 = 0;
	$result_a=get_AllData($dbh,$select_all);
   	//$count
	$count = $result_a->fetchColumn();
	$ret0=$count;
	echo $ret0.",".mt_rand();
 ?>
</html>


```
__実はソース(データソース名)で重要な部分がある。__
\$dsn='mysql:dbname=db_dino;host=localhost:__*3308*__;charset=utf8mb4';

__ローカルホストの後ろのポート番号が必要なのである。__

このポート番号を記述しないと、認証エラーが起きる。
(私の場合はデフォルトのポート番号を変更したためかも)

これにより正常に接続できる。
![php_auth_ok.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494408/bceecb29-40ca-603b-c683-137fefdf0ce0.jpeg)
Facebook広告にログインできないエンジニアが標準イベントなどの計測を実装するための情報共有について

Facebook広告で購入などのイベントを測定するために**必要な情報・手順（アカウント＋コード）**を、広告運用者が、ログイン権限・アカウントのない(※)エンジニア（実装担当者）に簡単に共有する方法のメモ。
※共有アカウント/同時ログインは基本Facebookから認められていないため、こうしたケースがありうる。

#前提(標準イベントとカスタムコンバージョンについて)
Facebook広告でイベント/コンバージョンを測定すれば、そのデータを入札戦略などに使うことで広告を最適化することができる。そのためには、

1. まず、HTMLに「**[Facebookピクセルベースコード](https://www.facebook.com/business/help/742478679120153?id=1205376682832142)**」を追加する
2. そのうえで、以下いずれかを設定する
    - **標準イベント**
    - **カスタムコンバージョン**

(※詳細：[標準イベントとカスタムコンバージョンの違い](https://www.facebook.com/help/1669861173231595))

※備考：**カスタムコンバージョン**は、管理画面でURLをコンバージョンポイントとして指定すれば測定が可能になるため、設定がシンプル・簡単。一方**標準イベント**は、Facebookが推奨しているテンプレ化されたイベント取得方法。精緻なデータを取得できるが、イベントの内容をコードに追加するカスタマイズが必要（∴カスタムコンバージョンよりはエンジニアに実装を依頼するケースが多いと思われる（つまり手順を共有するケースが多い））。


#手順を共有する手順

① 広告マネージャ≫イベントマネージャ≫ピクセルを表示
<img width="869" alt="facebook-console - pixel.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/e41ce886-b218-dee3-5cec-3c95d15c20ce.png">

② 「開発者にメールで手順を送信」を選択
<img width="456" alt="facebook-console-setting-pixel-developer.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/6fae581f-58af-533b-57b5-93d2396d5bbf.png">

③ 宛先を指定して送信する
<img width="902" alt="facebook-console-setting-pixel-developer-detail.png.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/846db56a-fc79-7dcc-312e-b322072b8c33.png">
このポップアップ通りの情報（以下必要な情報）が送られる

- Facebookピクセルのベースコード
- [標準イベント計測のための追加コード](https://www.facebook.com/business/help/402791146561655)

#その他:検証の手順
④ エンジニアはイベント計測を実装したサイトをブラウザで読み込み、HTTPリクエストを確認し、実装の成否を確認する
Request URL: https://www.facebook.com/tr/?id={アカウントID}&ev={イベント名(PurchaseやAddToCartなど)}
<img width="863" alt="facebook-ads-event-request.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/43cb1587-590e-c0ba-5dac-a1c1bbc16872.png">
※(③)に記載の手順｢4 ピクセルステータスを確認する｣は管理画面を見ることが前提の検証方法だが、エンジニアはブラウザの通信内容を見ることでコードの動作を仮チェックをすることができる。

⑤ 運用者は管理画面で計測状況を確認する
※ちなみに「広告マネージャ≫URLパラメータを作成」で以下のようにキャンペーンソース / キャンペーンメディアを設定をすると、`utm_***`というURLパラメータが広告URLに付与される。このパラメータによりGoogleアナリティクスのレポート「参照元 / メディア」でFacebook広告経由のコンバージョンが計測できるため、計測状況の比較ができる。
<img width="545" alt="ads-manager-utm-parameter-setting.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/47351be1-2b74-cc73-6ffd-e899186cf037.png">



---
何かあればお手数ですが、本記事か以下アカウントでお知らせください！

**\ *Follow Me!* /**
**[*Qiitaアカウント*](https://qiita.com/MasatoEmata)**
**[*Twitterアカウント*](https://twitter.com/masatoemata)**
【Pandasの勧め】数十万行あるエクセルシートを、n個のCSVに分け各ファイルに連番を1から振る例。

# そうだ、Pandas(python)にしよう
　社内のエクセルをどうにかするのを、2020年にもなったのでさすがにVBAは止めて、そろそろ、Pandas&pythonにしよう、という小話。
　以下、Python入門記事とかは読んだことある人向けなので、細かい解説は抜き。
Pandasやpythonの情報はwebにはいっぱい転がっているから、Pandas&pythonを使ってみようと思った良い子は、困った時は、いろいろググって見てね。


## (学生さん向け？の付記)　コンプライアンス強化がうたわれる中で...
　テレビCMなんかで多くの人が名前はご存知だったりする、いわゆるユーザー企業というところでは、平成の古(いにしえ)のAcesssでのクエリがどこぞのデータベースにクエリを発行してから個人情報入りのファイルをエクセルに出力して...そのあと、ローカルでちまちまと切り貼りして何か別の用途に使ったりなんて事務作業があったりします。
　上場企業の場合、こうした作業がコンプラ的に微妙とか言われちゃうことがしばしばあるのです(誰が個人情報を目にしたのか、すべて明らかにする、といったところがコンプラ的な要請の例)。
　そんな時は、取り急ぎ、AWSなどのサーバ上のWindowsでAccessを動かすようにして、定時実行で出力されたCSVをサーバ側で処理を完結させるようにしちゃえば、ひとまずコンプライアンス的にオーケーなわけです。AWSならば、SystemsManagerでスクリプトを走らせてS3にファイル置いてしまう...といったあたり。ところが古いAccessがある企業では、それに付随したVBスクリプトだのVBAだのがあって、辛いので、もうそこは Pandas&pythonに置き換えちゃいなよという話。

# [1]準備作業:エクセルの特定シート手作業支度
## 1-1.pandasでエクセルを読めるようにライブラリをインストール
```
$ pip install xlwt
$ pip install openpyxl
```
pnpってなんですか、という方はPandas&pythonの日本語解説で外さない鉄板、こちらのnkmk様あたりからいろいろググってください:
>https://note.nkmk.me/python-pandas-to-excel/

## 1-2.pandasでエクセルのn番目のシートを読む。
Excelのシートのどれか一つをサクッと読めると便利ですよね。
Pandasでは、ExcelのシートをDataFrame(df)というものにすぐに変換できます。

```.py
n=0 #pandasではエクセルのシートの右から順に0,1,2...と指定します。
# targetというファイル名のn番目のシートを読む例
df= pd.read_excel(target, sheet_name=n)
```

、ExcelのシートをDataFrame(df)として読み込むのは、その一部分だけを取り出したり、特定の列を消したり加えたりできるところ。

#[2] Dataframeの一部を切り出して、連番を1番から振り直す
## 2-1.連番付与関数の例

こんな感じ。連番について、エクセルは1始まり、pandasは0始まりの文化であることに注意。
連番振りたいカラム名は適宜指定してください。

```.py
# new_index_col列(ディフォルト値は"連番")に1から連番を付与する関数　
def getPartDf(df,start, step=5, debug= True, new_index_col="連番"):
    dfx = df[start:start+step].reset_index()
    dfx[new_index_col] = dfx.index +1 #連番改めて付与。ここを1以外にすれば、
    dfy = dfx.set_index(new_index_col)
    return dfy if debug else dfy.drop("index", axis=1)
```
(私のように)馬鹿でかいエクセルファイルから読んだDataFrameを使う場合、ほんとに読めたか確かめたくなるだろうから、元のindexも残すようするdebugモードも用意(注、)

## 2-2.forループで連番付与関数を呼び出す例
range関数を用いて一定ステップ(step_num)毎にループを回します。

```.py
core_name = """切り出し後ファイル"""
step_num= 10000
debug = False

# step_numずつExcelの行を別ファイルに切り出していく処理。
for i in range(0, len(df), step_num):
    print(f"{i}以上{i+step_num}未満")
    savedDf = getPartDf(df,i, step_num, debug)
    if (debug):
        print(savedDf.head())
    fn = f"{out}/{core_name}{i}_{i+step_num -1}.csv"
    savedDf.to_csv(fn, encoding="cp932")
```

端数はpandasがよしなに処理してくれます。


# 実行例:数十万行あるエクセルシートを処理した場合
`debug =Falseの場合`


画面出力:

```
0以上10000未満
10000以上20000未満
20000以上30000未満
30000以上40000未満
40000以上50000未満
50000以上60000未満
60000以上70000未満
(略)
len 836543
```

出力されたエクセルファイルの一部(拡張子表示しないと何が何やらですが...):
![切り出し後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16455/954682e6-e16d-417d-bbc9-e72abf50fbdd.png)

ちなみに、でかいExcel相手だと処理には結構時間がかかります。
この記事は、その待ち時間に書いたともいう。。
Widgetを画像ファイルとしてエクスポートする

# 概要

Flutterで作ったアプリの画面を画像ファイルにする要件があったので調べた。
具体的には、アプリで生成したQRコードをSNSでシェアしたい、というニーズに応えるもの。
英語ではたくさん情報があるが、日本語の情報が見当たらなかったので記載する。

スクリーンショットを撮ってくれとユーザーに促す手もあるが、シェア用に画面を加工したあげた方が見栄えが良い。
SNSでシェアする部分は割愛。


# 実装
以下最小限の実装。

1. Widgetへアクセスできるようにするために、GlobalKeyを生成しておく。
2. 画像ファイル化したい範囲のウィジェットをRepaintBoundaryでラップする。
3. RepaintBoundaryのkeyに、手順1で生成したGlobalKeyを割り当てる。
4. どこかのイベント内にWidgetを画像ファイル化する処理を入れる。


```dart
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui' as ui;

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey _globalKey = GlobalKey(); // 1. GlobalKey生成

  // 4. ボタンが押された際の処理
  void _exportToImage() async {
    // 現在描画されているWidgetを取得する
    RenderRepaintBoundary boundary =
        _globalKey.currentContext.findRenderObject();

    // 取得したWidgetからイメージファイルをキャプチャする
    ui.Image image = await boundary.toImage(
      pixelRatio: 3.0,
    );

    // 以下はお好みで
    // PNG形式化
    ByteData byteData = await image.toByteData(
      format: ui.ImageByteFormat.png,
    );
    // バイトデータ化
    final _pngBytes = byteData.buffer.asUint8List();
    // BASE64形式化
    final _base64 = base64Encode(_pngBytes);
    print(_base64);
  }

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary( // 2. 画面全体をキャプチャするならScaffoldを囲ってやる
      key: _globalKey, // 3. GlobalKeyを割り当てて子のボタンからアクセスできるようにしてやる
      child: Scaffold(
        appBar: AppBar(
          title: Text("sample"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Widget to Image sample.',
              ),
              RaisedButton(
                onPressed: _exportToImage,
                child: Icon(
                  Icons.image,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
```

# 参考

https://medium.com/flutter-community/export-your-widget-to-image-with-flutter-dc7ecfa6bafb
https://api.flutter.dev/flutter/widgets/BuildContext/findRenderObject.html
https://api.flutter.dev/flutter/rendering/RenderRepaintBoundary/toImage.html
Action Cableへのidの受け渡し

[Action Cableの設定でつまずいたこと](https://qiita.com/kazama0119/items/755e8ff6f77aafb830d7)をする際につまずいたので備忘録も兼ねて共有します。
ご指摘やアドバイスがありましたらコメントよろしくお願いします。

##わからなかったこと
`channel.rb`の`speak関数`が実行した際に、user_id と chatroom_id を含むテーブルを作成したいが、`channel.rb`で id を取得する仕方がわからない


##コードの説明

###html.erbですること

1.属性値として`data_user` と `data_room` を設定する
2.その値として`current_user.id` と `@chatroom.id` を与える
(current_userにはログイン中のユーザー情報。@chatroomには、現在いるチャットページの情報が入っています。)

```erb:html.erb
 <div>
   <textarea id="chat_input" data_user="<%= current_user.id %>" data_room="<%= @chatroom.id %>"></textarea>
   <button id="chat_button">送信</button>
 </div>
```

###chatroom.coffeeですること
1. chat_inputというidであるものを探す
2. 1が見つかると以下を実行
3. 属性値が data_user, data_room のものを取得
4. chat_buttonというボタンをクリック
5. App.chatroom.speakの引数にid情報を渡す
6. 5で受け取ったもので`chatroom_channel.rb`のspeak関数を実行

```chatroom.coffee
# クライアントサイドの処理を受け持つチャンネ
App.chatroom = App.cable.subscriptions.create "ChatroomChannel",
  #(省略)

  received: (data) ->
    $('#posts').append data['message']


  speak: (content, data_user, data_room) ->
    @perform 'speak', message: content, user_id: data_user, room_id: data_room


document.addEventListener 'DOMContentLoaded', ->
  input = document.getElementById('chat_input') 
  if input?
    data_user = input.getAttribute("data_user")
    data_room = input.getAttribute("data_room")
    button = document.getElementById('chat_button')
    button.addEventListener 'click', ->
      content = input.value
      App.chatroom.speak(content, data_user, data_room)
      input.value = ''
      return
    return
```

###chatroom_channel.rbですること
1. dataにハッシュで`chatroom.coffee`での値が入っているので data['キー'] を指定し取得し、Post.create!を実行

```chatroom_channel.rb
#(省略)
  def speak(data)
    message = Post.create! content: data['message'], user_id: data['user_id'], chatroom_id: data['room_id']
    template = ApplicationController.renderer.render(partial: 'posts/post', locals: { post: message, current_user: current_user })
    ActionCable.server.broadcast 'chatroom_channel', message: template
  end
```

以上でuser_id と chatroom_id を含んだテーブルを作成することができます。
是非参考にしてみてください。

##関連記事
・[Action Cableの設定でつまずいたこと](https://qiita.com/kazama0119/items/755e8ff6f77aafb830d7)
・[DOMContentLoadedからturbolinks:loadへ変更](https://qiita.com/kazama0119/items/d52fbd918f7e1150f4b2)


##参考記事
[Rails 5 Action Cable メッセージとルームを紐付ける。](https://qiita.com/kohei1228/items/7aed5aad9c63e834c0e1)
Google Apps Script で集金メモサービスを作る

#概要
GoogleAppsScript (GAS) でWEBページ、サーバーを作り、GoogleSpreadSheetをデータベースとして、複数人から現金を集めるときのメモを作りました。
紙にメモするとあとの計算がめんどくさい
→スプレッドシートに書き込むからデータ処理しやすい
直接エクセルに書くのはめんどくさい
→スマホのブラウザから簡単に入力できる

#動機 
部活の会計をしていた経験があるが、集金は本当にめんどくさい。
メモミスったり、あとで計算したりがめんどう。
LINEPAYの送金サービスなどを使えば簡単かもしれないが、みんなにLINEPAYを始めさせるのもめんどくさい。
そこで、簡単に導入できる会計メモアプリを作ろうと思った。今回はその第一弾である。

#システム構成
webページでデータ（項目、人名、金額）を書く。
↓
サーバーに送信され、スプレッドシートに記入される。
以上
###サーバー
GASのプロジェクト内のgsファイルを編集

```javascript:code.gs
function doPost(e) {
  var date = new Date();
  Logger.log(e);
  var Data = [[Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd:hh-mm-ss'),
             e.parameter.category, e.parameter.name, e.parameter.money]];
  
  var key = 'キーをいれてね'
  var spreadsheet = SpreadsheetApp.openById(key);
  var sheetname = 'Collection'
  var sheet = spreadsheet.getSheetByName(sheetname);
  
  
  sheet.insertRows(2,1);
  sheet.getRange(2,1,1,4).setValues(Data);
  
  return 0;
}
```

キーをいれてね、のところにDBにするスプレッドシートのURLの一部
（https://docs.google.com/spreadsheets/d/{ここ}/edit#gid=0）
の｛ここ｝をいれる。

これで完成。公開ーウェブアプリケーションとして導入から、
Project version - New
Execute the app as - Me
Who has access to the app - Anyone,even anonymous
で公開。表示されるURLをメモ。


###webページ
GASのプロジェクト内にhtmlファイルを作り、以下のように編集

```html:post_data.html
<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>入力テスト</title>
</head>
<body>
  <h1>入力</h1>
  <form method="post" action="サーバURL">
    <p>
      <label>項目 <input type="text" name="category"></label>
    </p>
    <p>
      <label>人名 <input type="text" name="name"></label>
    </p>
    <p>
      <label>金額 <input type="text" name="money"></label>
    </p>
    <p>
      <input type="submit" value="送信">
    </p>
  </form>
</body>
```
サーバURLのところに先ほどのURLを入れる。

同じプロジェクト内でgsファイルを作り、以下のように編集

```javascript:code.gs
function doGet(request) {
  return HtmlService.createTemplateFromFile('post_data')
      .evaluate();
}
```
同様に公開。出てきたURLにブラウザからアクセス。

#結果
問題なく動作しました。
##問題（今後の課題）
・入力ページが一度入力すると再度アクセスしないと連続で入力できない。
・スマホにやさしくないHTMLデザイン
・項目や人名を選択式にする
　・そのために項目、人名登録用のページもつくる。


#参考資料
https://developers.google.com/apps-script/guides/html/best-practices?hl=ja
https://qiita.com/taromorimotohf/items/5e52cb9062600e8ccac3
https://breezegroup.co.jp/201906/gas-get/
https://breezegroup.co.jp/201906/gas-get/
https://qiita.com/negito6/items/c64a7a8589faaffcfdcf
https://tonari-it.com/gas-spreadsheet-insertrows-splice/
http://www.googleappsscript.info/2017-07-27/get_now.html
https://qiita.com/ShishidoToru/items/0ab9de4ea281df9358f4
1/28 授業ノート

#昨日の復習
・ページのタイトルに付けるタグは？→```<h1>~<h6>```
・タイトル以下の段落などに付けるタグは？→```<p>```
・＜＞の読み方→アングルブラケット
・コンテンツ前にスペース→インデント


#今日習ったことまとめ
**範囲：教科書(HTML5&CSS3標準デザイン講座)P16～P35,P45**
・```<!DOCTYPE html>```などの宣言をDTD(Document Type Definition)と呼ぶ
・head要素→html文書のタイトル、文字コード等文書の補足情報を記載するもの。
　ex::)```<head>``` ```</head>```で記述
・```<html lang="ja">```などのことを属性と呼ぶ
　ex:)上記タグの場合「lang属性」と呼ぶ
タグについて
・metaタグ→ブラウザには表示されない文書情報を記述するための要素
・charset→文字コード
　ex:)```<meta charset=”utf-8”>```→このサイトの文字コードはutf-8ですよとブラウザに伝える記述
・titleタグ→html文書のタイトル（タブに表示される）

記述チェックサイト
https://validator.w3.org/

**画像の挿入(教科書P45)**
・画像を表示させるときはimgタグを使用
・画像はindex.htmlがある階層に画像用フォルダを作成(今回はフォルダ名「img」)
・src属性→目的の画像までのパスを記述する
　ex:)```<img src=”img/xxxx.png”>```
・alt属性→画像が表示されない環境で閲覧した際に表示する代替テキスト。視覚障害者の音声ブラウザのための配慮として画像を端的に説明した言葉を指定。
　ex:)```<img src=”img/xxxx.png” alt=”xxxxの画像”>```
・コメントタグ→ブラウザに一切反映されないメモ書き。ショートカットキーはctrl+/
　ex:)```<!--メモやで-->```
・discription→サイトの説明。検索に上がってくるのでサイトの中身と密接した内容を記述する。140字程度までが検索エンジンに表示される。
・copylightなど小さく表示すべきものにはsmallタグで括る
　ex:)```<small></small>```
・utf-8の場合copylightマークは```&copy;```で文字参照して表示させる
　ex:)```<p><small>Copyright&copy;All rights reserved.</small></p>```


#感想
久しぶりにWinPCを使ったので、何よりもタイピングがストレス過ぎた…。
しかし自分のMacを持ち歩くのはリスク高いし、何より重いし。
キーボードだけ持ち歩くとかしようかな。
uBlock Origin/Adblock Plus 用フィルタの書き方まとめチートシート

uBlock Origin/Adblock Plus 用フィルタの書き方について長々とした記事ばかりなのでシンプルにまとめました。
おそらく最も多くの人が使用している uBlock Origin は Adblock Plus のフィルタ形式をサポートしているため、Adblock Plus のガイドを参考にします。
> uBlock Origin ("uBO") supports Adblock Plus ("ABP") filter syntax, so you can refer to existing filter syntax documentation from Adblock Plus web site and ABP's filter cheatsheet. For quick overview you can also check Introduction to basic filtering syntax in this wiki.
https://github.com/gorhill/uBlock/wiki/Static-filter-syntax

なお、インストールするのは Adblock Plus ではなく uBlock Origin を推奨します。
https://gigazine.net/news/20160314-ublock-vs-abp/

フィルタのシンタックスについての詳細：
https://github.com/gorhill/uBlock/wiki/Static-filter-syntax
https://adblockplus.org/filter-cheatsheet
https://help.eyeo.com/en/adblockplus/how-to-write-filters

CSSセレクタについて：
https://webliker.info/css-selector-cheat-sheet/
https://shge.github.io/docs/css.html

# シンタックス

`*` はワイルドカード(すべての数字・文字)

### ドメイン単位でブロック

```
||example.com^
||example.*^
```

### タイプ指定ブロック

```
||example.com^$script,image
```

### 要素ブロック(非表示)

```
###id_name
##.class_name
example.*###id-name
example.com###id-name
example.com##.class-name
example.com##a[href="https://example.com"]
example.com##footer
example.com##div > p
example.com##div(p:has-text(/^Ad$/))
```

### ホワイトリスト

```
@@||example.com^
```

### コメント

```
! This is a comment
```
PJ立ち上げで使う課題管理ツールを無心に構築する on AWS

# 動機
PJの立ち上げで「課題管理ツールがほしい」と言われたため、AWSにRedmineを立てることにしました。
また、[昔の経験](https://qiita.com/yamatok/items/ee93b6f45910d20c66be)でCodiMDがあると会議や情報共有が捗ると思ったため入れさせてもらうことにしました。

# 前提条件

* AWS
* EC2(Amazon Linux 2 AMI)上に構築
* Proxyがいる（！）

# Amazon Linux 2のProxy設定
各コマンドのProxy設定をしておきます。
## yum
```/etc/yum.conf（追記）
～～～～～～
proxy=http://proxy:port/
```
## docker
```
sudo mkdir -p /etc/systemd/system/docker.service.d
```
```/etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy:port" "HTTPS_PROXY=http://proxy:port" "NO_PROXY=localhost"
```
※Dockerを入れたいだけの方はこちら
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html

# Redmineのdocker-compose.ymlを用意しておく
```
mkdir ~/redmine34
vi ~/redmine34/docker-compose.yml
```
```
version: '3.3'

services:
    redmine:
        container_name: redmine
        image: redmine:3.4.13
        restart: always
        ports:
            - 80:3000
        volumes:
            - ./data/plugins:/usr/src/redmine/plugins
            - ./data/themes:/usr/src/redmine/public/themes
        environment:
            REDMINE_DB_MYSQL: redmine-db
            REDMINE_DB_PASSWORD: redmine

    redmine-db:
        image: mariadb
        container_name: redmine-db
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: redmine
            MYSQL_DATABASE: redmine
        volumes:
            - ./data/db:/var/lib/mysql
        command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
```

## 参考にしたサイト
* http://sig9.hatenablog.com/entry/2019/07/06/000000

# 無心に構築
## まだProxyの出番があるのでSet
```
export HTTP_PROXY=
export HTTPS_PROXY=
```

```
# Install and launch docker
sudo yum update -y
sudo amazon-linux-extras install docker
sudo systemctl daemon-reload
sudo systemctl enable docker
sudo systemctl start docker

# Install docker-compose
sudo curl -L -x ${HTTPS_PROXY} https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# Install git
sudo yum install -y git
git config --global http.proxy ${HTTP_PROXY}
git config --global https.proxy ${HTTPS_PROXY}

# Install and launch hackmd(CodiMD)
cd ~
git clone https://github.com/hackmdio/docker-hackmd.git
cd ~/docker-hackmd/
# See https://qiita.com/yamatok/items/ee93b6f45910d20c66be
# vi ~/docker-hackmd/docker-compose.yml
sudo docker volume create --name=hackmd-postgres-data
sudo /usr/local/bin/docker-compose up -d

# Launch Redmine 3.4.13
cd ~/redmine34/
sudo /usr/local/bin/docker-compose up -d
```

# 動作確認

## Redmine
http://${EC2のIP}/

## CodiMD
http://${EC2のIP}:3000/