OmniAICreator/Qiita-1.07M huggingface dataset:
【Django】ユーザ登録フォームのカスタマイズ

#はじめに
以前、[【Django】ユーザ登録機能の実装](https://qiita.com/onishi_820/items/f8d7cfe0deb828c40381)という記事を作成しましたが、
この時のユーザ登録フォームをカスタマイズしたいなと思ったのでそれに関して調べたことを記事にします。

上記の記事の内容が終わっている状態から進めていきますので、
まだご覧になっていない方はぜひご覧ください。

ちなみに、今現在の私のフォームは下記のようになります。
![スクリーンショット 2021-07-27 22.44.48.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/6d1d1c0f-9317-fba2-d6cc-c7bb95c8f03c.jpeg)



##カスタマイズ

forms.pyを下記のように修正します。
`fields`の箇所は表示したい内容にしてください。

```python:forms.py
from django.contrib.auth.forms import UserCreationForm

from .models import User


class SignUpForm(UserCreationForm):
    class Meta:
        model = User
        fields = ("username", "channel_name", "email", "password1", "password2")

    ### ここから追加
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs["class"] = "form-control"
```

`__init__`をオーバーライドしてfor文の処理を記述します。

何をやっているのかというと、`self.fields.values()`の内容を
for文で順に処理しています。

`self.fields.values()`の中には`class Meta:`で記載したfieldsの内容が入っています。
それらを順に取り出し、`field.widget.attrs["class"] = "form-control"`で
classにform-controlを設定しています。

恐らくですが、各フィールドに`form-control`というクラスを追加し、
cssを反映させているのだと思います。

もし間違っていたらすみません。

上記の内容を記述した結果下記のようなフォームになります。
![スクリーンショット 2021-07-27 22.47.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/17b20ae4-158f-6fbc-cff1-92f11e972fa2.jpeg)

結構見やすくなりました。

チャンネル名は任意入力、Eメールアドレスは必須入力なので、
その旨を記載しようと思います。

```python:forms.py
class SignUpForm(UserCreationForm):
    class Meta:
        model = User
        fields = ("username", "channel_name", "email", "password1", "password2")
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs["class"] = "form-control"
        self.fields["channel_name"].help_text = "任意入力"    ### 追加
        self.fields["email"].help_text = "必須入力"    ### 追加
```

追加した結果が次のようになります。
![スクリーンショット 2021-07-27 22.55.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/9d0aa37e-df08-bdde-e212-69f7d0cb3d57.jpeg)


無事追加されました。

#さいごに

今回の記事は短いですが、これ以上書くこともないので以上にします。。。(笑)

forms.pyをいじることで結構色々できそうなので、
みなさんもぜひ色々試してみてください。
達人プログラマー第二版 社内読書会（7. 伝達しよう！）

達人プログラマー 第二版をつまみ食いする読書会の資料です。

本を読んで印象に残った部分を取り上げていきます。

-----

# 2021/07/29 柴崎担当回
## 「7. 伝達しよう！」

-----

# 「Tips 11. 日本語をもうひとつのプログラミング言語として考えること」

-----

- 自然言語なのにプログラミング言語とは？
  - プログラムの範囲とは？
  - 言語の役割とは？


-----

### プログラムの範囲
- 人間系を含む、広くシステムに関する、プログラムとプロセスの集合体。
  - （システム）全自動⇆半自動⇆手動（利用者or運用者）

-----

- システムは人間系も含める。
- 人間系とは？→システムにかかわる人。
  - エンドユーザー
  - ビジネスサイド
  - サービス運用担当
  - システム管理者
  - 保守開発担当SE。

-----

### 言語とは？
- 構造（ストーリーとして論理関係が整理された意味のあるまとまり）を示す手段
- 結果の再現性
    - 誰がよんでも同じ理解をできるか？
    - 手順書なら、誰がやっても同じ結果になる

-----

- よい文章（自然言語で書かれたプログラム）とは、解釈の余地が少ない。
    - シンプルに伝えるには長い文章にしない。修飾語をなるべく削る。
    - コードもドキュメントもKISS原則至上主義。
    - よい手順書とは？

-----

※誰かに意思決定してもらうためだったり、合意形成をするために、意思疎通するための手段としても言語は使う。
そっちも大事。

-----

### 構造を表現する手段
- 自然言語
- 図によるスケッチ(UMLなどの図式言語など）
  - →図式言語を使うには、図形や線などのあらゆる表現の意味を明確にしないとミスコミュニケーションの原因になる。
    - この図はどう読むのか。

-----

# 「あなたのコミュニケーションが持つ意味は、あなたの元に返ってくる応答だ」

-----

- コミュニケーションは双方向で成り立つ。
  - タイミングを選ぶ、スタイルを選ぶ
  - 聞き手のレベル感や求める情報にあわせて伝え方も大事。
  - 説明する側の時、質問を待つのではなく、こちらからも質問をする。

-----

- 聞き手を巻き込む
    - どんな情報を残し、引き継いでいくべきかを議論する
- 聞き手になる
    - こちらの話を聞いてもらうための姿勢

-----

# 「Tips 13. ドキュメントは付け足すものではなく、作り上げるものである」

-----

いまいちピンと来てない。
ソースコードを主とし、ドキュメントはおまけ的に扱いがちだけど、どっちも大事ということ？

-----


#『APIを開発している場合を除き、コメントは「なぜこれが必要なのか」、すなわちその目的とゴールの記述にとどめておくべきでしょう。（続）

-----

#「どのようにして実行しているのか」はコード自体に記されているため、冗長な情報であり、DRY原則に違反しているのです。』

-----

- ドキュメントとコードの内容が重複するのはよくない。
    - 同じ情報が何度も出てくるのは読むのが大変。
    - また、コードの内容をコメントで補足しなければならないのは不吉な臭い



-----

（そしたら、こんな極論は出ないか？）

- 仕様書とプログラムって同じことを書いてるし重複してないか？仕様はコードにすべて書いてあるから不要では？
- 仕様書つくったら、DRY原則に反するので、プログラムを修正したら仕様書も直す必要がある。

-----

- →仕様書は誰に向けたドキュメントか？誰でもソースを理解できるわけではない。
- →エンジ向けだとしても、目的に合わせてドキュメントが必要なことがある。例えば膨大なソース読むより、システム構成のドキュメントがあった方が、システム理解が早くなる。
- 読者別、目的別にドキュメントを考える

-----

## 「ソースコードへのコメントによって、工学上のトレードオフや、この意思決定に至った理由、棄却した代替案といった、どこにも残すことができないプロジェクトの理解しにくい側面を文書化するまたとない機会が与えられます。」

-----

- 情報の伝え方にもTPOがある。
    - ソースコードへのコメントが適切な場合がこれ。
- 伝える相手、場所、伝え方の例

-----

### 伝える相手
  - どの役割の人か？
  - その情報をもとに、どんな意思決定をしてもらう必要があるか？

-----

### 伝える場所
  - ソースコードなのか、Merge Request/Pull Requestなのか、チケットなのか、Wikiなのか。実行画面なのか、ヘルプやマニュアルに記載するべきか。
    - 伝えたい相手の目につく場所か？
    - 管理画面の説明とかもドキュメントの一つ。
  - 例えば、コメントは誰に向けてのドキュメント？
  - ログに必要な情報って何？
    - 監査ログ
    - 実行ログ
    - エラーログ


-----
### 伝え方の例 1
Sansanの [Values](https://jp.corp-sansan.com/company/philosophy)

- 意志と意図を持って判断する
- [新卒1年目エンジニアがぶつかった壁を振り返る](https://buildersbox.corp-sansan.com/entry/2021/04/08/110000)
    - 自分の判断をのせる

-----
### 伝え方の例 2
- →判断を伝えるために意図が必要。判断しても意図がなければ伝わらない
    - テストがないコード、意図が分からないコード（開発時のコンテキストが失われたコード）は技術的負債になりかねない。

-----

### 伝えた後に 1

そういえば。。。

ドキュメントは古くなると腐る。メンテする人がいないと古くなって、かえって混乱を招く。
どうするべきか？

-----

### 伝えた後に 2

- DRY原則でドキュメントのメンテコストを最小限にする。
- ドキュメントがいつ時点の情報なのか分かるようにし、古いかどうかを判断できるようにする。
- ドキュメントの改版履歴を残す。

-----

→そんな話ではなくて、そもそも、ドキュメントこそメンテする意識が大事。コードは動かすから確認するけど、ドキュメントはQA対象ではないから、気づきにくい。

-----

### 言わない後悔より言った後悔 1

伝えようという気持ちが大事。

-----

### 言わない後悔より言った後悔 2

- 例えば、誰かの社会の窓が開いていたとき、あなたはこっそり伝えられますか？
- 自分の恥よりも、相手の役に立つことを優先させられますか？

ドキュメントのメンテは未来に作業する人に必要な情報を伝えようという気持ちが大事。

-----

おわり
numpy.piecewiseとmatplotlibで区分関数を描画する

# はじめに
最近高校物理の復習をしていて、折角だからグラフを描く問題をmatplotlibで解いてみようと思ったんですが、一次関数の`x`の値で傾きが変わるやつを描くいいやり方がわからない。通る点をハードコーディングして`plt.plot`に渡すという方法はすぐ見つかりましたが、できれば関数は関数として記述したい。しかし調べようと思っても「一次関数の`x`の値で傾きが変わるやつ」の呼び方がわからないから全然正解にたどり着けない。

といった具合に暗中模索していたんですが、小一時間かかってようやく「区分関数」という名称がわかり、`numpy.piecewise`というソリューションに行き着くことができました。

私のように「区分関数」なんて言葉を知らない新米文系エンジニアのためにも、記事として残しておこうと思います。

# やりたいこと
`0 ≦ x ≦ 5` の範囲で、以下の区分関数のグラフを書きたい（`x`は0.1刻みとする）。

```math
y = \begin{cases}
3x + 4 \quad(x ≦ 2) \\
10\hspace{29pt}(2 < x) \\
\end{cases}
```

# numpy.piecewise(x, condlist, funclist)
区分関数（piecewise-defined function）を評価する関数。

x: 定義域。ドキュメントには`ndarray`か`scalar`と書いてありますが、どんな時に`scalar`を使うかはわかりません。普通は`arange`とか`linspace`で生成した`ndarray`を渡すんだと思います。
condlist: 条件文のリスト
funclist: 各条件文がTrueの時の関数のリスト
戻り値: `x`が`ndarray`の場合、`x`の各要素に指定の関数を適用した`ndarray`が返る。

# コード
何も指定しないとy軸が切片の4からになってしまうので、原点を表示させるために`ylim`で表示範囲を指定しています。

```Python
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 5, 0.1)
y = np.piecewise(x, [x <= 2, x > 2], [lambda x: x * 3 + 4, 10])

plt.plot(x, y)
plt.ylim(0, 12)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
```

# 実行結果
Colaboratoryで実行し、想定通りのグラフが表示されました。
![ダウンロード (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/7c9b1044-583a-f00c-bf72-b8355bddc788.png)

# 感想
やっぱり関数は関数のまま記述できたほうがすっきりしますね。

matplotlib初心者ですが、こんなところで躓くとは思っていませんでした。心が折れる前に解法が見つかってよかったです。

最後までご覧いただきありがとうございました。

# 参考文献
[numpy.piecewise — NumPy v1.21 Manual](https://numpy.org/doc/stable/reference/generated/numpy.piecewise.html)
[Mac] Blender上のPythonで特定のファイルを再帰的にインポート（オプション指定あり）


備忘録 \:snake: 

# 前提
* mac OS Big Sur 11.2.3
* Blender2.93.0

# あるディレクトリ内の全ての.objファイルをインポートしたい
```python:
import os
import bpy

# 該当ディレクトリの絶対パス
search_dir = bpy.path.abspath('/Path/to/the/Dir')
ext_list = ["obj"] # ⇦ 他の拡張子をインポートしたい場合，ここを変更

# 該当ファイルをリストアップ
obj_list = []
for root, dirs, files in os.walk(search_dir):
    for ext in ext_list:
        obj_list.extend([os.path.join(root, file) for file in files if ext in file])

# ひとつずつインポート．OBJファイルの場合
for item in obj_list:
    bpy.ops.import_scene.obj(filepath = item)
```

# インポートのオプションを変更したい
GUIでモデルをインポートする場合と同様に，オプションを指定してインポートすることも可能です．下はOBJファイルをインポートする場合に指定可能な引数です．
インポートしたいモデルの拡張子によって関数及び引数は異なるため，[Import Scene Operators - Blender Python API] (https://docs.blender.org/api/current/bpy.ops.import_scene.html)等を参考に調べましょう．

```python:OBJファイルの場合のデフォルトの引数
bpy.ops.import_scene.obj(filepath='', filter_glob='*.obj;*.mtl', use_edges=True, use_smooth_groups=True, use_split_objects=True, use_split_groups=False, use_groups_as_vgroups=False, use_image_search=True, split_mode='ON', global_clamp_size=0.0, axis_forward='-Z', axis_up='Y')
```

↓はY軸を前方向に，Z軸を上にするべく引数を変更した場合です．

```python:
bpy.ops.import_scene.obj(filepath = item, axis_forward='Y', axis_up='Z')
```

# エラーが出たとき
>Pythonスクリプトが失敗。システムコンソールのメッセージをチェックしてください

というエラーが出ることがあります．
Mac PCでLaunchpad等のボタン操作でBlenderを起動した場合，エラーメッセージを確認することができません．
ターミナル上から下のようにBlenderを起動するとコンソールが別ウィンドウで立ち上がり，エラーメッセージを見ることができます．

```sh:
# 一例
open /Applications/Blender.app/Contents/MacOS/Blender
```

****

この記事は以下を参考に作成しました．

* [[自分用メモ] Blender Python を使ったバッチ処理まとめ](https://zenn.dev/jujunjun110/articles/203ad46ba57beb)
* [Blender Pythonで複数メッシュをOBJ形式で一括エクスポートする。](https://note.com/heroyuki/n/nec4180721373)
* [指定した複数の拡張子のファイルを再帰的にすべて検索](https://qiita.com/sakiyamaK/items/63e57dec25296c1ccdc4)
デリゲートメソッドを作成 -swift

◉デリゲートとは
　プロコトルを用いたデザインパターンで「他のクラスのインスタンスに、処理を任せることができる」もの

◉主役
・プロトコル
・処理を任せるクラス
・処理を任せられるクラス
　ex)
 UITableViewを表示するUIViewControllerがあるとする。
　　UITableViewだけではUIとして完成しない(セルやセルの数自体がない為)
 ・プロトコル→UITableViewDelegateとUITableViewDataSource
 ・処理を任せるクラス→UITableView
 ・処理を任せられるクラス→UIViewController

◉デリゲートメソッド作成・使用方法
①プロトコールの作成

```
protocol プロトコール名　{
 //規則のみ定める
　　func メソッド名(引数：外部引数)
}
```

②プロトコールを変数化して使えるようにする

```
var 変数名:プロトコール名？
```

③任意のタイミングで発動

```
@IBAction func Action名(_ sender: Any) {
   //処理を任せるクラスで発動させる
     変数名.メソッド名(引数：外部引数)
}
```

④処理を任せられるクラスでプロトコールを宣言

```
class ViewController: UIViewController,プロトコール名 {
　　　　override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
}
```

⑤プロトコールに書かれたメソッドを記述

```
 func メソッド名(引数：外部引数)　{
    //外部引数には処理を任せるクラスの変数の値が入っている
 }

```

⑥ 処理を任せるクラスから処理を任せられるクラスへ委任を受ける

```
override func prepare(for segue:UIStoryboard,sender:Any?) {
    let 変数　= segue.instination as! 処理を任せるクラス
    変数.プロトコールの変数名 = self
}
```
ノードがHTML内に存在するかを調べる６つの方法

## はじめに

ノードがHTML内に存在するとは、開発ツール(DevTools)でHTMLを見たときノードが存在するということです。

HTML内に存在しないノードは、削除したノードやcreateElementで作成したばかりのノードです。これらはプログラミング内で変数として存在し得るがHTML内に存在しません。

ReactなどのSPAなページで動的に変化するノードをブックマークレットやユーザースクリプトから操作しようとしたときノードがHTML内に存在しないことが問題になることがあります。

## 6つの方法

### 1. getBoundingClientRectを使う方法

```javascript
function exist_in_html_1(node) {
	var bcr = node.getBoundingClientRect();
	return bcr.height > 0 || bcr.bottom !== 0;
}
```

### 2. closestを使う方法

```javascript
function exist_in_html_2(node) {
	return Boolean(node.closest('html'));
}
```

### 3. containsを使う方法

```javascript
function exist_in_html_3(node) {
	return document.contains(node)
}
```

### 4. compareDocumentPositionを使う方法

```javascript
function exist_in_html_4(node) {
	return !(document.compareDocumentPosition(node)
		& Node.DOCUMENT_POSITION_DISCONNECTED);
}
```

### 5. compareBoundaryPointsを使う方法

```javascript
function exist_in_html_5(node) {
	var range = document.createRange();
	range.selectNode(document.body);
	try {
		var sourceRange = document.createRange();
		sourceRange.selectNode(node);
		range.compareBoundaryPoints(Range.START_TO_START, sourceRange);
	} catch (error) {
		return false;
	}
	return true;
}
```

### 6. isConnectedを使う方法

```javascript
function exist_in_html_6(node) {
	return node.isConnected;
}
```

## 最後に

最適解は最後に紹介した方法です。最適解を知らなかったので5つも自作することになりました。[MDN Web Docsの英語のドキュメント](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected)に日本語訳がないので最適解をご存じない方も多いのではないでしょうか。最適解と5つの自作方法を紹介しました。
Nuxt.jsでpdf.jsを使うときにハマったこととその解決策

Nuxt.jsでpdf.jsを使おうとしたらいくつか困るポイントがあり、またドンピシャな解決策もなかなか見つからなかったので備忘録的に残しました。
体系だった使い方は、参考にあげたGoodpatchさんの記事がよくまとまっています。
しかし、この記事通りにやってもハマると思うので、合わせて読むと良いと思います！

ちなみに、この段階で私が使っていたNuxtのバージョンは2.15.7です。

また、pdf.jsはnpmでインストールできる`pdfjs-dist`を使っています。

https://www.npmjs.com/package/pdfjs-dist

## pdfjs-distのバージョン

この記事を書いている時点で最新のpdfjs-distのバージョンは2.9.359ですが、新しいバージョンでは新しいJavascriptの記法をつかっているということだと思われ、pdf.jsが呼ばれるタイミングでSyntax Errorが起きてしまいます。

WebpackやBabelに精通しているわけではないので深追いはせず、pdfjs-distのバージョンをもどすのが手っ取り早いと思い2.5.207に戻すことで対処しました。

## CMap、worker

pdf.jsでPDF内の文字を表示させるには、CMapが必要です。
また、こちらは絶対必要というわけではないですが、パフォーマンス的に処理をメインスレッドから逃すためにWeb Workerを使うためのスクリプトも使うことができると望ましいです。

ブラウザがこれらのファイルを読みにいけるようになっている必要があります。Nuxtを使っている場合は、staticディレクトリの中に配置してしまうのが手っ取り早いと思います。(参考で挙げたように、クロスオリジン関連には気をつけましょう)

これらは`node_modules/pdfjs-dist/`のなかに含まれているので、

```bash
cp -r node_modules/pdfjs-dist/cmaps/ static/cmaps/
cp node_modules/pdfjs-dist/build/pdf.worker.min.js static/
```

と`static/`の中にコピーしておいて、コンポーネントの中でそれぞれの位置を指定します。

```vue
<template>
...
</template>
<script>
import * as PDFJS from 'pdfjs-dist'
PDFJS.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js' // ← workerスクリプトを配信するパスを指定

export default {
  ...
  async mounted() { // 別にmountedである必要はないです
    this.pdf = await PDFJS.getDocument({
      data: <PDFファイルのデータ>,
      cMapUrl: '/cmaps/', // ←ここでCMap関連のファイルを配信するパスを指定
      cMapPacked: true
    }).promise
  },
  ...
}
</script>
```

CMapについて詳しくは↓

https://www.morisawa.co.jp/culture/dictionary/1921

## レンダータスクのキャンセル

最初はこんな感じで、表示するページを表す`this.currentPageNum` が変化するたびに同じcanvasを使いまわして新しいページを表示するようにしていました。
参考のGoodpatchさんの記事と同じ内容です。

以下は`methods`の中に書くメソッドです。

```vue
    async renderPage() {
      const page = await this.pdf.getPage(this.currentPageNum)
      const canvas = this.$refs.previewZone
      const viewport = page.getViewport({ scale: 1 })
      const context = canvas.getContext('2d')
      const renderingTask = page.render({
        canvasContext: context,
        viewport: viewport,
      })

      await this.renderingTask.promise
    },
```

だいたいこれで動くのですが、ページ切替を早く行うと`pdfjs Cannot use the same canvas during multiple render() operations`というエラーが起きていました。

まだ前の`render`が終わっていないのに次の`render`が呼ばれるとダメなようです。
そこで、`renderingTask`を`render`処理が終わっていない間はコンポーネントのプロパティに持たせるようにして、次の`render`が来たときに前のが終わっていなかったらキャンセルするようにしました。

```vue
    async renderPage() {
      if (this.renderingTask) {
        await this.renderingTask.cancel()
        this.renderingTask = null
      }

      const page = await this.pdf.getPage(this.currentPageNum)
      const canvas = this.$refs.previewZone
      const viewport = page.getViewport({ scale: 1 })
      const context = canvas.getContext('2d')
      this.renderingTask = page.render({
        canvasContext: context,
        viewport: viewport,
      })
      this.renderingTask._internalRenderTask.callback = () => {
        this.renderingTask = null
      }

      await this.renderingTask.promise
    },
```


## 参考

https://qiita.com/kazu_death/items/f29b110cb2d4b482ff94

https://medium.com/studist-dev/pdfjs-worker-cross-origin-7efe24540be4
Swift MacアプリでDockにアイコンを表示しない方法

Dockにアイコンを表示するかの判定はInfo.plistに`LSUIElement`を定義することで実現できる。  
`LSUIElement`はDockにアイコンを置かないアプリかどうか(エージェントアプリかどうか)を判定するキー。

https://developer.apple.com/documentation/bundleresources/information_property_list/lsuielement

以下のように`true`を指定することでアイコンを非表示にできた。

```xml
<key>LSUIElement</key>
<true/>
```
言語はtypescript.CDKでLambda Layers の設定をする

## やりたいこと

　CDK でAPIを作成しており、axiosを使ってAPIを叩けるようにしたい。
ただ axios は lambda の中に用意されていないライブラリなのでインポートする必要がある。

## Lambda layers とは

Lambda で利用するライブラリを保存して利用可能にしてくれる AWS のサービスである。
これを活用することで axios が　Lambda でも利用可能になる
他にもaxiosをLambdaで使う方法があるけどこれが便利

## 使い方

まずは Lambda Layer に保存するライブラリの保存箇所を作成する必要があります。
通常利用しているプロジェクトから`layer/nodejs`というディレクトリを作成し、そこにパッケージを一通り定義して保存します。

```

mkdir layer
cd layer
mkdir nodejs
cd nodejs

```

`layer/nodejs`に移動したら`yarn init` をしてプロジェクトを作成。そこでライブラリをインストールして保存します。

```
yarn init
yarn add --dev axios

```
その後Lambda関数のインスタンス化をしている箇所でlayersを定義。Lambda関数を作成します。
そうするとLambda関数でインストールしたライブラリが利用可能になります。

```

const func = new lambda.Function(context ,functionName, {
   functionName: functionName,
   runtime: lambda.Runtime.NODEJS_12_X,

   // 下記追加
   layers: [nodeModulesLayer],
 });

```

###最後に

Youtubeチャンネルはじめてました！
エンジニアの姿は十人十色。
今後も色んなエンジニア像を捉えて、それを目指す人たちの参考になる動画を作っています。

https://youtu.be/KRTo7MlOd9w

あと、プログラミングもメンタで教えているので興味があったらみてください。

https://menta.work/plan/1734
eachを使うと情報が全部表示される

#はじめに

![スクリーンショット 2021-07-27 21.31.16（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/e1edf69c-84cd-1a6b-84f3-b8ca0568ce48.png)

コメント機能を実装しました。
しかし何故かDBの情報が全部表示されてしまいます。

すごい凡ミスだったのですが投稿します。

#現在の記述

```erb
<%= form_with(model: [@review, @comment], local: true) do |f| %>
 <%= f.text_area :content %>
 <%= f.submit "コメントする", class: "btn btn-outline-info" %>
<% end %>

<%= @comments.each do |comment| %>　#コメント一覧を表示
 <%= comment.user.nickname %> #コメントしたユーザー名表示
 <%= comment.content %>　＃コメント表示
 <%= time_ago_in_words(comment.created_at) %>前にコメント　　＃コメントした時間表示
<% end %>
```

![スクリーンショット 2021-07-27 21.40.38（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/0ce73887-0112-eb1b-d3d9-b01989713579.png)

コメントする前から最初から`[]`があったでおかしいとは思ってました。

#結論

```erb
<%= @comments.each do |comment| %>　
```
こいつに問題がありました。

これは表示されてはいけないので`<%  %>`このように記述しなけらばなりません。

なので以下のように記述します。

```erb
<% @comments.each do |comment| %>　
```
Wifiルータを中継APにして、TelloEduドローン２機の無人プログラム編隊飛行に成功（Macbook PC）


__過去2本の記事__の続編に続いて、いよいよ2機のドローンに対して、Macbook PCから同時に操作コマンドを送信してみます。__2機とも、離陸から着陸まで、意図した通りに動作しました。__

- __[前回の記事](https://qiita.com/electronics_diy721/items/781a1d9dc89802072add)__
- __[前々回の記事](https://qiita.com/electronics_diy721/items/0b9dd5127870ecba75b5)__


###実行画面 （Macbook PC）

####実行コード

>```text:
> python3 two_drone_remote_ctl.py -drone1_ip 192.168.0.9 -drone2_ip 192.168.0.11
>```

```bash:Terminal
electron@diynoMacBook-Pro TelloEduSwarm % python3 two_drone_remote_ctl.py -drone1_ip 192.168.0.9 -drone2_ip 192.168.0.11
1機目のドローンに接続します。('192.168.0.9', 8889)
2機目のドローンに接続します。('192.168.0.11', 8889)
electron@diynoMacBook-Pro TelloEduSwarm % 
```

###実行したスクリプトファイル

```Python3:two_drone_remote_ctl.py
import socket, argparse, time    

# 各機体のIPアドレスを、コマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='')  
parser.add_argument('-drone1_ip')  
parser.add_argument('-drone2_ip')  

args = parser.parse_args() 
fst_dron_ip = args.drone1_ip
snd_dron_ip = args.drone2_ip

#print("IPアドレス {0} 番のTelloEduドローンに操作コマンドを送ります。".format(tello_ip))

# TelloEduのポート番号は全機体、同じ定数文字列
tello_port = 8889
fst_drone_address = (fst_dron_ip, tello_port)
snd_drone_address = (snd_dron_ip, tello_port)

print("1機目のドローンに接続します。" + str(fst_drone_address))
print("2機目のドローンに接続します。" + str(snd_drone_address))

socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 両機にcommand指令を伝達
socket.sendto('command'.encode('utf-8'), fst_drone_address)
socket.sendto('command'.encode('utf-8'), snd_drone_address)

# 前の動作が終わるまで、sleepで待機
time.sleep(3)

# 両機、同時に離陸
socket.sendto('takeoff'.encode('utf-8'), fst_drone_address)
socket.sendto('takeoff'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 機体1: 右20, 前20, 上20の座表地点に向けて、右斜め上に移動
socket.sendto('rc 20 20 20 0'.encode('utf-8'), fst_drone_address)
# 機体2: 左20, 前20, 上20の座表地点に向けて、右斜め上に移動
socket.sendto('rc -20 20 20 0'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 機体1: 時計回りに45度回転座
socket.sendto('cw 45'.encode('utf-8'), fst_drone_address)
# 機体2: 反時計回りに45度回転座
socket.sendto('ccw 45'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 機体1: 50前進
socket.sendto('forward 50'.encode('utf-8'), fst_drone_address)
# 機体2: 50前進
socket.sendto('forward 50'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 機体1: 100上昇
socket.sendto('up 100'.encode('utf-8'), fst_drone_address)
# 機体2: 100上昇
socket.sendto('up 100'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 機体1: 20上昇
socket.sendto('up 20'.encode('utf-8'), fst_drone_address)
# 機体2: 20降下
socket.sendto('down 20'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 機体1: 20降下
socket.sendto('down 20'.encode('utf-8'), fst_drone_address)
# 機体2: 20上昇
socket.sendto('up 20'.encode('utf-8'), snd_drone_address)

time.sleep(3)

# 両機、同時に着陸
socket.sendto('land'.encode('utf-8'), fst_drone_address)
socket.sendto('land'.encode('utf-8'), snd_drone_address)

time.sleep(3)
```
cmake + pybind11 で Blender でロードできる native module を作るメモ

## 背景

Blender の plugin(addon)を作りたいが, pure Python だと遅くなるのが見込めるため C++ native module を作りたい.

## 構成

Blender 2.93 LTS(Python 3.9)を想定します.

* pybind11(最新版)
* Python interpreter, library は Blender のを使います
* Python header files は Python ソースコードから取得します.

https://qiita.com/syoyo/items/ed9a9678a707f1578d74

にあるように, Blender のパッケージには native module ビルドに必要な Python ヘッダファイルがありません.

Linux であれば apt とかで入れるのも手ですが, Windows, Linux, macOS でのビルドを考える場合, Blender と同じバージョンのソースコードを拾ってきて, 自前 repo にヘッダファイルだけ追加して対応するのが面倒が無くてよいでしょう.
(pyconfig.h だけ Blender パッケージのを使う)

## CMakeLists.txt

```
add_subdirectory(${PROJECT_SOURCE_DIR}/external/pybind11 pybind11_build)

set(SOURCES binding.cc)

pybind11_add_module(mymodule ${SOURCES})

# For Python.h header files.
# Assume Blender 2.93 LTS(Python 3.9)
target_include_directories(mymodule PRIVATE ${PROJECT_SOURCE_DIR}/python3.9/Include)

```

という感じで, `target_include_directories` で `Python.h`　へのヘッダパスを追加してあげればいけます!

## cmake bootstrap

```


# Set path to blender's python
PYTHON_EXE=$HOME/local/blender-2.93.1-linux-x64/2.93/python/bin/python3.9

curdir=`pwd`

builddir=${curdir}/build

rm -rf ${builddir}
mkdir ${builddir}

cd ${builddir} && CXX=clang++ CC=clang cmake \
  -DPYTHON_EXECUTABLE=${PYTHON_EXE} 
  ..
```

のように `PYTHON_EXECUTABLE` 指定で cmake 処理します.


## アドイン(module)の置き場所

https://docs.blender.org/manual/en/latest/advanced/blender_directory_layout.html

USER に入れるのが楽でしょうか.

Linux だと

`~/.config/blender/2.93/scripts/addons/modules`

になります.

探索パスは Blender Python コンソールで

```
>>> import sys
>>> sys.path
```

で確認できます.

注意点として, `USER` フォルダの場合, `scripts/addons/modules` はデフォルトでは作られないため, 自前でフォルダを作る必要があります. またフォルダを作った場合 Blender を再起動しないと module ファイルを見つけてくれません.

あとは Blender の Python から

```
>>> import mymodule
```

などとすればインポートできるはずです!

## C++ から bpy など Blender API へのアクセス

https://qiita.com/vipper36/items/3e6012c3c770ade0d412

https://i-saint.hatenablog.com/entry/2019/01/06/203356

ありがとうございます. 

最近の Blender は numpy(もどき?)が標準でついたので, たとえばメッシュデータは numpy 配列にして一括アクセス... みたいにすると, C++ で頑張らずとも Python レイヤーでも高速に処理できるやも?(要検証)
ImaginaryCTF WRITEUP

# 初心者が ImaginaryCTF 出てみたので WRITE UP 書いてみた
CTFを解き始めてまだ数ヵ月の自分ができる範囲でやってみた。
(まぁ、といっても解けた問題は少ないんですが...)

* 解けた問題一覧
    * Chicken Caesar Salad (50pts) - Crypto 
    * Hidden (50pts) - Forensics 
    * Imaginary (100pts) - Misc 
    * Spelling Test (100pts) - Misc 
    * Vacation (100pts) - Forensics 
    * Lines (150pts) - Crypto 

# Chicken Caesar Salad (50pts) - Crypto 

これはCaesar cipherなので、cyberchef等で探せばすぐに終わります。
```qkbn{ePmv_lQL_kIMamZ_kQxpMZa_oMb_aW_pIZl}```
```⇒ictf{wHen_dID_cAEseR_cIphERs_gEt_sO_hARd}
```

# Hidden (50pts) - Forensics 

.psdファイルなので、フォトショップのファイル(?)らしい。　　
なので、以下のサイトを用いて行うと
https://www.photopea.com/
```ictf{wut_how_do_you_see_this}```が赤のボックスの後ろに隠れている


# Imaginary (100pts) - Misc   
netcatでサーバに繋ぐと数学の問題が出てくるのでそれを解いて送り返すというのを300回行うことになる。ただ、まれに問題ではなく文字列が問題として出てくることがあるので例外として処理する必要があるっぽい。
なので、pythonで処理させて解いてみると以下のようなフラグが入手できる
```ictf{n1c3_y0u_c4n_4dd_4nd_subtr4ct!_49fd21bc}
```

#Spelling Test (100pts) - Misc 

wordがlistで出てくるのでgooglespreadsheetで関数を用いて一括翻訳し翻訳できないところをlistとして抜き出す。それを予測の翻訳で差分をとってflagが出る。
```ictfyoupassedthespellingtest
⇒ictf{youpassedthespellingtest}
```

#Vacation (100pts) - Forensics 

以下の写真の場所を特定し、緯度経度をflagとして答えを出せというものらしい

![image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1810405/636f7425-2bc9-8961-cd23-10bef8d6571a.jpeg)

画像検索すると全く異なる場所に飛ばされてしまうので、画像の電柱の旗から「city of south lake tahoe」の文字が読み取れと検索すると場所が出てくるので、あとは「sugar pine bakery」と検索すると詳しい場所が特定できる。
flagは「38.94730200596602, -119.96089901908834」を四捨五入して```ictf{38.947_ -119.961}```となる。

#Lines (150pts) - Crypto 

RSA暗号と似たような形式の問題で単純な有限体の計算を求められている感じです。
ここでメッセージは```msg = bytes_to_long(b":roocursion:")```より

```math
\begin{align}
flag=\frac{encrypt(flag)*msg}{encrypt(msg)}  \ \ \ mod\ p \\
\end{align}
```
以上のように計算すると```ictf{m0d_4r1th_ftw_1c963241}```というflagを入手できる。


#解いた感想
数ヵ月なのでweb,pwnの問題が全くと言っていいほど解けないので要練習かなぁ...としみじみ思いました。

初めてQiita使ってみたので誤植等がありそうで怖いですがなにとぞご容赦ください...
エラー発生（未解決）→解決！！

#はじめに
エラーが解決せず、１２時間が経ちました。
一体何が悪いかさっぱり分かりません。
もう永久にブラウザが表示されないのではないかと思っています。

過去にこんなことがあったんだということを忘れないためにも、
備忘録として残します。

#コード
routes.rb

```ruby
Rails.application.routes.draw do
  devise_for :users
  get 'prototypes/index'
  root to: "prototypes#index"

  resources :prototypes
  
end
```

prototypes_controller.rb

```ruby
class PrototypesController < ApplicationController
  def index
    @prototypes = Prototype.all
  end

  def new
    @prototype = Prototype.new
  end

  def create
    @prototype = Prototype.new(prototype_params)

    if @prototype.save
      redirect_to root_path
    else
      render :new
    end
  end

  private

  def prototype_params
    params.require(:prototype).permit(:title, :catch_copy, :concept, :image ).merge(user_id: current_user.id)
  end

end
```

index.html.erb

```ruby
<main class="main">
  <div class="inner">
    <% if user_signed_in? %>
      <div class="greeting">
        <%= "こんにちは、" %>
        <%= link_to "#{current_user.name}さん", root_path, class: :greeting__link%>
      </div>
    <% end %>
    <div class="card__wrapper">
      <%= render partial: 'prototype', collection: @prototypes %>
    </div>
  </div>
</main>
```

_prototypes.html.erb

```ruby
<div class="card">
  <%= image_tag "プロトタイプの画像", root_path, class: :card__img%>
  <div class="card__body">
    <%= link_to "プロトタイプのタイトル", root_path, class: :card__title%>
    <p class="card__summary">
      <%= "プロトタイプのキャッチコピー" %>
    </p>
    <%= link_to "by プロトタイプの投稿者名", root_path, class: :card__user %>
  </div>
</div>
```

# ここが間違いではないか
_prototypes.html.erbの

```
<%= image_tag "プロトタイプの画像", root_path, class: :card__img%>
```
が間違いだと思う。
しかし、image_tagとlink_toの記述の違いがわからない。
ここから復習します。

#終わりに
今回は完全に私事で記事を書いてしまいました。

この問題が明日に、
未解決→解決にできるよう精一杯エラーと向き合います。

まずは落ち着いて、リフレッシュしながら頑張ります。

# 追記
案の定、以下が間違いでした！！

（誤）

```ruby
<%= image_tag "プロトタイプの画像", root_path, class: :card__img%>
```
（正）

```ruby
<%= link_to image_tag(prototype.image, class: "card__img" ), prototype_path(prototype.id) %>
```

エラー解決！！
気持ちいい！！
イニシャライザの４種類（Swift)

Swiftのイニシャライザには４つの種類がある
--
①デフォルトイニシャライザ
②メンバーワイズイニシャライザ
③カスタムイニシャライザ
④失敗可能イニシャライザ

デフォルトイニシャライザとは
--
デフォルトイニシャライザとはデフォルトでストアドプロパティが入っているので引数がなくてもインスタンス化できるイニシャライザのこと。
暗黙的にイニシャライザが実装される

```swift
struct Fish {
　　 var area = "北海道"
　 var price = ３０００
}
```

メンバーワイズイニシャライザとは
--
構造体にしか使われないイニシャライザ。型指定のみのデータしか入っていない場合に使われる。
通常は```init()```で初期化処理をしなくてはならないが、この場合は書かなくてもインスタンス化できてしまう

```swift
  struct Fish {
　　 var area:String
  var price:Int
     //init(area:String,price:Int) {
       //self.area = area
       //self.price = price
    //}
 通常はコメントアウト部分必要だが、なくてもいける
}
 let fish = Fish(area:"北海道",price:3000)
```

カスタムイニシャライザとは
--
通常の```init（）```を使って初期化処理をするイニシャライザのこと

失敗可能イニシャライザとは
---
文字通り失敗可能なイニシャライザ。

```swift

struct Fish{
     var area:String
       init?(area:String?) {
             gurad let a = area else {//アンラップする処理
                return nil//何も入っていなければnilを返す。
       }
     self.area = a
  }
}
```

初期化処理時に```init?```で値が入ってこない場合は処理をスキップするようにし、その場合は後のguard let else構文もしくはif let などでアンラップしてあげてnilをかえしてあげる。
自動化による品質保証を適度な開発速度で維持したい

テストを自動化したいが，テストケースが多すぎると開発速度が落ちる．
（全体の自動テストの実行時間が遅くなる．確認・修正のサイクルも遅くなる）

品質を自動で担保したい時に考えていることをまとめてみた．

## コードの正しさを自動化で確認する方法

現実的な方法としては，大きく分けて二つある．

- 静的解析（契約で保証する）
- 自動テスト（実行で保証する）

個人的には，静的解析に頼ることが多い．
静的解析できないことを自動テストで補うスタイルをとりがち．

### 静的解析

ファイル保存などのタイミングで型の整合性を確認し，定義に合わないコードを自動で検出させる．

インターフェースによる契約で品質を担保する技術とも言える．

Rust とか関数型言語の流れを強く受けた言語でよく使う．

完全に静的解析だけで保証する方針の場合，Rustでは `cargo check` をCIにさせればよい．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801258/9a83b5df-749f-3fc1-5d56-e2be6ac29f1f.png)


#### メリット

- 異常に気付くタイミングが早く，対応を打ちやすい
- テストコードを書く必要がなく，定義変更に伴う影響を網羅的に保証できる

#### デメリット

- 型で表現できない問題は対象外（実行時にパニックが起こるものなど）
- 味方のはずのコンパイラと戦うことになり，開発速度が低下することがある

### 自動テスト

テストコードを書き，テストコードを別途実行させる．

動くコードが正義という考え方．

自動テストを行う方針の場合，Rustでは `cargo test` をCIにさせればよい．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801258/ee23be27-629f-7fe2-fad0-a450c28e43b7.png)


#### メリット

- テストコード自体が，使用方法の簡単な説明になる
- 静的解析では検知できない問題に対応できる（特に結合テストなど）

#### デメリット

- 倍近いコードを書くに等しい
- 複雑な対象はテストコードの組合せ爆発に繋がる
- 規模が大きくなるとテストの実行時間も長くなる（負債扱いされだす）

## 静的解析する際に意識してきたもの

### エディタの PROBLEMS を常に0にする

Warning や Error がひとつも出ない状態を維持する．

自分の加えた変更による影響点が原因なのか，元々問題であったのかを切り分けるため．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801258/ebe2e69c-dfdb-f674-9610-c53fb0cfa2b6.png)


### 早い段階で型を断定する

曖昧なコードは抽象的とは違う．
入力は受け取った段階で具体的な型に変換し，静的解析の恩恵を最大限に利用する．
（具体的には JSON などのをシステムの内部で使い回さず，早い段階で構造体にマップする）

### 具体的な型を使う

NewType パターンはうっかり間違った情報源からデータを取ってこないように，よく使う．

コンテキストにあった型を使った方が，間違えにくく，コードも追いやすくなる．

```rust
// 間違えやすい
fn get_prize(id: uuid::Uuid) -> Result<Prize, Error> {
    ...
}

// 間違えにくい
struct PrizeUuid(uuid::Uuid);

fn get_prize(id: PrizeUuid): -> Result<Prize, Error> {
    ...
}

```

## 自動テストで意識してきたもの

### 宣言的なものはテストしない

例えば，宣言的なバリデーションを利用しているときは，それをテストをしない．

```python
class UserValidator(Validator):
    @not_null
    @min(5)
    @max(50)
    name: int

    ...
```

宣言的なテストは，いつも奇妙なテスト内容だ．

**「Null を入れたらエラーになる時，Null を入れたらエラーになること」**

この場合，テストで捕まる要因はバリデータの書き忘れだが，
バリデータを書き忘れるときは，テストケースも書き忘れる．

バリデータの定義を確認するだけの方が効率が良い．

静的解析で保証できることも，もちろんテストしない．

### 公開されたインターフェースをテストする

インターフェース上できない操作は起こる事がない．
（もちろん，インターフェースに基づいた設計をしていればの話だが...）

クラスのインターフェースの単位で単体テストを書いている．

下記は単体テストで書かない

- private な関数のテスト
- 単体テストされた別のクラスを内部で利用した際，その別のクラスに関するテスト

### 一つのクラスを多機能化させない

クラスのインターフェースが増えれば組み合わせによるテストケースも増える．

特に，内部状態が変化するインターフェースには注意が必要だ．

クラス設計は 1 つの機能を上手くやるレベルの方が，バグは少ない．

```python
class CsvWriter:
    def write(self, file: File):
        ...

class FileChecker:
    def check(self) -> bool:
        ...
```

### テストコードを他人への説明に利用する

どのような条件の時にテスト対象が使えるのかを説明するようにテストを書く．
（ DocTest の考え方をテストでよく利用する）

```rust
# テスト対象が使える状況までの道筋（使用方法）
let user = create_user()?;
let campaign = create_campaign(user)?;
let prize = create_prize(campaign)?;

# テスト対象
let response = api::update_prize(prize)?;

# テスト判定
assert_eq!(response.status, RESPONSE_SUCCESS);
```
Processing: text()の日本語入力が文字化けする問題を超簡単に解決する方法

#はじめに
今回はProcessingを使う人が困りがちな、text()で日本語入力しようとした際に文字化けする問題を最も簡単に解決できる方法(筆者体感)を紹介します。

**筆者はPythonで説明します。**
※Javaでの動作は確認できていないのでもし確認できた方はコメントで教えてください!

#本題
###文字化け
みなさん、Processingにて下記のように**text()** を使って日本語を表示しようとしたことはありませんか？

```Python
def setup():
    size(400, 400)
    background(0)
    font = createFont("Meiryo", 50)
    textFont(font)
    textSize(50)

def draw():
    fill(255, 0, 0)
    textAlign(CENTER, CENTER)
    text("文字化け嫌い", width/2, height/2)
```
一見なんの問題もないコードなのに実行結果は。。。
![スクリーンショット 2021-07-27 20.37.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811712/584e271c-5612-7224-ee2e-0b41732389b9.png)
こうなってしまいました。。。

**createFont()** と**textFont()** でちゃんとフォントも指定してるのに。。。って思いますよね
でもこれ以下のような、ワンステップですぐに解決できます。

###解決方法
その簡単な方法とは
**""の前にuを打ち込むだけ！**
以下の通りです

```Python
text(u"#入力したい文字列", x座標, y座標)
```
先程の全体のコードの場合はこんな感じ

```Python
def setup():
    size(600, 400)
    background(0)
    background(0)
    font = createFont("Meiryo", 50)
    textSize(50)

def draw():
    fill(255, 0, 0)
    textAlign(CENTER, CENTER)
    text(u"文字化け嫌い", width/2, height/2)
```
実行結果は以下の通りです。
![スクリーンショット 2021-07-27 20.41.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811712/03a7c201-7b6c-a33e-275e-74c8330a2860.png)
以上になります。

この記事がProcessingの**text()** で困ってる誰かさんの役に立てればと思います。
Wifiルータに2機目のTelloEduを接続する

__[前回の記事](https://qiita.com/electronics_diy721/items/0b9dd5127870ecba75b5)__の続編です。

前回は、TelloEduドローン（１機）を、Wifiルータ（NEC製Atermルータ）に接続して、次のネットワーク構成を組みました。

![スクリーンショット 2021-07-27 0.03.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1754134/d27b57ed-5e97-4834-d7c5-4b524adfd0ef.png)

今回は、このネットワークに、__2機目のTelloEduドローン__を登場させます。
手順は、__1機目のTelloEduドローンをWifiルータに接続したときと同じ__です。

##実行手順

-1 新しい機体に電源を入れる
-2  MacbookをTELLO-XXXXのAPにつなぐ

iPhoneからTELLO-XXXXのAPにつなぎ、Telloアプリを起動すると、TelloEduのカメラ画像が受信できる

-3. Terminalで以下を実行する

```bash:Terminal
electron@diynoMacBook-Pro TelloEduSwarm % python3 telledu_connect_to_wifi_router.py -ssid aterm-xxxxxxxxxx -pw yyyyyyyyyyy
Wifiルータ（SSID）：　aterm-xxxxxxxxxx
Wifiルータ（パスワード）：　yyyyyyyyyyy
ap aterm-xxxxxxxxxx yyyyyyyyyyy
electron@diynoMacBook-Pro TelloEduSwarm % 
```

- MacbookのWifi AP一覧から、TELLO=XXXXが消えている
- TELLO-XXXXのAPに接続済みのiPhone内のTelloアプリを見ると、これまで受信できていたTelloEduのカメラ画像が消えている。（アプリは起動中）
- iPhoneのWifi接続先を、（TelloEduが接続中の）Wifiルータに切り替える。iPhone内のFingアプリを見ると、IPアドレス一覧に、新たに'192.168.0.11'が表示されている。


-4. MacbookのWifi接続先を（TelloEduが接続中の）Wifiルータに切り替えて、Pythonスクリプトファイルを実行。

```bash:Terminal
electron@diynoMacBook-Pro TelloEduSwarm % python3 telloedu_single_remote_control.py -ip 192.168.0.11
IPアドレス 192.168.0.11 番のTelloEduドローンに操作コマンドを送ります。
('192.168.0.11', 8889)
electron@diynoMacBook-Pro TelloEduSwarm %
```

TelloEduは離陸し、しばらく待つと着陸した。

##実行したスクリプトファイル

```Python3:telledu_connect_to_wifi_router.py
import socket, argparse    

# WifiルーターのSSIDをコマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='')  
parser.add_argument('-ssid')  

# Wifiルーターのパスワードをコマンドライン引数から受け取る
parser.add_argument('-pw')  

args = parser.parse_args() 
wifi_host_ssid = args.ssid
wifi_host_pw = args.pw

message_1 = "Wifiルータ（SSID）：　" + str(wifi_host_ssid)
message_2 = "Wifiルータ（パスワード）：　" + str(wifi_host_pw)

print(message_1)
print(message_2)

# TelloEduのプラウベートIPアドレスとポート番号は全機体、同じ定数文字列
tello_ip = '192.168.10.1'
tello_port = 8889

# (Wifi client) Macbook -> (Wifi host) TelloEduに接続
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

tello_address = (tello_ip , tello_port)
wifi_host_ap = "ap {0} {1}".format(wifi_host_ssid, wifi_host_pw)
print(wifi_host_ap)

socket.sendto('command'.encode('utf-8'),tello_address)
socket.sendto(wifi_host_ap.encode('utf-8'),tello_address)
```


```Python3:telloedu_single_remote_control.py
import socket, argparse, time    

# WifiルーターのSSIDをコマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='')  
parser.add_argument('-ip')  

args = parser.parse_args() 
tello_ip = args.ip

print("IPアドレス {0} 番のTelloEduドローンに操作コマンドを送ります。".format(tello_ip))

# TelloEduのポート番号は全機体、同じ定数文字列
tello_port = 8889
tello_address = (tello_ip , tello_port)
print(tello_address)

socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

socket.sendto('command'.encode('utf-8'),tello_address)
time.sleep(10)
socket.sendto('takeoff'.encode('utf-8'),tello_address)
time.sleep(10)
socket.sendto('land'.encode('utf-8'),tello_address)
time.sleep(10)
```
AIスピーカーYoSiE制作日誌2

#AIスピーカーYoSiE制作日誌ダイ２カイ～とりあえず書こう編チュン～
##この記事の目標的なこと
###とりあえず一か月！
この記事を書き続ける以上！
##今日やったこと
とりあえずYoSiEをどうゆうものにするかで、
しっかりと話し合いが必要だと思った
まだ中身の設計ができていない
……
……
###まあ楽しくやりますか！

##技術的なこと
今日は特にこれといったことをしてないので
mark down記法について軽く
この記事をもっと楽しくするにはどうすればいいか考えたとき
私はこう考えました
###いろいろ試してみよう
と考えましたなのでいろいろ…
調べてみました。
##太字
文字を大きくしてみましょう

こんにちは！
↑これだけでは文字を太くすることができません
なので
↓

![スクリーンショット 2021-07-27 201509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/aefc055b-cd3b-40e2-34f6-2a6d9b400998.png)
こんなかんじで太くしたいところをアスタリスク
で囲んであげると
↓


**こんにちは！**
おお！文字が太めに！！！

別のやり方で↓

![スクリーンショット 2021-07-27 202036.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/48b49c80-d121-864d-be88-d846a5a153d9.png)

太くしたいところをアンダーバー
二つで囲んであげると
↓


どうぞ__よろしくお願い__いたします。
できた！いい感じだ
超初心者がPythonで移動平均線をPlotlyを使ってグラフ化してみた（5分足チャートと同時に表示）

移動平均線もPlotlyで表示してみたい

## 参考

以下のコードに少し足すだけ

https://qiita.com/emilia/items/28ef0152600a2fca76c0

## コード

``` draw_with_plotly.py

import pandas as pd
import plotly.graph_objects as go
import datetime

# 1分足データを取得
df = pd.read_csv('./temp_historical_data/USDJPY.csv', nrows=1500)
df.columns = ["Date", "Open", "High", "Low", "Close", "Volume"]
df["Date"] = pd.to_datetime(df["Date"])
df.set_index("Date", inplace=True)

# 5分足に変換
df5 = pd.DataFrame()
rule = '5T'
df5['Open'] = df.Open.resample(rule).first()
df5['Close'] = df.Close.resample(rule).last()
df5['High'] = df.High.resample(rule).max()
df5['Low'] = df.Low.resample(rule).min()

# SMA計算
df5["SMA5"] = df5["Close"].rolling(window=5).mean()
df5["SMA20"] = df5["Close"].rolling(window=20).mean()

# グラフ化
interval = 12
vals = []
labels = []
for i in range(len(df5)//interval):
    vals.append(df5.index[i*interval])
    labels.append(df5.index[i*interval].strftime('%Y-%m-%d %H:%M'))


fig = go.Figure(
        data=[
                go.Candlestick(
                    x=df5.index,
                    open=df5['Open'],
                    high=df5['High'],
                    low=df5['Low'],
                    close=df5['Close'],
                    hovertext=['date:{}<br>open:{}<br>high:{}<br>low:{}<br>close:{}'
                        .format(i.strftime('%Y-%m-%d %H:%M'), df5.loc[i,'Open'],df5.loc[i,'High'],df5.loc[i,'Low'],df5.loc[i,'Close']) for i in df5.index],
                    hoverinfo="text"
                ),
                go.Scatter(x=df5.index, y=df5.SMA5, line=dict(color='orange', width=1)),
                go.Scatter(x=df5.index, y=df5.SMA20, line=dict(color='green', width=1))
            ],
        layout = go.Layout(
                xaxis = dict(
                    ticktext = labels,
                    tickvals = vals,
                    tickangle = -90
                ),
        )
)
fig.show()

```


## グラフ

![スクリーンショット 2021-07-27 20.08.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69727/7f446a7e-90b7-3005-477e-e54caaa86fee.png)

## 感想

簡単。ボリンジャーバンドの同時表示も同じ要領でできそうなのでそちらは割愛しようかな。
EBS のサイズを拡張しようとしたら `FAILED: failed: sfdisk --list /dev/nvme0n1` とか言われる

## 問題

`/` ファイルシステムが 100% になったので以下を参考にボリュームの拡張を行ってみたところ `growpart` コマンドのところでエラーが発生した。

- [ご存知でしたか？EC2インスタンスは再起動なしにディスクサイズ(EBSボリュームサイズ)を増やせます | DevelopersIO](https://dev.classmethod.jp/articles/extending-disk-size-without-reboot/#toc-10)
- [ボリュームサイズ変更後の Linux ファイルシステムの拡張 - Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/recognize-expanded-volume-linux.html)

```
$ sudo growpart /dev/nvme0n1 1
failed [sfd_list:1] sfdisk --list --unit=S /dev/nvme0n1
FAILED: failed: sfdisk --list /dev/nvme0n1
```

## 原因

どうやら Disk 100 % ままコマンドを実行してしまったのがダメだったみたいで、原因となった巨大なファイルを一旦削除した後、同じコマンドを実行したら普通に正常終了した…というオチだった。
CloudComposer で gcloudコマンドを使って execution_date を指定してDAGを実行する

# 背景
CloudComposerでexecution_dateを指定してDAGやtaskを実行したい。
実行コマンドの1例を紹介する。

# コマンド

DAGを実行する場合

```sh
gcloud beta composer environments run my-env --location asia-northeast1 dags test -- --subdir /home/airflow/gcs/dags dag_name 2021-06-30
```

taskを実行する場合

```sh
gcloud beta composer environments run \
  my-env \
  --location asia-northeast1 \
  tasks test -- --subdir /home/airflow/gcs/dags \
  dag_name 2021-06-30
```


# 参照

https://cloud.google.com/composer/docs/triggering-dags?hl=ja#airflow-2.0-cli

https://cloud.google.com/composer/docs/how-to/using/testing-dags?hl=ja

https://airflow.apache.org/docs/apache-airflow/stable/cli-and-env-variables-ref.html#dags
超初心者がPythonで5分足チャートをPlotlyを使ってグラフ化してみた

Plotly使った方が見やすいグラフができそう？と思ったのでやってみた。

## 参考

https://qiita.com/toyolab/items/db8a1e539d4f995079d5

1分足チャートのデータの取得方法は以下

https://qiita.com/yamaji_daisuke/items/28e9875d273c8f052cbd

1分足チャートの5分足への変換は以下

https://qiita.com/yamaji_daisuke/items/7f9d137ad3e557df0535

## コード

``` draw_candlestick_chart_with_plotly.py

import pandas as pd
import plotly.graph_objects as go
import datetime

# 1分足データを取得
df = pd.read_csv('./temp_historical_data/USDJPY.csv', nrows=1500)
df.columns = ["Date", "Open", "High", "Low", "Close", "Volume"]
df["Date"] = pd.to_datetime(df["Date"])
df.set_index("Date", inplace=True)

# 5分足に変換
df5 = pd.DataFrame()
rule = '5T'
df5['Open'] = df.Open.resample(rule).first()
df5['Close'] = df.Close.resample(rule).last()
df5['High'] = df.High.resample(rule).max()
df5['Low'] = df.Low.resample(rule).min()

# グラフ化
interval = 12
vals = []
labels = []
for i in range(len(df5)//interval):
    vals.append(df5.index[i*interval])
    labels.append(df5.index[i*interval].strftime('%Y-%m-%d %H:%M'))

print(labels)


fig = go.Figure(
        data=go.Candlestick(
                x=df5.index,
                open=df5['Open'],
                high=df5['High'],
                low=df5['Low'],
                close=df5['Close'],
                hovertext=['date:{}<br>open:{}<br>high:{}<br>low:{}<br>close:{}'
                    .format(i.strftime('%Y-%m-%d %H:%M'), df5.loc[i,'Open'],df5.loc[i,'High'],df5.loc[i,'Low'],df5.loc[i,'Close']) for i in df5.index],
                hoverinfo="text"
                ),
        layout = go.Layout(
                xaxis = dict(
                    ticktext = labels,
                    tickvals = vals,
                    tickangle = -90
                ),
        )
)
fig.show()

```

## グラフ

![スクリーンショット 2021-07-27 19.48.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69727/4d83ca49-cd49-46db-90be-812c71d9e3bc.png)

![スクリーンショット 2021-07-27 19.49.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69727/e7342ed9-596a-f79f-c78f-dd99cb7b3849.png)

## 感想

Plotlyの方がお手軽に見やすいグラフが作れそう。SMAとか同時に描画してみたい。
SQL Server: トランザクションレプリケーションの情報を収集する

SQL Serverのトランザクションレプリケーションに関連した情報の収集方法をまとめてみました。

#1. perfmonのメトリクス
参考：[システム モニターによるレプリケーションの監視](https://docs.microsoft.com/ja-jp/sql/relational-databases/replication/monitor/monitoring-replication-with-system-monitor?view=sql-server-ver15)

ログリーダーエージェントとディストリビューションエージェントに関して、遅延や配信コマンド数を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148310/9411331f-8cec-1f2f-2aa6-61bed323c822.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148310/d2fb01a7-8170-4a68-02a5-bd99ac2e4117.png)
また、「SQL Server:Databases\Repl. Pending Xacts」を確認することで、保留中のレプリケーショントランザクション数を確認できます。

これらの値をダッシュボード化しておけると、遅延の際にログリーダーエージェント起因なのか、ディストリビューションエージェント起因なのかの切り分けを行いやすいかと思います。

#2. レプリ関連のシステムテーブル
[ドキュメント](https://docs.microsoft.com/ja-jp/sql/relational-databases/system-tables/replication-tables-transact-sql?view=sql-server-ver15)にあるように、様々なレプリケーション関連のシステムテーブルが提供されています。
これらを組み合わせて、様々な情報を取得できます。

専用のテーブルを作成して定期的に情報をダンプしておくことで、例えば「〇月〇日〇時～〇時の間に、更新数が多かったレプリ対象テーブルは何か」といったことを後追いできるようになります。

[github](https://github.com/masaki-hirose/SQLServer-Info/tree/master/%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AC%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)でクエリを公開しています。

保存する情報は全部で5種類を整理しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148310/96a97573-7fca-be86-b6f7-2c4822ae69f9.png)

特に、「アーティクルごとのレプリ対象コマンド数」は後追いにとても便利です。
perfmonのメトリクスで遅延に気づき、遅延の原因として「アーティクルごとのレプリ対象コマンド数」をみることで、例えば特定のテーブルのレコード更新が大量に実施されたことで遅延時間が伸びた、といった後追いが可能になります。

トランザクションレプリケーションをお使いの環境は現在ではあまり存在していないかもしれませんが、お使いの方がいればぜひ活用してみてください。
プログラミング初心者によるPython3 エンジニア認定基礎試験　勉強方法

#■Python3 エンジニア認定基礎試験 概要
pythonの<font color="Crimson">**基本的な文法を問う試験**</font>

#■筆者の試験結果
<font color="Crimson">**以下に記載する勉強法で925点/1000点を取ることができました。**</font>
勉強方法に悩んでいる方は以下の勉強方法を参考にしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1801316/9b47e315-5eca-882a-8257-7d8ec71cd34d.png)

#■受験前の筆者情報
○ech AcademyのPythonコースを受けていたので勉強時間はだいぶ短くなったと思います。
上記以外はまるっきりの素人です。
※オンラインスクールに通わないといけないわけではないので誤解の無い様お願いします。

####実務経験
無し
####資格
無し
####勉強状況
Tech ○cademy Pythonコース終了済み（2021/6月初旬）

#■勉強方法全体像＆時間

|順番  |勉強内容　　　　|勉強方法  |所要時間  |
|---|---|---|---|
|1  |Pythonの基礎を学ぶ  |プログラミング超初心者が初心者になるためのPython入門(1)~(3)を読む　　|12時間/3冊  |
|2  |自分の理解度を把握  |DIVE INTO EXAMで模擬試験を解く  |3時間  |
|3  |試験範囲を理解  |Python チュートリアルを読む  |32時間  |
|4  |模擬試験を解いて理解度向上  |DIVE INTO EXAM・PRIME STUDYを解く/PYTHON チュートリアルで間違えた問題を理解する  |32時間  |

#■勉強方法詳細
<font color="Crimson">**いきなりPython チュートリアルを勉強するのはやめましょう。**</font>
∵基礎知識がない状態で理解しようとすると非常に難しいため。
##1.　Pythonの基礎を学ぶ
私はプログラミング超初心者が初心者になるためのPython入門(1)~(3)を読んで基礎を確認しました。
AmazonのKindle unlimitedで無料で読めるのでおすすめです。

##2. 自分の理解度を把握
[DIVE INTO EXAM](https://diver.diveintocode.jp/dive_into_exam)で模擬試験を解いて、今の自分の実力を確認しました。
ここでぼろぼろな結果を見て、自分の尻に火をつけました。
##3. 試験範囲を理解
ここでついにPython チュートリアルに手を付けます。
[Python チュートリアル](https://docs.python.org/3/tutorial/index.html)を上から順に読んでいきます。
私は下記のようにこのチュートリアルを読みました。
どう勉強をすすめるか迷っている方は参考にしてください。
######1回目
・ざっと読んでどこにどんなことが書いてあるのかを確認しながら、覚えれるところは覚える（ここで本気でわからないところを全部理解しようとすると時間がいくらあっても足りない）
・Evernoteを使って各章をまるごとノートにコピーする（後の模擬試験で間違えた際の勉強時にハイライトをつけたりすることができる）
######2回目以降
模擬試験で間違えた問題の箇所をEvernoteにまとめる

##4. 模擬試験を解いて理解度向上
[DIVE INTO EXAM](https://diver.diveintocode.jp/dive_into_exam)・[PRIME STUDY](https://study.prime-strategy.co.jp/)で模擬試験を解き、間違えた問題を[Python チュートリアル](https://docs.python.org/3/tutorial/index.html)の対象箇所をEvernoteにまとめて理解しました。
<font color="Crimson">**ノートにまとめるのは理解向上に非常に役に立ったと思っているので皆さんも是非実施してみてください。**</font>

#■勉強の進め方で参考にしたサイト
https://qiita.com/gomasa/items/a0c91cea24f41fd63c1c
https://ccie-go.com/python-exam-study/
LPをデプロイする技術

# 目的
仕事がら、短期のキャンペーンのランディングページ(LP)を構築することが多いです。AWSを使ってS3にコンテンツを置きCloudFrontで公開します。またデータベースとしてDyanamoDBを使っていてレコードを追加したりテーブルを追加したりします。ここではLPをデプロイするための簡単なCLIを紹介します。

# 各種AWS

ここではaws-cliはjqはインストール済としています。

## CloudFront
まず既に登録されているCloudFrontの情報を取得します。無い場合は最初はがんばってコンソールから作りましょう(^^;

```sh
export AWS_PROFILE=my-profile
export AWS_DEFAULT_REGION=ap-northeast-1
export CF_ID=zzzz
aws cloudfront get-distribution-config \
--id ${CF_ID}| \
jq -r ".DistributionConfig" \
> base.json
```

次に今回用に書き換えたいデータをJSONで準備します。ここで書き換えたいのは「ドメイン」と「S3のパス」と「コメント」です。

```json:cloud_front.json
{
  "cloud_front": {
    "domain": "xxxx.example.com"
    "origin_path": "/my-bucket/xxxx/public"
    "comment": "xxxx campaign"
  }
}
```

Rubyプログラムで書き換えます。

```ruby:make.rb
require "json"
require 'securerandom'

def read_json(path)
  File.open(path) do |j|
    hash = JSON.load(j)
  end
end

base = read_json("#{__dir__}/base.json")
params = read_json(ARGV[0])

base["Aliases"]["Items"][0] = params["cloud_front"]["domain"]
base["Origins"]["Items"][0]["OriginPath"] = params["cloud_front"]["origin_path"]
base["Comment"] = params["cloud_front"]["comment"]
base["CallerReference"] = SecureRandom.uuid

puts JSON.pretty_generate(base)
```

デプロイします。作成後IDが取得できるので、回収しておきます。

```sh
export AWS_PROFILE=my-profile
export AWS_DEFAULT_REGION=ap-northeast-1
ruby make.rb ./cloud_front.json > cloud_front_result.json
aws cloudfront create-distribution \
--distribution-config file://cloudfront_result.json \
| jq -r '.Distribution.Id'
```

## S3
ローカルにあるpublicディレクトリのファイルをS3なデプロイします。
またCloudFrontにキャッシュしているデータをクリアーしています。
ここで先ほど回収したIDを設定します。

```sh
export AWS_PROFILE=my-profile
export AWS_DEFAULT_REGION=ap-northeast-1
export CAMPAIGN_NAME=xxxx
export CF_ID=yyyy

# デプロイ
aws s3 sync public/ s3://my-bucket/${CAMPAIGN_NAME}/public

# キャッシュクリアー
aws cloudfront create-invalidation --distribution-id ${CF_ID} --paths "/*" | cat
aws cloudfront get-distribution --id ${CF_ID} | jq -r '.Distribution.InProgressInvalidationBatches'
```

## DynamoDB
### レコード追加
キャンペーンテーブルにレコードを追加します。キャンペーン名とキャンペーン開始時間とキャンペーン終了時間を設定します。

```json:data_json
{
  "campaign_name": {
    "S": "xxxx"
  },
  "start_at": {
    "N": "1577804400"
  },
  "end_at": {
    "N": "1640962800"
  }
}
```

```sh
export AWS_PROFILE=my-profile
export AWS_DEFAULT_REGION=ap-northeast-1
aws dynamodb put-item \
--table-name campaigns \
--item file://data.json \
--return-consumed-capacity TOTAL
```

### テーブル作成
例えば参加者を登録するテーブルを作ります。これは一度だけデプロイします。

```json:table.json
{
  "TableName": "paticipants_xxx",
  "AttributeDefinitions": [
    {
      "AttributeName": "uuid",
      "AttributeType": "S"
    }
  ],
  "KeySchema": [
    {
      "KeyType": "HASH",
      "AttributeName": "uuid"
    }
  ],
  "ProvisionedThroughput": {
    "WriteCapacityUnits": 1,
    "ReadCapacityUnits": 1
  }
}
```

```sh
export AWS_PROFILE=my-profile
export AWS_DEFAULT_REGION=ap-northeast-1
aws dynamodb create-table --cli-input-json file://table.json
```

# まとめ
AWS CLIを使ってLPでよく使うコマンドなどをまとめてみました。
CloudFrontを作るところやDynamoDBのテーブルを作る作業は1度しか行いませんが、コンソールでやると意外と時間がかかります。
S3にアップロードしたり、DymanoDBのレコード修正は頻繁に行われます。これは絶対にCLIを用意しておくべきで、だいぶ作業がはかどるようになります。
シェルスクリプトとして準備しておくとよいです。
Rails flashの使い方

###flashメッセージとは
何らかのアクションがあった時に一時的に表示させるメッセージのことです。
ログインや投稿の際に使用します。

```
#コントローラー
flash(:キー名) = 'メッセージ内容'
```

```
#ビュー
flash(:キー名)
```

###flashとflash.now
flash=次のアクションまでデータを保持する。redirect_toと一緒に使う。
flash.now=次のアクションに移行した時点でデータが消える。renderと一緒に使う。

redirect_to=処理を強制的に指定の場所にとばす。
render=アクションの実行はせずに指定の場所を表示する。

```
#例　コントローラー

def create
  @task = Task.new(task_params)

  if @task.save
    flash[:success] = '正常に送信されました'
    redirect_to @task
  
  else
    flash.now[:danger] = '送信されませんでした'
    render :new
  end
end
```

```
#例 ビュー
<% flash.each do |message_type, message| %>
    <div><%= message %></div>
<%= end %>

#@task.save が成功すると、message_typeに[:success]、messageに'正常に送信されました'が代入される。
```
flashはハッシュなので、eachで取り出すと|kye, value|で取り出されます。