OmniAICreator/Qiita-1.07M huggingface dataset:
Python初心者がバブルソートを整理する

###これは備忘録です　
~~忘れることないと思うけど~~

（追記　2020/0611：13：00）
@shiracamusさんからアドバイスを受けましたので修正します。


#バブルソートって
バブルソートとは、基本交換法とも呼ばれるソートアルゴリズムで、**大体適当に作ろうとするとこれになる**

![bable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650016/dc33e62a-8a47-bcc7-1a27-7e9cbcafa335.png)

#中身の解説

```bubble.py
'''1'''def bubble(T):
'''2'''    i = len(T)-1
'''3'''    while i:
'''4'''        for j in range(i-1):
'''5'''            if T[j] > T[i]:
'''6'''                T[j],T[i] = T[i],T[j]
'''7'''        i -= 1
'''8'''    return T
```

うわー、とっても短いアルゴリズムだー

と、書いた側も少しビックリ。
これだけ短いので行番号入れて解説してみる。

1. 関数宣言、引数は数字配列型で作成したT。
2. **注意点**`len(T)`で返ってくる数字は「長さ」なので、配列番号にそのまま挿入すると配列外を参照するエラーになる。
3. `while`文には`if`と同じく`true`となる文字が入ればいいので`i!=0`と同じ意味になる`i`単体を入れてみた。
  - `for`がどうしても使いたいのであれば1行目を消して`for i in range(len(T)-1,0,-1):`と書けばイける。
4. ここは`for`で。`range(i)`でもいいっちゃいいが、ループが一回無駄になります。
  - T[i]>T[i] 同じもの比べれば`false`やろ
5. 配列の右側が大きくなってほしいので、左が大きければスワップします。
6. スワップ。~~1行で済ませるサボリ魔の鑑~~1行でまとめられるからきれい。
7. バブルソートでは後ろから結果が確定していくので-1する。Pythonで一番気に入らないことはﾏｲﾏｲできないことです。
8. Tを返す。ループが中にあって返す形があると再起関数にしたくなってくる変人なのであとで遊んできます。


#バブルソートは実は重い
[Wiki](https://ja.wikipedia.org/wiki/%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88)を参考にしてもらうとわかるけれども、ソートするにあたって二重ループになっているアルゴリズムなので重いというのが特徴
また、いちいちすべてをスワップするのも重くなる原因なので、改善アルゴリズムではデータを退避させたりする形にしたりします。

```bubble2.py
def bubble2(T):
    for i in range(len(T)-1,0,-1):
        tmp = T[0]
        for j in range(1,i+1):
            if tmp < T[j]:
                tmp , T[j] = T[j], tmp
            T[j-1]=T[j]
        T[i] = tmp
        print(T)
    return T
```
一応その場のノリで作ってみたけどコレもまだ改善点あるかな？あるはず。


#余談

ランダムで数字の重複のない配列を作成するプログラムを組んだので例示しておきます。

（修正部分）
>デフォルト引数にリストを使うのは避けましょう。
参考： https://docs.python.org/ja/3/faq/programming.html#why-are-default-values-shared-between-objects

xMake(i , T=[-1])としていた部分とそれによるプログラムの本文を修正させていただきました。

```makeLis.py
import random as r
def xMake(i,T = None ):

    if T is None:
        T = [r.randint(1,i)]*i
        return xMake( 1 , T )
    if i == len(T):
        return T

    T[i] = r.randint(1,len(T))
    for j in range(i):
        if T[i] == T[j]:
            return xMake( i , T )
    return xMake( i+1 , T )


print(xMake(10))
>>[2, 1, 3, 6, 4, 10, 9, 5, 7, 8]
print(xMake(20))
>>[13, 20, 1, 12, 7, 8, 6, 4, 17, 11, 14, 9, 18, 3, 5, 10, 15, 2, 19, 16]
```
~~意地でも再起関数を使う民~~ もっといい書き方やスッキリした書き方があれば教えてください。

@shiracamusさんから教えていただきました。
>rangeとsampleを使うとスッキリ書けます。

```By_shiracamus.py
import random as r

def xMake(i):
    return r.sample(range(1, i + 1), k=i)

print(xMake(10))
print(xMake(20))
```

`random.sample`を使うとこんなにも楽になるのですね……！
ありがとうございます！参考にさせていただきます！

関数の宣言する際に自分は`x〇〇()`と名前を付けることが多いです(大体が番号)。
目的無くプログラムを書いたりコピーして書き方を変えたりするのと、関数名に法則がないとプログラムするときに書き間違えたりするので。
そして、実際に使うことになったときにテキストエディタの置換機能で書き換えてわかる名前にする、ということをします。
コレがいいことなのかはわかりませんが、元々英語が苦手なのでスペルミスをする等の恥ずかしいことを時々するので。
Windows 10 + Excel2016 VBA + seleniumbasic で chromedriver / msedgedriver を使ってみる

Windows 10 + Excel2016 VBA  seleniumbasic で chromedriver / msedgedriver を使ってみる
#目的
今日の時点で Chrome や Edge(Chromium)をSeleniumBasicより操作してみる
Firefox(geckodriver)については以下にあるように、使用不可だと思ったほうが良いようだ
※geckodriver.exe -> firefoxdriver.exe に修正後起動してもエラーストップでした
[Where can I found FirefoxDriver XPI? #199](https://github.com/florentbr/SeleniumBasic/issues/199)

##SeleniumBasicのインストール
[Seleniumbasic](https://florentbr.github.io/SeleniumBasic/)の Release page より SeleniumBasic-2.0.9.0.exe をDLする
exeを実行すると、C:\Users\user_name\AppData\Local\SeleniumBasic にインストールされる
ソースコードのプロジェクトをVS2019で開くと .NET Framework 3.5 を指定しているので
Windowsの設定 -> アプリ -> オプション機能 -> Windowsのその他の機能 -> .NET Framework 3.5 が有効であることを確認する

##ChromeDriverのインストール
[Chrome について](chrome://settings/help)よりChromeのバージョンを確認する
今日の時点では バージョン: 83.0.4103.61（Official Build）（64 ビット）
[ChromeDriver - WebDriver for Chrome](http://chromedriver.chromium.org/downloads)よりバージョンに合わせてDLする
chromedriver_win32.zip を解凍後 chromedriver.exe を SeleniumBasic フォルダに上書きする

##MSEdgeDriver
[バージョン情報](edge://settings/help)よりEdgeのバージョンを確認する
今日時点では バージョン 83.0.478.45 (公式ビルド) (64 ビット)
[WebDriver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/)よりバージョンに合わせてDLする
edgedriver_win64.zip を解凍後 msedgedriver.exe を SeleniumBasic フォルダに上書後 edgedriver.exe に変更する

##Excel VBA で使用する
VBAのIDEの　tool -> 参照設定より C:\Users\user_name\AppData\Local\SeleniumBasic\Selenium32.tlb を追加する
##サンプルコード

```vb
Sub OpenEdge()
'
    Dim drv As New EdgeDriver
    Set drv = New EdgeDriver
'
    drv.Start
    drv.Window.SetPosition 0, 0
    drv.Window.SetSize 800, 800
    drv.Get "https://www.google.co.jp/search?q=selenuim&oq=selenuim"
'
    MsgBox drv.Window.Title
'
    drv.Quit
'
End Sub

Sub OpenChrome()
'
    Dim drv  As ChromeDriver
    Set drv = New ChromeDriver
'
    drv.Start
    drv.Window.SetPosition 0, 0
    drv.Window.SetSize 1000, 800
    drv.Get "https://www.google.co.jp/search?q=selenuim&oq=selenuim"
'
    MsgBox drv.Window.Title
'
    drv.Quit
'
End Sub
```
#参考にしたサイトはこちら
[Windows 10 Pro x64 + Excel2016 x86 VBA で Seleniumbasic + chromedriver を使ってみる](https://qiita.com/tabizou/items/886369d829cbd99d32d4)
[Windows 10 + Python3 + selenium + chromedriver で headless chrome を試してみる](https://qiita.com/tabizou/items/71911a4d55e9c35b4546)
[Windows 10 + Python3 + selenium + msedgedriver で headless edge(Chromium) を試してみる](https://qiita.com/tabizou/items/249b3c03e5322828e848)
[Where can I found FirefoxDriver XPI? #199](https://github.com/florentbr/SeleniumBasic/issues/199)
CLion + OpenOCD + Nucleo F401REで書き込みとデバッグ [Mac]

CLionからOpenOCD経由でNucleo F401REにファームウェア書き込みとデバッグが出来るようにした。

## 前提

STM32CubeIDEのプロジェクトをCLionで読み込んで使用しています。

## 使ったもの / 必要なもの

* MacBook Pro 15 (late 2016)
* CLion
* OpenOCD
* gcc-arm-embedded
* Nucleo F401RE
    * オフィスのおもちゃ箱から拾ってきた

## インストール

CLion, OpenOCD, gcc-arm-embeddedはHomebrewから入れる

```bash
brew install open-ocd
brew cask install clion
brew cask install gcc-arm-embedded
```

## toolchainの設定

`Default` を `gcc-arm-embedded` という名前にコピーする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/0c01d489-07de-eab9-b104-3ef99cdde913.png)

C Compilerと C++ Compilerをgcc-arm-embeddedのものに変更する。ファイルは `/usr/local/bin` 以下の `arm-none-eabi-gcc` と `arm-none-eabi-g++` とする。デバッガはBundled GDBに設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/a23fa7f7-adf7-d36d-bd87-8f0328b0e6bb.png)

## CMakeの設定
CMakeで使用するtoolchainを `gcc-arm-embedded` に切り替える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/a83140f7-0b2c-5b57-b6c6-f83c2a1d9c04.png)

## Run / Debug Configurationの設定

CMake ApplicationとOpenOCD Download & Runを追加する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/1307c42d-4a47-bae7-d0a3-31af5840b29b.png)

OpenOCDの設定を行う場合、Board config fileは `st_nucleo_f4.cfg` を指定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/0b9b9ac7-662d-e764-5119-451ebaaf9cf3.png)


## トラブルシュート
### デバッガが動かない
デバッガにGDBを指定しているにも関わらず、次のようにLLDBでは接続できないというエラーが出る。

> Error running 'OCD led_blink': GDB Remote Debug using LLDB is not supported in CLion yet

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/0ca0cbf0-2d10-1591-b715-6d998762cf12.png)

次の画面のように、toolchain内でデバッガをGDBにセットしたコンフィグを一番上にする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/f59ced97-25c1-876a-d1de-df053f7fc36e.png)

### ST-Link/V2に接続できない

F401REには `ST-Link/V2-1` が内包されている。 `STM32 Debug+VCP` と `STM32 Debug + Mass storage + VCP` という2つのバージョンがあり、この2つのFWは、USBデバイスとしてのPIDが異なる（前者が `0x374b` で後者が `0x3752`）。前述のBoard config fileの指定では後者のFW用のもの。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/d7ce6eca-c675-5877-2a11-c592c0951fbc.png)



# 参考

* https://ryochack.hatenablog.com/entry/2017/11/03/234216
* https://yuqlid.sakura.ne.jp/dokuwiki/stm32
EC2にディスク監視やメモリ監視を追加しよう（CloudWatchMonitoringScripts）

# 概要
デフォルトのCloudWatchだと取れないメトリックがあります。
たまに調べたりするので、ここに書いておこう。

基本的には下記を参考にすると良いです。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html

# IAMロールを用意しよう

EC2からCloudWatchを使ったりするために、下記のようなポリシーのついたIAMロールを用意しましょう。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricData",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:ListMetrics",
                "ec2:DescribeTags"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

# EC2にIAMロールを設定しましょう

昔は起動中にIAMロールを変更できなかったんですが、今はAWSコンソールから起動中でも変更できます。

# 今回はUbuntu

必要なパッケージをインストールします。

```bash
sudo apt-get update
sudo apt-get install unzip
sudo apt-get install libwww-perl libdatetime-perl
```

# AWS提供の監視スクリプトをダウンロードします

最新バージョンは下記のURLを確認してください。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html

```bash
curl https://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.2.zip -O
unzip CloudWatchMonitoringScripts-1.2.2.zip && \
rm CloudWatchMonitoringScripts-1.2.2.zip && \
cd aws-scripts-mon
```

そうすると下記のようなファイルができます。

> - CloudWatchClient.pm – 共通 Perl モジュール。これを使って、他のスクリプトから簡単に Amazon CloudWatch を呼び出すことができます。
> - mon-put-instance-data.pl – Amazon EC2 インスタンス (メモリ、スワップ、ディスクスペースの使用状況) のシステムメトリクスを収集し、Amazon CloudWatch に送信します。
> - mon-get-instance-stats.pl – Amazon CloudWatch に問い合わせて、このスクリプトが実行される EC2 インスタンスの最新の使用状況統計を表示します。
> - awscreds.template – アクセスキー ID とシークレットアクセスキーを保存する AWS 認証情報のファイルテンプレートです。

# 動作確認

解凍してできたディレクトリの中で、下記のようにすると動くかの確認ができます。

```bash
$ ./mon-put-instance-data.pl --mem-util --verify --verbose
MemoryUtilization: 53.4314735431687 (Percent)
No credential methods are specified. Trying default IAM role.
Using IAM role <HogeHogeRole>
Endpoint: https://monitoring.ap-northeast-1.amazonaws.com
Payload: {"__type":"com.amazonaws.cloudwatch.v2010_08_01#PutMetricDataInput","MetricData":[{"Unit":"Percent","MetricName":"MemoryUtilization","Value":53.4314735431687,"Dimensions":[{"Name":"InstanceId","Value":"i-hogehoge"}],"Timestamp":159184XXXXX}],"Namespace":"System/Linux"}

Verification completed successfully. No actual metrics sent to CloudWatch.
```

# cronに設定しよう

cronに設定していきましょう

```bash
$ crontab -e

# 最後の行に書きを付け足します。（メモリ使用量、ディスク使用量を監視してます。メモリではcache、buffもusedに計上します）
*/5 * * * * ~/aws-scripts-mon/mon-put-instance-data.pl --mem-used-incl-cache-buff --mem-util --disk-space-util --disk-path=/ --from-cron
```

# おわり

多分これで、CloudWatchにディスクの情報とメモリの情報が送られるようになりました。
UiPath DateTimeに関するコツ

#現在時刻

**DateTime.Now**

```vb:1行を書き込みの式：
' 既定フォーマットで出力
DateTime.Now.ToString()
' 指定したフォーマットで出力
DateTime.Now.ToString("hh:mm:ss")
```

#時刻調整
**Add[Unit of Time]**

```vb:1行を書き込みの式：
' 現在時刻を10分引く
DateTime.Now.AddMinutes(-10).ToString()
' 現在時刻を2時間足し
DateTime.Now.AddHours(2).ToString()
```
VirtualBox Extension Packegeのインストール失敗対応

VirtulBoxのExtension Packをインストールを実行したところ、エラーでインストールができない。
解決に手こずったのでメモしておきます。

#### 環境
- Virtualbox：6.1.2
- GUEST OS：Ubuntu MATE 19.04

#### インストール手順

1. 対応したExtension Packageをサイトからダウンロードする。<br />
   - ダウンロードサイト：[Oracle](https://www.virtualbox.org/wiki/Downloads)
   - ダウンロードファイル：Oracle_VM_VirtualBox_Extension_Pack-6.1.2.vbox-extpack

2. Oracle VM VirtualBoxマネージャーを起動

3. Extension Packageを追加する<br />
環境設定から追加する。<br />（Oracle VM VirtualBoxマネージャーを起動時に追加を促すダイアログが表示された場合は、以下の操作は不要で流れに従う。）
※画面内の設定ボタンではなく、メニューバーから選択する。
**Windows**
ファイル - 環境設定
**MAC**
VirtualBox - 設定<br />
表示された設定画面の機能拡張アイコンをクリック。右側にある「＋」ボタンからダウンロードしたExtension Packageファイルを選択し、「OKボタン」を押下する。

4. インストールがはじまる。<br />ライセンス確認が表示される。読んで（スクロールバーを最後まで下げて）「同意します」をクリック

5. インストール完了

---
通常はこの方法でインストールが完了するが、
今回は手順４で以下のエラーが発生して、インストール出来ない。


> The installer failed with exit code 1: VBoxExtPackHelperApp.exe: error: Failed to rename the temporary directory to the final one: VERR_ACCESS_DENIED ...

ACCESS DENIED ...??
インストールプロセスのExtension Package設置で弾かれてる模様。
実行は管理ユーザで行っているので、このインストール方法では為す術がない。
仕方がないので、手動でインストールを行うことにします。

#### 手動インストール手順
1. ダウンロードしたExtension Packageファイルの拡張子を「tar.gz」に変更する。
変更後
Oracle_VM_VirtualBox_Extension_Pack-6.1.2.vbox-extpack.tar.gz
2. Oracle_VM_VirtualBox_Extension_Pack-5.0.16-105871.vbox-extpack

↓

Oracle_VM_VirtualBox_Extension_Pack-5.0.16-105871.tar.gz

２．適当な解凍ソフトで解凍

３．C:\Program Files\Oracle\VirtualBox\ExtensionPacks下に「Oracle_VM_VirtualBox_Extension_Pack」フォルダを作成

４．解凍したエクステンションパッケージのファイルをすべて手順３のOracle_VM_VirtualBox_Extension_Pack内にコピーする（管理者権限を求められたら「はい」）

５．Oracle VM VirtualBox マネージャーを起動

６．ファイル ＞ 環境設定 ＞ 機能拡張 の一覧リストにコピーしたエクステンションパッケージが追加されており、有効にチェックが入っていることを確認する。

７．VirtualBoxから仮想マシンを起動

８．仮想マシンのメニューから デバイス ＞ Guest Additions CDイメージの挿入を選択

９．セットアップ画面が表示されるのでセットアップを行う

（途中ハードウェアのインストール警告が何度か出るが「続行」を選択）

１０．再起動されたら完了

----

 

汎用的な方法だと思いますので、

今後のアップデートなどで対応できないときは同様に手動解凍を行いたいと思います。
360急速浏览器和Google浏览器还是有差别的

现在总算知道问题出在哪里了。360急速浏览器和Google浏览器还是有差别的。就老师演示了一个添加用户我也折腾了一天，以后还是少用360急速浏览器了。就这画面，一般人绝对找不到问题点的。居然能少个输入框什么，这个差距简直哈死我也。以前劝我用谷歌浏览器的那些大佬，我确实错了，我错了！！！！！！！！


![46cec3b0340d7bfbd5f9fb648951f69.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652938/30c033db-fdd0-2b69-87ae-69f07c3922b0.png)
競技プログラミング練習記 No.6【ABC150練習】

初回 -> [はじめに](https://qiita.com/easychoco/items/a9ae28aca97cfe47091f)

[ABC150](https://atcoder.jp/contests/abc150)を解きました。
4完です。
D問題を解いたところで時間がきました。
今回から実行時間もかきます。

|問題|時間|アルゴリズム|実行時間|
|:-:|:-:|:-:|:-:|
| A |  1min |-|1ms|
| B |  3min |-|1ms|
| C | 14min |組み合わせ|2ms|
| D | 75min |最小公倍数|17ms|



## A
```c++
	int k, x;
	cin >> k >> x;
	cout << (k * 500 < x ? "No" : "Yes");
```
やるだけ

## B
``` c++
	int n;
	string s;
	cin >> n >> s;

	int ans = 0;
	for(int i = 0; i < n - 2; ++i)
	{
		if (s.substr(i, 3) == "ABC")
		{
			ans++;
			i += 2;
		}
	}
	cout << ans;
```
やるだけ。
`for`の範囲に注意。
`i += 2` で気持ち少し高速化しています

## C
``` c++
	int n;
	cin >> n;
	int ans_p = 0, ans_q = 0;

	vector<int> p(n);
	vector<int> q(n);
	vector<int> v(n);

	for(int i = 0; i < n; ++i){ v[i] = i + 1; }
	for(int i = 0; i < n; ++i){ cin >> p[i]; }
	for(int i = 0; i < n; ++i){ cin >> q[i]; }

	int loop_cnt = 0;
	do{
		loop_cnt++;
		if (v == p) { ans_p = loop_cnt; }
		if (v == q) { ans_q = loop_cnt; }
	} while(next_permutation(v.begin(), v.end()));

	cout << abs(ans_p - ans_q);
```

`O(N!)`です。やばい。`N = [2, 8]`なので助かりました。
スマートな解法が思いつかなかったのと、`next_permutation`という便利関数の存在を聞いていたので使ってみました。
スマートでないと思っていたのですが、解説を見たら同じことが書いてあったので安心しました。
でも`O(N!)`はやばいと思います。

## D


``` c++
	ll n, m;
	cin >> n >> m;
	vector<int> a(n);

	ll a_lcm = 1;
	for(int i = 0; i < n; ++i)
	{
		cin >> a[i];
		if (a[i] / 2 / gcd(a[i] / 2, a_lcm) > m / a_lcm)
		{
			cout << 0;
			return;
		}
		a_lcm = lcm(a[i] / 2, a_lcm);
	}

	for(int i = 0; i < n; ++i)
	{
		if (a_lcm % a[i] == 0)
		{
			cout << 0;
			return;
		}
	}

	ll ans = ((m - a_lcm) / (a_lcm * 2)) + 1;
	cout << ans;
```
難易度みたら青diffでした。初めて自力で解けた。やったー！
`O(N)` です。
入力値全体のLCM(最小公倍数)を2で割ったものを`a_lcm`として、
`lcm * (2n + 1) : n = 0,1,...`
が求める半公倍数になります。
`a_lcm`が`m`より大きいときや、`a_lcm`が入力値のどれかの整数倍になっているときは答えが`0`になります。

以下の部分で `a_lcm`が`m`より大きいときを判定しています。
`a[i] / 2 / gcd(a[i] / 2, a_lcm) > m / a_lcm`
移項してまとめると、
`(a[i] / 2) * a_lcm / gcd(a[i] / 2, a_lcm) > m`
となります。左辺はLCMの計算式ですね。つまり、
`(これまでに与えられた入力値全体のLCMを2で割ったもの) > m`
の判定をしています。
ただ、このまま計算すると左辺がオーバーフローする可能性があるので、
それを防ぐためにこの形に変形して判定しています。

```c++
        if (a[i] / 2 / gcd(a[i] / 2, a_lcm) > m / a_lcm)
```



以上です。ありがとうございました。
terraformにおいてarrayをfor_eachでloopさせ、リソースを作成する例



例えば以下の様なarrayに対応する複数リソースの作成を考える

```json
{
  "locals": {
    "addresses": [
      {
        "ip": "aaa.aaa.aaa.aaa",
        "network_name": "net-0"
      },
      {
        "ip": "bbb.bbb.bbb.bbb",
        "network_name": "net-1"
      }
    ]
  }
}
```

参考までyamlで表記すると以下の通り

```yaml
---
locals:
  addresses:
  - ip: aaa.aaa.aaa.aaa
    network_name: net-0
  - ip: bbb.bbb.bbb.bbb
    network_name: net-1
```

## count
countを用いると tf.json ファイルは以下の様な感じ

```json
{
  "resource": {
    "local_file": {
      "ip": {
        "count": "${length(local.addresses)}",
        "content": "${local.addresses[count.index].ip}",
        "filename": "ip_${local.addresses[count.index].network_name}"
      }
    }
  }
}
```

この例では、ip_<ネットワーク名>というファイルに、対応するipアドレスを記載している。

参考までYAML表記

```yaml
---
resource:
  local_file:
    ip:
      count: "${length(local.addresses)}"
      content: "${local.addresses[count.index].ip}"
      filename: ip_${local.addresses[count.index].network_name}
```

## for_each

for_eachでは、loop対象はmap(もしくは文字列のlist)でないといけないとのことなので、rangeを用いてキーを作成し、zipmap にて map とする
(もっと良い方法がありそうに思えるが。。)

```json
{
  "resource": {
    "local_file": {
      "ip2": {
        "for_each": "${zipmap( range( length(local.addresses)), local.addresses) }",
        "content": "${each.value.ip}",
        "filename": "ip_${each.value.network_name}"
      }
    }
  }
}
```

こちらの方が直感には合っている

参考までYAML表記

```yaml
resource:
  local_file:
    ip2:
      for_each: "${zipmap( range(length(local.addresses)), local.addresses) }"
      content: "${each.value.ip}"
      filename: ip_${each.value.network_name}
```


この例における変数の値の変移(YAML表記)

```yaml:local.addresses
- ip: aaa.aaa.aaa.aaa
  network_name: net-0
- ip: bbb.bbb.bbb.bbb
  network_name: net-1
```

```yaml:length(local.addresses)
1
```

```yaml:range(length(local.addresses))
- 0
- 1
```

```yaml:zipmap(range(length(local.addresses)),local.addresses)
0:
  ip: aaa.aaa.aaa.aaa
  network_name: net-0
1:
  ip: bbb.bbb.bbb.bbb
  network_name: net-1
```


```yaml:初回ループのeach.key(未使用)
0
```

```yaml:初回ループのeach.value
ip: aaa.aaa.aaa.aaa
network_name: net-0
```

なお、zipmapの第一引数はmust be a list of stringsとのことなので、残念ながらzipmap(local.addresses, local.addresses)は使用できない。
しかしrange(N)はstringsのリストなのだろうか？本当は明示的に文字列とする必要がある？






## 参考

- https://www.terraform.io/docs/configuration/functions/range.html
- https://www.terraform.io/docs/configuration/functions/zipmap.html
- https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances-by-count
- https://www.terraform.io/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings
Streamlitで作ったWebアプリをHerokuにデプロイする

`Streamlit`と`Heroku`を使って簡単に画像加工を行うWebページを作れたので、その導入を残します。

## 作ったアプリ
### デモ動作
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235435/9d1818d2-382e-b9c4-721a-ada04e517040.gif)

[デモページ](https://still-sands-82310.herokuapp.com/)

[ソースページ (Github)](https://github.com/tomowarkar/stapp)

作業ログ: [streamlit で画像処理アプリを作る。 :: tomowarkarの技術ブログ — ３歩進んで２歩下がる](https://tomowarkar.github.io/blog/posts/heroku_streamlit/)

### ローカルで実行

```bash
pip install streamlit
streamlit run https://github.com/tomowarkar/stapp/blob/master/app.py
```

※ 顔検出など一部機能は使えません

## Streamlitとは
[Streamlit — The fastest way to build custom ML tools](https://www.streamlit.io/)

>Streamlitのオープンソースアプリフレームワーク は 、データサイエンティストと機械学習エンジニアが数時間で美しく高性能なアプリを作成する最も簡単な方法です。純粋なPythonですべて。すべて無料です。[Streamlit — The fastest way to build custom ML tools](https://www.streamlit.io/)(Google 日本語翻訳)

## この記事の目標

- HerokuにStreamlitで作ったWebアプリをデプロイする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235435/19c6b015-1798-2b37-82f8-7cecc9cb102b.png)


## 前提
- [Heroku アカウント](https://id.heroku.com/login) と [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli)の準備が必要です
- `pipennv`を用いてライブラリ管理を行っていますがもちろん`requirements.txt`を使用しても大丈夫です。

## ワークスペースの作成, streamlitのインストール

```bash
$ mkdir stapp
$ cd stapp
$ pipenv install --python 3
$ pipenv install streamlit
```

### requirements.txtを使う場合

```bash
$ mkdir stapp
$ cd stapp
$ pip insatll streamlit
$ echo streamlit==0.60.0 >requirements.txt
```

## アプリ作成

```bash
$ touch app.py
```

```python:app.py
import streamlit as st

st.title("Hello Streamlit!!")

st.subheader("This is calculator.")

a = st.slider("a: ", 0, 10, 5, 1)
b = st.slider("b: ", 0, 10, 5, 1)

st.write(f"{a} x {b} = {a*b}")

```
たったこれだけです

## Heroku用設定[^1]

```bash
$ echo "web: streamlit run --server.enableCORS false --server.port \$PORT app.py" >Procfile
```

## Git リポジトリ初期化

```bash
$ git init
$ git add .
$ git commit -m "first commit"
```

## Heroku アプリの作成

```bash
$ heroku create
$ git push heroku master
$ heroku open
```

無事webサイトは表示されていましたか?

## Next step

[Tutorial: Create a data explorer app — Streamlit 0.61.0 documentation](https://docs.streamlit.io/en/latest/tutorial/create_a_data_explorer_app.html)

Streamlitの公式チュートリアルが丁度よく面白いです!

## おわりに

いかがでしたでしょうか。早ければ10分もかからずにwebアプリを公開できてしまいます。

streamlitはカスタマイズ性には乏しいですが、`pandas`の`DataFrame`で作った表や, `matplotlib`でプロットしたグラフ, `OpenCV`での画像処理の結果などを簡単かつ数行でwebアプリに落とし込むことができます。

pythonだけで完結し気軽に成果物をアウトプットできるのがとてもいいですね。


[^1]: [Hosting streamlit on Heroku - Questions - Streamlit](https://discuss.streamlit.io/t/hosting-streamlit-on-heroku/132/12)
laravel 5,6 , vue.js2,3 , centos7,8 の違い

また、時代が変わる。
新しい技術を取り入れなければいけない。
ということで、どんな違いがあるのかざっくりまとめてみた。

# laravel 5と6の違い

Laravel 6.0はLaravel 5.8と大きな違いはありません

php7.2以上が必須


# vue.js 3
まだβ版なので利用はしないでおこう。



# centos7と8の違い


なお、yum コマンドは dnf コマンドのラッパーとして用意されているため、yum コマンドを入力しても内部的には dnf が呼び出されるようになります。


一方で、CentOS 7 からは firewalld でもネットワーク制御が可能となっています。
新しく nftables を覚えるよりは、firewalld を習得した方が良いでしょう。



まぁ、あんまり変わらないって感じでしょうね。
競合他社調査から引き出す価格と品揃え戦略

元記事：https://www.octoparse.jp/blog/competitor-monitoring-for-price-strategy-and-product-planning/


新型コロナウイルスによる肺炎の感染を警戒することで、消費者が外出を控えるなどして、停滞しつつある消費を刺激しようと、EC企業が相次いで割引セールや企業向けのマーケティング支援を打ち出しています。

ECセールといえば、日本では「楽天スーパーSALE」、「Amazon Prime Day」、「Yahoo!ショッピング プレミアム会員感謝デー」など代表的なセールがありますね。中国なら、ダブル11や618など、アメリカはブラックフライデーとなっており、毎年すごい盛り上がりを見せています。セールイベントは消費者にとってただの祭典ですが、ネットショップ運営者にとっては真剣勝負です。この勝負では、お客様の購買意欲を掻き立てやすい価格戦略が最も重要だと認識されています。同じ商品でも、なるべく安価で買いたいと思うのは消費者にとって自然の心理でしょう。

今回のテーマとして、ECセールで、適当な価格と品揃え戦略を通じ、如何にして自社の売上を上げるのか、この勝負に勝つのかについて紹介します。
 

#価格戦略

多くの消費者がインターネットで商品を購入する時は価格重視が殆どです。情報化が進み、お客様自ら情報を収集・比較・検討して商品やサービスを選ぶ時代になりました。商品を購入する前により安く買える他店を探したり、インターネットなどを利用してよりお得な買い物をしたりすることができます。そのため、競合店舗より、競争力のある価格を設定することが重要です。もちろん、必ずしも商品の価格を下げることではありません。価格を下げるということは、お客様が商品に支払う額が少なくなるということです。つまり、一つの売り上げから得られる利益が小さくなるので、儲けが少なくなってしまいます。値下げは、シンプルで手っ取り早い戦略の一つではありますが、経営者にとっては必ずしも最善の選択とはいえないかもしれません。

競合他社の商品リストを把握して最適な価格を決めるには、まず次の質問に答えてください：

##自社サイトの価格モデルは何ですか？

まず、自社製品に最適な価格モデルを決めます。たとえば、競合他社製品をすでに利用している消費者を、自社製品に乗り換えようとする場合、おそらく競合他社の価格より安くする価格モデルは有効になります。一方、有名人に高級ハンドバッグを販売している場合、価格を下げると実際に売り上げに影響が出る可能性があります。

コストプラス（原価加算）の価格モデルでも、または商品の価値をベースとした値決めでも、競合他社製品やサービスの価格を知ることが重要です。

 

##お客様は製品の価値をどのように認識していますか？

価格を下げたが、やはり売れなかったことがありますか？それはおそらく、値下げることで商品価値の低下を感じて「安いものは買わない」というお客様もいるでしょう。値下げしている間だけ購入すると決めているわけではありません。代わりに、適当な価格での購入をきっかけに商品に魅力を感じたお客様がいますね。

そのため、経営者は、お客様が知覚する価値に適合するターゲット価格を設定する必要があります。競合他社の価格を参考することは、お客様が同じ商品をどのように知覚しているかを理解するのに役立つ1つの方法です。

 
#品揃え戦略

競合他社の追跡では、競合ECサイトでどういった商品が品揃えされているのかなどを分析することが必ず行われ、市場トレンドに関する貴重な洞察が得られる場合があります。たとえば、スポーツ用品を販売するショップを経営しています。競合他社がさまざまなブランドのダンベルを追加していることに気付いた場合、彼らはダンベルの市場価値が高まっていると推測できます。もし、自社のショップにダンベルがない場合は、品揃えを充実することができますね。

 

##真の競合相手が誰なのか？

競合他社の品揃えを把握し、市場変化に対応する準備ができていることは重要です。ただし、真の競合相手が誰なのかを明確することも重要です。多くの場合、競合他社と考えると、必ず同じ業界内のビジネスについて考えます。理論的には問題ないように見えますが、実際には必ずしもそうとは限りません。間違ったライバルを基準にすると、価格と品揃えの戦略は不十分です。

真の競合相手を見つけるには、価格指数を計算する必要があります。価格指数は経済学の概念であり、インフレ率を測定するために使用されます。eコマースの分野では、競合他社が自社ビジネスに与える影響を調べるために使用できます。

特定の製品（上記のダンベルなど）の価格指数を測定するには、競合他社のダンベルの価格を自社店舗のダンベルの価格で割り、100を掛ける必要があります。

**価格指数=（競合他社の製品価格/自社の製品価格）x 100**

もちろん、1点製品の価格指数から得られる価値は何もありません。各製品の価格指数を合計し、製品数で割り、得られる製品の平均価格指数を取得する必要があります。上記の計算を繰り返すと、すべての競合他社の各製品の価格指数が得られます。そこから、視覚的なグラフを介してすべてのデータポイントを接続し、偏差値を分析することで、どの競合他社が自社に最も影響を与えているかを判断できます。

![competitor-monitoring-for-price-strategy-and-product-planning.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262932/164a4e77-b1e2-224e-8fe1-356abc7de8f5.png)


##競合他社の追跡をどのように実施しますか？

市場では、競合他社調査ソリューションを提供している企業が多くあるが、どちらでもかなりの費用がかかりますね。ただし、費用が高いにもかかわらず、セキュリティ問題に対処する必要も時々あります。[Octoparse](https://www.octoparse.jp/)のような[Webスクレイピングツール](https://www.octoparse.jp/blog/the-10-best-web-scraping-tools/)は、セキュリティに慎重で予算きつい企業にとって、代替手段として機能します。Octoparseは、あらゆる規模の企業に自動的に情報を取得する機能を提供し、小規模の経営者でも低いコストで各競合他社のWeb上の情報を追跡できるようにします。

 

 

#まとめ

｢友を近くに置け、敵はもっと近くに置け｣という言葉は、eコマースの業界に特に当てはまりますね。ですから、定期的な競合他社調査を行い、市場動向を把握し、それに応じてマーケティング戦略を策定して、最も良い効果をもたらす方法を見出すのは重要です。
ユーザの参照項目が更新された時に起動するワークフロールールを設定する

ついつい、Apexトリガーで書いてしまいますが、
ワークフロールールでのやり方。

https://success.salesforce.com/answers?id=9063A000000Dxv5QAC

```
AND (
NOT (ISBLANK(Late_Investigation_Owner__c)),
ISCHANGED(Late_Investigation_Owner__c)
)
```

ポイントは起動条件みたいですね。
created, and every time it's edited.
にするといいようです。
【Python】python-pptxでテーブルスタイルを書き換える方法【python-pptx】

## 概要
* pythonで自動pptx作成をしたい。
* tableのstyleが気に食わないので変更したい！
* document見ながらやってるのになぜ動かん。。。

## 問題
* [github](https://github.com/scanny/python-pptx/issues/27)を参考にしても、うまく動かなかった。
* `shape._element`がそもそもいないんだが？

## 解決方法
* UUIDをgithubから拾って、入れ替えることで任意のスタイルに変更ができる。

```python
table = slide.shapes.add_table(rows, cols, table_left, table_top, table_width, table_height).table

tbl = table._graphic_frame.element.graphic.graphicData.tbl
style_id = '{E8B1032C-EA38-4F05-BA0D-38AFFFC7BED3}' #UUIDはgithub参照
tbl[0][-1].text = style_id
```

## まとめ
* 業務時間削減のために、自動化してるのにデザインに凝ってしまい、結果増大させることになった。
* 悩んでいる人の助けになれば…
内部テーブルの重複を削除する時は事前にソートする事

`DELETE ADJACEMENT DUPLICATES FROM 内部テーブル COMPARING 項目.`で内部テーブルの重複を削除する場合は、事前にソートされた状態にしましょう。

```ABAP
REPORT ZTEST.
TYPES:
  BEGIN OF TYP_TEST,
    INTG TYP I,
  END OF TYP_TEST,
  TYP_IT_TEST TYPE STANDARD TABLE OF TYP_TEST.

DATA:
  ST_TEST TYPE TYP_TEST,
  IT_TEST TYPE TYP_TD_TEST.

START-OF-SELECTION.

ST_TEST-INTG = 1.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 3.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 2.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 1.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 1.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 3.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 2.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 1.
APPEND ST_TEST TO IT_TEST.

ST_TEST-INTG = 1.
APPEND ST_TEST TO IT_TEST.

DELETE ADJACEMENT DUPLICATES FROM IT_TEST COMPARING INTG.

LOOP AT IT_TEST INTO ST_TEST.

  WRITE:
    /006(5) ST_TEST-INTG.

ENDLOOP.
```
`DELETE ADJACEMENT DUPLICATES`で重複を削除する前のIT_TESTは、

* IT_TEST

| # | INTG |
|---|------|
| 1 | 1    |
| 2 | 3    |
| 3 | 2    |
| 4 | 1    |
| 5 | 1    |
| 6 | 3    |
| 7 | 2    |
| 8 | 1    |
| 9 | 1    |

↑こうなっています。

`LOOP AT IT_TEST INTO ST_TEST.`の時点でIT_TESTがどうなっているかと言うと、

* IT_TEST

| # | INTG |
|---|------|
| 1 | 1    |
| 2 | 3    |
| 3 | 2    |
| 4 | 1    |
| 5 | 3    |
| 6 | 2    |
| 7 | 1    |

↑こうなっています。
`DELETE ADJACEMENT DUPLICATES`は隣接する行で重複しているか判断するので、ソートされてないと
うまくいかないんですよね。

>DELETE ADJACENT DUPLICATE ENTRIES FROM itab 
                                 [COMPARING f1 f2 ... |ALL FIELDS].
内部テーブル itab から、すべての隣接する重複エントリが削除されます。
>https://help.sap.com/doc/saphelp_nw70/7.0.12/ja-JP/06/aafd54fc4011d195280000e8353423/content.htm?no_cache=true

これを回避するためには、重複を削除する前に`IT_TEST`にSORTをかけます。

```ABAP
*中略
APPEND ST_TEST TO IT_TEST.

SORT IT_TEST BY INTG ASCENDING.

DELETE ADJACEMENT DUPLICATES FROM IT_TEST COMPARING INTG.

LOOP AT IT_TEST INTO ST_TEST.

  WRITE:
    /006(5) ST_TEST-INTG.

ENDLOOP.
```

こうすれば、↓のようにちゃんと重複が削除されます。

* IT_TEST

| # | INTG |
|---|------|
| 1 | 1    |
| 2 | 2    |
| 3 | 3    |

##と言うかSTANDARD TABLEなんか今時使うなって事なんでしょうか？？
jq コマンドで新規JSONファイルを生成するには

# TL; DR

次のワンライナーで可能です。

```bash:新規JSONファイルを生成するワンライナー
echo {} | jq '.is_created = "true"' > file.json
```



# はじめに

JSONファイルを新規生成（新規作成）したいです。

jq コマンドは既存ファイルを整形するためのコマンドであり、新規ファイルを生成するためのコマンドではありません。
そのため、入力ファイルが無い場合にコマンドを実行しようとしても、正常に動作してくれません。

```bash:ファイル引数が無いために正常動作しないワンライナー
jq '.is_created = "true"' > file.json
```

これを解決する手法を探します。



# 解決策

echo コマンドによって、空っぽのJSONを引数にすることで、解決できます。

```bash:新規JSONファイルを生成するワンライナー
echo {} | jq '.is_created = "true"' > file.json
```

```json:上記ワンライナーで生成されたfile.json
{
  "is_created": "true"
} 
```

jq コマンドを駆使すれば、複雑なJSONも通常通りに生成できます。



# おわりに

考えればなんてことはないものですが、地味に頭を捻らせたのでまとめておきました。
AWS EC2 AmazonLinux2 composerをインストールする

# 目的

- インスタンスにcomposerをインストールする方法をまとめる。

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| AWS EC2インスタンス | AmazonLinux2 | こちらの方法を用いてイメージからインスタンスを作成→[AWS EC2 をMacで使ってみよう!](https://qiita.com/miriwo/items/a1ab84c098008e43d042) |
| MySQL バージョン | 8.0.20 for Linux on x86_64 (MySQL Community Server - GPL) | こちらの方法を用いてMySQLのインストールを行った→[AWS EC2 AmazonLinux2にMySQLを導入する。](https://qiita.com/miriwo/items/a1ab84c098008e43d042) |

# 前提情報

- 下記、または下記に準ずる方法でAmazonLinux2のインスタンスを起動する。
    - [AWS EC2 をMacで使ってみよう!](https://qiita.com/miriwo/items/a1ab84c098008e43d042)

# 読後感

- `$ composer`コマンドが正常に実行できる。

# 詳細

- ※本説明にて実行するコマンドは全てインスタンスにssh接続を行い、実行するものとする。

1. 下記手順を実施してPHPを入れる。(実施済みの方は飛ばす。)
    - [AWS EC2 AmazonLinux2 PHPをインストールする](https://qiita.com/miriwo/items/7d94303e7185e4118f52)
1. 公式のインストール方法に記載されているコマンドを実行してcomposer本体を取得する。([Download Composer](https://getcomposer.org/download/))(※`$ php -r "if (hash_file・・・`のコマンドは変更になる可能性があるので最新のコマンドは公式ページをご確認いただきたい。)

    ![Composer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/16441ee5-e483-fbda-0b70-866ea2ab5b6e.png)

    ```terminal
    cd
    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    php -r "if (hash_file('sha384', 'composer-setup.php') === 'e5325b19b381bfd88ce90a5ddb7823406b2a38cff6bb704b0acc289a09c8128d4a8ce2bbafcd1fcbdc38666422fe2806') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
    php composer-setup.php
    php -r "unlink('composer-setup.php');"
    ```
1. 下記コマンドを実行してcomposerの実行ファイルを移動する。

    ```terminal
    sudo mv composer.phar /usr/local/bin/composer
    ```
1. 下記コマンドを実行してcomposerの実行ファイルを実行する。

    ```terminal
    php /usr/local/bin/composer
    ```
1. 下記コマンドを実行してパスを通す。

    ```terminal
    echo "export PATH=~/.config/composer/vendor/bin:$PATH" >> ~/.bash_profile
    source ~/.bash_profile
    ```

1. 下記コマンドを実行してコマンドにパスが通ったことを確認する。

    ```terminal
    composer
    ```

# 参考文献

- [Download Composer](https://getcomposer.org/download/)
Heroku デプロイできてるのにエラー出て開けない

# 環境

- Ruby 2.7.1
- Rails 6.0.3
- Centos 7.6
- MySQL 8.0.20
- 仮想環境 Vagrant + VirtualBox

# We're sorry, but something went wrong.If you are the application owner check the logs for more information.

<img width="972" alt="スクリーンショット 2020-06-11 9.30.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628315/3b59223c-e3a7-52ce-d60f-2fa81e32c96f.png">

このように、デプロイしても開けない状況に。

# 解決策
データベースが原因でした。
herokuはデフォルトがMySQLじゃないので自分で設定してあげないといけないみたい。

この2つの記事がわかりやすい！↓

- CUIで設定
https://qiita.com/senou/items/108ef1d94dcb5b227b4f

- GUIで設定
https://qiita.com/poster-keisuke/items/f27e190e22d80dc254ed

この2つの記事を読んで概要をつかんでからCUIで設定していった。

## herokuのデータベースをMySQLに変更

```
[vagrant@localhost memopy]$ heroku addons:create cleardb:ignite
Creating cleardb:ignite on ⬢ memopy... free
Created cleardb-aerodynamic-24825 as CLEARDB_DATABASE_URL
Use heroku addons:docs cleardb to view documentation

[vagrant@localhost memopy]$ heroku config | grep CLEARDB_DATABASE_URL
CLEARDB_DATABASE_URL:     mysql://bc0ee5063e4f00:e1d0665c@us-cdbr-east-05.cleardb.net/heroku_fb9e9b74813be35?reconnect=true

[vagrant@localhost memopy]$ heroku config:set DATABASE_URL=mysql2://bc0ee5063e4f00:e1d0665c@us-cdbr-east-05.cleardb.net/heroku_fb9e9b74813be35?reconnect=true
Setting DATABASE_URL and restarting ⬢ memopy... done, v7
DATABASE_URL: mysql2://bc0ee5063e4f00:e1d0665c@us-cdbr-east-05.cleardb.net/heroku_fb9e9b74813be35?reconnect=true

[vagrant@localhost memopy]$ heroku config
=== memopy Config Vars
CLEARDB_DATABASE_URL:     mysql://bc0ee5063e4f00:e1d0665c@us-cdbr-east-05.cleardb.net/heroku_fb9e9b74813be35?reconnect=true
DATABASE_URL:             mysql2://bc0ee5063e4f00:e1d0665c@us-cdbr-east-05.cleardb.net/heroku_fb9e9b74813be35?reconnect=true
LANG:                     en_US.UTF-8
RACK_ENV:                 production
RAILS_ENV:                production
RAILS_LOG_TO_STDOUT:      enabled
RAILS_SERVE_STATIC_FILES: enabled
SECRET_KEY_BASE:          57c40cfca095d1fb6419a4e567f5d16f11d3d5827d045def500cff321f31bfa7aefe3ebc740f678ea62a4db48a32f76c7d7569c06295d7aed89d8df62a87b7c4
```

これでheroku上でMySQLが使えるように！

## アセットパイプラインの設定

あとはアセットパイプラインも設定してあげないといけないみたい。
アセットパイプラインって何って方はこの記事を。↓
https://www.transnet.ne.jp/2016/02/28/rails%E5%88%9D%E5%AD%A6%E8%80%85%E3%81%8C%E3%81%A4%E3%81%BE%E3%81%9A%E3%81%8Dcolnr%E3%80%8C%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3/

config/environments/production.rb を見てみると、

```
（中略）
config.assets.compile = false
（中略）
```

になってたのでこれを

```
（中略）
config.assets.compile = true
（中略）
```

に変更。

## マイグレーション

```
[vagrant@localhost memopy]$ git add -A

[vagrant@localhost memopy]$ git commit -m 'アセットパイプラインの設定'

[vagrant@localhost memopy]$ git push

[vagrant@localhost memopy]$ git push heroku master

[vagrant@localhost memopy]$ heroku run rake db:migrate
```

これでmigrate完了！

heroku open で開いてあげると、、、

<img width="972" alt="スクリーンショット 2020-06-11 9.27.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628315/c7504e06-2fad-5bec-ba30-6688e6d6f838.png">

開けた！

やったね！！！
主要型のDataType.FullName

# 概要
数年ぶりのQiitaだけど、超しょーもない糞メモです。
自分でDataTableからSQLiteのテーブルに置き換えるコードを作る際のSQL側のテーブル定義を作るときに、
カラムの型をどう判定するかで使うために調べたメモです。


# 結果
Windows10 64bit PC
コンパイルは32bit

```vb
Module Module1

	Sub Main()
		Dim dt As New DataTable("dt")
		dt.Columns.Add("String", Type.GetType("System.String"))
		dt.Columns.Add("Double", Type.GetType("System.Double"))
		dt.Columns.Add("Int32", Type.GetType("System.Int32"))
		dt.Columns.Add("Int64", GetType(Int64))
		dt.Columns.Add("Integer", GetType(Integer))

		Console.WriteLine($"
		String:{dt.Columns("String").DataType.FullName} 
		Double:{dt.Columns("Double").DataType.FullName} 
		Int32:{dt.Columns("Int32").DataType.FullName} 
		Int64:{dt.Columns("Int64").DataType.FullName} 
		Integer:{dt.Columns("Integer").DataType.FullName}
		")
	End Sub

End Module
```

```console
                String:System.String
                Double:System.Double
                Int32:System.Int32
                Int64:System.Int64
                Integer:System.Int32

続行するには何かキーを押してください . . .
```
【Auth0】認証時に任意のパラメータをRuleに渡す。

認証時に色々やりたい時に、フロントからこのパラメータをRuleに受け渡したい！というケース、ありそうです。

今回はフロント側auth0-spa-js,loginWithRedirectでログインするとして、Auth0のUniversalLoginを利用します。

# やり方

```typescript
      this.$auth.loginWithRedirect({
        hoge: 'nyaaa'
      });
```

と書けば Ruleのcontext.request.queryには

```json
{
  "protocol": "oauth2",
  "client_id": "xxx",
  "redirect_uri": "http://localhost:3000",
  "hoge": "nyaaa",
  "scope": "openid profile email",
  "response_type": "code",
  "response_mode": "query",
  "state": "TnM2UTRhR2ZvanBna28zSklZSjdxNFlfRGpoMDMtY3FKdX5TVUl6ZXduQg==",
  "nonce": "vhGKxvRCUezZ6eLlpO-.fD17O0xXZd5JJoFr~37~S9Q",
  "code_challenge": "",
  "code_challenge_method": "S256",
  "auth0Client": "eyJuYW1lIjoiYXV0aDAtc3BhLWpzIiwidmVyc2lvbiI6IjEuMi4zIn0=",
  "connection": "Username-Password-Authentication",
  "realm": "Username-Password-Authentication"
}
```

hoge:"nyaaa"のKey Valueが追加される！
json-serverの復習

最近SPAと触れ合っているのですが、フロントエンド実装中に連携APIサーバーが（お金的に）用意（出来なく）しきれなくて、ダミーAPIを作成して開発しています。

そこで使う[JSON Server](https://github.com/typicode/json-server) について備忘をば。

#JSON ServerはダミーAPIツール
JSON ServerはCreate、Read、Update、Deleteといったデータ連携の基本的な操作であるCRUD機能がある。

#JSON Serverのインストール

```
npm install --save-dev json-server
```

#初期データの作成
インストール完了後、db.json というファイル名で以下のようなJSONファイルを作成、pacakage.jsonと同じ階層に配置する。

```json

{"todos":
  [
    {"id":1,"todo":"ID-1のTODO","completed":false},
    {"id":2,"todo":"ID-2のTODO","completed":true}
  ]
}
```


#JSON Serverの起動

```
npx json-server --watch db.json
```

JSON Serverが立ち上がるとコンソールに以下の出力がある。

```
  \{^_^}/ hi!

  Loading db.json
  Done

  Resources
  http://localhost:3000/todos

  Home
  http://localhost:3000

  ・・・・・
  ・・・・・
  ・・・・・
  ・・・・・
```
※db.jsonに既にresourceを作成済みなので、resourcesが表示される
#動作確認

##Create
POSTでTODOを追加してみる。

terminalからcurlで実行

```shell
curl --request POST --header "Content-Type: application/json" --data '{"todo":"IDxxxのTODO","completed":false}' "http://localhost:3000/todos/"
```

http://localhost:3000/todos にアクセスすると現在のデータがわかる。

idを指定していないのでおそらく、「IDが自動附番」されているはず。
id指定して入れることも可能。（それがいいかどうかはちょっとわからぬ）


##Read
http://localhost:3000/todos アクセスすると以下のようなJSONが出力されるのが確認できる。

```json
{"todo":"IDxxxのTODO","completed":false,"id":1}]
```

##Update
UpdateするときはPUT
PUTで更新したいレコードのidをURLに付け、更新したい内容を指定
※該当IDの内容を全部送る

```shell
curl --request POST --header "Content-Type: application/json" --data '{"todo":"IDxxxのTODOを変更","completed":true}' "http://localhost:3000/todos/1"
```


##Delete
削除したいレコードのidをURLに付けDELETEメソッドを実行。

```shell
curl --request POST "http://localhost:3000/todos/1"
```


#もうちょい高度に
db.jsonファイルの中身を以下の様にしてみる。

```json
{
  "todos": [
    { "id": 1, "todo": "TODO-1", "completed": "false" }
  ],
  "description": [
    { "id": 1, "text": "comment"}
  ],
  "user": { "name": "shihou22" }
}
```
※ルート直下のkey項目がそのままResource urlとなる

```URL
http://localhost:3000/todos
http://localhost:3000/description
http://localhost:3000/user
```
MySQLとPostgreSQLのtimestamp

CakePHPで「id,created,modified」は必ず入れますよね。
そんな時、ポスグレとMySQLでの違い。

ポスグレではcreatedもmodifiedも【timestamp】で宣言します。
でもMySQLで同じ事したら、createdも更新されました。

MySQLはtimestampのカラムを自動で更新するようです。
【datetime】で宣言しないといけないんですね。( ..)φ
「マンガでわかるMSLearn」でさらにスキルアップ！

MSLearnを使って、無料でスキルアップ！
って聞いたことがあるけどよくわからない…

そんなあなたの「MS Learnって何？」「無料でAIやクラウドが学べるって本当？」という疑問を、マンガで解説！
➡ [マンガでわかる MS Learn: 無料でAI・クラウド・アプリ開発を学ぼう Kindle版](https://www.amazon.co.jp/dp/B089M7LC28?fbclid=IwAR1QAe7iQqNgUHmimJ0yNLPpm3JO1shyf9rl_hPgFC6p-pUxkQgCjDEYFLM)
◎10ページなのですぐ読み終わります！

■あらすじ
いたって普通の大学生みっくんは、友人のトオルにそそのかされてアプリを作ることに。
困っていたら、隣に住んでいるソフィアが部屋に乗り込んできた！
無料でプログラミングが学べるサイト「Microsoft Learn（以下MS Learn）」で、Pythonやクラウド、人工知能にふれるうちに、学生向けハッカソン「Imagine Cup」に出場することに…？

Imagine Cup 世界大会受賞者のインタビューや、おすすめのラーニングパス（チュートリアル）も収録！

■登場人物
・みっくん（主人公）
文系の大学生。本名はミツル。プログラミングは初心者。悩みは、アイデアはたくさん浮かんでくるがそれを作る技術がないこと。自分に自信がなかったが MS Learn に出会って変わる。 

・ソフィア
主人公の幼なじみ。小学生の頃からプログラミングが好き。プログラミングの腕はピカイチだが、イラストやデザインは苦手みたい。

・トオル
主人公と同じ大学に通っている。イラストと3Dモデリングが得意。自分の作ったキャラクターがゲームやサービスの中で動くのが夢。


▼今すぐ誰でも・無料で始められる「MS Learn」を使ってみませんか？
https://aka.ms/MSLearn-JPN
2020-06-11 Windows 10 > HDMIモニタが映らなくなる > Windows Updateが中途半端に適用された？ > KB4497165適用で回復 | KB4497165(謎の再リリース)

```txt:動作環境
Windows 10 Pro (v1909) OSビルド 18363.900
```

### 状況

- HDMI接続が認識しない
    - DVI, RGB(VGA?)接続は認識する

起動したままのVMWare Workstationが落ちているところを見ると、Windows Updateが適用されたようだ。


### 対応

Windows Updateを見たところ、未適用の更新プログラム(KB4497165)があった。

- 2020-01 x64ベースシステム用 Windows 10 Version 1909 更新プログラム (KB4497165)

これを適用して再起動したところ、HDMI接続が認識されるようになった。


### 関連

- [[謎]Windows 10 1903/1909 Intelマイクロコード更新プログラムKB4497165が再リリース](https://a-zs.net/kb4497165/)

推測だが、Windows UpdateにHDMIがらみの不具合があり、KB4497165で修正できるから再リリースしたんだろうか？
スプレッドシートのセル内にある特定の文字列を探索する

# 前提
GAS

# 内容
forループを入れ子にして、縦横方向に探索しました。

```
function searchKeyword() {
  const UI = SpreadsheetApp.getUi();
  const ThisSpread = SpreadsheetApp.getActiveSpreadsheet();
  const BeSearchedSheet = ThisSpread.getSheetByName('sheet5');
  for (let vertical = 1; vertical<=3; vertical++){
    for(let horizontal = 1; horizontal <= 3; horizontal++){
      let search_node = BeSearchedSheet.getRange(vertical, horizontal).getValue();
      if(search_node.match('here!')){
         UI.alert('i did it ! => ' + 'vertical:' + vertical + 'horizontal:' + horizontal);
         break;
         }
    }
  }
}

```
CKAに合格した話

# 概要
CKA(Certified Kubernetes Administrator)を受験し無事合格したので、勉強法等を簡単に共有します。

# 動機
- 約2年ほどKubernetesに関連する仕事をしてきたので、身に付いたスキルを資格という形で残しておきたかった
- 会社が受験費用を負担してくれたため

# 勉強方法
約30時間ぐらい勉強しました。

## 1. CKAの公式ドキュメントの読み込み (1h)
試験範囲からズレた勉強はしたくなかったのでCKAの公式ドキュメントのハンドブックやFAQを読み込みました。
2020年9月から試験範囲が改定されるようなので、今後受験される方はご注意ください。

## 2. Kubernetes 完全ガイド(3h)
これまでの業務経験から基本的な操作やアーキテクチャは理解していたつもりですが、念のため試験に関連しそうな章を読み込みました。試験範囲から明らかに外れていそうな章は読まなかったです。
今思えば、何か困ったときの参考書的なポジションとして使うのが一番学習のコスパが良さそうでした。

## 3. Kubernetes The Hard Way (5h)
色々な方が勧められている[Kubernetes The Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way)を実践しました。

etcdの管理、証明書関連、ネットワーク関連等のクラスタ管理系の知識が足りないことに気付きました。

## 4. Udemy Certified Kubernetes Administrator (CKA) with Practice Tests コース (15h)
Kubernetes The Hard Wayで気付かされた抜けていた知識・経験のフォローをするために、試験範囲に紐づいたKubernetes学習コンテンツを探しており、[こちら](https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/)に辿り着きました。
感想としては、非常にやって良かったです。演習が豊富でCKA本番の対策になりました。

## 5. Kubernetes The Hard Way (1h)
学習度合いを図るために、2週目を実践しました。
大体のコマンドや操作については理解できるようになっていたため、高速で終了しました。

## 6. ブックマーク作り (4h)
試験中は[kubernetes.io](https://kubernetes.io/)の参照が許可されているため、素早く欲しい情報にアクセスできるようにブックマークしました。オススメは試験範囲に沿ってフォルダを切って(ex:Networking,Security...)、そのフォルダの中に関連するドキュメントをブックマークしていくことです。

以下のリポジトリも参考になりました。

- https://github.com/leandrocostam/kubernetes-certified-administrator-prep-guide

# 受験
試験内容に関することは書けないので、それ以外で知っておくと良かったこと等を記載します。

- CKA-JPの問題の日本語訳が微妙で苦労しました。英語が苦労せず読めるなら、最初から英語で読んだ方が良いかと思います。（ある問題で何を解答して欲しいのか分からず、30分ぐらい迷走しました。。）
- 試験会場は貸会議室の個室を予約して使いました。
- 試験管とのチャットで、Google ChromeのGoogle翻訳プラグインの利用が許可されていることを確認しました。
- Google ChromeのAdBlockプラグインが有効な状態だと試験が開始できませんでした。一時的に無効化しておくことを推奨します。
- tmuxは使えなくても特に試験に支障ありませんでした。
- カメラに寄りすぎると注意されます。（普段からモニタ(カメラ)と近い姿勢だったため、試験中に意識して矯正するのが少し辛かったです）

# 結果
74%で合格の所、92%で無事合格しました。

# 今後受験される方へ
K8s初学者もK8s経験者もとりあえず[Udemy Certified Kubernetes Administrator (CKA) with Practice Tests](https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/)に取り組むのが良いと個人的には思いました。初学者は講義＋演習に真面目に取り組み、中級者は演習だけ実施して分からない部分は講義も聞く形が効率良さそうです。
Dart SassをwebpackとGulpで使う方法

# はじめに
Sassの<span>@</span>importが将来的に廃止になるということで新ルールが使えるdart-sassをwebpackとGulpで使う方法をまとめてみました。
# webpackの場合
## パッケージのインストール
Sassのビルドに必要なパッケージをインストールします。
`sass`がDart Sassです。
`fiders`は処理速度でエラーが出るの回避するのに必要なパッケージです。

```
yarn add webpack webpack-cli style-loader css-loader postcss-loader sass-loader sass fibers -D
```
## 設定ファイル
`webpack.config.js`に設定を記述します。

```js
const Sass = require('sass');
const Fibers = require('fibers');
module.exports = {
  ... //entryやoutputの設定を記述
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          {
            loader: 'sass-loader',
            implementation: Sass,
            sassOptions: {
              fiber: Fiders
            },
          }
        ]
      }
    ]
  }
};
```

# Gulpの場合
## パッケージのインストール
webpackと同様、`sass`と`fibers`をインストールします。
細かい設定を省くと必要なパッケージは以下になります。

```
yarn add gulp gulp-sass sass fibers -D
```

## 設定ファイル
`gulpfile.js`に設定を記述します。

```js

const gulp = require('gulp');
const gulpSass = require('gulp-sass');
const Fibers = require('fibers');
gulpSass.compiler = require('sass'); //Dart Sassを指定
const taskSass = () => {
  return gulp
    ... // srcやplumberの設定を記述
    .pipe(
      gulpSass({
        fiber: Fibers,
        outputStyle: 'expanded',
      })
    )
    ... // destの設定を記述
};
exports.sass = taskSass;
```

# さいごに
webpackもGulpも`sass`と`fibers`をインストールし、設定に追記すると`Dart Sass`を使用できます。
<span>@</span>useや<span>@</span>forwardを使ってみたいという人は試してみてください。
動的にスプレッドシート のシート名をログ出力する

# 前提
GASで実行してます

## インデックス
配列の開始番号は０から数えます。
一番最初のシートの要素番号は０です。
よって、２番目のシートを指定するためには要素番号１を指定する必要があります。

また、シートの最終ページは、全てのシート数から１を引いた値をキーとしてループ処理する必要があります。

まとめると、実際のページ番号と、配列にしたときに指定すべき要素数は−１ずれています。

```

function getContentsSheets() {
  const ThisSpread = SpreadsheetApp.getActiveSpreadsheet();
  const AllSheets = ThisSpread.getSheets();
  const sheets_count = ThisSpread.getNumSheets();
  Logger.log(sheets_count);
  const FIRST_PAGE = 1;
  const LAST_PAGE = sheets_count-1
  for(let page = FIRST_PAGE; page <= LAST_PAGE;page ++){
  Logger.log(AllSheets[page].getName());
  }
}
```
Ruby 配列について

# 配列
配列は、複数の値を保持できます。
変数は、1つの値しか保持できません。

配列は、`配列名 = ["値1","値2","値3"]`のように、複数の値を大括弧[]で囲うことによって使用できます。
それぞれの値は、カンマ(,)で区切って表現します。

## 配列を使用するメリット
配列を用意して値を格納する方法には、以下のメリットがあります。

- 変数を毎回定義する必要がない
- コードがみやすくなる
- コードの記述量が減る

配列は複数の値を保持できるだけでなく、それらの値を変数に代入し、中身を出力できます。

(例)

```ruby
names = ["sawamura", "yamada", "tanaka"]
puts names
#=> sawamura
#   yamada
#   tanaka
```

上記のように、配列に格納されている値が順番に表示されます。

## 配列の要素の取得
配列に格納されている値には、順番に番号が振られています。
この割り振られている番号を**インデックス番号**、配列の中に入っている値のことを**要素**と呼びます。
※**インデックス番号は0から始まります**

特定の要素を取り出す方法としては、以下のような構文を使用します。

`配列名[インデックス番号]`
(例)

```ruby
names = ["sawamura", "yamada", "tanaka"]
puts names[0]
#=> sawamura
```

## 配列に要素を追加
配列に要素を追加する場合は、<<を使って追加できます。

```ruby
names = ["sawamura", "yamada", "tanaka"]
names << "sato"
puts names
#=> sawamura
#   yamada
#   tanaka
#   sato
```

### pushメソッド
pushメソッドは、<<メソッドと同じく配列の末尾に新たな要素を追加するメソッドです。<<メソッドだと1要素ずつしか配列に追加できませんが、pushだと複数要素を一気に追加できるという違いがあります。

(例)

```ruby
names = ["sawamura", "yamada", "tanaka"]
names.push("sato","wakabayashi")
puts names
#=> sawamura
#   yamada
#   tanaka
#   sato
#   wakabayashi
```

## 配列から要素を削除
### shiftメソッド
shiftメソッドは、配列の最初の要素を削除するメソッドです。

(例)

```ruby
names = ["sawamura", "yamada", "tanaka"]
names.shift
puts names
#=> yamada
#   tanaka

# インデックス[0]を確認
# インデックスも更新されている
puts names[0]
#=> yamada
```

# まとめ

- 配列には1つ1つに要素の番号を表すインデックスがある
- 配列のインデックスを指定して要素を取り出すにはnames[0]のような形を用いる
- 配列に要素を追加する場合、<<を使って追加する
スプレッドシートの全シート名をログ出力する

# 前提
GASで実行
オブジェクトは単語の一文字目大文字にしてます

```
function getAllSheets() {
  const ThisSpread = SpreadsheetApp.getActiveSpreadsheet();
  const AllSheets = ThisSpread.getSheets();
  for( let Sheet of AllSheets){
    Logger.log(Sheet.getName());
  }
}
```
rs232cの実験

#概要

rs232cの実験してみた。
閃きは、時間さえ合わせれば0101010101で送信できるんじゃね。

#実験１

9600ボー８N1で、０１０１０１０１０１になるよう、”U”を送信して、pin1からusb-serialで受けてみる。

#サンプルコード


```
void setup() {
	Serial.begin(9600);
}
void loop() {
	Serial.print("U");
}
```

#結果

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b40ccc78-5f8d-bd38-6d1e-f6a5f6424e3d.png)

#実験２

delayMicroseconds(100)で、０１０１０１０１０１になるよう、pin1をon-off,usb-serialで受けてみる。


```
void setup() {
	pinMode(1, OUTPUT);
}

void loop() {
	digitalWrite(1, HIGH);
	delayMicroseconds(100);
	digitalWrite(1, LOW);
	delayMicroseconds(100);
}

```

#結果

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b40ccc78-5f8d-bd38-6d1e-f6a5f6424e3d.png)


以上。
diff目的でExcelファイルをテキストにPythonで変換

Excelファイルをテキストファイルに変換します。cliでdiffすることが目的です。

diff目的なのでテキストファイルからExcelの内容を復元できる必要はありません。CSVだとかにしてしまうと、1行が長くなってdiffしてもコマンドラインでの差分が非常に見づらいので、セルごとに1行にしたいです。

都合の良さそうなツールがすぐに見つからず、スクリプト書いたほうが早かったので書きました。

Pythonでopenpyxlというライブラリを使います。

```console
$ pip install openpyxl
```

ソースコードはこれだけです。

```python
import sys
import openpyxl

filepath = sys.argv[1]
sheetname = ""
if len(sys.argv) > 2:
    sheetname = sys.argv[2]

wb = openpyxl.load_workbook(filepath)

for ws in wb:
    if sheetname != "" and ws.title != sheetname:
        continue
    print(f"sheet:{ws.title}")
    for row in ws:
        print("  row")
        for cell in row:
            if cell.value == None:
                print("")
            else:
                print(f"    {cell.value}")
```

`xls2txt.py` のような名前で保存しておけば、以下でExcelファイルに含まれる全シートの内容がテキストで出力されます。

※セルに入っている値または数式が出力されるのみですので、書式やコメントなどは考慮外です。

```console
$ python xls2txt.py foo.xls
```

特定のシートのみを見たければシート名を指定します。

```console
$ python xls2txt.py foo.xls Sheet1
```

diffを見るにはたとえば次のような感じです。

```console
$ diff -U5 <(python xls2txt.py foo.xls Sheet1) <(python xls2txt.py bar.xls Sheet1) | less
```

diffでの差分を見やすくしたければこちらを参照。
[diffコマンドをカラー表示にして見やすくする方法](https://suzuki-navi.hatenablog.com/entry/2020/05/26/204848)
vistaでquartus その3

#概要

vistaでquartusやってみた。
polyphonyでserial叩いてみた。

#環境

windows vista 32bit
quartus ii v13.0
ep2c5t144ボード

#写真

![CIMG2956.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f6f99ad4-b8cc-b692-fcd3-210c85950fcb.jpeg)


![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b40ccc78-5f8d-bd38-6d1e-f6a5f6424e3d.png)


#サンプルコード


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

@module
class tx0:
	def __init__(self):
		self.led2 = Port(bit, 'out', init=1)
		self.led4 = Port(bit, 'out', init=1)
		self.led5 = Port(bit, 'out', init=1)
		self.tx = Port(bit, 'out', init=1)
		self.append_worker(self.worker)
	def _wait(self):
		for i in range(5000):
			pass
	def worker(self):
		v = 1
		while is_worker_running():
			self.tx(v)
			v = ~v
			self._wait()

m = tx0()


```

以上。