OmniAICreator/Qiita-1.07M huggingface dataset:
【ニッチなトラブル】Ubuntuで固定IPがうまくいかない（DHCPでMACとIPを紐づけできない）ときの対応

### MACとIPを紐づけても、IPが固定しない

Kubernetesクラスターを構築しようと、Raspberry Piに **Ubuntu Server 20.04 LTS** の64bit版を導入しました。
**IPアドレスを固定化** するため、いつものように [^1] 、ルーターのDHCPサーバーの設定で、Raspberry Piの **MACアドレスとIPアドレスを紐づけましたが、うまくいきません。**

[^1]: Raspberry Pi OS(Raspbian)の場合は、問題ありません。

![dhcp01a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280182/735f7f3a-abc9-eebc-78dc-0e66c3fd3795.png)

**【上図について】** raspi001～raspi003を、192.168.1.151～192.168.1.153に割り当てしようとしたものの（赤枠の部分でMACとIPの紐づけを設定）、動的に192.168.1.10xが割り当てられてしまいました。本来、Raspberry PiのMACアドレスは `b8:27:eb` や `dc:a6:32` 、 `e4:5f:01` で始まりますが [^2] 、raspi001～raspi003には、まったく異なる値が表示されています。

[^2]: http://standards-oui.ieee.org/oui.txt

悩みましたが、下記の対応策で解決しました。

### ルーター側で固定IPを設定するメリット

ちなみに、Raspberry Pi側で固定IPを設定せず、ルーター側で設定しているのは、 **次のようなメリットがある** からです。

- K8sクラスターを構成するすべてのRaspberry Pi（今回は3台）のIPアドレスを、ルーターで一括して設定できる
- 今後、ネットワーク構成に変更が生じても、ルーターの設定変更だけで済む

### 原因は‥

実は、Ubuntu（少なくとも20.04）では、DHCPのリクエスト時に、 端末識別子として **MACアドレスとは別の識別子** を送信します。このため、ルーター（DHCPサーバー）でMACアドレスを指定しても、別の端末と見なされ、IPアドレスが動的に割り振られます。

### 対応策：識別子としてMACを使うように設定

これを回避するには、Ubuntuのネットワーク設定で、DHCPの識別子にMACアドレスを使うよう設定します。最近のUbuntuでは、ネットワークの設定にnetplanを用いるため、 `/etc/netplan/99_config.yaml` を次のような内容で作成し、デフォルト設定を上書きします [^3] （Raspberry Piの場合、有線のネットワークインターフェースは `eth0` です）。

[^3]: https://ubuntu.com/server/docs/network-configuration

```
$ sudo vi /etc/netplan/99_config.yaml
```

```/etc/netplan/99_config.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: true
      dhcp-identifier: mac
```

次のコマンドで、設定を仮反映します。

```
$ sudo netplan try
```

新しいIPでSSHを接続し直し、問題がなければ、次のコマンドで確定反映します。
問題がある場合は、120秒間待つと、元の設定に戻ります。

```
$ sudo netplan apply
```

以上の設定にすると、ルーター側でIPアドレスを固定にすることができました。

![dhcp02a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280182/6fe6b143-9fbd-4961-e049-51dc9589ce39.png)

**【上図について】** raspi001～raspi003に、192.168.1.151～192.168.1.153が割り当てられました（赤枠の部分でMACとIPの紐づけを設定）。

なお、今回の設定は、netplanのドキュメントでは [^4]  `Integration with a Windows DHCP Server` の設定例として書かれており、なかなかわかりづらかったです。

[^4]: https://netplan.io/examples

### 参考：Raspberry Pi側で固定IPを設定する場合

`/etc/netplan/99_config.yaml` を次のような内容で作成します（反映方法は、DHCPの場合と同じです）。

```/etc/netplan/99_config.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: false
      addresses:
        - 192.168.1.151/24
      gateway4: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
```
ゼロから始めるLeetCode Day95「82. Remove Duplicates from Sorted List II」

# 概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

Python3で解いています。

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day94 「929. Unique Email Addresses」](https://qiita.com/KueharX/items/432198bf73c6d047c501)

[Twitter](https://twitter.com/kueharx)やってます。

**[技術ブログ](https://kueharx.blogspot.com/)始めました！！**
技術はLeetCode、Django、Nuxt、あたりについて書くと思います。**こちらの方が更新は早いので**、よければブクマよろしくお願いいたします！


## お知らせ
Day 100でQiitaでの投稿はひとまず区切りを付けようかと思います。
タグの記事が僕の記事ばかりになってしまうのもいかがなものかと思いましたし、他に有益な情報を提供している方の邪魔になってしまうこともあると考えたので、こうすることにしました。
至らない部分は多々ありましたが、今までお付き合い頂きありがとうございました。

問題を解いて記事を書く、というのは上記の個人ブログで続けるつもりですし、興味ある方はたまにそちらを覗いていただけると嬉しいです。
Twitterの方のアカウントはほとんど更新通知用と化しているので、Leetcodeを解く記事について気になる方はそちらも合わせてフォローいただくと良いかもしれません。

# 問題
[82. Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/)
難易度はMedium。
[コーディング面接対策のために解きたいLeetCode 60問](https://1kohei1.com/leetcode/)からの抜粋です。

問題としては、ソートされた連結リストが与えられた場合、重複した番号を持つすべてのノードを削除し、元のリストとは異なる番号のみを残します。
同様にソートされた連結リストを返します。

>Example 1:

>Input: 1->2->3->3->4->4->5
Output: 1->2->5

>Example 2:

>Input: 1->1->1->2->3
Output: 2->3

# 解法

```python
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head:
            return
        node = pre = ListNode(0)
        node.next = cur = head
        while cur.next:
            nex = cur.next
            if cur.val == nex.val:
                while(nex.next and nex.val == nex.next.val):
                    nex = nex.next
                pre.next = cur = nex.next
                if not cur:
                    return node.next
            else:
                pre,cur,nex = cur,nex,nex.next
        return node.next
# Runtime: 48 ms, faster than 42.22% of Python3 online submissions for Remove Duplicates from Sorted List II.
# Memory Usage: 14 MB, less than 18.49% of Python3 online submissions for Remove Duplicates from Sorted List II.
```

ランナーをいくつか用意してそれをひたすらずらして仮に一致した場合に異なる要素が出るまでずらし続ける、という方法を取りました。

連結リストは結構パターンが決まっていて解くに連れてすんなりいくことが多くて好きです。
ただ、面接などにおいては単方向か双方向かなどを聞いたり前提条件を整理しておかないとめちゃくちゃになりそうですね。

では今回はここまで。
お疲れ様でした。
【Ubuntu】ライブラリをpkg-configで管理する

Ubuntu18.04にinstallしたライブラリをg++でコンパイルする際にパスを通すのが面倒だったのでpkg-configで管理する

Ubuntuの端末で```pkg-config```を実行した際、```/usr/lib/pkgconfig```と```/usr/share/pkgconfig```内部にある```.pc```ファイルを順番に実行していく。```.pc```ファイルにはライブラリのパス情報などが記述されている。これ以外のディレクトリを走査して欲しい場合は、```$PKG_CONFIG_PATH```にパスを通す。なのでこれのいずれかのディレクトリに```.pc```ファイルを作成する

■```.pc```の書き方

```mylib.pc
prefix=/home/path-to-your-library
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: mylib
Description: my library
Version: 1.0.0
Cflags: -I${includedir}/mylib
Libs: -L${libdir} -lmylib
```

**Name**: pkg-configを実行する際に渡すライブラリ名
**Description**: ライブラリの説明
**URL**: ライブラリを公開している場合、利用者向けのURL
**Version**: ライブラリのバージョン
**Requires**: ライブラリを利用するために必要なパッケージ一覧
**Requires.private**: ライブラリを利用するために必要なプライベートパッケージ一覧
**Conflicts**: 競合情報
**Cflags**: ライブラリのincludeパス
**Libs**: ライブラリのlibパス
**Libs.private**: ライブラリのプライベートlibパス

■実行

```terminal
pkg-config --cflags --libs mylib
```

　
**参考：**
Guide to pkg-config
https://people.freedesktop.org/~dbn/pkg-config-guide.html
PKG_CONFIG_PATH environment variable
https://askubuntu.com/questions/210210/pkg-config-path-environment-variable
ViewPager2で端までスクロールしたときのエフェクト(overScrollMode)を消す

横スワイプで画面を切り替えて新機能を呼び出せるように[ViewPager2](https://developer.android.com/reference/androidx/viewpager2/widget/ViewPager2)を導入しようと思いますが、まずは過渡期実装として1ページだけ含むViewPager2を設置しました。そうなると端までスクロールしてもう先がないことを表す光が漏れ出すようなエフェクトをいったん無効化したいです。

![device-2020-07-23-034158.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334798/9ad44d8a-04b4-c1b5-e434-375b28c990fe.gif)


ViewPagerでは `android:overScrollMode="never"` を設定するだけでエフェクトを消せます。

```xml:activity_pager.xml
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:overScrollMode="never"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
```

ViewPager2では同じやり方ではエフェクトを消せませんでした。

```xml:activity_pager.xml
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
```

検索してみたところ、Stackoverflowに答えがありました。
https://stackoverflow.com/questions/56878906/remove-viewpager2-overscroll-animatoin

```kotlin:PagerActivity.kt
val childView = viewPager.getChildAt(0)
if (childView is RecyclerView) {
    childView.setOverScrollMode(View.OVER_SCROLL_NEVER)
}
```

ViewPager2はRecyclerViewを子供として持っていて、それに対してoverScrollModeを設定します。
AWS BlackBeltのPDFをローカルに取得して学習効率化を図る（ブックマークレット）


# AWS BlackBeltのPDFをローカルに取得して学習効率化を図る（ブックマークレット）

## やること

AWS BlackBeltのPDFをローカルに取得するためのCURLコマンドを生成する
ローカルに取得して学習効率化を図ろう！

## できること

BackBeltのPDFを取得するためのCURLコマンドがクリップボードにコピーされます。

## 前提条件

- curlコマンドが実行できる環境
- 取得対象のページはこちら
    - <https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/>
- 取得するPDFはページ内にPDFとしてリンクが存在するもののみ
- ※リンク切れなど、場合によってはすべての資料を取得できない可能性があります

## やりかた

ブックマークレットでサクッと

以下をブックマークレットとしてブラウザに登録してください。

```javascript
javascript:function zeroPadding(num,length){    return ('0000000000' + num).slice(-length);}function execCopy(string) {  var tmp = document.createElement("div");  var pre = document.createElement("pre");  pre.style.webkitUserSelect = "auto";  pre.style.userSelect = "auto";  tmp.appendChild(pre).textContent = string;  var s = tmp.style;  s.position = "fixed";  s.right = "200%";  document.body.appendChild(tmp);  document.getSelection().selectAllChildren(tmp);  var result = document.execCommand("copy");  document.body.removeChild(tmp);  return result;}var seq = 0;var ret = [];document.querySelectorAll(".aws-table").forEach(el=>{  var category = el.parentElement.previousElementSibling.innerText;  seq = seq + 1;  var seqStr = zeroPadding(seq, 2);  if(category) { category = category.split(" ").join(""); }    el.querySelectorAll("tr").forEach(tr=>{    var tds = tr.querySelectorAll("td");    if(tds[4] && tds[4].innerText == "PDF") {      var serviceName = tds[0].innerText;      var publishDate = tds[1].innerText;      var title = tds[2].innerText;      var fileName = [seqStr,category,serviceName,publishDate,title].join("_") + ".pdf";      fileName = fileName.split("/").join("-");      fileName = fileName.split(" ").join("");      fileName = fileName.split("\n").join("");      fileName = fileName.split(":").join("：");      var pdfPath = "https:" + tds[4].querySelector("a").getAttribute("href");      var command = `curl ${pdfPath} -o "${fileName}"`;      ret.push(command);    }  });});execCopy(ret.join("\r\n"));alert("コマンドのコピーが完了しました！");
```

## 使い方

- BlackBeltのページを開く
    - ※2020-07-23時点で以下のページが対象
    - <https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/>

- ブックマークレットを実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108839/f79ad06a-2eb7-ae07-66f7-417d648371f8.png)

- コマンドプロンプト（curlが実行できるコンソールを開く）
- 取得したい任意のディレクトリに移動

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108839/2f07f38b-6d2d-9315-e72e-8b7eaf01ef9b.png)

- コピーされたコマンドを貼り付ける！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108839/8e5b400e-eba8-5fec-cefd-98d1396a04f4.png)

取得が終わるのを待ちます...


以上！

## 解説

- 追って記載します...

```javascript:整形


```

## あとがき

取得対象の要素名（クラス名など）が変わると動かなくなります。
2020-07-23現在動いているので目次を取りたい際は試してみて下さい。
python信者がVSCodeを使わずにMacでC#を扱いたい

# まえがき
pythonってTerminal上で**対話型**でコードを書き込んだり，**ファイルにコードを書いて実行**したり，**jupyter notebook**でコードを書いて実行したりと非常に便利にやれる感覚でした．pythonがメインなのにC#を勉強しようと思ったのはこんなコロナ禍で夏休みに入りUnityでスクリプトを書けるようになりたいからです．

## なぜVSCodeを使わないのか
pythonを書くときには`Sublime Text3 + Terminal`(環境設定については省く)でやっています．一時期VSCode使用していてパケージの多さから「むっちゃ便利やん！」とも思っていたんですけど，どうも**挙動**というか**仕様**というか...自分に**フィット**しなかったんですよ．Sublimeが好き・使っている理由として，これもまた**パケージが結構揃っている**のと**カスタマイズができる**のと**軽量**なのと**色が美しい**ってのが大きな理由です．こう文章に書き出すと**使う理由って実に単純**なものですねぇ．

## やばいpythonしかやったことない
とりあえずググって見様見真似でコードを書いて保存しようとしたとき，「あれ，拡張子なんだ！？」ってなったわけですよ（笑）これまたググったところ拡張子は`.cs`．そしてさらにpythonのようにすぐには実行できないらしい．

# 本題
## とりあえず実行できるようにする
どうやら`Homebrew`にいいものがあるらしい．Homebrewが入ってない方は[MacOS（またはLinux）用パッケージマネージャー](https://brew.sh/index_ja)にて導入を．

Homebrewが使える環境であれば...

```Terminal
brew install mono
```

実行すると

```Terminal
==> Downloading https://homebrew.bintray.com/bottles/mono-6.8.0.123.catalina.bot
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/5d9418923f6bc1705af86
######################################################################## 100.0%
==> Pouring mono-6.8.0.123.catalina.bottle.tar.gz
==> Caveats
To use the assemblies from other formulae you need to set:
  export MONO_GAC_PREFIX="/usr/local"
==> Summary
🍺  /usr/local/Cellar/mono/6.8.0.123: 4,023 files, 427.6MB
```

とりあえずうまく導入できたっぽい．一応これで下準備的なのは完了！

## C#で書いてみる
今回は`Hello world`と表示されるプログラムを書いてみよう．
適当にフォルダを作成して...

```Terminal
mkdir test
```

```Terminal
cd test
```

それぞれ使っているテキストエディタを開いて...
階層的には `./test/hello.cs`

```C#:hello.cs
using System;
public class Hello{
	public static void Main(){
		Console.WriteLine("Hello world"); // 文字を表示
	}
}
```

こんな感じ．今はVSCodeを使わずにC#を実行することが目的なので3行目くらいまではおまじないだと思ってください！！

pythonでのコメントアウトは`#`でしたが，C#では`//`なんですね！複数行？まとめてコメントアウトしたい場合は`/* */`で挟むと一気にできるみたい．

## 先ほど導入したmonoを使うぞ！

これが**コンパイル**というものをすることらしい...

### コンパイルとは
`プログラミング言語で書いた文字列をコンピュータが実行可能な形式に変換することらしい．`

pyhton使用時は**コンパイル**ってものをやったことなかったから初めまして．

```Terminal
mcs test.cs
```

実行しても何も表示されないけど...

```Terminal
ls
```

すると...

```Terminal
hello.cs  hello.exe
```

なんか増えてる！！この拡張子みたことあると思ったらWindowsでよくみるやつですね．ってことで...

```Terminal
mono hello.exe
```

実行すると...

```Terminal
Hello world
```

表示されました！！意外と簡単にVSCodeを使わずに実行できました．

# まとめ
C#でいったいどんなことができるかまだまだ把握しきれていませんが，初歩的な実行環境は作れたんじゃないでしょうか．ここからC#を扱い慣れるよう頑張りたいと思います！最後までご覧いただきありがとうございました！
第一種完全楕円積分の微分を導け

それはさておき

```math
\begin{align*}

\eqalign{
  & p = \sqrt {1 - k^2 \sin ^2 \phi }   \cr 
  & k^2 \sin ^2 \phi  = 1 - p^2 ,\;\;\;\;\sin ^2 \phi  = k^{ - 2}  - k^{ - 2} p^2   \cr 
  & \frac{d}
{{d\phi }}p^m  =  - mk^2 p^{m - 2} \sin \phi \cos \phi  \cr} 

\end{align*} 
```
```math
\begin{align*}

\eqalign{
  & \frac{d}
{{d\phi }}p^m \sin \phi \cos \phi  = \left( { - mk^2 p^{m - 2} \sin \phi \cos \phi } \right)\sin \phi \cos \phi  + p^m \left( {1 - 2\sin ^2 \phi } \right)  \cr 
  &  = \left( {1 - 2\sin ^2 \phi } \right)p^m  - mp^{m - 2} k^2 \sin ^2 \phi \cos ^2 \phi   \cr 
  &  = \left( {1 - 2k^{ - 2}  + 2k^{ - 2} p^2 } \right)p^m  - m\left( {1 - p^2 } \right)\left( {1 - k^{ - 2}  + k^{ - 2} p^2 } \right)p^{m - 2}   \cr 
  &  = \left( {1 - 2k^{ - 2} } \right)p^m  + 2k^{ - 2} p^{m + 2}  - m\left( {1 - k^{ - 2}  + k^{ - 2} p^2 } \right)p^{m - 2}  + m\left( {1 - k^{ - 2}  + k^{ - 2} p^2 } \right)p^m   \cr 
  &  = \left( {1 - 2k^{ - 2} } \right)p^m  + 2k^{ - 2} p^{m + 2}  - m\left( {1 - k^{ - 2} } \right)p^{m - 2}  - mk^{ - 2} p^m  + m\left( {1 - k^{ - 2} } \right)p^m  + mk^{ - 2} p^{m + 2}   \cr 
  &  =  - m\left( {1 - k^{ - 2} } \right)p^{m - 2}  + \left\{ {1 - 2k^{ - 2}  + m\left( {1 - 2k^{ - 2} } \right)} \right\}p^m  + \left( {m + 2} \right)k^{ - 2} p^{m + 2}   \cr 
  &  = m\left( {k^{ - 2}  - 1} \right)p^{m - 2}  + \left( {m + 1} \right)\left( {1 - 2k^{ - 2} } \right)p^m  + \left( {m + 2} \right)k^{ - 2} p^{m + 2}  \cr} 

\end{align*} 
```

$$
m\left( {1 - k^2 } \right)\int {p^{m - 2} d\phi }  - \left( {m + 1} \right)\left( {2 - k^2 } \right)\int {p^m d\phi }  + \left( {m + 2} \right)\int {p^{m + 2} d\phi }  = p^m \sin \phi \cos \phi 
$$


$$
m\left( {1 - k^2 } \right)\int_0^{\frac{\pi }
{2}} {p^{m - 2} d\phi }  - \left( {m + 1} \right)\left( {2 - k^2 } \right)\int_0^{\frac{\pi }
{2}} {p^m d\phi }  + \left( {m + 2} \right)\int_0^{\frac{\pi }
{2}} {p^{m + 2} d\phi }  = 0
$$

これを次数の上げ下げに使う

```math
\begin{align*}

\eqalign{
  &  - \left( {1 - k^2 } \right)\int_0^{\frac{\pi }
{2}} {p^{ - 3} d\phi }  + \int_0^{\frac{\pi }
{2}} {pd\phi }  = 0  \cr 
  & \int_0^{\frac{\pi }
{2}} {p^{ - 3} d\phi }  = \frac{{E\left( k \right)}}
{{1 - k^2 }}  \cr 
  & \frac{d}
{{dk}}p^{ - 1}  = k^{ - 1} \left( {p^{ - 3}  - p^{ - 1} } \right)  \cr 
  & \frac{d}
{{dk}}K\left( k \right) = \frac{1}
{k}\left\{ {\frac{{E\left( k \right)}}
{{1 - k^2 }} - K\left( k \right)} \right\} =  - \frac{{K\left( k \right)}}
{k} + \frac{{E\left( k \right)}}
{{k\left( {1 - k^2 } \right)}} \cr} 

\end{align*} 
```
いかにして問題をとくか

# はじめに

`いかにして問題をとくか`（と, `ライト、ついてますか`（今、手元にない））の宣伝.

# 問題を理解すること

## 問題とはなにか

* プロダクトのパッケージングに失敗すること.

## 分かっていることは何か

* アプリケーションのビルドまで成功している.
* パッケージングに失敗している.
    * パッケージングに必要な設定ファイルとスクリプトの場所は分かっている.

（＊ここでのビルドは, ただアプリケーションがコンパイルの意味でビルドできること）
（＊ここでのパッケージングは, プロダクトを顧客がインストールして実行できる状態にすること）

# 計画を立てること

* 過去に似た事例はないか.
    * 内容が完全に同一のブランチのパッケージングに成功している.
    * 違いは何か.
        * 成功例では、パッチパッケージングではない、更新パッケージングである.
            * 完全に置き換え（更新）か、一部置き換え（パッチ）の違い.
        * ビルド・パッケージング環境を更新した.
* 未知のものはなにか.
    * 更新パッケージングであるかどうか.
    * パッケージング環境の更新.
* 未知のものが何に影響するか.
    * 更新パッケージングかパッチパッケージングか
    * パッケージングの設定ファイル
        * システム更新によって, ビルド・パッケージングマシンのアドレスも更新しなければならない.

## 計画を検証すること

`計画を立てること`と前後したり, 同時に実行していることです.
私は **自分を信じないし, 他人も信じない** ので本当に考察したとおりなのか調査しています. ここに時間がかかり, 数十分消費します.

* 過去の似た事例は本当にそうであったか.
* 未知と思っているものは本当にそうか.
* 影響範囲は本当に考察したとおりか.

# 計画を実行すること

各段階を検討せよ, 影響範囲を考慮して, 閉じているか検討せよ（設定ファイルに原因があるという前提で）.

* 設定ファイルを変更したことによって, 意図したとおりにパッケージングが行われるか.
* 他のシステムに影響を及ぼさず, 閉じているか.

# ふり返ってみること

* より良い方法があったか.
    * より良い方法はシステム化できるか.
* 過程と結果を次の問題に応用できるか.
* 過程と結果を知識にできるか.

# まとめ

パッケージングに必要な `場所` の指定が複数に分散しているのは, システムを構築したものとして反省すべき点です. `振り返り` に関して, 私の記憶力と応用力に依るものが大きいため, どうしたものかと悩みます.

ただのPDCAじゃねーか！, そのとおり.
Blue Prism で「営業日」を扱う

はじめに
--------------

Blue Prism を使って「カレンダー」や「営業日」を扱う小ネタです。

カレンダー
--------------
Blue Prism にはカレンダーを管理する機能があり、「創立記念日」など組織固有の休日情報を設定することができます。

システムタブ > システム > カレンダー から設定できます。
![00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/e8f3097b-a26f-658d-45ae-f14eb8f74543.jpeg)

右側にある、「その他の祝日」エリアで、日付を指定し「追加」を押すことで、固有の休日情報を追加できます。
尚、一度設定したカレンダー名を変更するUIは用意されていないようです（v6.8.0）。（方法をご存知の方がいらっしゃったら教えてください。。）

スケジューラー上でのカレンダー指定
-----------------------------
スケジューラーから、カレンダーで設定した営業日のみ実行することができます。
通常はこの使い方をしそうですね。

![01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/a26fc52e-83de-1e92-209e-2bc746f18cb3.jpeg)

「前営業日」を取得する
------------------------------
さて、業務を自動化する際に、前営業日や翌営業日を取得したいケースがあるかと思いますが、 Blue Prism では組み込みVBO「カレンダー」の、「稼働日です」アクションを使うことで、簡単に実装できます。（アクション名の日本語が若干不自然ですね。。）


「稼働日です」アクションは、「カレンダー名」と「日付」をパラメーターとして取り、その日がカレンダー上で営業日かどうかをフラグで返します。

![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/aa07d427-0d3c-e876-c870-5045f1092d3a.jpeg)


```AddDays([判定日], -1)``` のような計算ステージを使って、判定する日付をずらして再度判定していき、営業日と判定された時点で終了するようなフローを作ると、「前営業日」や「翌営業日」を取得することができます。

![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/27e9bf1a-a43d-c688-bb7f-e8e956d722e0.jpeg)
iOS対応のWebサイトでは、「ページ下部の隅に追従するボタン」を置いてはいけない

PCのレスポンシブレイアウトで動作確認を行っていて、実機での動作確認を怠っているとハマる罠
「ページ下端固定のボタン」の罠についてご紹介します。

iPhoneのMobile Safariにはデッドゾーンとか言われるものが存在します。
画面を下スクロールしてアクションバーを消えている状態で、下端をタップすると
「Safariのアクションバーを表示する操作」として認識されていまうのです。
そして、意図していたタッチイベントは発火しません。

ちょっと参考画像が縦に長いですがデッドゾーンがこんな風にあるイメージです。

![IMG_0505-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122390/9be34da3-8670-6c08-def5-af16f6b88ced.png)

このアクションバーが現れるデッドゾーン、具体的には44pxらしいです。
さらに、iPhone X系などのホームボタンのない機種ではセーフゾーンなんかも現れて
当たり判定が奪われてしまうこともあるようです。

詳しいことはこの記事が詳しいです。
[iOS Safariのアクションバー表示エリアはタップイベントをブロックする \| Orime](https://blog.umeru.ma/post/ios-safaris-action-bar-area-block-tap-event/)

このことを考えると、SP Web向けに行うUIデザインでは、
下端に追従するようなボタンを作るときは、少し下端を開けても成立するように
「丸の中にアイコン」とかにしてあげるとよいでしょう。

メジャーなサイトでよく見るあのボタン（Floating Actionボタンというそうです）には
こういったデバイス上の制限という合理的な理由もあるのですね。
OCIのNetwork Security Group をCLIで作成する

OCIにはインスタンスなどの単位でアクセスを制御することができるNetwork Security Groups(NSG) という機能があります。

[ネットワーク・セキュリティ・グループ](https://docs.cloud.oracle.com/ja-jp/iaas/Content/Network/Concepts/networksecuritygroups.htm)

こちらのリソースの作成はOCIのコンソール画面からは簡単にできますが
OCI CLIから作成するときはjsonの書き方や指定の方法でハマることもあったので
今回はその方法を紹介します。

この記事ではNSGの作成部分を紹介します。
次の記事で作成したNSGへのルールの適用までを紹介します。

# 前提条件
* OCI CLI が利用できること

# NSG作成

まずはNSGを作成する際に必要になるjsonフォーマットを取得します。
CLIでcreateする場合のリファレンスは以下です。

https://docs.cloud.oracle.com/en-us/iaas/tools/oci-cli/2.12.3/oci_cli_docs/cmdref/network/nsg/create.html

今回はjsonフォーマットを取得するために以下のコマンドでjsonのフォーマットを取得します

````
oci network nsg create --generate-full-command-json-input > create.json
```

jsonのフォーマットがcreate.jsonに出力されたので中身を確認します。

```create.json
{
  "compartmentId": "string",
  "definedTags": {
    "tagNamespace1": {
      "tagKey1": "tagValue1",
      "tagKey2": "tagValue2"
    },
    "tagNamespace2": {
      "tagKey1": "tagValue1",
      "tagKey2": "tagValue2"
    }
  },
  "displayName": "string",
  "freeformTags": {
    "tagKey1": "tagValue1",
    "tagKey2": "tagValue2"
  },
  "maxWaitSeconds": 0,
  "vcnId": "string",
  "waitForState": [
    "PROVISIONING|AVAILABLE|TERMINATING|TERMINATED"
  ],
  "waitIntervalSeconds": 0
}
```

今回は最低限の項目でいいため、以下まで項目を削り必要な項目を入力します。
compartmentIdにはNSG作成対象のコンパートメントのOCID
vcnIdにはNSG作成対象のVCNのOCIDを記載します。
今回はOCID部分はマスクしています。

```create.json
{
  "compartmentId": "ocid1.compartment.oc1..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "displayName": "cli_create",
  "vcnId": "ocid1.vcn.oc1.ap-tokyo-1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

jsonファイルをinputにしてNSGを作成します。
使用するコマンドは以下です。
今回はOCI上のLinuxのデフォルトユーザのホームディレクトリで作業しているため
ファイルの場所は適宜読み読み替えてください。

```
oci network nsg create --from-json file:///home/opc/create.json
```

以下のような出力が表示されば正常にNSGの作成が開始されているはずです。

```
{
  "data": {
    "compartment-id": "ocid1.compartment.oc1..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "display-name": "cli_create",
    "freeform-tags": {},
    "id": "ocid1.networksecuritygroup.oc1.ap-tokyo-1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "lifecycle-state": "AVAILABLE",
    "time-created": "2020-07-22T17:02:10.069000+00:00",
    "vcn-id": "ocid1.vcn.oc1.ap-tokyo-1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  },
  "etag": "aa248bce"
}
```

実際にコンソール画面にアクセスして確認してみましょう。

OCIのコンソール画面で
ハンバーガーメニュー > ネットワーキング > 仮想クラウド・ネットワーク > 仮想クラウド・ネットワークの詳細 > ネットワーク・セキュリティ・グループ
と進むと今回作成したNSGが確認できるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62936/daea1eec-aa5a-143c-e7e7-339bd5d6c321.png)

# まとめ

まずは今回はCLIを使用してNSGを作ってみました。
次の記事ではこのNSGへのルール適用をCLIから行っていきます。
(本当は1つの記事にしようと思いましたが眠気に負けて半分に・・・)
CloudFrontにマルチオリジン設定するときに勘違いで詰まった話

# 3行で分かる概要
1. CloudFrontにS3とAPI Gatewayをマルチオリジンで設定して同じカスタムドメインにしようとした
2. 無限に`missing authentication token`で怒られた
3. API Gatewayのリソース階層とCloudFrontのBehaviorのPath Patternが一致していないのが問題だった

# 本題
S3にフロントエンドのファイル群を置いて、CloudFrontを間に挟むよくある(?)形式
この際にページの一部コンテンツについては定期的に内容を更新したかったのでAPI経由で取るようにした
APIエンドポイントもWebページのカスタムドメインと同じドメインを使いたかったのでCloudFrontにマルチオリジン設定をして振り分けることにした
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/7b59af50-01a7-704a-b137-ad41de9ca649.png)

この設定をしようとして`missing authentication token`が返されるという典型的なミスにハマり、原因が分からず1週間以上詰まったという話

# 原因
当初、API Gatewaのリソースは下記のようにルートの直下にAPIエンドポイントを生やし、それを`prod`ステージにデプロイしていた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/199609a8-7089-1c43-2e23-017147253dd3.png)

その状態でOriginとBehaviorの設定は下記にしていた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/3bfad692-4665-8967-4e79-cac9b3cb3bf0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/41d74b06-bfea-c242-fc0f-eb32b89dd026.png)

で、`https://hogedomain/api/endpoint`にアクセスして`missing authentication token`で怒られた
OriginDoaminName/OriginPathがBehaviorのPath Patternまで含めたURLにマッピングされると勘違いして、API GatewayのURL`https://XXXXX.amazonaws.com/prod/endpoint`が、`https://hogedomain/api/endpoint`で呼び出されると思っていたのが原因

実際には`https://XXXXX.amazonaws.com/prod/`が`https://hogedomain/`にマッピングされるので上記ではアクセスできない


# 解決
API Gateway側のリソースにCloudFrontのPath Patternで設定したいパスを1階層掘ることで当初の意図通り`https://hogedomain/api/endpoint`でAPI GatewayのURLが呼び出される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/a32defcb-9e45-9412-c306-d733390ad125.png)
競プロで使うための GO 入門 ～型変換～

# Index

- [はじめに](https://qiita.com/CamouflageSix/items/ab004a1078f491bd15ef)
- [Hello World](https://qiita.com/CamouflageSix/items/05e5a0f9616e28d6fca4)
- [標準入出力]
- [変数・定数]
- [型変換]
- [制御構文]
- [配列～](https://qiita.com/CamouflageSix/items/41d901b9b170d5565895)
- [ソート](https://qiita.com/CamouflageSix/items/dbc2017504571e5a65aa)
- [関数](https://qiita.com/CamouflageSix/items/afb42d399a27f5ca3cf8)
- [ASCII変換](https://qiita.com/CamouflageSix/items/283655027e6581a79b4b)

# 型変換
Go は、別の型同士の演算・代入・比較が行えないため、型変換を頻繁に利用する。

## int <-> float64
```GO:
package main

import (
    "fmt"
)

func main() {

    var i int = 5
    var f float64 = 5.9
    
    // float64をintへキャスト(小数点切り捨て)
    fmt.Println(i + int(f)) // ->10

    //intをfloat64へキャスト
    fmt.Println(float64(i) + f) // ->10.9
}
```

## 数値 <-> 文字

"strconv"パッケージを使用する

```GO
package main

import (
    "fmt"
    "strconv" // strconv
)

func main() {

    var s_1 string = "12"
    var s_2 string = "34"
    var i_1 int
    var i_2 int

    i_1, _ = strconv.Atoi(s_1)
    i_2, _ = strconv.Atoi(s_2)
    
    fmt.Println(i_1 + i_2) // ->46
    
    s_1 = strconv.Itoa(i_2)
    s_2 = strconv.Itoa(i_1)
    
    fmt.Println(s_1 + s_2) // ->3412
}
```

## 文字列 <-> 論理型

```GO
package main

import (
    "fmt"
    "strconv" // strconv
)

func main() {

    var s string = "true"
    var b bool
    b, _ = strconv.ParseBool(s)
    fmt.Println(b) // ->true

    s= strconv.FormatBool(b)
    fmt.Println(s) // ->"false"
}
```
エクセルの独自ショートカットキー登録方法と自分が登録している機能

こんにちは。永野と申します。普段はWebの制作で何とか食べる人です。

業務でexcelをよく使うので、マクロに登録しているショートカットキーなどを紹介します。

#VBAでのショートカットキー登録方法
マクロ使っている方はご存じと思いますが、マクロのメニューには標準でショートカットキーの登録項目があります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434191/e62e8baa-e0de-1b8d-ff91-68615289aee0.png)
マクロを使うだけならこちらで十分とも思いますが、

 - 一覧性がないので、たくさん登録していると分からなくなる&確認が面倒
 - F1～F12や方向キーなどは登録できない
 - Ctrlを外したショートカットキーの登録はできない

など、不便なところもちらほらあります。
VBAを使えるなら、Application.OnKey を使って登録していったほうが
上記の欠点は解消されて便利です。

##Application.OnKey

例えば値貼り付けのShift + ctrl + vで登録したければこんな風になります。

```
Sub 値貼り付け()
'
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=True, Transpose:=False
End Sub
```
```
(別のsubプロ―ジャに記録)
Application.OnKey "+^v", "値貼り付け"
```
+はshift,^はctrl、そしてプロ―ジャ名(ここでは「値貼り付け」)を書けば、登録したショートカットキーで割り当てれたマクロが実行されます。

またF1でヘルプが起動しますが、もし不要なら

```
Application.OnKey "{F1}", ""
```
と書けば、F1を押してもヘルプが出てこなくなります。

OnKey メソッドの詳細はこちらに書かれています。
●OnKey メソッド (Excel)　-  Office VBA リファレンス
https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.onkey

ただし、これらApplication.OnKeyで登録したショートカットキーを有効にするにはプロ―ジャを一度実行しなければなりません。
そのため、Workbook_OpenやAuto_Openでファイルが開いたとき、もしくはエクセルが開いたときにまとめて実行させるのがいいと思います。

```
Private Sub Auto_Open()

Application.OnKey "+^f", "式貼り付け"
Application.OnKey "+^v", "値貼り付け"
Application.OnKey "+^d", "シート削除"
Application.OnKey "+^t", "データ貼り付け"
Application.OnKey "+^g", "値入れ替え貼り付け"

End Sub
```
#マクロ紹介

ついでなので、私がショートカット登録したり、作成したマクロも軽く紹介
(随時追加…の予定ですが、おまけなのであしからず)

###式貼り付け

```
Sub 式を貼り付け()
    Selection.PasteSpecial Paste:=xlPasteFormulas, Operation:=xlNone, _
        SkipBlanks:=True, Transpose:=False
End Sub
```
###現在のシート削除

```
Sub シート削除()
    ActiveWindow.SelectedSheets.Delete
End Sub
```
###データ貼り付け
データをサイトからコピーした時、HTMLのフォーマットなどは反映せずに貼り付けます

```
Sub データ貼り付け()
    ActiveSheet.PasteSpecial Format:="HTML", link:=False, DisplayAsIcon:= _
        False, NoHTMLFormatting:=True
End Sub
```

#参考・関連リンク

https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.onkey
https://qiita.com/okunokento/items/788c44bd2cc3186f1845
https://excel-ubara.com/excelvba1/EXCELVBA428.html
複数サーバに対して並列処理を実行するときの書き方

未検証。手動実行想定。

```powershell:単純に実行するときの書き方
# コマンドを実行したときにホスト名が縦に並ぶので実行している処理が判りやすい。

$Job = {
    # 各サーバで実行したい処理
}

Invoke-Command -AsJob -ScriptBlock $Job -ComputerName hoge
Invoke-Command -AsJob -ScriptBlock $Job -ComputerName fuga
Invoke-Command -AsJob -ScriptBlock $Job -ComputerName piyo
# ...

Get-Job | Wait-Job | Receive-Job
```

```powershell:まとめて実行したいけどスロットリングしたいときの書き方
# 一気に流すと負荷が怖い
$Job = {
    # 各サーバで実行したい処理
}

# ジョブの数が減るまで待機するだけの関数
function throttle {
    param($n = 5)
    $jobs = get-job -state running
    while($jobs.Count -ge $n){
        sleep 1
        $jobs = get-job -state running
    }
}

throttle; Invoke-Command -AsJob -ScriptBlock $Job -ComputerName hoge
throttle; Invoke-Command -AsJob -ScriptBlock $Job -ComputerName fuga
throttle; Invoke-Command -AsJob -ScriptBlock $Job -ComputerName piyo
```
Visual StudioのC++とかC#コンパイラをWindows Terminalで呼び出そうね

# Visual StudioのC++とかC#コンパイラをWindows Terminalで呼び出そうね

## なんで
VisualStudio重すぎてつらい

## 今まで
VSにくっついてくるバッチファイルを開いてcmdでやってた

これ、めちゃくちゃ見にくいしVSCodeをここからさらに開いてデバッガ開くのもスマートさ０
## そういえば
WindowsTerminalとかいう超絶便利ソフトがあるからなぁ

## なので
```
  "commandline": "cmd.exe /k \"\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\Common7\\Tools\\VsDevCmd.bat\""
```

## 感想
WindowsTerminalは便利。
レジストリ my tips

# Windows Registry まとめ

## レジストリとは

* レジストリはデータベース
* サービスやアプリケーションなどの設定が格納されている
* KeyとValueで構成されている
(Keyはディレクトリのようなもの)

## ROOT Key (ルートキー)

ルートキーというものがある。
(ディレクトリのルートと同じ理解でいい)

ルートキーはレジストリの分類。
５つのルートキーがある。

* HKEY_CLASSES_ROOT
* HKEY_CURRENT_USER
* HKEY_LOCAL_MACHINE
* HKEY_USERS
* HKEY_CURRENT_CONFIG

## Root Key の種類

|ルートキー|短縮キー|内容|権限|リンク先|
|---|---|---|---|---|
|HKEY_CLASSES_ROOT|HKCR|・ファイルの拡張子情報</br>・関連付け情報|ROOT|`HKLM\Software\Classes`|
|HKEY_CURRENT_USER|HKCU|ログイン中のユーザーの設定|USER|`HKU\ログイン中のSIM`|
|HKEY_LOCAL_MACHINE|HKLM|システムについての全ての設定|ROOT|-|
|HKEY_USERS|HKU|ユーザー毎の情報|ROOT(USER)|-|
|HKEY_CURRENT_CONFIG|HKCC|プリンタ/ディスプレイ|ROOT|-



### HKEY_CLASSES_ROOT

短縮`HKCR`

内容:
 * ファイルの拡張子情報
 * 関連付け情報

編集権限
 * 管理者権限のみ


リンク: `HKLM\Software\Classes`

### HKEY_CURRENT_USER

短縮: `HKCU`

内容: 
 * ログイン中のユーザーの設定
 * ユーザーが変更できるアプリケーションの設定
 * HKUの内容がコピーされる
 <!-- TODO レジストリはいつコピーされるの？ -->

編集権限
 * ユーザー権限で変更・追加が可能

リンク: `HKU\ログイン中のSIM`

### HKEY_LOCAL_MACHINE

短縮: `HKLM`

内容:
 * システムについての全ての設定が格納されている
 * HKLM\Softwareのサブキー情報は特定のユーザではなくPC全体に設定される内容
 * ハードウェアのドライバ情報も含む

編集権限:
 * 管理者権限

リンク:
* リンク先はない

### HKEY_USERS

短縮: `HKU`

内容:
 * ユーザーのデフォルト設定
 * 全てのユーザーの`HKCU`
 * サブキーはSIDで表示されている

編集権限:
 * 管理者権限

リンク:
 * ログイン時HKCUにコピー

### HKEY_CURRENT_CONFIG

短縮: `HKCC`

内容:
 * 使用中のプリンタ情報
 * ディスプレイ機器情報

リンク:
 * HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current

## Value(値)の種類


|種類|略称|説明|
|---|---|---|
|文字列|REG_SZ|固定長の文字列|
|バイナリ値|REG_BINARY|未加工のバイナリデータ  16進数|
|DWORD値|REG_DWORD|ドライバやアプリやサービスに使用  2/8/16進数|
|QWORD値|REG_QWORD|DWORD の 64 ビット版  2/8/16進数|
|複数行文字列値|REG_MULTI_SZ|複数行の文字列|
|展開可能な文字列値|REG_EXPAND_SZ|固定長の環境変数で使われる可変長の文字列文字列|
[SQL]getdate()関数がUTF時間になって困ったときの対象法

<h2>背景・目的</h2>
諸々の処理実行後に現在時刻をDBにログとして登録することって結構多いんのではないでしょうか？(社会人2年目IT初心者なのでよくわからないですが、、、笑）
Microsoft AzureのSQLDBのテーブルに現在時刻(日本時間)をInsertするため、
valuesにformat(getdate(),'yyyyMMddHHmmssfff')を指定したが、
UTF時間になってしまいました。(日本時間-9時間)
ストアドなどの解決策も浮かんだのですが、運用観点から関数は増やしたくないので、
どうにか1つのクエリで解決できないか考え、解決策を見つけたので共有します。
(備忘録的な扱いです)

<h2>実行環境</h2>
Azure SQLDB
<h3>実行結果before</h3>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678667/63a72f90-27fa-1ee5-1980-cde5c68b2dd1.png)
実行時刻：2020年07月23日01時05分....

<h3>実行結果after</h3>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678667/9724af8d-4ee0-7b56-693b-e3f35f481d2c.png)
実行時刻：2020年07月23日01時07分....
(日本時間と同じ時間が表示された！)
投稿とユーザの紐づけ(Ruby on Rails)

#プログラミングの勉強日記
2020年7月23日　Progate Lv.215
Ruby on RailsⅨ

#postsテーブルにuser_idのカラムの追加
　各投稿にどのユーザがその投稿を作成したかという情報を持たせるためにpostsテーブルにuser_idというカラムを用意する。`rails generate migration`を用いて`add_user_id_to_posts`というファイル名のマイグレーションファイルを作成し、マイグレーションファイルを変更して`rails db:migrate`を実行する。

```terminal
$ rails generate migration add_user_id_to_posts
　マイグレーション変更後
$ rails db:migrate
```
```ruby:2020..._add_user_id_to_posts.rb
class AddUserIdToPosts < ActiveRecord::Migration[5.0]
  def change
    add_column :posts, :user_id, :integer
  end
end
```

誰が投稿したかという情報は必要不可欠なので、user_idにバリデーションを設定する。

```ruby:models/posts.rb
class Post < ApplicationRecord
  validates :user_id, {presence: true}
end
```

#新規投稿をログインユーザに紐づけ
　新規投稿作成時にuser_idの値を入れて保存する。投稿したユーザは現在ログインしているユーザ(`@current_user`)

```posts_controller.rb
def create
  @post=Post.new(
    content: params[:content}
    user_id: @current_user.id
  )
end
```

#投稿でユーザ情報の表示
　ユーザ名やユーザ画像を表示するためには、user_idカラムの値からそのユーザの情報を取得する。投稿詳細ページなので、postsコントローラのshowアクション内で`@post.user_id`を用いてそのidに該当するユーザ情報をデータベースから取得。

```ruby:posts_controller.rb
def show
  @post=Post.find_by(id: params[:id])
  @user=User.fnd_by(id: @post.user_id)
end
```

```erb:posts/show.html.erb
<div class="post_user_name">
  <img src="<%= "/user_images/#{@user.image_name}" %>">
  <%= link_to(@user.name, "/users/#{@user.id}") %>
</div>
```

#インスタンスメソッドの定義
　投稿に紐づくユーザの情報は良く使うので簡単に使えるようにメソッドにする。Railsではモデル内にインスタンスメソッドを定義できる。Postモデル内にその投稿に紐づいたuserインスタンスを戻り値として返すuserメソッドを作成する。

```ruby:models/post.rb
class Post < ApplicationRecord
  def user
    #インスタンスメソッド内でselfはインスタンス自身を指す。
    return Post.find_by(id: self.id)
  end
end
```

#ユーザ詳細ページに投稿を表示
　ユーザ詳細ページにそのユーザが作成した投稿を一覧で表示する。あるユーザに紐づいている投稿を取得する。<font color=blue>find_byメソッドではその条件に合致するデータを1件だけ取得する。複数のデータを取得するためにはwhereメソッドを用いる。</font>whereメソッドで取得した場合、それぞれのデータは配列で入っている。

```ruby:models/user.rb
class User < ApplicationRecord
  def posts
    return Post.where(user_id: self.id)
  end
end
```

```erb:users/show.html.erb
<% @user.posts.each do |post| %>
  #ここに表示する内容を書く
<% end %>
```

#投稿者のみが編集・削除できるようにする
　ログインしているユーザがその投稿の作成者である場合のみ編集・削除のリンクを表示する。

```erb:posts/show.html.erb
<% if @post.user_id == @current_user.id %>
  <%= link_to("編集", "/posts/#{@post.id}/edit") %>
  <%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "post"}) %>
<% end %>
```

このままだとURLに直接アクセスすると編集・削除できてしまうので、これの対処をする。

```ruby:posts_controller.rb
class PostsController < ApplicationController
  before_action :ensure_correct_user, {only:[:edit,:update,:destroy]

  def ensure_correct_user
    @post=Post.find_by(id: params[:id])
    if @post.user_id != @current_user.id
      flash[:notice]="権限がありません"
      redirect_to("/posts/index")
    end
  end

end
```
PythonでMP3→WAV変換

## まえがき
初投稿になります。普段はC#er[^1]でガチガチのデスクトップアプリの開発をしていますのですが知見を広めるべくpythonに取り組んでみます。フロントエンド？それ喰えるのか？という世界に生きてますのでPythonは結構新鮮。

## お題
MMD[^2]にどっぷりな我が娘がファイル形式の変換をいちいち変換サイトにいってファイルをアップロードして・・とやっているのでそんな面倒なことせずとも自分のPCだけで完結するやんという話をしましてコンバータを作ることになりました。
今回はMMDで使うためのMP3→WAV変換になります。

## 開発環境
- OS:Windows10Home(1903)
- Editor:Visual Studio Code
- Python:3.8.3

## 調べてみた
「python mp3 wav」でググるとどうやらpydubというライブラリを使えば変換できるらしいので早速導入。

```
> pip install pydub
```
えーと、ffmpegが必要？なるほど、ffmpegのラッパー的なライブラリなのか。ffmpegのコマンドを自分でチョイスして書けばいいのだろうけど折角なのでpydubのお世話になることに。

## コード
```Python:mp32wav.py
import pydub
import os
import sys

if __name__ == "__main__":
    mp3 = sys.argv[1]
    print(f"IN:{mp3}")

    dirname = os.path.dirname(mp3)
    baseName = os.path.splitext(os.path.basename(mp3))[0]
    wav = os.path.join(dirname, f"{baseName}.wav")
    print(f"OUT:{wav}")

    audio = pydub.AudioSegment.from_mp3(mp3)
    audio.export(wav, format='wav')
```
拡張子を挿げ替えたいだけなのになんかめんどくさいコードになってしまいました。本質的には・・・

- 元のファイル(mp3)の拡張子を.wavにしたものを出力ファイルとする
- .mp3を読み込んで.wavとして出力する

だけなんですけどね。
C#erとしては`import os`と書いてるのになぜ`os.path...`と書かねばならないのか疑問。

## 運用
さて、期待通り動くことは確認できましたがこのmp32wav.pyをデスクトップに置いてもD&Dできるわけではないのでバッチファイルを用意します。

```mp32wav.bat
@echo off
py mp32wav.py %1
```
このバッチファイルのショートカットをデスクトップに作り、変換したい.mp3をD&Dすれば元ファイルと同じフォルダに.wavが生成されます。めでたし。

## だがしかし・・・
どうやらこれは既知の問題のようですが、全角スペースを含むファイル名を与えるとそこでぶった切られてしまうようです。半角スペースもクォートしてやれば問題ありませんしD&Dの時には勝手にクォートしたものがコマンドライン引数として渡されるようですが全角スペースの場合はうまくやってくれません。
テストコードをC#で書いてみますが

```argsTest.cs
static void Main(string[] args)
{
    Console.WriteLine($"len={args.Length}");
    foreach (var i in Enumerable.Range(0, args.Length))
    {
        Console.WriteLine(args[i]);
    }
    Console.ReadLine();
}
```
さらにこれをバッチファイルから呼び出すようにして"aaa bbb.txt"(半角スペース)と"aaa　bbb.txt"(全角スペース)を喰わせてみると

```:半角スペース
len=1
C:\Tmp\aaa bbb.txt
```
```:全角スペース
len=1
C:\Tmp\aaa
```
となります。

尤も普通はフォルダ名・ファイル名に全角スペースを使いませんがそういう名前をOSが許容してますし中には半角スペースと全角スペースを全く意識しない人もいるでしょうから何かしらの対処は必要かなと考えています。
娘にはフォルダ名・ファイル名には半角スペースのみ使ってよいと伝え、当面運用で回避です(一応回避案はないこともない・・・)
[^1]: C#が7.5のVB6が2.0のVB.NETが0.5でしょうか。
[^2]: [MikuMikuDance](https://ja.wikipedia.org/wiki/MikuMikuDance)