OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon Rekognitionによる顔認識

Amazon Rekognitionを使って、入力した画像に映っている顔を矩形で囲むという基本的な処理を試してみました。

# Amazon Rekognitionとは
Amazon Rekognitionは、AWSのAIサービスの一つで、画像認識に対応したものです。
また、AWSのAIサービスは画像認識・自然言語処理など様々な領域をカバーしたもので、機械学習の深いスキルなしに機械学習をアプリケーションに組み込める、データを用意するだけでAPIから機械学習を利用できる、といった特徴があります。

# 実行環境

OS：Windows10
言語：Python3.7

# 事前準備

AWS CLI(aws configure)にて、以下の認証情報をセットしておきます。

AWS Access Key ID
AWS Secret Access Key
Default region name
Default output format

# ソースコード(face_detect.py)

	import boto3
	import sys
	from PIL import Image,ImageDraw

	# 引数のチェック
	if len(sys.argv) != 2:
		print('画像ファイルを引数に指定してください。')
		exit()

	# Rekognitionのクライアントを作成
	client = boto3.client('rekognition')

	# 画像ファイルを引数としてdetect_facesを実行
	with open(sys.argv[1],'rb') as image:
		response = client.detect_faces(Image={'Bytes':image.read()},Attributes=['ALL'])

	# 顔が認識されない場合は処理終了
	if len(response['FaceDetails'])==0:
		print('顔は認識されませんでした。')
	else:
		# 入力された画像ファイルを元に、矩形セット用の画像ファイルを作成
		img = Image.open(sys.argv[1])
		imgWidth,imgHeight = img.size
		draw = ImageDraw.Draw(img)
		
		# 認識された顔の数分、矩形セット処理を行う
		for faceDetail in response['FaceDetails']:
		
			# BoundingBoxから顔の位置・サイズ情報を取得
			box = faceDetail['BoundingBox']
			left = imgWidth * box['Left']
			top = imgHeight * box['Top']
			width = imgWidth * box['Width']
			height = imgHeight * box['Height']		

			# 矩形の位置・サイズ情報をセット
			points = (
				(left,top),
				(left + width,top + height)
			)

			# 顔を矩形で囲む
			draw.rectangle(points,outline='lime')
			
		# 画像ファイルを保存
		img.save('detected_' + sys.argv[1]) 	

		# 画像ファイルを表示
		img.show()

# 簡単な解説

概略としては以下のような処理を行っています。

①プログラム実行時の引数からRekognitionに入力する画像ファイルを取得する。
②上記①の画像ファイルを引数としてRekognitionのdetect_facesを実行する。
③Rekognitionから返却されるJsonのFaceDetails・BoundingBoxから、認識された顔の位置・サイズ情報を取得する。
④上記③から矩形付きの画像ファイルを作成し、表示する。

# 実行結果

## コマンド
python face_detect.py ichiro1.jpg

## 入力画像(ichiro1.jpg)

![ichiro1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240454/4e1dc567-abb3-b1c9-3088-5a0e2e770f30.jpeg)

## 出力画像(detected_ichiro1.jpg)

![detected_ichiro1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240454/ebae8b7c-24be-c969-309b-2f0f40ef94aa.jpeg)

イチロー選手はもちろんのこと、観客席の人たちも認識してくれています。

# まとめ

Rekognitionに限らずですが、AWSのAIサービスはAPIから機械学習を手軽に利用できる便利なサービスです。
また、今回は矩形しか試しませんでしたが、Rekognitionから返却されるJsonには性別・年齢など様々なものがありますので、他にも色んなことを試せると思います。
Githubでドラフトしなきゃいけないのにプルリクエストしちゃった場合

タイトルにある通り
**「ドラフトしなきゃいけないのにプルリクエストしちゃった…」**
という場合の対処法です。

焦らないで。1分かからないでドラフトプルリクエストに変更できるから。

1.プルリクエストのタブを押します
2.該当のブランチを押します
3.右側のReviewersを見ると、レビュアーの方の名前の下に
**「Still in progress? Convert to draft」**
というのがあります。
「まだ進行中ですか？ドラフトに変換する？」的なことを聞かれてます。
4.まさにそれじゃん！！！ということでこの灰色の文字を押します
5.**赤文字で「Convert to draft」**と出ます。
「ドラフトに変更」ってことです。押しましょう。
6.終了

めちゃくちゃ簡単じゃないか…焦って損した…って感じでしょ。

[公式参照ページ]
プルリクエストのステージの変更 - GitHub Docs
https://docs.github.com/ja/github/collaborating-with-issues-and-pull-requests/changing-the-stage-of-a-pull-request#converting-a-pull-request-to-a-draft
Objectの子要素までimmutable/readonlyにする

## tl;dr

`const variable = <element> as const` の形で定義する

```ts
// object
const immutableObj = {
    a: 1,
    b: "test message",
    inner: { key: "foo" },
  } as const;
// =>型
// const immutableObj: {
//    readonly a: 1;
//    readonly b: "test message";
//    readonly inner: {
//        readonly key: "foo";
//    };
// }

const immutableList = [1, "test message", ['inner']] as const;
// => 型
// const immutableList: readonly [1, "test message",
//            readonly ["inner"]
//       ]
```

## `as const`

- ネストされた子要素までreadonlyになる
    - 上記だとinnerの箇所
- リテラル型が使われる
    - 上記だと`b: string`でなくて、`b: "test message"`型になる
- TypeScriptレイヤーの話なのでトランスパイルされたJSには何も影響がない
    - （左TS、右トランスパイルされたJS）<img width="1152" alt="memo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186228/fc87846e-3333-22e9-7f25-a3f8550d38c1.png">
- Classは`as const`できない。なので、`Object.freeze`を使うか、クラスプロパティにreadonlyを指定する（後述）

## `Object.freeze`

[Object.freeze() - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)

- 子要素までfreezeされない
    - そのため、`Object.freeze`を使う＋nestされた要素までfreezeする場合はオレオレなdeepFreezeが必要
    - (REF: [ES6のconstを使い倒すレシピ2 - Object.freeze編 〜 JSおくのほそ道 #035 - Qiita](https://qiita.com/hosomichi/items/84b05c1b0c09d26cd11e)）

  ```ts
      const mutableObj = { a: 1, b: "test message", inner: { key: "foo" } };
      const freezed = Object.freeze(mutableObj);
      freezed.b = 'dar'          // ERROR
      freezed.inner.key = "bar"; // SUCCESS
  ```


- JavaScriptレイヤーの実装なので、トランスパイルされたJSにも処理が入る
  - （左TS、右トランスパイルされたJS）<img width="1268" alt="object.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186228/3e113a72-300c-f20a-9154-aca1278be6fb.png">
- Object.freezeを使ったことによるperformace劣化はほぼない
      - REF: [ecmascript 5 - Any performance benefit to "locking down" JavaScript objects? - Stack Overflow](https://stackoverflow.com/a/23198265/8842333)

- リテラル型の情報がロストしてしまう

```ts
  const freezed = Object.freeze(
     { a: 1, b: "test message", inner: { key: "foo" } }
  );
  // => 型
  // const freezed: Readonly<{
  //  a: number;
  //  b: string;     << stringでなくて'test message'型であってほしい
  //  inner: {
  //      key: string;
  //  };
  //}>
```

- Classでは `as const` でなくて `Object.freeze` が使える。
    - ただ、nestしたオブジェクトに対するfreezeがガバガバなので注意

  ```ts
  class Person {
    public obj: { a: number; b: string, inner: {key: string} };
    constructor() {
      this.obj = { a: 1, b: "hello world", inner: {key: 'foo'} };
    }
  }
  const p = new Person();

  const freezed = Object.freeze(p);
  freezed.obj = {...freezed.obj, b: 'bar1'}; // ERROR TS-2540
  freezed.obj.b = 'new bar';                 // SUCCESS
  freezed.obj.inner = {key: 'bar' };         // SUCCESS
  ```


## まとめ

- 極力 `as const` を使う
- Class のときは仕方ないので `Object.freeze` を使う
ある日突然 fish が激重になった → asdf を brew で入れてるせいだったパターン

# 結論

asdf を brew 経由でいれていて

`~/.config/fish/config.fish` に以下を書いていたのが原因。

```
source (brew --prefix asdf)/asdf.fish
```

で、これに1秒以上かかってました！！

```
$ time brew --prefix asdf
/usr/local/opt/asdf

________________________________________________________
Executed in    1.35 secs   fish           external
   usr time  489.69 millis  106.00 micros  489.59 millis
   sys time  313.33 millis  467.00 micros  312.86 millis
```

なので、以下のようにパスをベタガキして人権を取り戻しました。

```
source /usr/local/opt/asdf/asdf.fish
```

# 感想
brew で入れないで素直に git とかでいれておけばこんなことにはならなかった。のかもしれないけど、fish のプロファイリングの勉強になったので、逆によかった！

# 調べ方

```
$ fish --profile /tmp/fish.prof -c 'complete -C"fis"'

$ sort -nk2 /tmp/fish.prof | tail -n 20
665	789	------> source /usr/local/Cellar/fish/3.1.2/share/fish/functions/seq.fish
124	817	---> for x in (string split ":" -- $fish_user_paths[-1..1])
7	841	--> if set -q fish_user_paths
842	864	--> source /usr/local/Cellar/fish/3.1.2/share/fish/functions/__fish_set_locale.fish
49	1030	-> __fish_reconstruct_path
286	1361	-> __fish_set_locale
5481	5515	---> dirname (status -f)
105	5620	--> set -x ASDF_DIR (dirname (status -f))
5615	5663	-----> seq 1 (count $PATH)
122	6099	----> for i in (seq 1 (count $PATH))
8	6136	---> if test -d $x
5320	6203	-----> seq 1 (count $PATH)
1584	6296	> builtin source /usr/local/Cellar/fish/3.1.2/share/fish/config.fish
107	6551	----> for i in (seq 1 (count $PATH))
8	6596	---> if test -d $x
38	12975	--> for x in $asdf_bin_dirs
18305	18305	> complete -C"fis"
1251826	1251826	--> brew --prefix asdf
602	1271876	-> source (brew --prefix asdf)/asdf.fish
359	1272262	> builtin source /Users/mochizuki/.config/fish/config.fish
```

参考: https://github.com/fish-shell/fish-shell/issues/6611
高位合成言語Polyphony その8

#概要

polyphony、やってみた。
fizzbuzz、書いてみた。

#サンプルコード


```
from polyphony import testbench, module, is_worker_running
from polyphony.timing import clksleep
from polyphony.io import Port
from polyphony.typing import bit, uint8

@module
class fizzbuzz0:
	def __init__(self):
		self.append_worker(self.worker)
	def worker(self):
		i:uint8 = 1
		s:uint8 = 1
		l:uint8 = 1
		m:uint8 = 1
		while is_worker_running():
			if (i < 101):
				s = i % 15
				l = i % 5
				m = i % 3
				if (s == 0):
					print ("fizzbuzz")
				elif (l == 0):
					print ("buzz")
				elif (m == 0):
					print ("fizz")
				else:
					print(i);
				i = i + 1

m = fizzbuzz0()

@testbench
def test(m):
	clksleep(100)
	print("ok")

test(m)




```

#python実行結果



```

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
31
32
fizz
34
buzz
fizz
37
38
fizz
buzz
41
fizz
43
44
fizzbuzz
46
47
fizz
49
buzz
fizz
52
53
fizz
buzz
56
fizz
58
59
fizzbuzz
61
62
fizz
64
buzz
fizz
67
68
fizz
buzz
71
fizz
73
74
fizzbuzz
76
77
fizz
79
buzz
fizz
82
83
fizz
buzz
86
fizz
88
89
fizzbuzz
91
92
fizz
94
buzz
fizz
97
98
fizz
buzz
ok


```

以上。
swiper.min.cssが404のとき

# スライダー が突如表示崩れした
→だいたいcdnのせい。
console見るとswiper.min.cssが404になってる。


## unpkgはdist用で使うな
swiperの公式に、
>a. Use Swiper from CDN
If you don't want to include Swiper files in your project, you may use it from CDN. The following files are available:

```html

<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.css">
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">

<script src="https://unpkg.com/swiper/swiper-bundle.js"></script>
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
```

これを鵜呑みにしてはいけない。
そもそもunpkgはお試しみたいなもん。
以下のサイトはそう言ってる（公式だとどこに書いてあるかわからなかった）。

https://kentcdodds.com/blog/unpkg-an-open-source-cdn-for-npm
>unpkg is great for open source project demos and instructional material (I use it heavily in my Beginner's Guide to ReactJS), but it’s not well suited for mission-critical applications at scale because:
unpkg is a free, best-effort service and cannot provide any uptime or support guarantees.
That’s why Michael recommends:
if you rely on it to serve files that are crucial to your business, you should probably pay for a host with well-supported infrastructure and uptime guarantees.


https://co.bsnws.net/article/233
>本番環境での利用は推薦されていませんが、プロジェクトで使うか検討したい時、
codepen等のオンラインエディタで使用する時には 非常に役立つサービスです。

## じゃあどうする
cloudflare使おうぜ
https://cdnjs.com/libraries/Swiper




<br>
<br>
<br>
swiper便利だけど、IE11非対応（というか内部のdom7）なので、<a href='https://qiita.com/mah_lab/items/5bcd0edc0a68f882a2a7'>うまいこと対処</a>して使おう
EC-CUBE4系、テスト受注データ・ダミーデータの削除・初期化手順

[EC-CUBE Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ec-cube) 2日目の記事です。

制作中のテスト購入で、受注したデータなど削除して初期化状態にする手順メモ（初心者向け）になります。
受注データをまとめて初期化状態にするものなので、削除の際は注意してください。

## 受注に関わるテーブル
[データベースの各テーブルの一覧](http://ec4.umebius.com/)を参考に受注に関するテーブルを把握。
受注に関わるテーブルは以下になります。

```
dtb_order_item　  #注文商品の個別明細
dtb_mail_history  #受注メールの履歴
dtb_shipping      #注文の配送先情報
dtb_order         #注文
``` 


## phpMyAdminで以下のSQL文実行

EC-CUBEのデータベースを選択し、SQLタブ切り替えします。
![sql.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668571/d798f3e4-fc82-bcff-4b28-4b5e1b567315.jpeg)


以下のSQL文を入力実行してください。 
該当テーブルのデータ削除と受注IDを１に戻す処理になります。

```
delete from dtb_order_item;
delete from dtb_mail_history;
delete from dtb_shipping;
delete from dtb_order;
ALTER TABLE dtb_order AUTO_INCREMENT = 1;
```

※バックアップなど行った上で自己責任で実行お願いいたします。

■参考リンク 
・[EC-CUBE4開発リファレンス](http://ec4.umebius.com/)
・[EC-CUBE4で「受注」「商品」「会員」のデータを初期化する方法](https://techmemo.biz/ec-cube/eccube4-data-reset/)
Janusインストール法(Ubuntu 18.04.4 Server)

#WebRTCとJanusについて
簡単にWebRTCとJanusについて説明します。
####WebRTCとは？
WebRTC(Web Real-Time Communication)はブラウザーやクライエント間で直接にリアルタイムで(大体P2P)つながり画像ストリーム、オーディオやデータを送ることが出来る複数のプロトコールとAPIなどの組合です。

WebRTC搭載のブラウザーならディベロパーはブラウザーのAPIを使いリアルタイムアプリケーションを作ることが可能です。

HTTPやWebSocketとの違いとしては、WebRTCの通信はクライエントの間のサーバーがないです。

ですが、サーバーが必要ないわけではないです。サーバーはクライエントたちを最初に見つけてあげる役割などを行います。これをどうやって行うかはとても大きいものなのでこの投稿には説明しません。

####Janusとは？
JanusはWebRTCサーバー、ゲートウェイとして作られたopen sourceサーバーです。

WebRTC間の通信やレガシーRTCテクノロジーと相互作用するようにすることも可能です。

Janusはプラグインを使いアプリケーション用の機能を追加する仕組みです。

詳しいことはjanus-gatewayのgithubを参考して下さい。

#必要環境
 - Ubuntu 18.04.4 Server x86_64

#設置

必要なパッケージ

```bash
sudo apt-get install libmicrohttpd-dev libjansson-dev \
	libssl-dev libsofia-sip-ua-dev libglib2.0-dev \
	libopus-dev libogg-dev libcurl4-openssl-dev liblua5.3-dev \
	libconfig-dev pkg-config gengetopt libtool automake
```
libnice (ここがすこし大変です)

```bash
sudo apt install python3-pip

#meson-0.52以上をインストールして下さい
pip3 install meson==0.52 ninja --user

PATH="${PATH}:$(python3 -c 'import site; print(site.USER_BASE);')/bin"
export PATH=$PATH:~/.local/

git clone https://gitlab.freedesktop.org/libnice/libnice
cd libnice

meson ~/libice2

#'ubuntu'はユーザー名です
ninja -C ~/libnice2
cd /home/ubuntu/.local/bin/
sudo ./ninja -C /home/ubuntu/libnice2/ install

```

libsrtp 最新のv2.3.0をインストールして下さい

```bash
wget https://github.com/cisco/libsrtp/archive/v2.3.0.tar.gz
tar xfv v2.3.0.tar.gz
cd libsrtp-2.3.0
./configure --prefix=/usr --enable-openssl
make shared_library && sudo make install
```

Data Channelsを使うためにusrsctpをインストールしましょう

```bash
git clone https://github.com/sctplab/usrsctp
cd usrsctp
./bootstrap
./configure --prefix=/usr --libdir=/usr/lib64
make
sudo make install
```

Janusをコンパイルしましょう。

```bash
git clone https://github.com/meetecho/janus-gateway.git
cd janus-gateway

sh autogen.sh

./configure --prefix=/opt/janus
make
sudo make install

#基本設定ファイル
sudo make configs
```

起動！

```bash
/opt/janus/bin/janus
```

ここでlibniceのエラーなどが有りましたらこちらをやってみて下さい(root権限で)
https://groups.google.com/forum/#!topic/meetecho-janus/fznCh3UYSCg参考しました

```bash
cd /etc/ld.so.conf.d
echo 'usr/lib64' > whatever.conf
ldconfig 
```

インストールが終わったあと他の機能(WebSockets,MQTT等)を追加したい場合は必要なパッケージを(libwebsockets,paho.mqtt.c等)をインストールしたあとJanusを再コンパイルして下さい。

```bash
cd ~/janus-gateway

make clean

./configure --prefix=/opt/janus
make
make install
```

#最後に
これからは簡単なWebRTCビデオ会議アプリケーションを作ってみようと思います。
Gatsbyでサイドバーに最近の投稿を表示する

#やりたいこと

componentsディレクトリ内は下記のようになっている

- components
    - Layout
    - Sidebar
    - BlogCard
   
Layoutにはサイドバーが組み込まれています

```react:components/Layout

const Layout = ({ children }) => {
  return (
    <div>
      <Header />
      <section style={{ marginTop: "9rem" }}>
        <Container>
          <div className="row">
            <div className="col-lg-8">{children}</div>
            <div className="col-lg-4">
              <Sidebar />
            </div>
          </div>
        </Container>
      </section>
      <Footer />
    </div>
  )
}
```

```react:index.js
<Layout>
      {posts.map(({ node }) => {
        return (
          <BlogCard
            key={node.id}
            title={title}
            readMore={node.slug}
          />
        )
      })}
</Layout>
```

indexから記事を指定数切り出して渡す事もできますが
引数やら責務範囲やらややこしいのでやりたくなかった

#やりかた

`useStaticQuery`を使う

https://www.gatsbyjs.org/docs/use-static-query/

公式の通りインポート

`import { useStaticQuery, graphql } from "gatsby"`

あとは、` const data = useStaticQuery(graphql``)`として、普通にGraphQLを書いていく
最近の投稿なので、日付でソートして、指定数取得するようにします


サイドバーは下記の様になった

```react:components/Sidebar.js
import React from "react"
import { Container, Row1 Nav } from "react-bootstrap"
import { useStaticQuery, Link, graphql } from "gatsby"

import Styles from "./sidebar.module.css"

const Sidebar = () => {
  const data = useStaticQuery(graphql`
    query {
      allContentfulBlogPost(
        sort: { fields: [publishDate], order: DESC }
        limit: 5
      ) {
        edges {
          node {
            id
            slug
            title
            publishedDateJP: publishDate(formatString: "Y年MM月DD日")
          }
        }
      }
    }
  `)

  const posts = data.allContentfulBlogPost.edges
  return (
    <div className={Styles.sidebar}>
      <Row>
        <div className="col-lg-12">
          <div className={Styles.sidebar_item + " " + Styles.recent_posts}>
            <div className={Styles.sidebar_heading}>
              <h2>Recent Posts</h2>
            </div>
            <div className="content">
              <Nav>
                {posts.map(({ node }) => (
                  <Nav.Link as={Link} to={`post/${node.slug}`}>
                    <h5 className={Styles.head}>{node.title}</h5>
                    <span className={Styles.date}>{node.publishedDateJP}</span>
                  </Nav.Link>
                ))}
              </Nav>
            </div>
          </div>
        </div>
      </Row>
    </div>
  )
}

export default Sidebar
```
☆AI_DEV_02_AI開発講座_環境準備_Microsoft Azureに登録しよう★

☆AI_DEV_02_AI開発講座_環境準備_Microsoft Azureに登録しよう★

  これは
高専キャリア × Microsoft　がコラボ主催するonline講座の進捗報告作業記事です！
https://online.kosen-career.tech/ai
 
今回のミッションは下記
「Azure for studensに登録する」
 
→高専機構は、教育機関認証受けているっぽいので、
学内で有効のメアド持っている人はすんなり、認証コードもらえるはず
 
→私の学生時代のメアドは認証されているみたいだけど卒業してもうメール受信する方法不明なので、
すでに、持っていたMicrosoft365のアカウントで、
Microsoft Azureの無料枠を有効化
 
○学生はこちら
https://azure.microsoft.com/ja-jp/free/students/
→クレジット不要
→100＄分クレジット
→無償の開発者用ツール
などなどがついてくるみたい
 
○学生以外はこちら
https://azure.microsoft.com/ja-jp/free/
→12ヶ月無料
→要クレジット(アップグレードするまでは課金なし)
→200＄分クレジット(30日以内に使おう)
などなど
 
まー、学生版との違いの詳細は、良く分からないけど、
とりあえず、ミッション達成かな♪

---------------------------------------------------------
▶ スケジュール
7/4 20:00-21:00 キックオフ・セッション（完了）
7/25 15:00-18:00 中間プレゼン
8/29 15:00-18:00 最終プレゼン

---------------------------------------------------------
▶ 7/25までのミッション

- [x] Azure for studensに登録する
	https://azure.microsoft.com/ja-jp/free/students/?WT.mc_id=azureforstudents-docs-nosuzuk
　→Microsoft Azureで対応

- [x] de:code2020の以下コンテンツを視聴して学習する
	https://www.microsoft.com/ja-jp/events/decode/2020session/detail.aspx?sid=Z01
        Z01:学生諸君！ Azure であそぼう！ ～Microsoft の AI を自作アプリに取り入れるまで～
	
	https://www.microsoft.com/ja-jp/events/decode/2020session/detail.aspx?sid=A02
	A02:Azure Bot Services を使って Teams bot を開発する


- [ ] Microsoft Learn for Studentsで学習する
https://docs.microsoft.com/ja-jp/learn/roles/student?WT.mc_id=BlendedCurriculum-MSLearn-nosuzuk

- [ ] ちょまどさんとおーちょさんのレッスンを消化する
https://qiita.com/chomado/items/6bda10abde0551f25723
https://qiita.com/miokawa/items/6f1a3e480580e1e29abc

---------------------------------------------------------


20200706 やったことまとめ
・Qiitaの登録/進捗報告up
・スケジュールの確認
・直近のミッションの確認達成状況の更新
・Microsoft Azureのアカウント作成

ではでは、よろしくお願いいたします。

By shin-chan-chan
RaspberryPiのセットアップ(インストールからSSH接続まで)

ブログから引っ張ってきました
https://wally-ngm.hatenablog.com/entry/2020/07/06/115909

## 1. OSのイメージをダウンロード

[公式からダウンロードできます](https://www.raspberrypi.org/downloads/raspberry-pi-os/)


今回は`Raspberry Pi OS (32-bit) Lite` をダウンロードしました.


## 2. SDカードに書き込む

diskutiコマンドでSDカードのデバイスファイル名を調べます

```
diskutil list
```

私の実行結果
![結果](https://cdn-ak.f.st-hatena.com/images/fotolife/u/ustrgm/20200702/20200702134740.png)


disk2に対してddコマンドで書き込みを行います.

```
sudo dd bs=1m if=2020-05-27-raspios-buster-lite-armhf.img of=/dev/rdisk2
```


## 3. ラズパイのセットアップ

ラズパイとディスプレイ, キーボードを繋げて設定をしていきます.

CUIのOSをインストールしたので, CUIの流れで説明していきます.

### 最初のログイン

以下でログインできます.

```
user名: pi
password: raspberry
```

### Wi-Fiの設定

```
sudo raspi-config
```

`Network Options` => `Wireless LAN` で, SSIDとパスワードを入力します.

### SSHできるようにする

```
sudo raspi-config
```

`Interface Options` => `SSH` でenalbleにします.


### ホスト名の設定
毎回IPアドレスを入力してSSHするのは面倒なのでホスト名の設定を行います.

`avahi-daemon` をインストールします.

```
sudo apt update
sudo apt install -y avahi-daemon
```

`/etc/hostname` をいじってホスト名を設定します. 以下はhostnameファイルの中身です. ただホスト名を書けばOKです.

```
YOUR_HOST_NAME
```

デーモンを再起動させて確認

```
/etc/init.d/avahi-daemon restart
```

これで, 後は以下のようなコマンドでsshできるようになります
```
ssh pi@YOUR_HOST_NAME.local
```

## 番外編ruby setup

今回セットアップしたOSにはrubyが入っていませんので, 自分でインストールしていきます.


```
sudo apt install -y git
sudo apt install -y libreadline-dev build-essential clang libboost-all-dev openssl libssl-dev
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo `eval "$(rbenv init -)”` >> ~/.bashrc
source ~/.bashrc
rbenv -v
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
~/.rbenv/plugins/ruby-build/install.sh
rbenv install 2.7.1
rbenv global 2.7.1
rbenv rehash
```
PythonでBigQueryを操作する方法



PythonでBigQueryを扱う方法の詳細は下記の公式サイトを確認してください。
https://googleapis.dev/python/bigquery/latest/usage/index.html

データセットを操作したい場合は上記サイトのManaging Datasets
テーブル操作したい場合はManaging Tables
に記載があります。

## テーブルの作成

テーブル作成後にすぐにデータを入れようとすると実行されないことがあるので注意。

```python:テーブルの作成
from google.cloud import bigquery

# Colabで使う場合はPJ名の指定が必要
client = bigquery.Client()
client = bigquery.Client(project=project_id) # "your-project"

schema = [
    bigquery.SchemaField("full_name", "STRING", mode="REQUIRED"),
    bigquery.SchemaField("age", "INTEGER", mode="REQUIRED"),
]

# table_id = "your-project.your_dataset.your_table_name"
table = bigquery.Table(table_id, schema=schema)
table = client.create_table(table)  # Make an API request.

print(
    "Created table {}.{}.{}".format(table.project, table.dataset_id, table.table_id)
)

```


### テーブル作成時のスキーマ指定方法

ステートメントの詳細については[こちら](https://googleapis.dev/python/bigquery/latest/generated/google.cloud.bigquery.schema.SchemaField.html#google.cloud.bigquery.schema.SchemaField)に記載あり、スキーマの指定方法については[BigQueryの公式サイト](https://cloud.google.com/bigquery/docs/schemas?hl=ja)に詳細が書かれているので、
必要に応じてfield_typeやmodeを変更していきます。


```python:ステートメント
SchemaField(name, field_type, mode='', description=None, fields=(), policy_tags=None)
```

```python:スキーマ指定の一例
# 文字列(空白あり)
SchemaField(name, 'STRING', mode='NULLABLE')
# 整数 (空白あり)
SchemaField(name, 'INT64', mode='NULLABLE')
# 浮動小数点(空白あり)
SchemaField(name, 'FLOAT64', mode='NULLABLE')
# 日付(必須)
SchemaField(name, 'DATE', mode='REQUIRED')
# 日時(必須)
SchemaField(name, 'DATETIME', mode='REQUIRED')
```




## queryを実行する方法

公式サイトはこちら
https://googleapis.dev/python/bigquery/latest/usage/queries.html

```python:queryの実行
from google.cloud import bigquery

# Colabで使う場合はPJ名の指定が必要
client = bigquery.Client()
client = bigquery.Client(project=project_id) # "your-project"

# 実行したいqueryを記載
query = '''
select * from `tableID`
where ...
'''

result = client.query(query)

# データフレームにする場合
df = result.to_dataframe()

# for文でも取り出し可能
for row in result:
  # 処理したい内容
```




## insertする方法

一度にinsertできる行数は10,000までなので注意してください。
10,000行より多いデータを入れたい場合は後述の方法で対応可能です。

```python
from google.cloud import bigquery

# Colabで使う場合はPJ名の指定が必要
client = bigquery.Client()
client = bigquery.Client(project=project_id) # "your-project"

# table_id = "your-project.your_dataset.your_table_name"
table = client.get_table(table_id)  # Make an API request.

# リストの二次元配列
# 例ではタプルになっているがリストでも問題なし(下記はカラムが2つの場合)
# ただしスキーマの数と中のタプル(or リスト)の要素の数が異なるとエラーになるので注意
rows_to_insert = [("string", num), ("string", num)]

errors = client.insert_rows(table, rows_to_insert)  # Make an API request.

# pandasのdataflameを使う場合は
errors = client.insert_rows(table, df.values.tolist())

if errors == []:
    print("New rows have been added.")

```

dfにはdataflameが入っている想定で下記でリストの二次元配列へ変更が可能

```python
df.values.tolist()
```

また、10,000行より大きいデータをinsertしたい場合は下記のように分割してあげてあげましょう。

```python
rows = len(df)
count = 0
while rows > 0:
  client.insert_rows(table, df[(count * 10000): ((count+1) * 10000)].values.tolist())
  rows = rows - 10000
  count = count + 1
```

もっと良い書き方があるかもしれませんが、上記で10000より大きくても全て追加することが可能です。
【Djangoメモ】モーダルを設置する際の失敗


## はじめに
　Djangoで写真投稿サイトを作成中、投稿を削除する際のモーダルをCSSフレームワークUIkitを用いて実装した。しかし本来削除されてほしい投稿が消えずに、関係ない投稿がされる不具合が生じたため、原因を調べてみた。

## 現状
#### 不具合
　以下の画像は１番という投稿の削除ボタンをクリックした時に出現するモーダルであるが対象の投稿が３番になっており「OK」をクリックすると３番の投稿が削除されてしまう。
![スクリーンショット 2020-07-06 10.41.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646903/66fa4802-f145-d383-cc24-dab9d49e9ab0.png)
　
#### コード
```html
{% for post in user_post %}
  省略
  {# 以下削除ボタン #}
  <a uk-icon="icon: trash" href="#modal" uk-toggle></a>
    {# 以下モーダル #}
    <div id="modal" uk-modal>
      <div class="uk-modal-dialog uk-modal-body">
        <h2 class="uk-modal-title">
          投稿削除確認
        </h2>
        <p>
          投稿: {{ post.title }} を削除します。よろしいですか？
        </p>
        <p class="uk-text-right">
          <button class="uk-button uk-button-default uk-modal-close" type="button">
            キャンセル
          </button>
          <a href="{% url 'sns:my_page_remove' post.pk %}">
            <button class="uk-button uk-button-primary" type="button">
              OK
            </button>
          </a>
        </p>
      </div>
    </div>
{% endfor %}
```
* 削除ボタン`<a uk-icon="icon: trash" href="#modal" uk-toggle></a>`の`href="#modal"`でidが"modal"であるモーダルと結び付けられる。
* `<div id="modal" uk-modal>`以下のコードでモーダル機能を実装している。

## 原因
　原因はそれぞれの異なる投稿に対応する削除ボタン（あるいはモーダル）が`id="modal"`というように等しいid名で管理されているため、削除ボタンをクリックした時に今クリックされた投稿が何番目の投稿なのか、加えて、どのモーダルと紐づけられているのかが不明であり、おかしな動きをしてしまうということであった。
　つまり削除ボタンの対象idとモーダルのidを投稿によって変える必要がある。

## 解決策
```html
{% for post in user_post %}
  省略
  {# 以下削除ボタン #}
  <a uk-icon="icon: trash" href="#modal{% post.pk %}" uk-toggle></a>             #変更
    {# 以下モーダル #}
    <div id="modal{% post.pk %}" uk-modal>                                       #変更
      <div class="uk-modal-dialog uk-modal-body">
        <h2 class="uk-modal-title">
          投稿削除確認
        </h2>
        <p>
          投稿: {{ post.title }} を削除します。よろしいですか？
        </p>
        <p class="uk-text-right">
          <button class="uk-button uk-button-default uk-modal-close" type="button">
            キャンセル
          </button>
          <a href="{% url 'sns:my_page_remove' post.pk %}">
            <button class="uk-button uk-button-primary" type="button">
              OK
            </button>
          </a>
        </p>
      </div>
    </div>
{% endfor %}
```
* 削除ボタンの対象idを`href="#modal{% post.pk %}"`モーダルのidを`id="modal{% post.pk %}"`とすることで投稿別にidを付与することが可能となり、指定した投稿を正しく削除することができた。
【Rails・ActiveRecord】_before_type_castを使って型が変換される前の値にバリデーションをかける

#はじめに

ActiveRecordではDate型やInteger型のカラムに文字列を入れると自動でそのカラムの型に変換してくれます。

例えば以下のようなusersテーブルがあったとします。(簡単の為にcreated_atやupdated_atは省略してます。)

~~~db/schema.rb
  create_table "users", force: :cascade do |t|
    t.string "name"
    t.integer "age"
  end
~~~ 

試しにRailsコンソールを使っていろいろな値を入れてみましょう。

~~~.rb
irb(main):001:0> User.new(name: "太郎", age: 21) #ageに数値を入れてみる
=> #<User name: "太郎" , age: 21>

irb(main):002:0> User.new(name: "太郎", age: "21") #ageに文字列を入れてみる
=> #<User name: "太郎", age: 21>

irb(main):003:0> User.new(name: "太郎", age: "2１") #ageに文字列を入れてみる(１は全角数字)
=> #<User name: "太郎", age: 2>
~~~

１つ目は数値を入れています。数値なのでそのまま入りますね。

2つ目は文字列を入れています。文字列の"21"が数値の21に変換されていますね。素晴らしいです。

3つ目はどうでしょうか、"2１"の１の部分は全角数字です。
なんと、age: 2になってしまっています。21とは全然違いますね。

ちなみに"2 1"(間にスペースを入れる)や"2ア"(数字以外の文字を入れる)などしても、age: 2となります。



##何が困るのか

数字以外の入力を弾こうとして以下のようなバリデーションをかけたとします。

~~~models/user.rb
  validates :age, format: { with: /\A[0-9]+\z/}
~~~ 

この場合、ユーザーが"2 １", "2ア"などの入力をするととageの2に対してバリデーションがかかることになり、正しいデータとして保存されてしまいます。


## 解決策 「\_before_type_cast」

解決策として、ageに_before_type_castをつけると型が変換された後の値ではなくユーザーの入力した値に対して、バリデーションをかけることができます。[※参考「rails/validatesでbefore_type_cast」](https://dora.bk.tsukuba.ac.jp/~takeuchi/?%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%2Frails%2Fvalidates%E3%81%A7before_type_cast)

~~~models/user.rb
  validates :age_before_type_cast, format: { with: /\A[0-9]+\z/ }, presence: true
~~~ 

## 応用(文字列の変換など)

_before_type_castはバリデーションの他に、文字列の英数字を全角から半角に変換したり、空白を取り除いてから保存したい場合などにも便利です。

例として以下のコードではMojiというgemを使って全角→半角の変換をしています。

今回はユーザーの“2１”(１は全角)などの全角と半角が混じった入力をバリデーション前に半角に揃えたいので_before_type_castを使います。

age_before_type_castでユーザーの入力したそのままの文字列を受け取って変換した後、ageに変換した文字列を入れています。

~~~models/user.rb
  validates :age_before_type_cast, format: { with: /\A[0-9]+\z/ }, presence: true

  before_validation do
    string = self.send(:age_before_type_cast)
    string = Moji.normalize_zen_han(string) 
    send(:write_attribute, :age, string)
  end
~~~

## _before_type_castの性質

###〇〇と〇〇_before_type_castの違い

まず通常の属性と_before_type_castのついた属性の違いです。
[:〇〇_before_type_cast]では値が取得できません。
具体的には

~~~.rb
irb(main):001:0> user = User.new(name: "太郎", age: "21")

irb(main):002:0> user.age
=> 21
irb(main):003:0> user.age_before_typecast
=> "21"

irb(main):004:0> user[:age] 
=> 21
irb(main):005:0> user[:age_before_typecast] 
=> nil 
~~~

user.age_before_type_castなら値が取得できますが、
user[:age_before_type_cast]を使って値を取得しようとするとnilが返ってきてしまいます。

### 〇〇_before_type_castの更新はできない

~~~.rb
irb(main):001:0> user.age = 21
=> 21
irb(main):002:0> user.age_before_type_cast = 21
=> #NoMethodErrorが発生します。
~~~ 

_before_type_castはageへの型変換前の入力を確認するためのものなので、それ自体を更新することはもちろんできないですね。


### save後はどうなるか

また、saveすると〇〇と〇〇_before_type_castは同じになります。
具体的には、

~~~.rb
irb(main):001:0> user = User.new(name: "太郎", age: "21")
irb(main):002:0> user.save
irb(main):003:0> user.age_before_typecast
=> 21
~~~

文字列の"21"ではなく、数値の21が返ってきています。


以上のような性質があるので実装やテストの際は気をつけましょう!

#参考記事

[rails/validatesでbefore_type_cast](https://dora.bk.tsukuba.ac.jp/~takeuchi/?%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%2Frails%2Fvalidates%E3%81%A7before_type_cast)
Javaの比較 compareTo()メソッドを使って

```ruby:filename.rb
public static void main(String[] args) {
        System.out.println("-----a.compareTo(b)を使ってみよう！-----");
		//aが大きい場合
		Integer a = 2;
		Integer b = 1;
		System.out.println("a の方が大きい場合" + " " +a.compareTo(b)); // 1 が返る
       //aが小さい場合
		a = 1;
		b = 2;
		System.out.println("a の方が小さい場合" + " " +a.compareTo(b)); // -1 が返る
      //a と b が同じ数字の場合
		a = 1;
		b = 1;
		System.out.println("a と　b が同じ場合" + " " +a.compareTo(b)); // 0 が返る
		
		
	}
```
compareTo()・・・・まだ使い道がよくわかりません(笑)
【tmux】resize-paneってどうやって入力すんねん

ペインのサイズを変えたくて調べていると、

`PREFIX :resize-pane -D 5`
とか書かれているが、
「え、それってどういうことｗｗ」
って思って１０分くらい悪戦苦闘したのでメモ。

## 難しく考えずにそのまま打てばいい

PREFIX（デフォルトだとctrl + b）を打った後に、

`:resize-pane -D 5`

をそのままタイピングすればいい。

つまり、コロンを打ってresize-pane -D 5を打って最後エンター。

そのまんまやん！って思うんだけどなぜかわからなかったんだ。

PREFIXのあとにコロンをうつと、左下がvimのコマンドモードみたいな感じになるのでそこにやりたいことをコマンドとして入力するということらしい。
デクリメントおじさん 〜擬人化で表す関数設計〜

あるところに数を渡すとひとつ引いた数を返す関数がありました。
関数だとイメージしづらいので擬人化してしまいましょう。
（伝わればいいなぁ）

**デクリメントおじさん**
<img height="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/01f2e6b4-38b5-f000-73d1-4f3bafe1edbd.png">
**「いつでも呼んでください」**

擬人化できました。イメージにピッタリです。

呼び出し側も擬人化しちゃいます。

**呼び出しJK**

<img height="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/504968b9-57d6-e1ce-f7db-65fb848114b4.png">
**「呼び出しちゃうぞ☆」**

かわいい感じに擬人化できました。自己主張が強そうです。


デクリメントおじさんの関数としてはこんな感じのコードです。
プログラム言語は javascript っぽい感じで書いておきます。

```javascript
function decrement(number) {
  return number - 1;
}
```
これで一つ減らした数を返せますね。
おじさんも大喜びです。

でもこれだとまだ不親切なんです。
<img height="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/5c47d673-1b33-fabe-b0a5-0ec416484653.png">


# なにが不親切か

```javascript
const number = 5
decrement(number)
// => 4
```

これはもちろんちゃんと返ってくるのですが、

```javascript
const number = null
decrement(number)
// => 意図しない動作（例外など）
```

と意図しない結果が返ってきてしまいます。
つまりこんな感じです。

<img height="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/b419f489-986e-8319-f495-9beda214d476.png">
**「呼び出し方、考えてくれないかな！？」**
おじさんはむっちゃ怒ってます。意図しないものを渡されたので、当然怒ります。

JKは泣きます。
<img height="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/06082f0a-f5c4-4c8c-163b-131ba1e5428f.png">
**「ごめんなさい。数字しか渡しちゃいけないならそう教えて欲しかった・・・ご飯、味しない・・・」**

JKは、おじさんを呼び出す時に大変気を遣って呼び出す必要が出てきます。

これはプログラム的な言葉でいうと、
**呼び出し側に大きな責任が存在している状態** ということになります。

こういう関数が増えていくと、事前に調べないといけないことが増え、
修正する際にも時間がかかるようになります。


# やさしいおじさんになるには

・事前に渡せるものを明確にしておく
・JKが何を渡してもやんわり注意してあげる

<img height="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/2fa3071a-4425-6a84-3cfd-fbc3b48f06b5.png">
**「どんな呼び出し方してもご安心を！間違えてたら何がおかしいかちゃんと言います」**

これにより、JK はおじさんに引数を渡す時に
気を遣わずに安心感を持って、渡すことができるようになります。

もし間違えたものを渡しても、おじさんの関数が何が悪かったか、
エラーメッセージなどで、ちゃんと教えてくれるため、すぐに気がつけるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/e12c0a17-6f2e-2ab0-4644-71cd2fbd9fdf.png)
**「間違えることもあるけど、安心感を持って、関数を呼び出せます。梅干しおいしい！」**

**これでおじさんが増えても大丈夫です。**


# 具体的には、どうすればよかったか

## 渡して欲しい引数の型を明確にする

数値しか渡せないならば、数値だけ渡せるよう、引数の型を明確にしておく。
JavaScript であれば、TypeScript化して、引数の型を使えるようにするなどの方法があります。

## 間違えたものを渡した場合でも適切な反応を返す

・渡されたものが無効である場合（警告不要レベル）
　・`return null` や、  `return number` などで返す。
・渡されたものが無効である場合（警告必要レベル）
　・エラーメッセージを戻り値として返す
・渡されたもので問題が起きる場合
　・例外を発生させる。 `throw new Exception("エラーメッセージ")`



# まとめ

## 呼び出される側の関数にて、どんなものが渡されても適切な対応を返すようにする

関数がたくさん増えても、どこで間違えたかわかりやすく、保守性が高くなります。

## 呼び出し側は気楽にその関数を呼べるようにする

例えば、マイナス値を渡されたら処理しない関数があった場合、
呼び出し側でマイナスになっているかどうかチェックして呼び出さないよりも、
呼び出された関数側で、マイナス値であれば、即時リターンしてあげると呼び出し側は気にすることが少なくなります。

```javascript:before
if(num > 0){
  // 
  kansu(num);
}
kansu(num) {
  // なにか
}

```

```javascript:after
kansu(num);

kansu(num) {
  if(num <= 0){
    // マイナス値のため、処理しない
    return;
  }
  // なにか
}

```

そのためには if文が増えたり、エラーチェックが増えても問題ありません。

## 擬人化

関数を擬人化して表すことで、
何を渡しても、いい塩梅で反応を返してくれる気のいいおじさんがイメージできたかと思います。
こういういい塩梅で反応が返ってくる関数、もしくはその上のレイヤーのクラスを作っていくことで、
複雑なシステムも安心感を持って、開発を続けていくことができます。

**仕事をする相手にどんなファイルや文書を渡しても、適切な反応を返してくれる方が仕事がしやすいはずです。**
**それと同じように関数、クラスを設計してあげることが大事です。**
Win回帰できなかった

久しぶりにWindowsに回帰したので初期設定メモ
https://qiita.com/takyam/items/a5071e48a49799e93084

↑の記事で書いたように、久しぶりにMacからWindowsに戻ったんですが、
無事にUbuntu（デュアルブート）に落ち着いたのでその備忘録です。

## Windowsの何が問題だったか

WSL2でUbuntu20.04を立ち上げて運用してたんですが、基本的には素晴らしい体験でした。
「Windows上でこんなにサクサクWeb開発ができるなんて！」という感動を覚えます。

「あぁ〜これでWindows回帰できるわ〜」「MacもARMになるしWin回帰勝ったんじゃね」みたいな謎の自信に満ち溢れてたんですが、最終的にダメでした。

### 問題その１: WinとUbuntuはどこまでいっても別モノ

まず、細かい問題として、「localhost以外は勝手にproxyしてくれない」です。

たとえば、 `npm run dev` して `localhost:3000` なサーバーがWSL2 Ubuntu上で起動したとして、
ブラウザはホストのWindows側のChromeから参照する場合、
そこはWSL2がいい感じに「3000はUbuntu側やな」って感じでproxyしてくれるので、サックリ閲覧できます。

最初はWSL2がproxyしてくれてることにすら気づかず、「何か普通に動きよった」って感覚です。

じゃぁ何が問題かっていうと `127.0.0.1 hoge.fuga.local` みたいな `hosts` を設定すると動きません。

いや、あとから考えれば「そりゃそやろ」なんですが、localhostをあまりにも自然にproxyしてくれるので、なぜか `hoge.fuga.local` にアクセスできず、非常に困りました。
ここでは `${ubuntuのローカルIP} hoge.fuga.local` を指定するのが正しいです。

これに気づいてから「こいつWin上に構築された謎技術のすごいUbuntuかと思ったら、ただの最適化されたVMか・・・？」みたいな感覚が強くなりました（よくわかってない）

hostsもUbuntu側とWindows側の両方に正しく定義する必要があり、まぁどこまでいっても別OSだなと。

とはいえコレは知ってれば特にトラブルにもなりにくいレベルの話なので、そんなに大きな問題じゃないです。

### 問題その２: なんか死んで編集中のファイルが消える

なんか死にます。

Ubuntu上にcloneしたgitレポジトリで、npm run devしたり、WEBサーバ動かしたりとかしながら開発してました。
IntellijからもUbuntuのdiskは透過的に見えるの、で `C:\Users\xxx\AppData\Local\Packages\...` みたいなパスで参照すればいけるです。

なので、普通に楽しく開発をできるんですが、たまにフリーズします。Windowsが。

特にパフォーマンス低下や遅延みたいなのを感じることなく開発していけるんですが、
半日とか開発してるあたりで、急にWindowsがフリーズします。

マウスもキーボードもディスプレイタッチも何も反応せず、「くっそー」と思いながら電源長押しからの再起動します。

嫌ですけど、半日に1回起こるか起こらないか、くらいなのでこれくらいなら耐えれるのですが、
このとき、 **編集中のファイルが空になってしまうことがよく起こりました。**

つまり、開発中の差分が吹っ飛びます。これは辛い。

特定のファイルに数十行の修正を加えてて、ここ２−３時間commitしてない、みたいな状況のときにフリーズし、再起動すると空ファイルになってるんです。
Ctrl+Zで戻ろうにも、OS再起動してるので戻れるわけもなく、Intellijのlocal historyにも残って無く、なんていうか、全てが消え去ります。

これを3回くらって、心が折れました。辛いて。

特に回避策とかぐぐっても「I have same issue!」みたいなのしか見当たらず、ぐぬぬって諦めました。

## 結論

Ubuntuデュアルブート最高です。
Ubuntu20.04のデスクトップ初めて触ったですが、とてもいい感じです。とても。
JIRAチケットの説明文にデフォルト値を設定したいのでブックマークレットを作ってみた

## はじめに
JIRAチケットを作成したとき、説明文にデフォルト値を設定したいときありませんか。
テンプレートを作ってそれを説明文に差し込みたい…

それっぽいのはあるんですが。

https://community.atlassian.com/t5/Jira-Core-articles/Jiraのチケット起票時にデフォルト値を設定したい/ba-p/766066

ということで、ブックマークレットでめちゃくちゃ簡単なコードを書きました！

■追記
「クリップボードにコピーさせた方がもっと便利かも！」というアドバイスを頂いたのでそちらも追加しました！

## ブックマークレットに登録するまで

### コードを書く
`descriptionText` の部分は便宜変更してあげてください。

```js
javascript:(
  function(){
    descriptionText = "■デザイン\n\n\n■概要\n\n\n■背景\n\n\n■実装方針\n\n\n■受入条件\n\n\n■リリース調整の有無\n\n";
    document.getElementById("description").value = descriptionText;
  }
)();
```

### ブックマークする
ブックマークをしてあげてください。名前は自分がわかるように適当に入力。
URL欄にコードをコピペしましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50208/06b01951-e30c-76d2-54e9-31a7d92499b0.png)

### あとは使うだけ
チケットを作成して、あとはブクマしたやつをクリックするだけ！

説明に `descriptionText` で設定した値が入ってると思います！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50208/3ca1e38c-a1d4-038f-7bf7-1a031b5c8485.png)


## クリップボードにコピーするまで

### コードを書く
`descriptionText` の部分は便宜変更してあげてください。
箱を作ってあげて `document.execCommand("copy");` を使うとコピーできます。


```js
javascript:(
  function(){
    descriptionText = "■デザイン\n\n\n■概要\n\n\n■背景\n\n\n■実装方針\n\n\n■受入条件\n\n\n■リリース調整の有無\n\n";

    ta = document.createElement("textarea");
    ta.value = descriptionText;
    document.body.appendChild(ta);
    ta.select();
    document.execCommand("copy");
    ta.parentElement.removeChild(ta);
  }
)();
```

### あとはブックマークして使うだけ
ブックマークレットに登録して使うだけ！
クリップボードにコピーされるのであとはペーストするだけです(´∀｀)

## 終わりに
簡単に設定することができました！
今回は説明の箇所に値を設定しましたが、他の箇所でもいい感じに処理を書けそうですね(о´∀`о)
Perl: Starttls でメールの送信

こちらと同じことを Node.js で行いました。
[Python3: Starttls でメールの送信](https://qiita.com/ekzemplaro/items/c248b52a6f36947af080)
[Node.js: Starttls でメールの送信](https://qiita.com/ekzemplaro/items/47c86f76e18e9a7cc7e9)
hi-ho.ne.jp で試しました。

```pl:hi-ho.pl
#! /usr/bin/perl
#
#	hi-ho.pl
#
#					Jul/06/2020
#
# ----------------------------------------------------------------
use Dotenv;
use Net::SMTP;
#
print STDERR "*** start ***\n";
#
my $env = Dotenv->parse('.env');
print STDERR %$env{'SERVER'} . "\n";
print STDERR %$env{'PORT'} . "\n";
#
my $mailhost = %$env{'SERVER'};
my $mailport = %$env{'PORT'};
my $mail_username = %$env{'FROM'};
my $mail_password = %$env{'PASSWORD'};
my $to_mail = %$env{'TO'};
my $from_mail = %$env{'FROM'};
my $smtp = Net::SMTP->new($mailhost, Port => $mailport);
#
$smtp->auth($mail_username, $mail_password);
$smtp->mail($from_mail);
$smtp->to($to_mail);
$smtp->data();
$smtp->datasend("From: $from_mail\n");
$smtp->datasend("To: $to_mail\n");
$smtp->datasend("Subject: Hello Jul/06/2020 AM 10:46\n");
$smtp->datasend("\n");
$smtp->datasend("Hello Everybody\n");
$smtp->datasend("おはようございます。\n");
$smtp->datasend("雨が降っています。\n");
$smtp->quit;
#
print STDERR "*** end ***\n";
#
# ----------------------------------------------------------------
```

```text:.env
SERVER = 'hi-ho.mose-mail.jp'
PORT = 587
USR = '****@hi-ho.ne.jp'
PASSWORD = '****'
FROM = '****@hi-ho.ne.jp'
TO = 'sample@example.com'
```

実行結果

```text
$ ./hi-ho.pl 
*** start ***
hi-ho.mose-mail.jp
587
*** end ***
```

次のバージョンで確認しました。

```text
$ perl --version

This is perl 5, version 30, subversion 3 (v5.30.3) built for x86_64-linux-gnu-thread-multi
```

Dotenv のインストール方法

```bash
sudo apt install cpanminus
sudo cpanm Dotenv
```
GithubのissueをAPI経由で作成する

issue管理大変ですよね。

複数のissueを一気に登録したり、システムと連携してイベントベースでissueを登録できたりすると、issueを管理するのがずっと楽になります。

node.jsで実装しているので、AWS Lambda経由で実行するといろんなイベントから呼び出せて汎用性が高そうです。

# 使うもの
octkitというGithubAPIクライアントのライブラリを使います。
https://developer.github.com/v3/libraries/

ドキュメントも豊富で使いやすいです。

# 実装

```javascript:create_issue.js
const { Octokit } = require("@octokit/rest");
const dotEnv = require('dotenv').config();
const octokit = new Octokit({auth: dotEnv.parsed.ACCESS_TOKEN});

if (process.argv.length !== 4) {
  console.log('タイトルと本文を指定して下さい');
  return;
}

octokit.issues.create({
  owner: '組織名',
  repo: 'リポジトリ名',
  title: process.argv[2],
  body: process.argv[3],
}).then(({data}) => {
  console.log(data);
}).catch(error => {
  console.log(error);
});

```

dotenvを使ってACCESS_TOKENを外から渡せるようにしてあります。

```text:.env
ACCESS_TOKEN=アクセストークン
```

これでissueを作成できます。
（初心者向け）【Rails】Deviseのインストール

#はじめに
こんにちは！　Rails学習中のYori-goreng(ヨリゴレン)です:sunny:
本記事では、ログイン機能を司る`devise`の導入と、ユーザーのアクセス許可についてご紹介します:relaxed:

より詳しく知りたい方は以下の参考記事をご覧ください。

- 参考記事

https://qiita.com/cigalecigales/items/f4274088f20832252374

https://qiita.com/tobita0000/items/866de191635e6d74e392

#環境 
- ruby 2.6.3
- rails 5.2.4.3
- MacOS Catalina バージョン10.15.4

# deviseとは
Rubyのgemの一つで、`devise`を使うことでログインの機能を容易に実装できるようになります。

#1. 【アプリの準備】
#1.1.  アプリ作成
`rails new アプリ名`でアプリを作成します。
ここでは、devise_testという名前にしてみます。

```ターミナル
rails new devise_test
cd devise_test
```


#1.2. DB作成
```
rails db:create
```

#2. 【deviseの準備】
#2.1. gemのインストール
`gemfile`にdeviseのgemを追記します。

```gemfile
gem 'devise'
```
gemをインストールします。

```ターミナル
bundle install
```

#2.2. deviseの関連ファイルを作成

```ターミナル
rails g devise:install
```

以下のような長文がターミナルに表示されれば、成功です。

```ターミナル
===============================================================================

Some setup you must do manually if you haven't yet:

  1.Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4.You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================
```

#2.3. モデル作成
以下のコマンドにより、Userモデルを作成します。

```ターミナル
rails g devise user
```

この時点でマイグレーションを実行すると、簡易的なログインページが完成します。

```
rails db:migrate
```

```ターミナル
rails s
```
`rails s`のあと、http://localhost:3000/users/sign_in でログインページを開きます。

<img width="223" alt="スクリーンショット 2020-06-15 12.02.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364582/17797466-f522-65d9-d248-9d31609d47c9.png">


#2.4. before_action :authenticate_user!
コントローラーに`before_action :authenticate_user!`を記載すると、ここで行われる処理がログインしたユーザーによってのみ実行することができるようになります。
例として、Homesコントローラーを作成します。
※コントローラーの命名規則に、homesのように複数形にするというものがあります。コントローラーの名前は自由に決めても問題ないようです。

```ターミナル 
rails g controller homes index
```

作成した`homes_controller.rb`に`before_action :authenticate_user!`を加えます。

```app/controllers/home_controller.rb
class HomesController < ApplicationController
  before_action :authenticate_user!
  def index
  end
end
```
これにより、indexアクションによる一覧表示はログインしたユーザーのみ確認できます。
俺のcss

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/%E4%BF%BA%E3%81%AEcss/)をご覧ください😀

覚えられなくてググってしまう記号（+とか&）のメモとかテクニックとか。

## 2個目の要素から何かしたい

間隔あけるためmargin-topつけたいとか。隣接セレクタを使う。

```sass
// sass
.item {
  & + & {
    margin-top: 10px;
  }
}

// css
.item + .item {
  margin-top: 10px;
}
```

## classAかつBのとき

```sass
// &と.をくっつけるのがポイント！
.item {
  &.-primary {
    background-color: #fff; // class="item -primary" のとき

    &.-hollow {
      background-color: #000; // class="item -primary -hollow" のとき（詳細度が高いのでこちらが優先される）
    }
  }
}
```

## クラスAをデフォルト値として使う（未指定でも適用されるようにする）

```sass
.item {
  &, // オレでなきゃ見逃しちゃうね！
  &.-primary {
    background-color: #fff;
  }
}
```

## 水平線とテキストのようなコンポーネント作りたい

イメージ

`----- ここから -----`

```sass

// HTMLとしてはタグは一つでいい。
<div class="hr">ここから</div>

// before,afterを使って3要素にして、よしなにやる！
.hr {
  display: flex;
  align-items: center;
  text-align: center;

  &::before,
  &::after {
    content: "";
    background: var.$border-color;
    height: 1px;
    flex: 1 1 auto;
  }
}
```

## 余白とか何ピクセルがええんや・・・

8の倍数でいけ！
aPaaS データソースまとめ

以前、[iPaaS のインテグレーション](https://qiita.com/matsukatsu/items/4efe0d8f8fa0e528f488)についてまとめてみたのですが、aPaaS のデータソースはどうなってるのだろうという疑問が湧いたので、同じように調べてみました。

Gartner によると、aPaaS 市場はこのような感じで、各社しのぎを削っているらしいです。
![aPaaS 市場](https://images.mendix.com/wp-content/uploads/gartner-mq-lcap.png)
ほとんどわかりませんでした。

とりあえず聞いた事がある aPaaS を対象にし、利用できるデータソースを調べてみる事にしました。

- Salesforce
- Kintone
- Microsoft(Power Apps)
- Google(AppSheet)

## 調査結果

利用できるデータソース数を棒グラフにしました。
外部データソースを利用できるものと、そうでないものに分かれました。
![スクリーンショット 2020-07-06 1.27.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/a108856d-1d9d-fdbf-fc96-586da1ed601d.png)

Microsoft と Google は PaaS を提供しています。
他社プラットフォームのデータにアクセスできる機能を提供する事で、データは他社にあってもアプリは自社に持ってくる作戦のように見えました。

aPaaS のデータソースをまとめたもの [aPaaS-DataSources](https://datastudio.google.com/reporting/d0bf7733-e711-475e-be6d-fa731f0c8184)

最近 AWS が Amazon Honeycode という aPaaS をベータ版としてリリースしました。
まだ触っていない上に、ベータ版なので何も書けないのですが、PaaS 提供者が aPaaS を出す意義を考えると、近い将来 Google Sheets や Microsoft Excel 、Salesforce なんかを外部データソースとして扱えるようになるのかなと思っています。

## 参考
- [Salesforce を外部データベースと統合するにはどうすればよいですか？](https://help.salesforce.com/articleView?id=000329420&language=ja&type=1&mode=1)
- [kintone データをまるっとDB やデータウェアハウスに連携・反復同期するCData Sync](https://developer.cybozu.io/hc/ja/articles/360022984291-kintone-%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%81%BE%E3%82%8B%E3%81%A3%E3%81%A8DB-%E3%82%84%E3%83%87%E3%83%BC%E3%82%BF%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%8F%E3%82%A6%E3%82%B9%E3%81%AB%E9%80%A3%E6%90%BA-%E5%8F%8D%E5%BE%A9%E5%90%8C%E6%9C%9F%E3%81%99%E3%82%8BCData-Sync-)
- [How to mobilize your cloud data from different platforms](https://www.appsheet.com/HowItWorks/DataSources)
- [AppSheet Pricing](https://solutions.appsheet.com/pricing)
- [List of all Power Apps connectors | Microsoft Docs](https://docs.microsoft.com/en-us/connectors/connector-reference/connector-reference-powerapps-connectors)
- [Why AWS built a no-code tool](https://techcrunch.com/2020/06/24/why-aws-built-a-no-code-tool/)
CIDコードの取得方法

# 背景
* 旧字体のCIDコードが知りたい場面に遭遇した

# ぐぐる

* グリフウィキで調べたい文字を検索
    * https://glyphwiki.org/
* キャプチャ雑で申し訳ないけど以下のような記述を見つける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480231/8c5b3d96-cae7-68ba-026b-60acf7825457.png)

* aj1= ${CIDコード}になってるっぽい
【Unity/C#】コムソートとは(コード付き)

#コムソートとは
コムソートはバブルソートの改良版です。<br>~~安定ソートではないため場合によっては処理が多くなってしまいますが基本的には早いです。~~

#アルゴリズム
1. 総数 n を 1.3 で割り、小数点以下を切り捨てた数を間隔 h とする。
i=0 とする。
2. i 番目と i+h 番目を比べ、i+h 番目が小さい場合入れ替える。
3. i=i+1 とし、i+h>n となるまで3を繰り返す。
4. hがすでに1になっている場合は入れ替えが発生しなくなるまで上の操作を繰り返す。
5. h を 1.3 で割り、小数点以下を切り捨てた数を新たに間隔 h とし、操作を繰り返す。

#実行結果
![コムソート.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211130/086f28a7-cf58-c89a-c92b-341a29a6f6fd.gif)

#サンプルコード
```C#
	int[] ComdSort(int[] _array)
	{

		// 交換したかのチェックフラグ
		bool isChanged = false;

		// 櫛の間隔を定義します。
		int h = _array.Length;


		// コムソートで配列の中身を昇順で並べ替えます。
		while (isChanged || h > 1)
		{

			// 櫛の間隔を計算します。
			if (h > 1)
			{
				h = Mathf.FloorToInt(h / 1.3f);
			}

			isChanged = false;
			for (int i = 0; i < _array.Length - h; i++)
			{
				// 指定した間隔の要素と比較し、順序が逆であれば入れ替えます。
				if (_array[i] > _array[i + h])
				{
					// 配列の要素の交換を行います。
					int temp = _array[i];
					_array[i] = _array[i + h];
					_array[i + h] = temp;

					// 交換フラグをtrueにします。
					isChanged = true;
				}
			}
		}
		return _array;
	}
```

#まとめ
~~交換ソートの中では比較的に早いですが安定はしていませんのでたまにソートが遅くなります。~~
交換ソートの中では比較的に早いです。
結局、品質とスピードはトレードオフなのか？

## 品質とスピードはトレードオフなのか？

そんな話がまわりであふれているので思うことつらつら書きます。

## まずやらないといけないのは「品質」と「スピード」のイメージあわせ


**「品質」**
これはいわゆる「質」「クオリティ」です。品質には ISO 的な定義として「機能的」「非機能的」「操作性」「快美性」「保守性」など含まれます。 つまりは、ちゃんと動いて、ちゃんとカッコよくて、ちゃんとメンテナンスもしやすいってことです。 「ちゃんと」とはどういうことでしょう？ これは「予定通り」「計画通り」の意味です。 予定以上、計画以上は単に過剰な品質です。


**「スピード」**
これは「単位時間あたりに進む距離」です。 １時間あたりに何Km進むか？
プログラムであれば１日でどれだけのプログラムが組めるか？ みたいな話です。

## さて本題です。

わたしは品質とスピードは直接的には関係ないと思います。 いや、もちろん品質下げれば早くなります。そのあたりをもう少し詳しく。

### 品質を落とすことはゴールの姿を変えること

勘のいい人はすぐわかると思いますが、最初の定義の通りで「品質」というのは「ちゃんと動く≒予定した状態にする」ことです。それは機能だけではなく保守性もそうです。保守性も要件です。一回限りの使い捨てソフトウェアに保守性は要りませんし、100年使うなら保守性は必要です。「〇〇機能」とかといっしょで「保守性」も必要だから担保するものです。

つまり機能であろうと保守性であろうと、「品質」を落とすという事は、本来作りたい／作る予定だったものの姿を変えることです。

それは「ゴールまでの距離を短くする」ことであって「スピードが上がってることにはなりません」。

「品質を落とす」は「本来100m走なのに50m走にした」みたいな意味に近いです。 100m を 50m にするだけなのでスピードは変わりません。「品質」と「スピード」は直接的に関係はありません。

> もちろん短距離走の方が速いというようなことも現実にはありますが……

### では「品質」とトレードオフになるのは？

と言われると「期間」だと思います。

作るものの質を下げる ≒ 作るものを減らす ≒ やることを減らせば、それは当然のように期間を短くできます。

## おまけ

けっこう勘違いしている人いますが……　スピードは「ゴールまでの時間」ではありません。「単位時間あたりの距離や作業量」です。

スピードの話をしているのに単位が「秒」「時間」「日」という「時間」になっている人がいたら要注意ですよ！！ スピードの単位は「km/h」「リリース数/月」とかそういうものです。

## おまけ ２

じゃあスピードを上げるにはどうすればいいかというと。 エンジンの馬力を増やすのです。スキルを上げるのです。 道路を整備するのです。 働きやすい環境を作るのです。 追い風をつくればいいです。 スピードを上げるってのはそういうことです。（再三言いますが距離を短くすることではありません）