OmniAICreator/Qiita-1.07M huggingface dataset:
QiitaでGIFをアップロード（ScreenToGif使用）

# はじめに

Qiitaに記事を投稿するにあたり、GIFをアップロードしたいという場面が出てきた。調査したところ、Windowであれば「ScreenToGif」なるソフトがよいとのことなので、ソフトのインストールから順に説明する。OSはWindows10 Pro。[GIFアニメで画面録画できる「ScreenToGif」の使い方と安全性を紹介！](https://aprico-media.com/posts/3674)を参考にした。

# インストール

[ScreenToGif](https://www.screentogif.com/)から"Installer"をクリック。（"Portable"はおそらく容量が小さいもの。理由がなければ選ばなくてよいと思う。）
![install1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/266e07a7-548a-091e-6070-ac97c72e530e.png)

「ScreenToGif.2.27.3.Setup.msi」というファイルがダウンロードされるので、実行。設定を変更することはとくに必要ないので、"Next"を押していくとインストールが完了する。![install2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/86ab8b73-465c-0006-642c-d43881b4947d.png)

# スナップの撮り方

ScreenToGifを起動すると、以下ウィンドウが立ち上がる。![usage1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/b1e4f98d-8940-a0bd-7c27-a6c01fcb9768.png)

左の"レコーダー"を選択すると、以下のようなウィンドウが立ち上がる。![usage3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/319a20ba-e3d9-2327-184b-635e80f77330.png)

キャプチャしたい部分がこの枠内に入るように調節して、右下の"録画"または"F7"を押す。（録画実行後、右下に"停止"が出てくるので、停止したい場合は"停止"または"F8"を押す。）
ウィンドウ全体をキャプチャしたい場合は、上図の下部中央にある"ウィンドウに吸着する"をドラッグしてスナップしたいところで離すときれいにハマってくれる。

実際にスナップを撮った後はさまざまな編集ができるが、ここでは一旦編集は置いておいてGIF形式での保存を行う。保存をする場合は、"ファイル"タブの"名前を付けて保存"を押す。
![usage4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/d3080e45-84b1-34ff-36dc-6df2bbc3bc2b.png)

すると、画面右側に以下のような設定が出てくるので、ファイルタイプを"GIF"にして、保存先、保存ファイル名を付けて保存を押せばよい。![usage5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/850a74a8-02d2-8f5d-126f-4f4a461624a8.png)

実際に撮ったスナップを以下に示す。Qiitaにアップロードする場合は、画像と同じでドラッグアンドドロップをすればよい。
![gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/677f4304-daba-364e-7187-a9e952bace89.gif)
【Django】JavaScriptで動的に作成されたformにcsrf_tokenを追加する

### 概要
htmlファイル内で簡単な処理を行った後、formを経由してviews側に情報を返す方法に3日ほど詰まったので、備忘録代わりに書き残しておきます。

### 参考サイト様
 - [How to properly append django csrf_token to form in inline javascript?
](https://stackoverflow.com/questions/42733761/how-to-properly-append-django-csrf-token-to-form-in-inline-javascript)
 - [【Django】 csrf_tokenの仕組みとCSRF無効化・画面カスタマイズする方法](https://djangobrothers.com/blogs/django_csrf/)

### 手法
formタグを利用した取得が基本となり、ここは公式のチュートリアルにも記載があります。(参照: [はじめての Django アプリ作成、その 4](https://docs.djangoproject.com/ja/3.1/intro/tutorial04/#writing-your-first-django-app-part-4))

ただ、単純にJavaScriptでform要素を追加してsubmitしようとすると、「csrf_tokenないよ」みたいなエラーを吐きます。そこで、csrf_tokenを手動で追加する必要があります。以下サンプルです。

```html:htmlファイル
<!--関数起動用のボタン-->
<input type="button" value="集計" onclick="aggregate()">
```

```javascript:
function aggregate() {
    //form作成、メソッドとリンク先の追加
    let form = document.createElement('form');
    form.method = "POST";
    form.action = "{% url 'myapp:feedback' %}";
    form.id = "aggregated-form";
    
    //送信したい情報を格納したinput要素作成、type,valueの追加など
    let input_container = document.createElement('input');
    input_container.type = 'hidden'; //入力フォームの非表示
    input_container.name = 'aggregated-information';

    //何かしらの処理を施した情報
    let information_to_post = .....
    //情報の追加
    input_container.value = information_to_post;

    //csrf_tokenの追加手動
    let csrf_element = document.createElement('input');
    csrf_element.type = 'hidden';
    csrf_element.name = 'csrfmiddlewaretoken';
    csrf_element.value = '{{ csrf_token }}';
    
    //csrf_tokenと送信したい情報の追加
    form.appendChild(csrf_element);
    form.appendChild(input_container);

    //文書への追加
    document.body.appendChild(form);
    
    //送信
    form.submit();
}

```

あとはurls.pyでfeedbackとviews.pyの紐付けを行い、返ってきた情報をrequest.POSTで取得すれば利用できます。

### まとめ
csrf_tokenの正体がinput要素であると知ることができました。JSONとして受け取るなどの工夫を行えばもっと使い勝手が良さそうです。集合知に感謝。
PowerShell でADユーザーの最終ログオン日時を取得する

使われていない(≒長期間ログインしていない)ADユーザーを無効にしたい。PowerShellで全ユーザーの最終ログオン日時を取得するコマンドを調べたので備忘メモを残しておきます。

# 前提条件
* PowerShell バージョン 4.0
* ADサーバー Windows Server 2012 R2 Standard
* 

# 作業
以下、最終形までの道のりです

## ユーザー一覧を取得
まずはユーザー一覧を取得

```powershell
Get-ADUser -Filter *
```

出力されない項目があるので追加します（LastLogon, LastLogonTimestamp, WhenCreated）

```powershell
Get-ADUser -Filter * -Properties LastLogon, LastLogonTimestamp, WhenCreated
```
## 横並び（表形式）に変換
縦並びでズラズラと表示されるので横並びに変換しました

```powershell
Get-ADUser -Filter * -Properties LastLogon, LastLogonTimestamp, WhenCreated|Format-Table
```

項目が多すぎるので必要な項目を指定

```powershell
Get-ADUser -Filter * -Properties LastLogon, LastLogonTimestamp, WhenCreated|
Format-Table SamAccountName, LastLogon, LastLogonTimestamp, WhenCreated
```

日時を読みやすく変換（LastLogonとLastLogonTimestamp）

```powershell
Get-ADUser -Filter * -Properties LastLogon, LastLogonTimestamp, WhenCreated|
Format-Table SamAccountName, 
@{name='LastLogon';expression={[DateTime]::FromFileTime($_.LastLogon)}}, 
@{name='LastLogonTimestamp';expression={[DateTime]::FromFileTime($_.LastLogonTimestamp)}}, 
WhenCreated
```

## 必要に応じてテキスト出力
テキストに出力しました。あとはテキストエディタでタブ区切りに変換してExcelに貼り付けての作業。

【最終形】

```powershell
Get-ADUser -Filter * -Properties LastLogon, LastLogonTimestamp, WhenCreated|
Format-Table SamAccountName, 
@{name='LastLogon';expression={[DateTime]::FromFileTime($_.LastLogon)}}, 
@{name='LastLogonTimestamp';expression={[DateTime]::FromFileTime($_.LastLogonTimestamp)}}, 
WhenCreated|
Out-File 'C:\TEMP\aaa.txt'
```
Excelのセルの内容でPPTのスライドを大量生成する


# なぜこんなものを？
以前大学で研究していたときに、被験者に単純作業を繰り返してもらって反応の変化をみるという実験をしたことがあります。
ただその作業がパターン化してしまうと実験として意味がないので全くランダムなテストを作るためにExcelでランダムなテストをつくり、PPTに飛ばすということをやったことがあります。

もちろんVBAが使える人ばかりならPPT側のVBAだけでも良かったのですが、Excelのマクロワンクリックにすることによって誰でもセルの内容をPPTに簡単に変換することができます。

# 実際のコード
``` vb
Sub ExcelToPPT()

  Dim ppt_app As Object 'PowerPoint
  Dim ppt_prs As Object 'PowerPoint Presentation
  Dim c As Long 'Column Number
  Dim r As Long 'Row Number
  Dim r_end As Long 'End Row Number
  Dim msg As String

  r_end = Range("A2").End(xlDown).Row
  If r_end >= 300 Then
    msg = "データが、" & Format(r_end, "#,##0") & "件あるため、処理に相当な時間がかかる可能性があります。実行しますか？"
    If MsgBox(msg, vbYesNo) = vbNo Then Exit Sub
  End If

  Set ppt_app = CreateObject("PowerPoint.Application")
  With ppt_app
    .Visible = True
    Set ppt_prs = .Presentations.Add
  End With

  For r = 1 To r_end - 1
  With ppt_prs.Slides
    .Add _
      Index:=r, _
      Layout:=12
End With
  
  ppt_prs.Slides(r).Shapes.AddTextbox(Orientation:=msoTextOrientationHorizontal, Left:=90.14, Top:=175.46, Width:=780.09, Height:=189.07).TextFrame _
    .TextRange.Text = ActiveSheet.Cells(r + 1, 1).Text
    
    
If r Mod 8 = 0 Then

With ppt_prs.Slides(r).Shapes(1)
    With .TextFrame.TextRange
        .Font.Size = 40
        .Font.Name = "游ゴシック Light"
        .ParagraphFormat.Alignment = 2
       .Text = "先ほどの文字列と一致するものがあれば" & vbCrLf & "対応する番号を囲んでください "
End With
End With

Else

With ppt_prs.Slides(r).Shapes(1)
    With .TextFrame.TextRange
        .Font.Size = 150
        .Font.Name = "Segoe UI"
        .ParagraphFormat.Alignment = 2
        
End With
End With
             
End If
  
  Next r

  Set ppt_prs = Nothing
  Set ppt_app = Nothing
  
 MsgBox "書き出しが終了しました。"
  
End Sub
```
# 使い方
なかなかこれを作成当時と同じ用に被験者実験目的で利用する人はいないかもしれませんが、ちょっと改良してあげることによってExcel上で発表スライドのアウトラインを構成してそれを元にPPTファイルを作ることに活かしたりはできるかもしれません。よいPPTライフを。
railsアプリのデプロイエラーの原因が、gemのuglifierのバージョンに依るものだった話

railsアプリのデプロイがこけたので、その原因を追求してみた。

デプロイ時のエラーメッセージを読むと、以下の様なメッセージが頻出していた。

```
Caused by:
V8::Error: SyntaxError: Unexpected token: name (jsの変数名)
at js_error (<eval>:3623:12167)
at croak (<eval>:3623:22038)
at token_error (<eval>:3623:22175)
at unexpected (<eval>:3623:22263)
at semicolon (<eval>:3623:22781)
at simple_statement (<eval>:3623:25959)
at <eval>:3623:23747
at <eval>:3623:22954
at block_ (<eval>:3623:28083)
at ctor.body (<eval>:3623:27686)
at function_ (<eval>:3623:27782)
at <eval>:3623:24469
at <eval>:3623:22954
at block_ (<eval>:3623:28083)
at <eval>:3623:23857
at <eval>:3623:22954
at <eval>:3624:3759
at parse (<eval>:3624:3999)
at parse (<eval>:3958:22)
at uglifier (<eval>:4003:13)
```

下記の記事で、jsで`let`を使用している場合`var`に変更すると良い、というアドバイスがあったので、変更してみた結果、デプロイ成功。
どうやら、gemのuglifierのバージョンが足りず、ES6をサポートしていなかったため、letという新しい書き方を許容していなかったため、エラーが起きたらしい。
https://stackoverflow.com/questions/39221152/rails-5-heroku-deploy-error-execjsprogramerror-syntaxerror-unexpected-token

尚、ES6の書き方を許容するのはUglifier 3.2.0以降からだそう。
amplifyの作法 その16

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from amplify import (BinaryPoly, BinaryQuadraticModel, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from typing import Set, Tuple, Container, Dict, Sequence, Collection, Mapping
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))



def qubo_qkp(value: np.ndarray, a: np.ndarray, b: float, penalty = 10.) -> np.ndarray:
	n = len(value)
	nslack = np.ceil(np.log2(b))
	slack = 2 ** (np.arange(nslack))
	a = np.concatenate([a, slack])
	q = penalty * (np.outer(a, a) - 2 * b * np.diag(a))
	q[ : n, : n] -= value
	return q

value = np.array([[2, 4, 3, 5], [4, 5, 1, 3], [3, 1, 2, 2], [5, 3, 2, 4]])
a = np.array([8, 6, 5, 3])
b = 16
q = qubo_qkp(value, a, b, penalty = 10.)
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
#n = len(a)
#assert is_contain(sample[:,:n], np.array([1,0,1,1]))

```

以上。
Slack API の channels.infoが使えなくなった対策

#Slack API の channels.infoが使えなくなった対策

##廃止されたAPI
2021/2/28で廃止された。
https://api.slack.com/methods/channels.info

##移行戦略
基本は
https://api.slack.com/methods/conversations.info
に移行する

channelの以下ははAPIを変更するだけで仕様は同じ
unread_count,unread_count_display は廃止されたようだ。これは他のAPIでもなくなっているので、同じ流れか
>id,name,is_channel,created,creator,is_archived,is_general,name_normalized,is_shared,is_org_shared,is_member,is_private,is_mpim,last_read,topic,purpose,previous_names

以下は追加されたもの
>is_group,is_im,is_read_only,parent_conversation,locale


なお、複数チャンネル取得のAPI
https://api.slack.com/methods/conversations.list
と、基本的には同じデータが返ってくる。(last_readのみ無い）

##membersは別APIになった
https://api.slack.com/methods/conversations.members

基本はそのまま使えばいいが、limitによる上限設定と、cursorによる継続取得のしくみがある。
limit規定値が100なので、メンバーが100人以上いるときは limit:1000 などと設定するか、
複数回にわけて取得する必要がある。
amplifyの作法 その15

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from amplify import (BinaryPoly, BinaryQuadraticModel, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from typing import Set, Tuple, Container, Dict, Sequence, Collection, Mapping
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))



def qubo_qap(flow: np.ndarray, distance: np.ndarray, penalty = 10.):
	n = len(flow)
	q = np.einsum("ij,kl->ikjl", flow, distance).astype(np.float)
	i = range(len(q))
	q[i, : , i, : ] += penalty
	q[ : , i, : , i] += penalty
	q[i, i, i, i] -= 4 * penalty
	return q.reshape(n ** 2, n ** 2)

flow = [[0, 5, 2], [5, 0, 3], [2, 3, 0]]
distance = [[0, 8, 15], [8, 0, 13], [15, 13, 0]]
q = qubo_qap(flow, distance, penalty = 200.)
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
#assert is_contain(sample, np.array([1,0,0,0,1,0,0,0,1]))

```

以上。
kubeflow pipelinesでpipelineをuploadする


pipelineのupload方法をメモ

```python
#!/usr/bin/env python3

import kfp
from kfp import compiler, dsl, components
from kfp.dsl._container_op import Container
 
 
def _preprocess(n: int) -> str:
    return f"preprocess {n}"
 
 
def _process(nums: str) -> int:
    return 1
 

@kfp.dsl.pipeline(name="parallel-pipeline")
def pipeline(n: int) -> None:
    image = "python:3.8-alpine"

    # preprocess
    preprocess_func = components.func_to_container_op(_preprocess, base_image=image)
    preprocess_op = preprocess_func(n)

    # process
    process_func = components.func_to_container_op(_process, base_image=image)
    process_op = process_func(preprocess_op.output)

    # preprocessの後にprocess
    process_op.after(preprocess_op)

    return process_op.output


if __name__ == "__main__":
    pipeline_package_path = "pipeline.yaml"

    # pipelineを生成
    compiler.Compiler().compile(pipeline, pipeline_package_path)

    # 生成したpipelineをupload
    response = kfp.Client().upload_pipeline(
        pipeline_package_path=pipeline_package_path,
        pipeline_name="my_pipeline",
        description="my_pipeline"
    )
```

* `compiler.Compiler().compile`でpipelineを生成する
* `kfp.Client().upload_pipeline`でpipelineをupload
amplifyの作法 その14

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from amplify import (BinaryPoly, BinaryQuadraticModel, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from typing import Set, Tuple, Container, Dict, Sequence, Collection, Mapping
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))



def qubo_general01(cost, a, b, sign, penalty = 10.):
	slack = - sign * b
	slack[sign == 0] = 1.
	slack[sign == 1] += a[sign == 1, : ].sum()
	slack = np.ceil(np.log2(slack)).astype(np.int)
	ni = a.shape[0]
	for i, ns in enumerate(slack):
		if ns:
			t = np.zeros((ni, ns))
			t[i] = -sign[i] * 2 ** np.arange(ns)
			a = np.concatenate([a, t], -1)
	return - np.diagflat(np.concatenate([cost, np.zeros(sum(slack))]) + 2 * penalty * b.dot(a)) + penalty * np.einsum("ij,ik->jk", a, a)

c = np.array([6, 4, 8, 5, 5])
a = np.array([[2, 2, 4, 3, 2], [1, 2, 2, 1, 2], [3, 3, 2, 4, 4]])
b = np.array([7, 4, 5])
s = np.array([-1, 0, 1])
q = qubo_general01(c, a, b, s)
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
#assert is_contain(sample[:,:5], np.array([1,0,0,1,1]))
 
```

以上。
amplifyの作法 その13

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from amplify import (BinaryPoly, BinaryQuadraticModel, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from typing import Set, Tuple, Container, Dict, Sequence, Collection, Mapping
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))

@dataclass
class Graph:
	edges: Collection[Collection[int]]
	n_nodes: int
	init_value: Mapping[int, int] = None
	nodes: Sequence[float] = None 
	def __post_init__(self):
		if self.nodes is not None: assert len(self.nodes) == self.n_nodes
		if self.edges is None: return
		if len(self.edges) == 0:
			self.edges = None
			return
		self.edges = np.array(list(self.edges))
		assert self.edges.max() < self.n_nodes
		assert self.edges.shape[1] == 2
		if self.init_value is not None:
			assert all(np.array(list(self.init_value)) < self.n_nodes)
	@classmethod
	def from_networkx(cls, graph: nx.Graph) -> nx.Graph:
		return cls(edges = graph.edges, n_nodes = graph.number_of_nodes())
	def to_networkx_graph(self) -> nx.Graph:
		nxg = nx.Graph()
		nxg.add_nodes_from(range(self.n_nodes))
		nxg.add_edges_from(self.edges)
		return nxg

def qubo_graph_coloring(g: Graph, n_color, penalty = 10.) -> np.ndarray:
	n = g.n_nodes
	q = np.zeros((n, n_color, n, n_color))
	i = range(n)
	q[i, :, i, :] = penalty * (np.ones((n_color, n_color)) - 2 * np.eye(n_color))
	i, j = g.edges.T[..., None]
	k = range(n_color)
	q[i, k, j, k] += penalty / 2.
	q[j, k, i, k] += penalty / 2.
	return q.reshape(n * n_color, n * n_color)

edges = [[0, 1], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [3, 4]]
n_nodes, n_color = 5, 3
g = Graph(edges = edges, n_nodes = n_nodes)
ans = np.zeros(n_nodes * n_color)
ans[[1, 3, 8, 10, 14]] = 1
q = qubo_graph_coloring(g, n_color, penalty = 4.)
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
#assert is_contain(qbsolv_from_ndarray(q)[0],ans)


```

以上。
amplifyの作法 その12

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from amplify import (BinaryPoly, BinaryQuadraticModel, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from typing import Set, Tuple, Container, Dict, Sequence, Collection, Mapping
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))



def qubo_spp(cost: np.ndarray, set_flag: np.ndarray, p = 10.):
	assert cost.shape[0] == set_flag.shape[1]
	b = np.ones(set_flag.shape[0])
	return np.diagflat(cost - p * 2 * b.dot(set_flag)) + p * np.einsum("ij,ik->jk", set_flag, set_flag)

c = np.array([3, 2, 1, 1, 3, 2])
a = np.array([[1, 0, 1, 0, 0, 1], [0, 1, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0], [1, 1, 0, 1, 0, 1]])
q = qubo_spp(c, a)
assert q.tolist() == [[-17, 10, 10, 10, 0, 20], [10, -18, 10, 10, 10, 20], [10, 10, -29, 10, 20, 20], [10, 10, 10, -19, 10, 10],	[0, 10, 20, 10, -17, 10], [20, 20, 20, 10, 10, -28]]
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
#	assert is_contain(sample, np.array([1,0,0,0,1,0]))


```

以上。
Lan内に設置されたRaspberry piで収集したデータを公開する方法

LAN内のRaspberrypiで収集したデータをGoogleSpreadSheetに書き込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/277e326f-31f2-35ff-4968-05aded94730d.png)

インターネットに接続されたRaspberry PIは、Google Driveを用いて簡単にWeb serviceとして公開できます。


## Postで行う

```sample.py
'''
ラズパイからGoogleSheetに書き込むサンプルプログラム
t:温度
h:湿度
p:気圧
'''
def ExportGoogleSheet(t,h,p):
    url='https://script.google.com/macros/s/○○○○○○○○○○○○○○○○/exec'
    data = '{"temp":t,"humid":h,"press":p}'
    r=requests.post(url, data=data)

```

```post.js
function doPost(e) {
  // スプレッドシートオブジェクトを取得
  var ss = SpreadsheetApp.getActive()
  var sheet = ss.getActiveSheet();
  var d=JSON.parse(e.postData.contents);
  // 日付、postDataオブジェクトを追記
  sheet.appendRow([new Date(),d.temp,d.humid,d.press]);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/411b3669-56a4-e853-0e1f-8e9b61a2ba2f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/6cbccaec-d900-9327-9b3b-1f56f2a72084.png)

## getで行う方法
###送り出し
```py
def getData(d,t,h,b,m):
    url='https://script.google.com/macros/s/AKfycbykJNNMPwirzk〇〇〇〇〇〇〇〇〇B3S2H1ZtM/exec?d=%s&t=%f&h=%f&b=%d&m=%s'%(d,t,h,b,m)
    r=requests.get(url)
```

## 受け取り

```js

//pythonからデータを受け取る
function doGet(e) {


        var d = e.parameter.d; //時刻データの受け取り
        var t = e.parameter.t; //温度データの受け取り
        var h = e.parameter.h; //湿度データの受け取り
        var b = e.parameter.b; //バッテリデータの受け取り
        //現状Activeになっているsheetを取得
        var sheet = SpreadsheetApp.getActiveSheet();

        //送信されたデータ値　を追記
        sheet.appendRow([d, t, h, b]);
        // response for debug    
        var ok = "OK " + d + " " + t + "℃ " + h + "% " + b + "% Bat"
        var output = ContentService.createTextOutput(ok);
        output.setMimeType(ContentService.MimeType.TEXT);
        return output;
```
amplifyの作法 その11

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from amplify import (BinaryPoly, BinaryQuadraticModel, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from typing import Set, Tuple, Container, Dict, Sequence, Collection, Mapping
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))

def qubo_set_pack(a: np.ndarray, weight: np.ndarray, penalty = 8.) -> np.ndarray:
	assert len(a.shape) == 2
	assert a.shape[-1] == len(weight)
	q = -np.diagflat(weight)
	c = np.einsum("ij,ik->ijk", a, a).astype(np.float) / 2.
	c *= (1 - np.eye(a.shape[-1]))[None, ...]
	q += penalty * c.sum(0)
	return q

a = np.array([[1, 0, 1, 1], [1, 1, 0, 0]])
w = np.ones(4)
q = qubo_set_pack(a, w, penalty = 6.)
assert q.tolist() == [[-1, 3, 3, 3], [3, -1, 0, 0], [3, 0, -1, 3], [3, 0, 3, -1]]
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
#assert is_contain(qbsolv_from_ndarray(q)[0], np.array([0,1,1,0]))

```

以上。
INSERT SELECTでWITHを利用したい

# TL;DR

MySQL8で、INSERT SELECTでWITHを利用したい場合、以下のように書けばよいです。

```SQL
INSERT INTO a (
  WITH c AS (
    SELECT * FROM b
  )
  SELECT * FROM c
);
```

WITH RECURSIVE (再帰SQL) も利用することができます。

```SQL
INSERT INTO e (
  WITH RECURSIVE r AS (
    SELECT 1 AS seq
    UNION ALL
    SELECT seq + 1 FROM r WHERE seq < 5
  )
  SELECT * FROM r
);
```


# 環境

mysql  Ver 8.0.23 for Linux on x86_64 (MySQL Community Server - GPL)

# 稼働確認用DDL

## WITH

```SQL
CREATE TABLE a (
  col text
);
CREATE TABLE b (
  col text
);

INSERT INTO b VALUES ('col1');
INSERT INTO b VALUES ('col2');
INSERT INTO b VALUES ('col3');
INSERT INTO b VALUES ('col4');
INSERT INTO b VALUES ('col5');

INSERT INTO a (
  WITH c AS (
    SELECT * FROM b
  )
  SELECT * FROM c
);

SELECT * FROM a;
```

このSQLが以下のような結果セットを返すことを確認する。

|col|
|:---|
|col1|
|col2|
|col3|
|col4|
|col5|

## WITH RECURSIVE

```SQL
CREATE TABLE e (
  seq INT
);

INSERT INTO e (
  WITH RECURSIVE r AS (
    SELECT 1 AS seq
    UNION ALL
    SELECT seq + 1 FROM r WHERE seq < 5
  )
  SELECT * FROM r
);

SELECT * FROM e;
```

このSQLが以下のような結果セットを返すことを確認する。

|seq|
|---:|
|1|
|2|
|3|
|4|
|5|
【JavaScript】substrメソッドの使い方

# substr()

String.prototype.substr()

文字列の一部を、指定した位置から後方向指定した文字数だけ返す

```js
//公式
str.substr(start[, length])

//サイト記事
var str = 文字列
 
str.substr( 開始位置, 文字数 )
```
## これが元になって調査
```js
watch: {
    // 入力された文字列を監視する
    inputText: function() {
        var pos = this.inputText.indexOf(this.forbiddenText); // indexOf：指定された値が最初に現れたインデックスを返す
        if (pos >= 0) {
            alert(this.forbiddenText + "は、入力できません。");
            // 入力文字列から禁止文字を削除する
            this.inputText = this.inputText.substr(0, pos); //str.substr( 開始位置, 文字数(indexOfででたインデックス) )
        }
    }
}

```

## 参考

https://www.sejuku.net/blog/50543
チートエンジンの使い方

#はじめに
前回の記事でポインターを取得する方法を書いていなかったので、今回は詳しく書こうと思います。
#準備
https://www.cheatengine.org/downloads.php
ここからチートエンジンをインストールしてください
#プロセスにアタッチ
![Cheat Engine 7.1 2021_03_02 10_09_17 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/83362953-4b20-cc7e-aac5-7f518c301e40.png)

チートエンジンを起動するとこのように枠で囲まれたボタンがあるのでそこを押します。
するとちっちゃなウィンドウが出てきます。Processというタブを選択しておきましょう
![Cheat Engine 7.1 2021_03_02 10_11_03 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/d42cff95-cfaf-b4f7-6f3b-6a164eebcc82.png)
このリストの中からアタッチしたいゲーム（かプロセス）を選びます
#アドレスを探す
早速探していきましょう
今回はfloatの値が調べたいので、4byteになっているところをfloatにして、今の値をValueに入れます。
![スクリーンショット 2021-03-02 101557.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/d883149c-02e3-75f6-7d59-49b6a2c4bd05.png)
そしたらfirst Scanを押しましょう
![スクリーンショット 2021-03-02 101926.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/59789398-b698-1c24-1b5d-1b2ac9692c64.png)


179件見つかりましたねこの中に欲しいアドレスがあるはずです。
見つけたいアドレスの値をゲーム内で変更しましょう。
変更したらチートエンジンで変えた後の値をValueに入れます。
そしたらNext Scanを押しましょう
お！一件に絞られました
#ポインタースキャン
![スクリーンショット 2021-03-02 102158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/4011d5dd-6eb9-626a-721d-27c7a206f340.png)
それではこのアドレスを選択して、赤い矢印を押します。
下に来ましたね。
下に来たアドレスを右クリックするとこのようなものが出てくるので、Pointer scan for this addressを押しましょう。
![スクリーンショット 2021-03-02 102401.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/72735c53-79a0-d355-7617-3399eb2e1ad3.png)
あとは、保存するファイル名を入れてその他の設定は基本無視でいいです。
そうすると2~3分でポインタースキャンが終わるはずです。
![スクリーンショット 2021-03-02 102854.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/03b2cf95-c189-fb1b-86b0-fe48a1311e54.png)
おっと3541747件見つかりましたね。これでは多すぎるので、ゲーム（かプロセス）を再起動しましょう。
この時にさっきのポインタースキャンのウィンドウは閉じないようにしましょう。
再起動したらすることは同じです。もう一度アドレスを探し出してください。
探し出したら、アドレスをコピーします。アドレスをコピーする方法は
下に持ってきたアドレスの``Address``のところをダブルクリックすれば選択できるのでそこをコピーします
![スクリーンショット 2021-03-02 103500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/ba7e4d44-6356-a753-5ea9-fd80c6cdb274.png)
アドレスをコピーしたところで、ポインタースキャンのウィンドウに戻りましょう。
![スクリーンショット 2021-03-02 103754.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/319c1ec8-c763-aa35-dc93-e758f6a367b6.png)
Pointer scanner → Rescan memoryを選択
![スクリーンショット 2021-03-02 103907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/a60d68a9-73b7-30f8-67af-7ba68b90f6ff.png)
そしたらテキストボックスに先ほどのアドレスを入れてOKを押します
ファイル名は同じにしてください。そしたら上書き保存します。
これを何回も繰り返します。
だいたい100~1000件に絞られたらいい感じです。
#ポインターの使い方
![スクリーンショット 2021-03-02 104346.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626228/5c11ea58-fb91-69c1-4421-e26b42a4bc88.png)
前回の記事でこのポインターからアドレスを計算する方法を書いたのでそちらを読んで、アドレスを計算してみてください。
[前回の記事](https://qiita.com/360tetsu360/items/ac5caab7d407ba8d8485)
#参考
[わかりやすい動画](https://www.youtube.com/watch?v=7srDM2AuNPs)
Datadogで一番簡単な(たぶん)カスタムメトリクスの使い方

##はじめに

システムの運用を担っているとそれなりに障害が発生し、何らかの対応が必要になります。とりあえず再発してもすぐに気づけるように…と監視で検知させるのが最初の一歩ですが、ツール標準の機能では検知させることが困難…というのもよくある話です。

とりあえず正常動作の判定はコマンドラインから叩けば出来るけど、アラート通知させるにはどうしよう？というところで、その昔は実行結果をログに出力してログ監視で拾ったりしていました。これでも実用には足りますが本来不要なログを経由して結果を取り出しているので、グラフ化が困難だったりログのローテート管理が必要になったり、想定外の結果が返った時は通知が抜けたりと強引な手法なのは否めません。

Datadogだとこのあたり簡単でわりとスマートに出来ますよというのがこの記事の主旨です。

##カスタムメトリクスって何？

Datadogのカスタムメトリクスは上で挙げたような「ツール標準の機能では取得できない項目」をデータとして活用するための機能です。
公式のドキュメントを追っていくと「カスタムメトリクスの送信」として以下4つの方法が記載されています。

 - カスタムagentチェック
 - DogStatD
 - PowerShell
 - DatadogのHTTP API 

このうち上から3つは多少なりともコードが書けること(主にpythonとか)が要求されます。自分も含めてインフラエンジニアは「コードはわからんけどシェルスクリプトなら書けるよ」という人が多いのでは？と思いますが、この属性の人でも簡単に使えるのが4番目の「HTTP API」です。おおざっぱに言えば「正常動作判定の処理をシェルスクリプトで作ったら、curlコマンドで結果をDatadogに送ることができる」という仕組みです。

## 実装方法
[公式ドキュメント](https://docs.datadoghq.com/ja/api/latest/metrics/#submit-metrics)の"Submit metrics"のコード例(curl)の項目を参照して…と一言で済ませたいところですが、微妙に分かりづらい感じなので自分が使っている（動いている）コードを載せて解説します（変数名やコマンド内容は修正しています）

目的としては「tomcat(java)プロセス内の特定スレッドが動作しているか定期的に監視し、落ちたらアラートを上げたい」というものです。基本はjpsコマンドでの出力結果をあれこれ加工して、最終的にwcコマンドに渡して数値化しています。


```check-java-thread.sh
#!/bin/sh

# setting
API_KEY=hogehogehogehoge
currenttime=$(date +%s)
WORKDIR=/home/ec2-user
GROUP=`echo $HOSTNAME | cut -b 1-9`
NAME=`echo $HOSTNAME | cut -b 1-21`

# main
check-java-thread=`sudo jps | grep hogehoge | wc -l `

# post
curl -s -X POST -H "Content-type: application/json" \
  -d "{ \"series\" :
        [{\"metric\":\"check.java-thread\",
          \"points\":[[$currenttime, $check-java-thread]],
          \"type\":\"gauge\",
          \"host\":\"$HOSTNAME\",
          \"tags\":[\"autoscaling_group:$GROUP\", \"name:$NAME\"]}
        ]
      }" \
        "https://app.datadoghq.com/api/v1/series?api_key=$API_KEY"

```

***

### setting(変数定義)

* API_KEY:DatadogのGUIから"Integration"→"API"で表示されるAPI Keyを設定
* currenttime:Datadogにメトリクスを送る時「何時のデータか」を指定するために、コマンド実行時間を取得
* GROUP:自分の運用するシステムではサーバ名に環境名を持っているので、hostnameコマンドで取り出す
* NAME:同上

### main(サーバ上で実行される確認コマンド)

* コマンドラインでの確認方法をそのまま変数に格納

### post(datadogにデータを送る、ここが一番重要)

* curlコマンド:POSTメソッドの使用とjson型の宣言
* series:このフィールド名で以下のメトリクスデータを定義
* metric:Datadog上で管理する時のメトリクス名
* points:送信するメトリクスの取得時間、データ本体(コマンドの実行結果が反映される)
* host:メトリクスに紐付けるホスト名
* type:メトリクスのデータ型を指定、string(文字列)/count(カウント数)/gauge(数字)/rate(パーセント)
* tags:メトリクスに紐づけるタグ
* interval:取得間隔、typeがcountかrateの場合は必要(この例では省略)

***

この書式でスクリプトを書いて、cronなどで任意のインターバルで実行するだけでDatadog上にカスタムメトリクスとして取得することが出来ます。この例の場合はJavaVMに特定スレッドが存在すれば=1、存在しない(落ちた)ときは=0なので、グラフで推移を見る事が出来て0の時はアラート通知させることが出来ます。

クラウド環境だとホスト名は可変する例が多いので、アラート通知の要/不要はモニター設定側でタグを使って制御するのが良いと思います（検証環境では通知不要とか）何らかの異常で結果がnullの時を想定するのであれば、アラート設定の"if data is missing"の設定などで対応できそうです。

## メリットとデメリット

**メリット**

 - シェルスクリプトで動かすことができればたぶんなんでもいける
 - データ形式が4パターンあるので、およそ何らかの実行結果であればこの中で納まるはず


**デメリット**

 - 「cronで回す」というところは変わらないので、cronが死んだら監視も止まる
 - シビアな運用であればシェルスクリプトの設計センスもそれなりに必要

## 最後に
今のところ自分の環境ではこれで問題なく動いていますが、Datadogは色々と進化が早いのでそのうちアップデートが必要になるかもしれません…
OpenStackの自動構築ツール　Packstackのインストール方法

###環境および作業の前提条件
OS：CentOS8
OpenStackのバージョン：victoria


###概要
OpenStackの自動構築ツールであるPackstackのインストール方法を記載する。

手順の流れは以下
① プロキシサーバーの設定(プロキシを使用している環境は)
② リポジトリ設定
③ PackStackインストール

###プロキシサーバの設定

構築するサーバーがプロキシサーバー経由でインターネットへアクセスする場合は、yum.confファイルを編集する。

```
$ vi /etc/yum.conf
(省略)
proxy=http://proxy.yoursite.com:8080
```

###リポジトリ設定
HTTPアクセスをプロキシサーバー経由で行う場合は、$HOME/.bash_profileファイルにプロキシサーバーのための環境変数を設定する。

```
$ vi /root/.bash_profile
(省略)
export http_proxy="http://proxy.yoursite.com:8080"←自社のプロキシサーバーを指定
export https_proxy="http://proxy.yoursite.com:8080"←自社のプロキシサーバーを指定
export no_poxy=(インストール対象ノードのIPアドレス),127.0.0.1,localhost
```

/root/.bash_profileに記述した環境変数をロードする。

```
$ . /root/.bash_profile
```

###環境変数の確認
上記手順でno_proxyにインストール対象ノードのIPアドレスを指定しています。環境変数が適切に設定されているか確認します。

```
$ printenv | grep proxy
export http_proxy="http://proxy.yoursite.com:8080"←自社のプロキシサーバーを指定
export https_proxy="http://proxy.yoursite.com:8080"←自社のプロキシサーバーを指定
export no_poxy=(インストール対象ノードのIPアドレス),127.0.0.1,localhost
```

###ネットワーク周りの事前設定
PackStack利用する際はNetworkNanagerとfirewalldの無効化が推奨されています。そのため、NetworkNanagerとfirewalldの無効化を行います。NetworkNanagerを無効化しただけだと通信できなくなってしまいますので、手動でネットワークスクリプトのインストールし、そちらを使って通信を行います。
ネットワーク周りの事前設定は以下の順序で行います。
① ネットワークスクリプトのインストール
② firewalldの無効化
③ NetworkManagerの無効化
④ ネットワークスクリプトの有効化

####ネットワークスクリプトのインストール

```
$ dnf install network-scripts -y
```

####firewalldの無効化
```
$ systemctl disable firewalld
$ systemctl stop firewalld
```

####NetworkManagerの無効化
```
$ systemctl disable NetworkManager
$ systemctl stop NetworkManager
```

####ネットワークスクリプトの有効化
```
$ systemctl enable network
$ systemctl start network
```

###OpenStackのリポジトリインストール
次にOpenStackのリポジトリをインストールします。CentOS8の場合、まずはpowertoolリポジトリを有効化する必要があります。その上でopenstackリポジトリをインストールします。今回インストールするopenstackのバージョンはvictoriaです。

```
$ dnf config-manager --enable powertools
$ dnf install -y centos-release-openstack-victoria
$ dnf update -y
```

###PackStackのリポジトリインストール
```
$ dnf install -y openstack-packstack
```

###PackStackを使ってOpenStackインストール

```
$ sudo packstack --allinone
```

インストールには1時間程度かかりました。


参考サイト
https://www.rdoproject.org/install/packstack/
https://docs.openstack.org/ja/install-guide/environment-packages-rdo.html
HTML　〜ブロック要素とインライン要素〜

#ブロック要素とインライン要素
###①ブロック要素
その名の通り一つのブロックのことです。見出し、段落、表などがあります。

```index.html
1. <form></form>
2. <table></table>
3. <ul></ul>
4. <div></div>
5. <p><p>
```
などがあります。
これらは横幅と高さの指定が可能です。横幅の初期値の値は親要素の横幅と同じになります😊

###②インライン要素
こちらはブロッレベル要素の中身になります。
文章の中の一部として使われたりします。
例としては以下になります😊

```index.html
1. <a></a>
2. <b></b>
3. <input></input>
4. <textarea></textarea>
5. <span></span>
6. <img>
```
などがあります！
これらは横幅と高さの指定ができません！（（筆者はこれを知らない状態でCSSに突っ込んでしまい、後悔することになりました(・・;)

ちなみに当たり前ですが、ブロックレベル要素の中にインライン要素を入れなくてはなりません！

```index.html
<div><a href="#">こちらをクリックしてください</a></div>
```
ちなみにですが、aタグのときに特にリンクが無い、またはとりあえずで付ける場合は"#"をつけときます👌

インライン要素とブロックレベル要素について詳しくはこちらのサイトがわかりやすかったのでご参考にしてください！
https://www.itra.co.jp/webmedia/block-inline-difference.html

それでは、CSSに入っていきます👍
amplifyの作法 その10

#概要

amplifyの作法、調べてみた。
qubo使ってみた。

#参考にしたページ

https://qiita.com/tamurahey/items/0c70a3d37e1367f3d67c


#サンプルコード

```
from typing import Set, Tuple, Container, Dict, Sequence,  Collection, Mapping
from amplify import (BinaryPoly, BinaryQuadraticModel, sum_poly, gen_symbols, Solver, decode_solution, )
from amplify.client import FixstarsClient
from dataclasses import dataclass
import networkx as nx

def to_dict(q: np.ndarray) -> Dict[Tuple[int, int], float]:
	assert len(q.shape) == 2 and  q.shape[0] == q.shape[1]
	return dict(zip(zip(*np.nonzero(q)), q[q != 0]))

@dataclass
class Graph:
	edges: Collection[Collection[int]]
	n_nodes: int
	init_value: Mapping[int, int] = None
	nodes: Sequence[float] = None 
	def __post_init__(self):
		if self.nodes is not None: assert len(self.nodes) == self.n_nodes
		if self.edges is None: return
		if len(self.edges) == 0:
			self.edges = None
			return
		self.edges = np.array(list(self.edges))
		assert self.edges.max() < self.n_nodes
		assert self.edges.shape[1] == 2
		if self.init_value is not None:
			assert all(np.array(list(self.init_value)) < self.n_nodes)
	@classmethod
	def from_networkx(cls, graph: nx.Graph) -> nx.Graph:
		return cls(edges = graph.edges, n_nodes = graph.number_of_nodes())
	def to_networkx_graph(self) -> nx.Graph:
		nxg = nx.Graph()
		nxg.add_nodes_from(range(self.n_nodes))
		nxg.add_edges_from(self.edges)
		return nxg

def test_graph():
	edges = {(1, 2), (3, 4)}
	graph = Graph(edges, 5)
	assert graph.edges.shape == (2, 2)
	nxg = graph.to_networkx_graph()
	_graph = Graph.from_networkx(nxg)
	assert np.array_equal(graph.edges, _graph.edges)
	assert graph.n_nodes == _graph.n_nodes
test_graph()

def qubo_max_cut(g: Graph) -> np.ndarray:
	n_nodes = g.n_nodes
	q = np.zeros((n_nodes, n_nodes))
	i, j = g.edges.T
	np.add.at(q, (i, i), -1)
	np.add.at(q, (j, j), -1)
	q[i, j] += 1
	q[j, i] += 1
	return q

def is_contain(x: np.ndarray, y: np.ndarray) -> bool:
	assert len(x.shape) -1 == len(y.shape)
	return any(np.array_equal(xi, y) for xi in x)


edges = [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]
g = Graph(edges = edges, n_nodes = 5)
q = qubo_max_cut(g)
assert q.tolist() == [[-2, 1, 1, 0, 0], [1, -2, 0, 1, 0], [1, 0, -3, 1, 1], [0, 1, 1, -3, 1], [0, 0, 1, 1, -2]]

#assert is_contain(sample, np.array([0, 1, 1, 0, 0]))
q = to_dict(q)
print(q)
f = BinaryPoly(q)
model0 = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model0)
values = result[0].values
print(values)
```

以上。
numpy.arrayインプレース演算の落とし穴(Python)

#概要
Python numpyでインプレース演算(`+=`など)をした際に思わぬ挙動をすることがあるので、
その確認をする。
#内容
##環境
macOS Catalina
Python 3.7.0
numpy 1.18.3
##再現
```Python
>>> import numpy as np
>>> a = np.array([3])
>>> b, c = a, a
>>> a, b, c
(array([3]), array([3]), array([3]))
>>> c += 1
>>> a, b, c
(array([4]), array([4]), array([4]))
```
##分析
`a`, `b`, `c`が参照しているのは、`np.array`オブジェクトに対してであるが、
`+=1`が実は変更したのは、その属性であるからである。
下記のように、`+=1`がオブジェクト自体を変更する場合は、予想通りの変化になる。

```Python
>>> a = 3
>>> b, c = a, a
>>> a, b, c
(3, 3, 3)
>>> c += 1
>>> a, b, c
(3, 3, 4)
>>>
```
##解決策
`c = c + 1`とし、オブジェクトを新たに生成する。

```Python
>>> import numpy as np
>>> a = np.array([3])
>>> b, c = a, a
>>> c = c + 1
>>> a, b, c
(array([3]), array([3]), array([4]))
```
##蛇足
`id`関数を使って確認することもできる。

```Python
>>> import numpy as np
>>> a = np.array([3])
>>> b, c = a, a
>>> id(a), id(b), id(c)
(4692042016, 4692042016, 4692042016)
>>> c += 1
>>> a, b, c
(array([4]), array([4]), array([4]))
>>> id(a), id(b), id(c)
(4692042016, 4692042016, 4692042016)
>>> c = c + 1
>>> a, b, c
(array([4]), array([4]), array([5]))
>>> id(a), id(b), id(c)
(4692042016, 4692042016, 4692041936)
```

なお、属性の直接の変更は、下記のように同一オブジェクトを参照している場合は、どちらも変わって見える。
インプレースかどうかの問題ではなく、オブジェクトと参照の問題であるはず。(言葉足らず)

```Python
>>> class Obj: pass
...
>>> a = Obj()
>>> a.name = 'mori'
>>> b = a
>>> a.name, b.name
('mori', 'mori')
>>> a.name += 'ta'
>>> a.name, b.name
('morita', 'morita')
>>> a.name = a.name + 'rou'
>>> a.name, b.name
('moritarou', 'moritarou')
```
#参考にさせていただいた本
『ゼロから作るDeep Learning③　フレームワーク編』斎藤康毅著 O'REILLY
#感想
numpyの配列を使う際に、気を付けようと思った。
#今後
代入演算子に注意。
Docker 全てのコンテナを再ビルドして起動する

## 目的

- Dockerの全てのコンテナを再ビルド指摘どうするコマンドをメモ的に記載する

## 紹介

- 下記をdocker-compose.ymlがあるディレクトリで実行する。

    ```terminal
    $ docker-compose down && docker-compose build && docker-compose up -d
    ```
簡単なタスクをAzure static web appsに載せてみる（HTML,C#）

## 前提
C#で書いた（ほぼ）スクリプトを特定の人がオンラインでできるようにWeb化したい。
ひとまず簡単にAzure FunctionとHTMLがあればいいか、と思ったらAzureにちょうどいいサービスができていたので、
それを使って構築してみる。

## Static Web Apps
https://docs.microsoft.com/ja-jp/azure/static-web-apps/overview
まずはこのへん見ましょう。
フロントエンドはJSとかシンプルなHTMLとか、バックAPIはFunction使われる。
ただしリポジトリはGithub限定で個人的にちょっと不便（Azureのレポはあかんのかい…）

## シンプルページをクローン
https://github.com/staticwebdev/vanilla-basic
このあたりからcloneする。
ただこのままだとルーティングがないので、`routes.json`を作成する必要がある。

## ルート定義（routes.json）
https://docs.microsoft.com/ja-jp/azure/static-web-apps/routes
このへんなんだが、シンプルHTMLだと一覧に入ってなかったり。

https://docs.microsoft.com/ja-jp/azure/static-web-apps/front-end-frameworks
この一覧参照

シンプルHTMLならルートフォルダにそのまま入れる。

`routes.json`の書き方は
> routes 配列に出現する順序で実行されます。

これを読んでないとマニュアルのスニペットをそのまま貼っつけてハマった。。

``` routes.json
{
  "routes": [
    {
      "route": "/profile",
      "allowedRoles": ["authenticated"]
    },
    {
      "route": "/admin/*",
      "allowedRoles": ["administrator"]
    }
  ]
}
```
↑ちゃんと書くといわゆるこういう感じになる。（一要素だけ書いちゃってて動かなかった）

## 認証つける
特定の人だけに見せるページなら別途roleを割り当てる。
`authenticated`のロールだとどんなアカウントでもひとまずログインした状態であれば見えてしまうので、
ちゃんとロール管理→招待、から対象のメールアドレスを入力しておく。（割り当てるroleはadminなどにすればいいかな）
※ここでロールのことが出てくる、`routes.json`や認証の説明だけ読んでもわからんかった…

## APIを追加する
https://docs.microsoft.com/ja-jp/azure/static-web-apps/add-api
大体ドキュメントの通りなんだが、例ではnodeでC#だとどうするのかわかりにくい。
C#はいらない子？
（というかVSCodeの操作前提ってなんだよ…ともなった）

けどちゃんとできるので、くじけずにやる。

### APIフォルダにAzureFunction追加
`api`フォルダを作成して、AzureFunctionプロジェクトをそこに作成する。（VSでもRiderでも大丈夫）
そいでAPIのコード書く（もちろんなんでもOK）
で、ちゃんと動くことを確認しておく。

ただ、このままだと`function.json`がない。
自分で作るの？けど例も無いのにどうやって？？
と思ったら、AzureFunctionの方のドキュメントに
https://docs.microsoft.com/ja-jp/visualstudio/mac/azure-functions-lab?view=vsmac-2019#exercise-4-working-with-functionjson
とあった。どうやらビルドした時に作成されているようだ。
それをルートの場所に持ってこよう。

## Github Actionは動くがビルドされない
これがまぁ困った。
最初はcsファイルと各jsonファイルしかコミットしてなかったが、それだとビルドができないらしい。
全然API動かん…と思ってgithubActionのログをみたら（詳細にログ見れます。動かないときは要チェック）
`Error: Could not detect the language from repo.`
と出ていて、ビルドも何もできていない様子だった。
https://docs.microsoft.com/ja-jp/azure/app-service/deploy-local-git
このへん見て解決。
`ASP.NET Core :	*.sln または *.csproj`
という様に、csprojファイルも追加するとちゃんとビルドできた。

## 所感
簡単にAPI付きのWebページを作れるのは便利。
認証もつけられるし。（BASIC認証もパッとできれば尚良）
ただAzure全体に言えることなんだが、ドキュメントがちょっとかゆいところに手が届かない感あり。
「0から作るDeepLearning」の4章を写経した時のエラー原因

こんにちは！

今日のエラー原因を書きます。

使用した本：「０から作るDeepLearning」
4章
１「two_layer_net.py」の写経について
・16行目のout_sizeの見逃し
・77行目の「＝」の写し間違い

２「train_neuralnet.py」の写経について
・6行目の「dataset.mnist」の写し間違い
・52行目の「ylabel」の写し間違い

所感
全体を通してみると、「俺はちゃんと写経できてるぞ」
と思っているときほど何か見落としてることが多いです。
後、原因としては「写経なんか楽勝！」と考えているからだと思います。
けど、人間だから仕方ない。（開き直り）
AtCoderをやる時によく使うコードまとめ


# はじめに
今からAtCoderを始めようと思うので、とりあえずよく使うコードをまとめてみようと思います。

# 基本のコードはこれ
- 入力、出力
- 代入、単純な四則演算処理（+, -, *, /, = など）
- 条件分岐（if 文など）
- 繰り返し処理（for 文など）
- 文字列（string）
- 浮動小数点（double 型など）
- 配列（二次元配列も含む）

# 入力、出力
Material UIをTailwind CSSのスタイルで上書きする方法

結論から言うと、Tailwind CSSの設定ファイルに`important: true`を追記します（[公式](https://tailwindcss-ja.entap.app/docs/configuration#important)）。

```tailwind.config.js
module.exports = {
  .
  .
  .
  variants: {
    extend: {},
  },
  plugins: [],
+ important: true,
}
```
こうすることで、className属性に指定したTailwind CSSが既存のスタイルの一部（あるいは全て）を上書きしてくれます。
***
Material UI便利ですよね。でも、使っているうちに既存のスタイルを少し修正したいときがあります。
例えば[Avatarコンポーネント](https://next.material-ui.com/ja/components/avatars/)は、画像をいかにもアイコン風な感じに切り取ってくれる点が優秀だと感じていますが、もし既存のサイズより小さくカスタマイズしたい場合次のように書く必要があります。

```react.tsx
import {
  Avatar,
  makeStyles,
  createStyles,
  Theme,
} from "@material-ui/core";
```
```react.tsx
const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    small: {
      width: theme.spacing(2), //= '16px'
      height: theme.spacing(2), //= '16px'
    }
  })
);
```

```react.tsx
const classes = useStyles();
return (
  <Avatar className={classes.small}/>
);
```
***
Tailwind CSSで書く場合、冒頭の設定を行ったならばこれだけで済みます。

```react.tsx
return (
  <Avatar className="w-4 h-4"/> //= 'width: 16px, height: 16px' 
);
```
なお`important: true`はTailwind CSSで記述した全てのクラスが`!important宣言`付きでマークアップされることを`true`にするものですので注意してください。
Express.jsでファイルダウンロード


Express.jsで画像などのファイルをダウンロードする方法です。
本記事の内容は以下のドキュメントに書かれている内容の説明になります。
https://expressjs.com/ja/api.html

## 実行環境
express.js 4.17.1
MacOS 10.15.7

## 方法その1 簡易的な方法

```typescript
import express from 'express';

export const router: express.Router = express.Router()

router.get('/download', (req, res) => {
  res.download('images/どね.jpg')
})
```
`download`メソッドを使います。ファイルパスを引数に取ることになるので、一度ファイルをストレージのどこかに置く必要があります。すでにBuffer形式になっている場合は少し面倒ですね。


https://expressjs.com/ja/api.html#res.download

## 方法その2 headerに指定
```typescript
import express from 'express';
import fs from 'fs/promises'

export const router: express.Router = express.Router()

router.get('/set', async (req, res) => {
  const img = await fs.readFile('images/どね.jpg')
  const fileName = encodeURIComponent('どね.jpg')
  res.set({'Content-Disposition': `attachment; filename=${fileName}`})
  res.status(200).send(img)
})
```

レスポンスのヘッダーを直接指定します。`Content-Disposition`の`attachment`を指定することでブラウザ側でダウンロードファイルであることを認識してくれます。
それ以外にも以下の処理が必要になります。

- Bufferファイルを一度読み込んでbodyに入れる
- 日本語ファイル名の可能性がある場合はファイル名にエンコードをかける


## filenameとfilename*の違いについて

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Disposition
>引数の filename と filename* の違いは、 filename* が RFC 5987 で定義されているエンコーディングを使用するという点のみです。単一のヘッダーフィールドの値に filename と filename* の両方が存在する場合は、両方が解釈できる場合、 filename* が filename よりも優先されます。

方法1では`filename*`が自動で使われて、方法2ではどちらも指定できます。

| 方法1 | 方法2 |
|-----------|------------|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305510/6939a03c-4f9c-6bb2-c249-7d8c5a8899ce.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305510/4c8a480b-8859-d5a2-4457-5b710771e195.png)|

いくつかのブラウザで試しましたがすべて`filename*`を認識できていました。使える文字もこちらのほうが多いようです。あえて`filename`を使う必要はなさそうです。もし使えないブラウザがあったら教えていただきたいです。

試したブラウザを以下に置いておきます。

| ブラウザ | バージョン | 対応状況 |
|-----------|:------------|:------------:|
| Chrome|88|○|
| FireFox|88|○|
| Microsoft Edge|88|○|
| Internet Explorer|11|○|

# まとめ

たいていはフレームワークに乗っかった方が後々困ることもないので**方法1推奨**です。
修正がかかったらフレームワーク側を直せば良い話ですし。
Brain-Body Model(Life hack)

Brain-Body Model とは
>- 人体は、頭脳と体に大きく分けられる。
- 様々なシステムを考える場合、頭脳と体に分けて考えるモデル。

例を挙げてみる。

>【　人体　　　　　：　頭脳　　　　　　ー　体　　　　　】
【　銀行システム　：　中央処理装置　　ー　ATM（複数）】

IoTの観点から検討すると、以下のようになる。

> 【　〇〇システム　：　クラウド　　　　ー　センサ　　　】

メタ視点になると（抽象度を上げてみると）、以下のようになる。

> 【　Something　：　Cyber Space　　ー　Real World　】

今回、銀行のATMの障害があったけど、人間の頭脳と銀行のシステムが連携すれば良いのかなと思った。

Cyber Spaceから見るとReal Worldは足枷でしかない。

そのうちATMの画面に以下のように表示されるかもしれない。

>「早くボタンを押してください。」
「ボトルネックはあなたです。」
スクレイピングとは

#スクレイピングとは
「webページから情報を取得し、加工すること」

似ている技術に「クローリング」がある。
両者の違いは取得した情報を加工するかどうかである。

クローリング：加工しない
スクレイピング：加工する

#プログラムの名称
スクレイピング：スクレイパー
クローリング：クローラー

#スクレイピングをするときに役に立つライブラリ
・Requests
＞webページを取得

・BeautifulSoup
＞webページからHTMLを抽出

・selenium
＞ブラウザを操作

#Requestsの基本操作
```python:requests.py
import requests
#request.get('url')でページの情報を格納
r = requests.get('https://news.yahoo.co.jp')
```

#BeautifulSoupの基本操作
```python:soup.py
from bs4 import BeautifulSoup

#例として解析するhtmlを用意してるだけ
html = "<h1>heygays</h1>"

#第一引数：解析したいもの,  第二引数：parser指定（後に説明）
soup = BeautifulSoup(html,"html.parser")

#取得部分の指定
print(soup.select("h1"))
```
出力

```
[<h1>heygays</h1>]
```

BeautifulSoupでは第一引数に何を解析したいか、第二引数にパーサを指定する。

パーサ：構文解析を行うためのプログラムの総称（今回はHTMLを解析するためhtml.perser）

最後に取得したい部分をselect()で指定する。

#RequestsとBeautifulSoupの併用

```python:main.py
import requests 
from bs4 import BeautifulSoup
r = requests.get('https://news.yahoo.co.jp/')
soup = BeautifulSoup(r.content,'html.parser')
print(soup.find('ul','newsFeed_list'))
```

#最後に
htmlのどの部分を取得すると自分の欲しい情報が手に入るかが分からない。
LinuxサーバでSolidfire iSCSIボリュームをマウントしてみる

# LinuxサーバでSolidfire iSCSIボリュームをマウントしてみる
LinuxサーバからSolidfireのiSCSIボリュームをマウントする時の手順の覚書です。

NetAppから[テクニカルレポート](https://www.netapp.com/media/10507-tr4639.pdf?v=9-3-2020-8-30-25-AM)が提供されているので、そちらも参考にして シンプルにiSCSIボリュームをマウントする手順を記載しています。

なお、Storage側のiSCSIボリューム作成・設定完了済みの前提です。
SolidfireのiSCSiボリューム作成・設定については、
[Ansibleを利用したiSCSIボリューム作成](https://qiita.com/yoihoka/private/63313f0532b3a61c215c)の記事があるので、よろしければそちらもどうぞ。

##前提
以下の環境で試しています

- Cent 7.7
- Solidfire 12.2

##作業の流れ
1. Linuxサーバに iSCSIパッケージ導入 
2. 認証方式にあわせてiscsi.confファイルを編集
3. iSCSIボリュームを検出
4. LinuxサーバでLVMボリュームとしてマウントしてみる

## 1. Linuxサーバに iSCSIパッケージ導入 
まずは必要なパッケージを導入

```shell:
$ sudo yum install –y iscsi-initiator-utils 
- 出力は省略：必要に応じて "y" を入力 -

$ cat /etc/iscsi/initiatorname.iscsi
$ sudo systemctl restart iscsid 
$ sudo systemctl enable iscsid 

```


## 2. 認証方式にあわせてiscsi.confファイルを編集

#### VAG認証方式
VAGでの認証方式（Initiator名とVolumeを紐づけてアクセス許可)を利用する場合は、特にLinuxサーバ側でiscsi.confファイルの設定作業は不要です。

#### CHAP認証方式
CHAP認証方式を利用する場合は、iscsi.confファイルを編集して、認証情報を記述します。ファイル編集後、設定反映のためiscsidサービスを再起動します。

以下認証情報である前提の記述例を記載します。

| 項目 | 値 | 備考
|:---|---|---|
|認証方式|CHAP |
|username| TenantA |
|Initiator Secret| zp9g_fW_Jt5C4Y6y |
|Target Secret| aZ_RKL_tw8w3_ZuS |

```shell:
$ sudo vi /etc/iscsi/iscsid.conf
ーー追記する内容ーー
node.session.auth.authmethod = CHAP
node.session.auth.username = TenantA
node.session.auth.password = zp9g_fW_Jt5C4Y6y
node.session.auth.username_in = TenantA
node.session.auth.password_in = aZ_RKL_tw8w3_ZuS

discovery.sendtargets.auth.authmethod = CHAP
discovery.sendtargets.auth.username = TenantA
discovery.sendtargets.auth.password = zp9g_fW_Jt5C4Y6y
discovery.sendtargets.auth.username_in = TenantA
discovery.sendtargets.auth.password_in = aZ_RKL_tw8w3_ZuS
ーー追記する内容ーー

$ sudo systemctl restart iscsid 
```

## 3. iSCSIボリュームを検出
LinuxサーバでiSCSIボリュームを認識できるようにします。
iSCSIボリュームを検出し、ログインすることで、Linuxサーバがデバイスとして認識します。

```shell:
$ sudo iscsiadm -m discovery -t st -p <Solidfire SVIP>:3260
$ sudo iscsiadm -m node -L all 

```

## 4. LinuxサーバでLVMボリュームとしてマウントしてみる
認識したiSCSiボリュームを、Linuxサーバでマウントしてみます。
今回はLVMボリュームとしてマウントします。

以下パラメータの前提でのコマンド例を記載します。

| 項目 | 値 |
|:---|---|---|
|disk | sdb |
|vg名| vg01 |
|lv名| lvol01 |
|ディレクトリ| /sfvol01 |

```shell: 
$ sudo pvcreate /dev/sdb
$ sudo vgcreate vg01 /dev/sdb
$ sudo lvcreate -l 100%FREE -n lvol01 vg01
$ sudo mkfs.xfs /dev/mapper/vg01-lvol01
$ sudo mkdir /sfvol01
$ sudo mount /dev/mapper/vg01-lvol01 /sfvol01/
```

なお、/etc/fstabに登録する場合は、"_netdev"のつけ忘れに注意ください。

```shell:
$ sudo cat /etc/fstab|grep sfvol01
/dev/mapper/vg01-lvol01 /sfvol01		xfs	defaults,_netdev 0 0
```
これで、再起動後も自動的にiSCSIボリュームをマウントしてくれます。

## まとめ
LinuxサーバでiSCSIボリュームをマウントする操作を記載してみました。

久しぶりにiSCSIボリュームをマウントしようとすると、コマンドなんだっけとかなることもあるかと思います。
今回は手動でマウント作業を実施しましたが、Ansibleとかの構成管理ツール等で自動化しておくと何かと便利（かも)です。