OmniAICreator/Qiita-1.07M huggingface dataset:
MySQLでSQL一発でグループごとに連番を振る

## やりたいこと

MySQL 5.7 で、グループ毎にレコードに連番を振りたいです（一度の SQL 実行で）。
その際、各グループ内は指定した順でソートしておきたい。

## ROW_NUMBER() について

行番号を振るときに使える `ROW_NUMBER()` が MySQL 5.7 にはありません。
そのため別の方法を考える必要があります。
調べていたら、SQL 中で変数を使って連番を振る方法が見つかりました。

## ROW_NUMBER() を使わないでやる

以下のテーブルで試してみます。

```
mysql> select * from history;
+----+----------+--------------------+------------+
| id | group_id | name               | created_at |
+----+----------+--------------------+------------+
|  1 |        1 | Cupcake            | 2020-01-01 |
|  2 |        1 | Donut              | 2020-01-02 |
|  3 |        2 | Eclair             | 2020-01-03 |
|  4 |        2 | Froyo              | 2020-01-04 |
|  5 |        2 | Gingerbread        | 2020-01-05 |
|  6 |        3 | Honeycomb          | 2020-01-06 |
|  7 |        4 | Ice Cream Sandwich | 2020-01-07 |
|  8 |        4 | Jelly Bean         | 2020-01-08 |
|  9 |        4 | KitKat             | 2020-01-09 |
+----+----------+--------------------+------------+
9 rows in set (0.00 sec)
```

このテーブルで `group_id` 毎に連番を振ります。
同一 `group_id` 内では `created_at` の降順でソートします。

```sql:mysql5.7.sql
SELECT
  @rownum := IF(@prev_group_id = group_id, @rownum + 1, 1) AS rownum, -- 連番の列
  history.id,
  @prev_group_id := group_id AS group_id,
  history.name,
  history.created_at
FROM
  history,
  (select @rownum := 0) hoge,
  (select @prev_group_id := '') fuga
ORDER BY
  group_id,
  created_at DESC
```

連番の算出は SQL 中で分岐して処理しています。
一つ前のレコードの `group_id` と値が同じなら 1 ずつ加算し、そうでないなら 1 から振り直す、という流れです。
実行結果は下記。

```
+--------+----+----------+--------------------+------------+
| rownum | id | group_id | name               | created_at |
+--------+----+----------+--------------------+------------+
|      1 |  2 |        1 | Donut              | 2020-01-02 |
|      2 |  1 |        1 | Cupcake            | 2020-01-01 |
|      1 |  5 |        2 | Gingerbread        | 2020-01-05 |
|      2 |  4 |        2 | Froyo              | 2020-01-04 |
|      3 |  3 |        2 | Eclair             | 2020-01-03 |
|      1 |  6 |        3 | Honeycomb          | 2020-01-06 |
|      1 |  9 |        4 | KitKat             | 2020-01-09 |
|      2 |  8 |        4 | Jelly Bean         | 2020-01-08 |
|      3 |  7 |        4 | Ice Cream Sandwich | 2020-01-07 |
+--------+----+----------+--------------------+------------+
9 rows in set (0.00 sec)
```

いい感じに連番が振れました。

## ROW_NUMBER() を使ってやる

MySQL 8 では `ROW_NUMBER()` が使えるため、下記のように書けます。

```sql:mysql8.sql
SELECT
  ROW_NUMBER() OVER(PARTITION BY group_id ORDER BY group_id, created_at DESC) AS rownum,
  id,
  group_id,
  name,
  created_at
FROM
  history
ORDER BY
  group_id,
  created_at DESC
```

## 所感

SQL 内で変数を使うので、少しとっつきにくい感じがあると思いました。
`ROW_NUMBER()` が使えればよりシンプルに書けますが、諸般の事情で MySQL 8 系を利用できない場合もあるので、記憶の片隅に置いておくと良いと思います。

## 参考サイト

https://riptutorial.com/mysql/example/19572/row-number-and-group-by-using-variables-in-select-statement
アソシエーションによるNameErrorの解決の例

NameError in Users Contoroller#show
unintialized constant User::Tweet
Extracted source

```@tweets = user.tweats```

user.tweetsは、ユーザーに紐づいたツイートを取り出します。
ユーザーとツイートは別モデルなのでアソシエーションが存在します。
その点からUserモデルとTweetモデルのアソシエーションの記述が違う可能性が考えられます。

models/user.rbとmodels/tweets.rbを確認し
tweatsの記述をtweetsに修正します。
ちょっと発展的な演算子

今日は少し発展した演算子の学び直し。

## 複合代入演算子

複合代入演算子とは、変数自信に対する演算と代入を組み合わせたもの。
aを足した値をそのままaに代入する、というあれです。
よく使います。

```swift
var a = 1
var b = 3
a += 1
b *= 2
print(a + b)
// 8
```

a += b  :  aにbを足した値をaに代入する
a -= b  :  aからbを引いたものをaに代入する
a *= b  :  aにbをかけたものをaに代入する
a /= b  :  aからbを割ったものをaに代入する
a %= b  :  aからbを割ったあまりをaに代入する
a && b  :  aとbの論理積の値をaに代入する
a ||= b  :  aとbの論理和の値をaに代入する

## 三項演算子

三項演算子は、条件によって式を変更できる便利なものです。こちらもよく現場で使います。

```swift
条件式 ? trueの場合の式 : falseの場合の式
```
if文を一行にした式、というイメージですかね。


例

```swift
let a = 300
let b = 200
let c = a>b ? "true" : "false"
print(c)
// "true"
```

## レンジ演算子

レンジ演算子とは、数値の範囲を指定できる演算子です。

```swift
（最後の値を含める場合）
開始値 ..< 終了値

（最後の値を含めない場合）
開始値 ... 終了値

```

また、レンジ演算子で数値の範囲を作った時、その中に任意の数値が含められているかどうかを判断するときは contains() でチェックできます。

例

```swift
let age = 6...12
print(age.contains(4))
print(age.contains(11))

//false
//true
```

## ビット演算子

ビット演算子を理解するのは少々難しいかもしれませんが、これは仕事でもビットフラグを読み込むのに使用しています。
結構大事なので、押さえておきましょう。

### 1. ビットシフト

ビットシフトは、数値を二進数で表現した時に、指定した方向に桁をシフトする演算です。

a<<b  :  aを左へb桁シフトする
a>>b  :  aを右へb桁シフトする

例

```swift
let v:UInt8 = 0b00000101
let v2 = v<<1
print(v,v2)

///5,10
```

### 2. ビット積、ビット和
こちらは、二進数のaとbの数値を書く桁のビットことに比較して演算するというものです。

```swift
a&b  :  両方の桁が1ならば1
a|b  :  どちらかの桁が1ならば1
```


こちらは今後もう少し深く掘っていこうかなと思います。

それでは。
効率的なSOQLの書き方

面白い質問がありました。

[Efficient List Initialization Technique](https://trailblazers.salesforce.com/answers?id=9064S000000DaYU)

どちらの書き方がいいのか？

List<Account> accList = new List<Account>([SELECT Name FROM Account]);

List<Account> accList  = [SELECT Name FROM Account];


個人的には２番目の書き方が多いですね。
ただ、そんなに違いはあるのかはよくわかりませんでした。

その中で回答がありました。

The second is definitely more efficient.

When executing a query, you are essentially calling a method that instantiates a list, populates it, and returns it to you. In your first example, you are instantiating a second list, and shallow-copying all items from the first list (the one returned from the query) to this second one. This means that if you had 10,000 results, you'd be copying 10,000 pointers to your second list.

回答を読むと

1番目の書き方では2番目のリストをインスタンス化し、最初のリスト（クエリから返されたリスト）からこの2番目のリストにすべてのアイテムを浅くコピーしています。つまり、10,000件の結果があった場合、10,000個のポインターを2番目のリストにコピーすることになります。
[2021]Ajax(非同期通信)フォロー機能(Rails・jQuery)

##前提
 - フォローボタンを実装していること
 - jQueryを使用できるようにしていること


```View.
<th class="follow"><%= render 'relationships/follow_button', user: @user %></th>
```
部分テンプレートを使用しているため
お好きなところに使用してください。


##部分テンプレート作成
```relationships/_follow_button.thml.erb

<% if current_user.following?(user) %>
    <%= link_to 'Unfollow', user_relationships_path(user.id), method: :delete, remote: true %>
　<% else %>
    <%= link_to 'Follow', user_relationships_path(user.id), method: :post, remote: true %>
<% end %>
```
- link_toを使用している場合はremote:trueを記載することで非同期通信になります



##次はcontroller
```ruby:relationships_controller.rb
 def create
    @user = User.find(params[:user_id])
    following = current_user.follow(@user)
    following.save
    flash[:success] = 'ユーザーをフォローしました'
  end

  def destroy
    @user = User.find(params[:user_id])
    following = current_user.unfollow(@user)
    following.destroy
    flash[:success] = 'ユーザーのフォローを解除しました'
  end
```
 - 重要なところは"redirect_to"の部分を記載しないこと
 - 処理が終わるとcontroller名と同じ名前のviewフォルダーの中の"アクション名/js/erb"へ処理が行われます
 
##viewファイル作成

```relationships/create.js.erb
$(".follow").html("<%= j(render 'relationships/follow_button', user: @user ) %>");
```
```relationships/destroy.js.erb
$(".follow").html("<%= j(render 'relationships/follow_button', user: @user ) %>");
```
内容は同じですが新しく作る必要があります。
follow classが部分テンプレートのものに置き換わるようなイメージです。

###補足
form_withを使用する場合はlocal:trueを書かないことで非同期通信になります。また、form_withはidなどが付与されているみたいですのでデベロッパツール（検証ツール）で確認することでcalssなど書く必要がなくなります。
webpack

<h1>はじめに</h1>
Typescriptを学び始めた際に、**webpack**について理解を深めたくなったので整理。

<h1>webpackとは</h1>

webpackは**モジュールバンドラ**の一つ。

そもそもモジュールバンドラが何かというと、複数のモジュールをファイルとしてまとめあげ、<br/>それを指定した場所に出力するツールのこと。
**＊モジュール＝機能ごとに分割されたファイルのこと。**

webpack（というかモジュールバンドラ）の利点は後述。

webpackを使用するにはインストールの必要がある。
webpackコマンドを使用するには、webpack-cliのインストールが必要。
インストールを行ったら、webpack.config.jsでファイルの設定を行う。

<h1>webpackを使うと良い点</h1>

webpackを使うことで、機能ごとにファイル分割して開発ができるようになる。
これにより、各ファイルのコードがシンプルになったり、モジュールの再利用がしやすくなり、コードが見やすくなる。
また、モジュール化によってタスクの境界を明確化できるので、開発作業を分担しやすくなる。

<br/>
webpackには多種多様な機能・設定が存在しているため、覚える必要はないがconfigの理解は必要。

例えば・・・
watchモードを使うと、ファイルを監視して変更があったらビルドを再実行できる。
また、ローダーによって、画像などJavascript以外のファイルをJavascriptで扱えるように変換してくれる。
babel-loaderを使えば、ES6で書いたコードをES5に変換してくれるため、<br/>ES6に対応していないブラウザでも正常に動くようにしてくれる。


<h1>まとめ</h1>

webpack以前にモジュールバンドラの理解が深まりました。
Lombokの設定方法

Springのアノテーションは使えるのに@Dataが使えない理由について調べたところ、Lombokをインストールする必要があると知りました。今回はpom.xmlに追加することで使えるように設定しました。

#前提#
・Spring starterプロジェクトで新規作成する
・ビルドツールにMavenを使用する

#設定手順#
１pom.xmlのdependencies内に下記を追加する。

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.8</version>
			<scope>provided</scope>
		</dependency>

もし追加したのに動作しない！追加したのに認識してくれない！等があればMavenプロジェクトの更新を行ってみてください。
（プロジェクトを右クリック>Mavan>プロジェクトの更新）

あと、バージョンが古い！って怒られますが気になる方は最新のバージョンに書き換えてみてください。
1.18.8でも問題なく動作します。
(2月8日時点では1.18.16が最新)

以上!
Windows10でHHKB-BTというキーボードを使うための設定（とりあえず１週間目）





# Summary

Windows10でHHKB-BTというキーボードを使ってみた

設定と使用感

## HHKBの種類

アマゾンセールで19,800円で買いました！

```
HHKB Professional BT 無刻印
PD-KB600BN
```
## ４つの設定

### 01.ポジションマーク

無刻印で数字キーを押すのが個人的につらかったので１００円ショップのシールを`５`と`０`の上に貼りました

これで数字キー、ファンクションキーが間違わずに打てるようになりました

![IMG-1788.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/8365c7a2-ad27-9246-5fb6-ad10434770e4.jpeg)

![IMG-1789.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/0ae2f374-9ae5-05ed-6568-bbd85c9b6b30.jpeg)

![IMG-1790.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/840da148-99b2-cb96-2ae1-1e215b3a7730.jpeg)

![IMG-1791.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/16a68219-5f79-7a91-de77-638871237589.jpeg)


### 02. DIP Switch ディップスイッチ

```
1 ON    Lite Ext.
2 OFF
3 ON    Back Space
4 ON    Left = function button
5 OFF
6 OFF

```

### 03. 101英語キーボード (Keyboard driver)

キーボードドライバを101英語キーボードに変更

```
// レジストリエディタを使用（管理者権限で起動）

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters

LayerDriver JPN            ：kbd101.dll
OverrideKeyboardIdentifier ：PCAT_101KEY
OverrideKeyboardSubtype    ：0
OverrideKeyboardType       ：7
```

### 04. IME ON/OFF (日本語・英語の切り替え）

アルファベット文字入力の切り替え

```
設定 > キーとタッチのカスタマイズ > キーの割り当て
Shift + Space -> IME-オン/オフ
```

![ccc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/963ce8b4-4fee-29b5-f7ca-36f1fd37d355.png)


![ddd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/fc67e0d0-f376-2257-719e-927cb73c66f2.png)


![bbb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/0c803ac1-0f40-052a-85b6-efae20f51c1e.png)


![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149269/1c5107ef-7e82-aeaf-9982-9bb72114a048.png)

## 一週間使ってみての使用感

よきよきなところ

```
かっこいい
音が素敵
リターンキーをたたくとストレスが溶けていく（ような気がする）
```

つらみなところ

```
厚みがあるので持ち運びたくない（家と会社用に購入したのでオサイフがつらみ）
⇒　厚みが現状のせめて半分だといい感じかもしれない。将来に期待？

値段が高すぎ
⇒ 消耗品の域を超えている

エクセルのセル選択がしにくい（矢印キーを多用するため）
⇒　慣れる必要がある
```

## 残された課題

リモート接続先のパソコンのキーボードレイアウトを一時的に101英語キーボードにする方法が現在のところ不明




## see also

[windows10　キーボードレイアウトを日本語に変更](http://watarisein.hatenablog.com/entry/2015/09/29/231552)
[【HHKB】英語キーボードの右Altキーに［全角／半角］キーを割り当てる](https://evacore.info/hardware-hhkb-alt/)
[HHKB Pro2（英語配列）Windowsのファンクションキー最適化【DIP設定】](https://bsj-k.com/hhkb-win-fn-dip/)



# 現場からは以上です
Bool型で判定する時に気をつけたいこと

#はじめに
メンターの方にコードレビューして頂いた時に指摘された部分です。

#指摘された部分
まずは、改修する前のコードです。

```swift
func hogehoge(bool: Bool) {
    if bool == false {
        // falseの時の処理

    }else {
        // trueの時の処理
    }
}
```
一見、何の変哲もないメソッドですが、これでは駄目です。

何が駄目なのかを説明する前に、上記のコードを改修してみて違いを比べてみましょう。

改修後のコードです。

```swift
func hogehoge(bool: Bool) {
    if !bool {
        // falseの時の処理

    }else {
        // trueの時の処理
    }
}
```
どこが改修されたか分かりますか？

falseが消えて、`！`が付きましたね。
これは、Bool値に対して！を一番前にくっつける事で`否定`を表すことができます。

※因みに！は`論理否定演算子`と呼ばれます。

```swift
var bool = true
!bool // false
```
この！を用いるとシンプルに書くことができ、判定する時に
`true`や`false`といった値を書かなくてもよくなります。

更に冒頭で出てきたコードはこのように書くこともできます。

```swift
func hogehoge(bool: Bool) {
    if bool {
        // trueの時の処理

    }else {
        // falseの時の処理
    }
}
```
trueの時の処理と、falseの時の処理を`逆`にしてしまえば
わざわざ！を使わなくてもよくなります。

#では、なぜ駄目なのか？
改修前・後の両方は意味合いとしては同じなので動きますが、`コードの可読性`が下がってしまいます。

例えば、以下のようなコードがあったとします。

```swift
var bool = true

if !bool != false {
    // trueの時の処理

}else {
   // falseの時の処理
}
```
非常に`読みにくい`ですよね。
私も理解するのに時間が掛かりました...。

このように理解するのに時間が掛かってしまうと、無駄な時間が発生してしまいます。

もしかしたら上記のようなコードが原因で`致命的なミス`を起こしてしまうかもしれません。

なので、Bool型で判定する時にはtrueやfalseを使わないようにコードを書いてみましょう！

#おわりに
今回は、Bool型で判定する時に気をつけたいことでした。

コードレビューで指摘されてなかったら、ずっと改修前のようにBool型を書いていたと思います。
Ubuntu20で Chrome remote desktop を使用する

Ubuntu20で Chrome remote desktop を使用します。

なんか純正だとうまく起動しないので下記コマンで対応します。

コマンド

~~~~bash
cd ;
sudo apt install -y wget ;
wget https://raw.githubusercontent.com/KeithIMyers/Chrome-Remote-Desktop-Ubuntu-Setup/master/chrome-remote-desktop-setup.sh ;
bash chrome-remote-desktop-setup.sh ;
~~~~

再起動後、chromeを立ち上げて拡張機能のリモートデスクトップをインストールします。

````
https://chrome.google.com/webstore/detail/chrome-remote-desktop/inomeogfingihgjfjlpeplalcfajhgai/
````

拡張機能のリモートデスクトップアイコンをクリックして、画面下までスクロールして、リモート受けの許可とPIN番号の設定をします。


あとは、リモート管理側で今回インストールした端末が表示されればOKです。

ただ、画面の共有というよりかは、別の画面での操作になりますので、もうちょっと調査が必要そう。
ラズパイはできません。vnc を使うか、Raspbian でなく ubuntu mate ならいけるのかも。
ACI Fabric 管理アクセス -Out of Band

# ◆ACI Fabricの管理アクセス

ACI FabricにおけるAPIC/Leaf/Spineに対しての管理接続には以下2つのアクセス方式があります。

- Out of Band
- In Band

主な用途の違いとしては、内部ネットワークからの接続(Out of Band)、外部ネットワークからの接続(In Band)で使い分けられます。

APICの初期セットアップ時には、デフォルトでOut of BandのIPを設定します。Leaf/Spineはコミッションのみではスイッチ自体にIPは割り振られません。
IPを割り振らずともAPICへCLIでログインし、ssh接続でLeaf/Spineへのログインが可能です。外部デバイス等からLeaf/Spineに対して管理アクセスを行いたい場合は、Tenant mgmtで上記いずれかの方式でIPを割り当てます。

# ◆Out of Band
APIC/Leaf/Spineの筐体裏面にはmgmtポートがあります。mgmtポートがOut of Band接続ポートとなり、Node IPとGateway IPを設定する事でアクセスできるようになります。

APICは初期セットアップ時にOut of BandのIP及びGatewayを割り振り、mgmtポートと外部デバイスを物理接続してアクセスできるようにします。
Leaf/Spineは管理アクセスが必要な場合、同様にmgmtポートと外部デバイスを接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056057/1c96b1f9-d9b4-2f3f-a604-e33fc4dedfd2.png)

Out of Band接続に関わる主な設定は以下です。

### ① APIC管理IP設定
Tenant mgmt > Node Management Address > Static Node Management Addressを右クリック、Create Static Node Management Addressで新規追加を行う。

- Node Range
Node IDを指定する。

- Config
Out-Of-Band Addressを選択

- Out-Of-Band Management EPG
defaultを選択

- IP Address/Gatewayを指定



### ② Contractの設定
Tenant mgmt > Contracts > Filters を右クリック、Create FilterでFilterの作成を行う。

Tenant mgmt > Contracts > Out-Of-Band Contracts を右クリック、新規にコントラクトを作成し、Subject配下にFilterを適用する。

Tenant mgmt > Node Management EPGs > Out-of-Band EPG - default を選択、Provided Out-of-Band Contractsの＋印でContractを選択し追加。

Tenant mgmt > External Management Network Instance Profiles を右クリック、Create External Management Network Instance Profile

Tenant mgmt > External Management Network Instance Profiles > default を選択、Consumed Out-of-Band Contractsの＋印でContractを選択し追加。SubnetsにAPICへ接続許可するサブネットを指定する。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056057/e08735f2-b46d-82ec-0143-bb857feb1140.png)
[ruby]繰り返し処理 times do end

#初めに
アウトプットさせてもらいます

#繰り返し処理の使い方
例えば１から10までの数を順に足した結果を求めるプログラムを作成してみます。

```
sum = 0

sum = sum + 1
sum = sum + 2
sum = sum + 3
sum = sum + 4
sum = sum + 5
sum = sum + 6
sum = sum + 7
sum = sum + 8
sum = sum + 9
sum = sum + 10

puts "合計は#{sum}です"

#実行結果
合計は55です
```

このように1つ1つ処理を記述していくことも可能ですが、このコードは非常に長く、かつ同じ処理が続いてるため、times文を使って効率的なコードに書き換えます。

#tims文を使った場合
```
sum = 0
10.times do |i|
  sum = sum + i + 1
end
puts "合計は#{sum}です"

#実行結果
合計は55です
```

times文では、変数iの中に繰り返しの回数が数値として自動で代入されます。よって、変数iを使えば繰り返しの回数を変数sumに足していくことができます。
ただし、プログラムなので1回目のiの数値は0となります。よってsumに足すのは1増やしたi + 1にします

#おわりに
簡単なアウトプットでした
awsでCentos6をインストール方法

１。awsにアカウントでログインEC2でトップの検索入力エリアにcentos6と入力しAWSmarketplaceサイトより下記手順で選択しインストールする。OSを選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/088b02b0-aea5-692e-e9ee-5b04bd8f1805.png" width="70%">

２。[Continue to Subscribe] をクリックします。
![スクリーンショット 2021-02-09 3.01.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/919a850d-4a2a-e6d8-5b77-4df86e9b34d6.png)

３。[Continue to Configuration] をクリックします。
![スクリーンショット 2021-02-09 3.01.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/2cc40c63-f93a-a352-356a-0b24cdc7ea96.png)

4.[Continue to Launch] をクリックします。
![スクリーンショット 2021-02-09 3.02.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/45ac67c5-4a52-f360-d26c-57991f6cc10e.png)

5.Choose Action を Launch through EC2 に変更して、[Launch] をクリックします。
![スクリーンショット 2021-02-09 3.02.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/e58b3c62-9e48-dbee-1a20-d90f6977dc24.png)

6.インスタンスのタイプを選びます。[確認と作成] をクリックします。
![スクリーンショット 2021-02-09 3.03.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/468758e1-748f-2b87-064c-df70716bc089.png)
PHPで文字列の中でハッシュタグから始まるワードを配列にして取り出す方法

```php
<?php

$tagsText = '#ラーメン #カレー #　 aaaaaaaa bbbbbbbb #カツ丼 #シチュー　#肉じゃが cccccccc';
$result = preg_match_all('/#([^\s#]+)/', str_replace('　', ' ', $tagsText), $m) ? $m[1] : [];
print_r($result);
// 結果 [ラーメン, カレー, カツ丼, シチュー, 肉じゃが]
```
TWE-LITE と Raspberry Pi 3 + PySerial でシリアル通信する

# 結線

- TWE側 <-> PI側
- 28: VDD <-> 17: 3V3 (1: 3V3でもよい)
- 1: GND <-> 14: GND  (9 とか 20 とかでもよい)
- 6: TX <-> 10: RX/GPIO15
- 7: RX <-> 8: TX/GPIO14

<img src="https://mono-wireless.com/jp/products/TWE-APPS/App_Twelite/asset/twe_app_pins.png"/>

TWE 側： 参考 [超簡単！標準アプリ（App_Twelite）](https://mono-wireless.com/jp/products/TWE-APPS/App_Twelite/index.html)

<img src="http://herb.h.kobe-u.ac.jp/raspiinfo/images/Raspberry_PiGPIO/media_1414553059026.png"/>

Raspberry Pi3 側: 参考 [Raspberry PiのGPIOピンの配置図カード](http://herb.h.kobe-u.ac.jp/raspiinfo/gpio_pins_card.html) 

# Raspberry Pi 側の準備

デフォルトではシルアルコンソールが ON になっていて、TX/RX のラインを使っているので、そのままでは混線してしまう。それを避けるために、シリアルコンソールを OFF にする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/57ce9967-942a-353a-ca50-063c938d8153.png)

デスクトップのメニューから Raspberry Pi の設定を開いて、インターフェイスのタグの「シルアルコンソール」の項目が「有効」になっているのを「無効」にし、シリアルポートを「有効」にする。右下の OK を押して設定画面を閉じる。(再起動が必要かも?)

これで ` /dev/serial0` が使えるようになるはず。

# pyserial のインストール

下記などを参考にして pyserial をインストールする。mac 用の記事だけど、raspberry pi でもほぼ同様にインストールできる(多分)。

- [https://qiita.com/mml/items/ccc66ecc46d8299b3346](python3 でバイナリデータをシリアル通信で送受信する (mac で))
 
# プログラム

受信だけなら下記のような感じでいける。(TWE-LITE 側の通信速度が 115200 bps の場合)。通信速度などの設定を変更したければ、コメントアウトしている部分を適切に書きかえる。

```.py
ser = serial.Serial(
      port = "/dev/serial0",
      baudrate = 115200,
      #parity = serial.PARITY_NONE,
      #bytesize = serial.EIGHTBITS,
      #stopbits = serial.STOPBITS_ONE,
      #timeout = None,
      #xonxoff = 0,
      #rtscts = 0,
      )

while True:
      if ser.in_waiting > 0:
            recv_data = ser.read(1)
            print(type(recv_data))
            a = struct.unpack_from("B",recv_data ,0)
            print( a )
```
【GitHub Actions】カスタム環境変数を読み込みたい

## やりたいこと

直接書きたくないトークン情報や環境変数を設定して、GitHubActions(`.github/workflows/**.yml`)で値を読み込む。

## やり方

### ▼設定

対象のGitHubリポジトリから「⚙️Settings > Secrets > New repository secret」で、`Name`(呼び出し時にキーとなるもの。"secrets."は付けなくて良いです)と`Value`(トークン情報とか)を設定してあげます。

![スクリーンショット 2021-02-09 1.31.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288343/0786d9ee-9cd4-3100-62c0-63b39df0fb04.png)

いくつか命名などにルールがあるようですが、[公式ドキュメント](https://docs.github.com/ja/actions/reference/encrypted-secrets#about-encrypted-secrets)みると詳しく載っています。

### ▼読み込み

値へのアクセスはシンプルです。

```yml:.github/workflows/**.yml
steps:
  - name: Hello world action
    with: # HOGEは設定した値によって読み替えてください
      super_secret: ${{ secrets.HOGE }}
    env:
      super_secret: ${{ secrets.HOGE }}
```

こちらも[公式ドキュメント](https://docs.github.com/ja/actions/reference/encrypted-secrets#using-encrypted-secrets-in-a-workflow)に詳しく載っています。
Qiitaの目次自動生成についての検証

## 概要
Qiitaのマークダウン記法で記事を書くことで自動生成される目次について気になったのでテスト記事(個人的な検証用なのですぐに消すかもしれません)

Qiitaの記事はマークダウン記法で書くと以下の画像のように右に目次が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508704/fcd07843-9d07-0b56-2a89-cd34f93ae564.png)

おそらく、この記事も目次がついていることでしょう。
これどうやらマークダウン記法で書くと、そこの見出しがそのままidとして付けられて、
右の目次は
\<a href="#このガイドラインについて">このガイドラインについて\</a>
って感じになってる。

HTML/CSSについて超詳しいわけじゃないんですが、同じidを複数個つけてはいけないことくらいは知ってます。

じゃあ同じ文章の目次が複数あったらどうするんでしょう？？

気になったので検証用の記事です。

僕自身も投稿しなきゃ確認ができないので気になった皆様はデベロッパーツールを開くなりしてご確認ください。

# 同じ文章
# 同じ文章
# 同じ文章
# 
#
Android10,Android11のファイルパーミッション




# パーミッション
また変更されてんのか...

manifest.xmlに次の宣言を入れる。レガシーのパーミッションを有効にする。
    <application
         android:requestLegacyExternalStorage="true" >


#[preserveLegacyExternalStorage ](https://developer.android.com/training/data-storage/use-cases?hl=ja)
>preserveLegacyExternalStorage フラグを使用して以前のストレージ モデルを保持し、ユーザーが Android 11 をターゲットとするアプリの新しいバージョンにアップグレードする際に、ユーザーのデータを移行できるようにします。

データ移行関係、まぎわらしい。

# [Androidのファイルアクセスの混乱](https://blog.goo.ne.jp/fhoshino/e/3c61807b6b406f7956a40dbfbde8498c)

俺もそう思う、このへん決めてるやつアホなのか。過去のしがらみでせざるを得ないのか...

>Android 11から変更される模様。
https://developer.android.com/preview/privacy/storage#all-files-access
-Android 4.4 SDCARDへの書き込みが禁止
-Android 5.0 SDCARDへの書き込みはStorage Access Frameworkで行えるようになった(READはJava File APIで可能)
-Android 10 内部ストレージと外部ストレージの両方でアプリ固有ディレクトリー以外はJava File APIによるアクセス不可となった。Storage Access Frameworkを使用すれば全てのファイルにアクセス可能。
-Android 11 アプリ固有ディレクトリー以外のファイルアクセスはMANAGE_EXTERNAL_STORAGE 権限を許可することでJava File APIで可能になる模様。（ACTION_OPEN_DOCUMENT_TREEでは外部ストレージと内部ストレージのルートが指定できなくなった）Scoped Storage対応でアプリをSAFに書き換えたのだが、 Android11では無駄になった模様！！何をしたいのか不明で、混乱させているようにしか思えない！！



# 参考
[Android 11 でのストレージに関する更新](https://developer.android.com/about/versions/11/privacy/storage?hl=ja)

>Android 10 デバイスで稼働するアプリが対象範囲別ストレージを無効にする場合、アプリのマニフェスト ファイルで引き続き requestLegacyExternalStorage を true に設定することが推奨されます。それにより、Android 10 を搭載するデバイスで引き続きアプリが想定どおりに動作できます。


[Android11 - Storage（ストレージ）の変更まとめ](https://codechacha.com/ja/android11-storage-updates/)

[Quest２でファイルが参照できない問題の解決法](https://qiita.com/colllet/items/5ab293c52f4bd4e2ecbb)

Quest2はAndroid10
Pixel5はAndroid11

# 検索用
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
【GCP】GCEで外部IPアドレスが割り振られてるVMインスタンスにSSH接続できない

GCEで外部IPアドレスが割り振られてるVMインスタンスにSSH接続できない場合の対応方法の1つを紹介します。

# 状況

- 自分で作成したVPCネットワーク内にVMインスタンスを作成
- 作成したVMインスタンスには外部IPアドレスが割り振られている
- 下のコマンドを実行したがエラーになる

```
$ gcloud beta compute ssh --zone "ゾーン名" "VMインスタンス名" --project "GCPプロジェクト名"

# エラー内容
ssh: connect to host 34.84.16.138 port 22: Operation timed out
ERROR: (gcloud.beta.compute.ssh) [/usr/bin/ssh] exited with return code [255].
```



# 今回の場合の解決方法

- 接続元IPアドレスからtcpプロトコルの22番ポートのアクセスを許可するFirewallルールを作成するだけでOK
- VMインスタンスにtagを設定してる場合は、Firewallルールでtagを指定してもOK

# 公式ドキュメント

- https://cloud.google.com/compute/docs/troubleshooting/troubleshooting-ssh?hl=ja
- めっちゃ詳しく様々なパターンについて書いてあるので、こちらをちゃんと読めばたいていの場合は解決しそう

# 解説

## GCPのVPCネットワークの特徴

AWSは外部からアクセスできるインスタンスを用意するためには、VPC、subnet、IGW、ルーティング、セキュリティーグループを用意する必要があります。

GCPの場合はVPCネットワークを作成するだけで、サブネット、インターネットゲートウェイ、ルーティング、Firewallなど、様々なものを自動で作成してくれます。
なので、GCPでは基本的に、VPCネットワークを作成し、その中に外部IPアドレスを持つVMインスタンスを起動するだけで外部のネットワークと接続できる状態になります。

## 暗黙のFirewallルール

GCPの全てのVPCネットワークには2つの暗黙のFirewallルールがあります。

- ほとんどの下りトラフィックを許可
- すべての上りトラフィックを拒否

（詳細 -> https://cloud.google.com/vpc/docs/vpc?hl=ja#affiliated_resources ）
VPCネットワークを作成すると絶対に存在するFirewallルールになります。
この暗黙のルールはコンソールに表示されません。なので、編集することもできません。

上にあるように暗黙のFirewallルールにより、VMインスタンスへの上りのトラフィックは拒否されてしまいます。
なので、新たにFirewallルールを設定して、VMインスタンスへSSH接続できるようにします。

## Firewallルールを作成する

接続元IPアドレスからtcpプロトコルの22番ポートのアクセスを許可するFirewallルールを作成します。
VMインスタンスにtagをつけてる場合は、tagを設定してあげたほうがいいと思います。

作成したFirewallルールは以下のような感じになります。
![スクリーンショット 2021-02-09 1.17.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84477/6f09593b-4691-413d-985f-32bb3459b5b4.png)

# おわり

GCPはいろいろなものを勝手にやってくれるので楽チンな面もありますが、勝手に色々やられてるので煩わしい面もありますね😅
UdonSharp覚え書き


注意：
本ページに記載されている情報は、Unity, UdonSharp初心者が試行錯誤中に「こうやったら動いた（と思う）」という内容です。
正確な情報はUdonSharpのGitHubページやUnityの公式ページを参照してください。


##調べ物をしたい
「UdonSharp やりたいこと」で出てこない場合、「unity c# やりたいこと」で結構出てきます。そのまま使えるものも多いです。

## Consoleに「TypeLoadExeption」エラーが消えない
TypeLoadException: Could not resolve type with token XXXXXXXX (from typeref, class/assembly TMPro.HorizontalAlignmentOptions, Unity.TextMeshPro, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
か、似たようなエラー消えないときは、SDK3を再Importすると直った。

##ワールドのアップロードが遅いのを何とかしたい
VRChat SDK コントロールパネルのSettingsの「Future Proof Publish」のチェックを外すと、アップロードが早くなります。
\#正式版のPublish時には付けたほうがいいかもしれません。

##同期をローカルでテストしたい
VRChat SDK コントロールパネルのBuilderの「Number of Clients」を2以上にすると、VRChatが複数立ち上がってテストできます。

##オブジェクトの位置をリセットしたい(リスポーンさせたい)
ワールドの初期設定では、Yの値が-100を超えるとリスポーンするので、オブジェクトの座標をY軸を-200とかに設定します。
例：

```
// リスポーンさせたいオブジェクトをUnity側で選択
public GameObject target;

// Interactしたときにリスポーンさせてみる
public override void Interact(){
  Vector3 pos = target.transform.position;
  pos.y = -200.0f;
  target.transform.position = pos;
}
```

##オブジェクトの位置を同期させたい
以下の手順で同期できます。
・Add ComponentからUdon Behaviourを追加。
・Syncronize Positionをクリック。
\#スクリプトを作成しなくていいかは要確認

##あるオブジェクトのスクリプトから別のオブジェクトを取得したい
Hierarchy上で自分の親は`this.GameObject.transparent.parent.GameObject`
あるゲームオブジェクトの子供を名前で指定する場合は`someGameObject.transparent.Find('nameOfChild')`

##別のオブジェクトのスクリプトのメンバ関数にアクセスしたい
例えばhogeというクラス名のstring test()というメンバ関数にアクセスしたい場合
`string test = hogeGameObject.GetComponent<hoge>().test()`

##プレイヤーをあるオブジェクトにワープさせたい
TBD

##プレイヤーから見える距離を制限したい
TBD

##同期変数を使いたい
TBD

##オブジェクトの所有権を取得したい

##長いstringを同期させたい
[Udonsynced]なstringには長さ制限がある模様です。
さらに変数単位ではなく、オブジェクト(1クラスファイル)単位で合計のバイト数での制限のようです。(未検証)
回避策として、文字列を分割し、複数のオブジェクトに持たせれば何とかなる。ただしその分重くなります。

##同期変数の値をCanvas上のTextに反映させたい
TBD
Basemapの使い方


# 天気図をgribファイルから作る方法

Basemapを使えば簡単に作成できるみたいです。
私は、dataの形式がいまいち分からなくて、理解するのに時間がかかりました。
データはgrib2のデータを気象予報センターとかから取得します。


```
import pygrib 

# ファイルを読み込む
grbs = pygrib.open(f"Z__C_RJTD_20171205000000_GSM_GPV_Rgl_FD0006_grib2.bin")
grb = grbs.message(1)

# 日本付近の緯度経度を設定する
lat_min = 28
lat_max = 50
lon_min = 125
lon_max = 150

# ここでデータの取得範囲を設定する
# 指定しなかった場合は、世界地図になる
value, lat, lon = grb.data(lat1=lat_min, 
                           lat2=lat_max, 
                           lon1=lon_min, 
                           lon2=lon_max)

# Basemapにも描画範囲を指定する
map = Basemap(llcrnrlat=lat_min,
              urcrnrlat=lat_max, 
              llcrnrlon=lon_min,
              urcrnrlon=lon_max)

# Basemapのレンダリング座標に変換する
# map(lat, lon)ではなく、map(lon, lat)にするみたいです
x, y = map(lon, lat)

# 海岸の線を引く (コメントアウトすると、意味がわかると思います)
map.drawcoastlines()

# カラーで描画する (contourfならカラーでcontourなら線になる)
map.contourf(x, y, value)
```

### こんな感じのものが描画できました。

![スクリーンショット 2021-02-09 1.00.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537802/9e462151-ab5b-ca2e-8cc4-8dbe1ec743a7.png)
【駆け出しエンジニアメモGit解説①】そもそもGitHubとは？Gitとは少し違う？どんなものなのかを解説。

#GitHubとは
**GitHubとは、Gitを利用した、開発者を支援するWebサービス**の事です。
Gitを使ったバージョン管理や、Gitに関連する様々なサービスを提供しているものです。

GitHubと聞いて、バージョン管理するやつね。と言っていましたが、少し違うようです、、、
GitとGitHubは似ていますが、違うサービスなので混同しないよう注意しましょう。

#Gitとは？
対して、**Gitとは一言で言うとバージョン管理ツール**です。
バージョン管理ツールというのは、アプリケーションなどをアップデートする際に使用するものです。

アップデートする際に、本番環境をそのまま変更していると、使用しているユーザーのアプリケーションにエラーが起きてしまったり、正常に動作しないことが多々存在します。結果的にユーザーはこのアプリめっちゃエラーが出るということで離脱（使うのをやめる）したり、UX（ユーザー体験）を低下させてしまうことになり、ユーザーが逃げてしまうことになります。

そこで、**途中経過を別の環境で実装し、実際にシステムが完成したら本番環境に移すということをやれるようになるのがGit**です。

#Gitで何ができるのか？
Gitでは、先ほど言っていた**「本番環境」**と**「開発環境」**を分けての開発や、リモートとローカルでの開発を分けて考えることができ、他の人との共同開発が可能です。

例えば、Ａさんがログイン機能を作っているときに、同時にＢさんが投稿機能を作っているとすると、2人が同時に完成した時にＡさんのコードにはＢさんのコードが反映されていません。逆にＢさんもＡさんのコードが反映されていない状態です。そして、本番環境はどちらも反映されていません。※世界線が違うと思うと分かりやすいかもしれないです。

ここで、Ａさんが本番環境にコードを移しました。ここで、本番環境にはＡさんが作ったログイン機能は反映されていますが、Ｂさんが作った投稿機能は反映されていません。Ｂさんが本番環境に作ったコードを移すことで、初めて本番環境でログイン機能と投稿機能の両機能が反映されます。
![S__18423847.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673966/9b2f4ba5-d87a-6d1a-db6c-fd1a22df568b.jpeg)


さらに、Gitには削除などもすることができます。例えば、匿名の掲示板のようなアプリに作り替えようと思った際に、Ａさんの作ったログイン機能はいらなくなります。本来ならば、ログイン機能のコード部分を消すなどをするのですが、Gitを使えばＡさんが本番環境に移したものを消すというコマンド一つで終わらすことができるなど、開発の管理をとてもスムーズに快適にすることができるものです。

そして、今説明してきたＡさんの作ったものを本番環境に反映させることや、Ａさんが作った機能を削除する機能などに、それぞれ特殊な名称がついていて、それをGitコマンドを使って実行することができるものです。

#まとめ
GitHubとは、Gitを利用した、開発者を支援するWebサービスであり、
Gitとは、開発におけるバージョン管理ツールである。

# 最後に
最後までお読みになってくださりありがとうございます。もし、参考になったり、少しでも役に立った、良い記事だなと感じていただけましたら**"LGTM"**を押してくださるととても励みになります！！！お願いします！ポチっと押してくださいー！

この記事は、駆け出しエンジニアの筆者が自分のメモと理解向上のために、自分と同じ駆け出しエンジニアでも分かるように、分かりやすく解説することを目的とした記事です。誤った記載をしてしまうかもしれませんがご了承下さい。誤ってる際はコメントにてご指摘してくださると幸いです。

少しでも駆け出しエンジニアの方の力になれると幸いです。また、同じく駆け出しエンジニアの方々、一緒に頑張っていきましょう。

Twitterもやっているのでぜひフォローしてください→https://twitter.com/EngineerShige
【初心者必見】Eclipseで作成したJavaWebアプリケーションをAWSにデプロイする。その③（最終回）

##初めに

[【初心者必見】Eclipseで作成したJavaWebアプリケーションをAWSにデプロイする。その①](https://qiita.com/AIM-Z/items/4848e061f21eacf0e815)
[【初心者必見】Eclipseで作成したJavaWebアプリケーションをAWSにデプロイする。その②](https://qiita.com/AIM-Z/items/4f94257bca30beec2cea)
の作業の続きの記事になるのでそちらを読んでからお越しください。

##STEP7 : jdbcドライバのダウンロードと配置
MySQLのjdbcドライバを以下からインストールする
https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.20
![スクリーンショット 2021-02-09 0.35.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712635/2a724acf-79b5-cbee-e551-7b8f06116608.png)

ここからは対象のWebアプリケーションにDLしたjarファイルを配置する。
DLしたmysql-connector-java.8.0.20.jarをProjectのWebContent/WEB-INF/libへ配置。
その後プロジェクト名で右クリック＞ビルド・ビルドパス＞ビルドパスの構成
「jarの追加」から、今配置したjarへの参照を追加
![スクリーンショット 2021-02-09 0.36.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712635/77a98054-a9da-473f-eb8b-d9eba5519154.png)

##STEP8 : DAOやDB接続のjavaファイルの設定
DBとの接続設定を記述する.javaファイルにて、

DRIVER_NAME = "com.mysql.jdbc.Driver";
URL = "jdbc:mysql://RDSのエンドポイント名/DB名<font color="Red">**?serverTimezone=JST**</font>";

と設定する。
<font color="Red">**赤字のところがないと動作しない。気が狂うほど悩んで解決した。多分AWSの地域設定の関係**</font>
ローカルでやってるときはあんまり考えないけど、AWSは世界的なサービスだからちゃんとタイムゾーンを設定しないとダメみたい。
USER,PASSWORDも自分で設定したものを打ち込む。

上のように記述してローカル環境でプログラムを動かせばRDSにアクセスできる。
適当にローカルで動作確認はしておこう（一旦デプロイしてからの修正は面倒なので）

##STEP9 : jdbcドライバとwarファイルのデプロイ
動作確認までした問題なければアプリをwarファイルに固めていよいよデプロイ。
TeratermからEC2にログインし、mysql-connector-java.8.0.20.jarと作成したwarファイルをTeratermにドラッグ＆ドロップ
次のような画面が出てくるが、そのままOKを押す。→warファイルがホームディレクトリに入る
![スクリーンショット 2021-02-09 0.48.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712635/60bed3f0-50f0-35e2-5b48-14c7683fc236.png)

さて、最後のコマンド操作
先ほど取り込んだ二つのファイルを然るべき場所に配置する。

```
//コネクタをインストール
sudo yum -y install mysql-connector-java

//指定の位置にコピー
cp /usr/share/java/mysql-connector-java /usr/libexec/tomcat8/bin/

//rootで操作していた場合は一度exitし一般ユーザに戻る
//homeディレクトリに戻るのでそこでlsして取り込んだmysql-connector-java.8.0.20.jar、hogehoge.warがあるか確認しておこう

//二つを然るべき場所に配置
sudo mv mysql-connector-java.8.0.20.jar /usr/libexec/tomcat8/bin/
sudo mv historyProgram.war /usr/libexec/tomcat8/webapps/
```

##LAST STEP : 動作確認
次のようにURLを打ち込むとデプロイしたアプリが確認できる。
###http://[EC2のIPアドレス]:8080/[アプリの構成（indexとか）]

DB連携もできるかどうか、 TeratermでMySQLを叩きながら確認しよう。
###<font color="Red">**ここまで長いこと本当にお疲れ様でした！！！**</font>

##残課題
- 今回はVPCの設定などはデフォルトだが、本来はサブネットなど適切に設定が必要
- https（セキュア接続）とかもチャレンジしてみたい
- URLにIPアドレスが入っているのでAWSのRoute53などのDNSサービスを適切に使いたい

##最後に
ここまで読んでいただきありがとうございます。
ストック、LGTM、励みになります。
この記事が何かお役に立てれば幸いです。

[p.s]
二人とも一緒に勉強してくれてありがとう！
https://qiita.com/SG_Sg
https://qiita.com/sukiJava
github actionsのsecretsからファイルを取り出す

ファイルは登録できないので工夫

## TL;DR;

- ファイルをGPGで暗号化し、`asc`ファイルの中身（base64形式）とパスフレーズをsecretsに登録 
- secretsから読み取った内容を `asc`に保存
- パスフレーズでデコードしてファイルを取り出す

## 利用場面例

リリース用のkeystoreファイルをgithub actionで参照したいとき

## ascファイル作成

## secretsに登録

- `asc`ファイルの中身
- パスフレーズ


## ファイルを暗号化してsecretsに登録


```bash
# 保存したいファイル（release.keystore）のディレクトリに移動
cd ./android/app #例
# gpg使えるまでが面倒そうだったのでdockerイメージつかう
docker run -it --rm -v `pwd`:/tmp olbat/gpg /bin/sh
cd /tmp
# 暗号化 パスフレーズを登録
gpg -c --armor ./release.keystore
gpg: keyserver option 'ca-cert-file' is obsolete; please use 'hkp-cacert' in dirmngr.conf
gpg: keybox '/root/.gnupg/pubring.kbx' created
Enter passphrase

Passphrase:
Please re-enter this passphrase
Passphrase:

# ascファイルの中身を取得
-----BEGIN PGP MESSAGE-----

jA0ECQMCYoX81ygPd6Hu0usB6j3tl1lgd7S5NmFGkpElZ2HvZr+n4k9IHUZa6bgm
# ....skip 
5sNiSmj864bjLsVaODFru9FOtZtnvcI1Uv/OFg==
=1d0X
-----END PGP MESSAGE-----
```

- 生成した `asc` ファイルの中身と暗号化のときに使ったパスフレーズをsecretsに登録


## workflows内部でsecretsからファイルを作成する

以下は、`KEYSTORE_GPG`と `KEYSTORE_PASSPHRASE`を参照して ディレクトリ`./android/app/`に `release.keystore｀を保存している例


```yaml
name: "build-android-apk"
on: [pull_request]

jobs:
  build-android-apk:
    name: "build-android-apk"
    runs-on: ubuntu-latest
    steps:
　　　 - name: checkout
　　　 # ... skip ....
      - name: save keystore
        run: |
          echo "${{ secrets.KEYSTORE_GPG }}" > release.keystore.asc
          gpg -d --passphrase "${{ secrets.KEYSTORE_PASSPHRASE}}" --batch release.keystore.asc >  ./android/app/release.keystore
```
No Code開発ツールが使っているクロスプラットフォームフレームワーク

No Code開発ツールにはiOS/Androidアプリを出力できるものがある。
なんらかのクロスプラットフォーム技術が使われていると思われ、興味を持ったのでざっくり調べてみた。

## 調査結果
8個のサービスについて調査したところ、

- React Nativeが、2サービス(Adalo/Thunkable)で使われている
- Flutter、Capacitor、Cordovaを使っているサービスは探した範囲では見当たらなかった。

## 調査結果詳細
ざっくり調べたので、すぐに分からなかったところは?を入れてある。

|サービス名|Webアプリ|iOSアプリ|Androidアプリ|iOS/Androidアプリフレームワーク|
|:--|:--|:--|:--|:--|:--|
|[Glide](https://www.glideapps.com/)|o|	x	|x|	-|
|[Adalo](https://www.adalo.com/)|	o	|o|	o	|React Native (根拠 https://developers.adalo.com/docs/workflow/cross-platform/)|
|[Bubble](https://bubble.io/)|	o	|x	|x	|-|
|[Thunkable](https://thunkable.com/#/)|	o	|o|	o	|React Native (根拠 https://community.thunkable.com/t/thunkable-is-using-react-native/3557)
|[AppSheet (Google傘下)](https://www.appsheet.com/)|o|	o|	o|	?
|[Amazon Honeycode](https://www.honeycode.aws/) |?	|?	|?|	?|
|[Yappli](https://yapp.li/)|?	|?|	?|	?|
|[Appify](https://appify.jp/)	|?|	?	|?	|? (SwiftUI/Jetpack Composeだという情報あり)|
【Ruby】ファイルや標準出力にログを出力したい

# ログを出力したい
Rubyでログを出力する場合は標準ライブラリの`Logger`を使用するとログ出力ができます。


## ログサンプル

```ruby
require 'logger'

log = Logger.new(STDOUT)

log.fatal("fatal message")
log.error("error message")
log.warn("warning message")
log.info("information message")
log.debug("debug message")
```

上記を実行すると以下のようなログが出力されます。

```
F, [2021-02-09T00:35:18.126927 #1063] FATAL -- : fatal message
E, [2021-02-09T00:35:18.127010 #1063] ERROR -- : error message
D, [2021-02-09T00:35:18.127024 #1063] DEBUG -- : debug message
I, [2021-02-09T00:35:18.127034 #1063]  INFO -- : information message
W, [2021-02-09T00:35:18.127042 #1063]  WARN -- : warning message
```
`Logger`で定義されているログの重要度は以下のように分かれています。
ログレベル

|  重要度  |  説明  |
| ------- | ----- |
|  FATAL  |  プログラムで対処不可能なエラー  |
|  ERROR  |  プログラムで対処可能なエラー  |
|  WARN   |  警告  |
|  INFO   |  一般的な情報  |
|  DEBUG  |  開発者向け情報  |


## 参考文献
Ruby 3.0.0 リファレンスマニュアル 
class Logger
https://docs.ruby-lang.org/ja/latest/class/Logger.html
[Ruby on Rails]  サーバー重複時の対処法について

自身の失敗から学んだことを書いて行きます。
  


まず、**rails s**コマンドで**localhost:3000**を起動中に重たくなって動かなくなったって事ありませんか？？


大抵が**control****+****C**を押せば直るんですけど、
その時、直らなくて焦ってターミナルを強制的に切ってしまったんです。
　　

すると、新しく開いたターミナルでサーバーが開かなくなってしまいました。
原因は<h3>サーバーが既に起動していたから


サーバーを付けたまま強制終了するとこいう事が起こるらしい。

　
その**解決方法**がこちら
　
　
先ほど新しく開いたターミナルで
<h4>lsof -i:3000
　

とコマンドを打つと![スクリーンショット 2021-02-09 0.24.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1078698/3b6b1062-ab7e-cb72-463c-da2042b288f8.png)

こんな感じで先ほど使っていたサーバーの状況を確認できます。

右の方に表示されている**（CLOSE_WAIT)**と書いてあるのが
**『サーバーが待機していますよ』**と言う証拠になります。（間違っていたらすみません。）

確認できたので、あとは**PID**のナンバーを確認して**kill**してあげます。
　
<h4>kill -9 18313
　

とコマンドを打つと、恐らくkillされて、
重複していたサーバーが元通りです。

最後に**rails s**で確認してみましょう。
これで元に戻っていたらok！


　

間違い等ございましたら、ご指摘、ご教示のほどよろしくお願い致します。
JUCE: バックグラウンドでの再生On/Offのコントロール

##課題##
JUCE/ProjucerのAudio Pluginテンプレートで作成したiOSアプリは、CapabilitiesでAudioのバックグランド再生をOnにするとその通りバックグラウンドでも再生できるが、常に再生になっている。これはユーザーにOn/Offを委ねたいところだが、テンプレートにはその機能は備わっていない。

##前提##
JUCE/ProjucerでAudioプラグイン/アプリを作っている。

##解決方法##
https://forum.juce.com/t/ios-background-processing/38308 に答えがあるのですが、JUCEApplicationBase::suspended()がバックグラウンドに回った時に呼ばれ、JUCEApplicationBase::resumed()がフォラグラウンドになった時に呼ばれるので、これらをオーバーライドすればできます。

Projucerの設定でPreprocessor DefinitionsにJUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1を書いておいて、juce_StandaloneFilterApp.cppをまんまコピーしたMyStandaloneFilterApp.cppをプロジェクトに追加しておきます。

その上で、単にAudioのOn/Offをするのであれば、下記のコードでOK。

```MyStandAloneFilterApp.cpp
    void suspended() override
    {
        StandalonePluginHolder* holder = StandalonePluginHolder::getInstance();
        jassert(holder != nullptr);
        holder->stopPlaying();
    }

    void resumed() override
    {
        StandalonePluginHolder* holder = StandalonePluginHolder::getInstance();
        jassert(holder != nullptr);
        holder->startPlaying();
    }
```

実際には、プラグインにフラグを持たせておいてそのフラグによってこの処理を行うか否かを決定することになると思うので、下記のような感じになるかと。

```MyStandAloneFilterApp.cpp
    void suspended() override
    {
        StandalonePluginHolder* holder = StandalonePluginHolder::getInstance();
        jassert(holder != nullptr);
        MyAudioProcessor* processor = (MyAudioProcessor*)holder->processor.get();
        jassert(processor != nullptr);
        if (!processor->isBackgroundProcessingEnabled())
        {
            holder->stopPlaying();
        }
    }
    void resumed() override
    {
        StandalonePluginHolder* holder = StandalonePluginHolder::getInstance();
        jassert(holder != nullptr);
        MyAudioProcessor* processor = (MyAudioProcessor*)holder->processor.get();
        jassert(processor != nullptr);
        if (!processor->isBackgroundProcessingEnabled())
        {
            holder->startPlaying();
        }
    }
```
how install python version 3.9.0 in macOS Big Sur 11.2


#I bought new mac book pro and set up my env.

But pyenv install 3.9.0 is not working...

#新しいMacBook Proを購入してセットアップ！
しかし、pyenv install 3.9.0 がerror。lol


```
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.9.0.tar.xz...
-> https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tar.xz
Installing Python-3.9.0...
python-build: use readline from homebrew

BUILD FAILED (OS X 11.2 using python-build 20180424)

Inspect or clean up the working tree at /var/folders/kl/fg7hszwx3hldt471m8jdkr0m0000gn/T/python-build.20210208235816.6951
Results logged to /var/folders/kl/fg7hszwx3hldt471m8jdkr0m0000gn/T/python-build.20210208235816.6951.log

Last 10 log lines:
checking for python3.9... python3.9
checking for --enable-universalsdk... no
checking for --with-universal-archs... no
checking MACHDEP... "darwin"
checking for gcc... clang
checking whether the C compiler works... no
configure: error: in `/var/folders/kl/fg7hszwx3hldt471m8jdkr0m0000gn/T/python-build.20210208235816.6951/Python-3.9.0':
configure: error: C compiler cannot create executables
See `config.log' for more details
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
```

I see...

```
BUILD FAILED (OS X 11.2 using python-build 20180424)
```

Okey.

review my setup.

Lets installed __Homebrew__!!!

and then

```

brew install pyenv
```

then above message "Build Failed" showed up.

I had no idea what I miss. Because I usually used to use windows OS.

I checked same problem who had at stack overflow.

https://stackoverflow.com/questions/51551557/pyenv-build-failed-installing-python-on-macos

I tried install
とりあえずxcodeが足りなかったわけなのね！

```
xcode-select --install
```

then my problem was solved. XD
checked version

```
pyenv versions
pyenv global 3.9.0
```

execute my setting

```
zsh -l
```

annnnnnnd

```
python --version
```

done!!!
you can checked also from this command too ↓

```
pyenv versions
```

have happy python life :)

xoxo
UniRxのFirstオペレータを使ったらInvalidOperationException: sequence is empty

# UniRxのFirstオペレータを使ったらInvalidOperationException: sequence is empty

## 経緯

UIに一定時間触れないと自動で消えてくれるようにしてくれ！と言われたのでこんなコードを書いた。

```C#
private float _lastTime;
private float lifespan;

private void OnEnable()
{
    this.UpdateAsObservable()
        .First(_ => Time.unscaledTime - _lastTime > lifespan)
        .Subscribe(_ =>
        {
            // UIが消える処理
        });
}
```

できたできたと思っていたら、`シーンから離れるとエラーになる`と言われた。

```
InvalidOperationException: sequence is empty
```

## AddTo忘れてた！

ちゃんと購読中止するの忘れてた、と思ったので`.AddTo(this)`を追加

```C#
private float _lastTime;
private float lifespan;

private void OnEnable()
{
    this.UpdateAsObservable()
        .First(_ => Time.unscaledTime - _lastTime > lifespan)
        .Subscribe(_ =>
        {
            // UIが消える処理
        })
        .AddTo(this);
}
```

それでもエラーは解消されない。

```
InvalidOperationException: sequence is empty
```

そもそも`UpdateAsObservable`はオブジェクトの破棄時に自動でDisposeしてくれるらしい
[参考](https://qiita.com/toRisouP/items/30c576c7b0a99f41fb87#updateasobservableとobservableeveryupdateの使い分け)
めっちゃ便利ですね。

## FirstはOnNextを発行しなければならない

どうやら`First`オペレータは値を発行する前に`OnCompleted()`しようとすると怒るらしい。
UniRxのソースコードは次のようになっている。

```C#
public override void OnCompleted()
{
    if (parent.useDefault)
    {
        if (notPublished)
        {
            observer.OnNext(default(T));
        }
        try { observer.OnCompleted(); }
        finally { Dispose(); }
    }
    else
    {
        if (notPublished)
        {
            try { observer.OnError(new InvalidOperationException("sequence is empty")); }
            finally { Dispose(); }
        }
        else
        {
            try { observer.OnCompleted(); }
            finally { Dispose(); }
        }
    }
}
```
`useDefault`が`false`かつ`notPublished`が`true`だと冒頭のエラーを吐くようになっていることがわかる。
`notPublished`は`OnNext()`の中で`false`にセットされる。
`First`オペレータは`useDefault`が`false`となってしまうので、値を発行する前に`Dispose`しようとする（今回はシーン移動によるオブジェクトの破棄がきっかけ）とエラーとなってしまう。

## 対策

`First`ではなく`FirstOrDefault`を使用する！
これで`useDefault`がtrueとなり、`OnNext()`を呼ぶ前であってもDefaultの値を発行した後、正しく購読中止される。

↓が完成形のコード

```C#
private void OnEnable()
{
    _lastTime = CurrentTime();
    this.UpdateAsObservable()
        .FirstOrDefault(_ => Time.unscaledTime - _lastTime > lifespan)
        .Subscribe(_ =>
        {
            // UIを消す処理
        });
}
```
Ichigojam BASICでDS1307+を使い時間を表示する。


前にichigojam用に書いたプログラム
書いたのは、本人だからコピーでは、ない。
説明は、特にない。

```

10 'GOTO 100:'DS1307
20 H=0:M=0
30 INPUT "H 0-23>",H
40 INPUT "M 0-59>",M
50 A=(M/10)*16+(M%10)
60 B=(H/10)*16+(H%10)
70 POKE #700,0,0,A,B,3,1,1,#20
80 R=I2CW(#68,#700,1,#701,7)
90 'READ
100 POKE #700,0
110 R=I2CR(#68,#700,1,#701,7)
120 FOR I=3 TO 1 STEP -1
130 ?HEX$(PEEK(#700+I));
140 IF I<>1 THEN ?":";
150 NEXT
160 WAIT 60:?
170 GOTO 100

```
create-react-appで環境変数の設定


## 前提
create-react-appには、[dotenv](https://github.com/motdotla/dotenv#readme)というパッケージが既に入っている。

## 環境変数の設定
`.env`ファイルを作成して環境変数を書く。ただ命名ルールがあり`REACT_APP_`から始める必要がある。

例

```
const apiURL = process.env.REACT_APP_API_URL
```

## 環境変数の読み込み方

Typescriptの場合、`config.ts`を作成して一括で環境変数を管理するのが良さそう。

```
type _Config = {
  apiUrl: string;
}
  
const Config: _Config = {
  apiUrl: process.env.REACT_APP_API_URL || ""
}
  
export default Config
```

読み込み例

```
import Config from "./config";
import axios from 'axios';

axios.get(Config.apiUrl).then(function (response) {
  console.log(response);
})
```

参考
https://sumii.io/posts/create-react-app-env-setup/
https://create-react-app.dev/docs/adding-custom-environment-variables/
Janomeで固有名詞の登場順を得る。


```Python
text="長い文章"
zyogaiList=["名詞,代名詞","名詞,非自立","名詞,数"]#除外
cf = [UnicodeNormalizeCharFilter()]#前処理フィルタ
    tf = [CompoundNounFilter(),POSKeepFilter(["品詞"]),POSStopFilter(zyogaiList),TokenCountFilter(att='base_form')] #後処理フィルタ準備 att="base_form"で品詞活用をまとめて基本形のみにする
    a = Analyzer(char_filters =cf,token_filters=tf)#解析器生成
    results = a.analyze(text)#解析
    print(syurui,"登場順")
    s =sorted(results, key=lambda x:x[1],reverse=True)#結果並べ替え
    for i,wc in enumerate(s):
      if i >= 50:break
      print((i +1),':',wc)
```
こういうやつで

```python

POSKeepFilter(["品詞"]
```
の品詞を"名詞"とか"動詞"とかにすることで、その品詞に該当する登場順が出力できることは本にもwebにも載っている。
でも**固有名詞**pを出したいときどうすれば良いのかが見つからなかったので、備忘録として残した。

結論
**名詞,固有名詞**
とすればいい！

つまり

```python
POSKeepFilter(["名詞,固有名詞"])
```
こういうことであり、

最初に提示したコードなら


```python

text="長い文章"
zyogaiList=["名詞,代名詞","名詞,非自立","名詞,数"]#除外
cf = [UnicodeNormalizeCharFilter()]#前処理フィルタ
    tf = [CompoundNounFilter(),POSKeepFilter(["名詞,固有名詞"]),POSStopFilter(zyogaiList),TokenCountFilter(att='base_form')] #後処理フィルタ準備 att="base_form"で品詞活用をまとめて基本形のみにする
    a = Analyzer(char_filters =cf,token_filters=tf)#解析器生成
    results = a.analyze(text)#解析
    print(syurui,"登場順")
    s =sorted(results, key=lambda x:x[1],reverse=True)#結果並べ替え
    for i,wc in enumerate(s):
      if i >= 50:break
      print((i +1),':',wc)
```

こうすると実現できる。
STM32F767のArduinoでの時計,DS1307+で時刻表示(i2c)


1.SCLとSDAを接続、プルアップも忘れずに
2.電源の接続
3.下記のソースコードを書き込む
4.コンパイル実行で表示されたら終了
5.おわり

```c++

#include <Wire.h>

// デバイスアドレス(スレーブ)
#define ADDR    0x68    // 2進数 1101000

int u_key;      // 受信データを格納するchar型の変数
int ch_in_key() {

  // 受信データがあった時だけ、処理を行う
  while(!Serial.available()) {}       // 受信データがあるか？
  u_key = Serial.read();            // 1文字だけ読み込む
  
  return(u_key);
}

int  ch_i;      //文字列のループカウンター
char ch_b[8+1]; //文字列のバッファー
int  ch_y;      //一文字分の一時バッファー

void ch_input()
{
    ch_i=0;
    while(1) {
        ch_y = ch_in_key();
        if(ch_y == 13){ch_b[ch_i]=0;Serial.println();break;}
        ch_b[ch_i]=ch_y;ch_i++;
        Serial.write( ch_y );
        if(ch_i >= 8){ch_b[ch_i]=0;Serial.println();break;}     
    } //while
} //ch_input

char ch_hex_b[3];
char *ch_hex(int l_num)
{
    ch_hex_b[0] = '0' + (l_num >> 4);
    ch_hex_b[1] = '0' + (l_num & 0xf);
    ch_hex_b[2] = 0;
    return(ch_hex_b);
}

void setup() {
  Serial.begin( 9600 );     // シリアル通信を初期化する。通信速度は9600bps

  // マスタとしてI2Cバスに接続する
  Wire.begin();

}

int h;
int m;
int a;
int b;

int p_val;
char data_read[16];
char cmd[2]={0,0};
int ii;     //ループカウンタ

void loop() {

///*INIT start *********  

    Serial.println( "" );  //改行

    Serial.print("H 0-23>");
    ch_input();         //文字列の入力
    h=atoi(ch_b);

    Serial.print("M 0-59>");
    ch_input();         //文字列の入力
    m=atoi(ch_b);

    a=(m/10)*16+(m%10);
    b=(h/10)*16+(h%10);

      // I2Cスレーブに対して送信処理を開始する
  Wire.beginTransmission(ADDR);
 
    // レジスタのアドレスを指定する(0-63の内、先頭から)
    Wire.write(0x00);
  
    // ---------------------------------
    //  タイマーキーパーレジスタ
    // ---------------------------------
    // 2進化10進数(BCD)で指定します。(03以外)
  
    // [00]Seconds(45秒)
    Wire.write(0);
    // [01]Minutes(59分)
    Wire.write(a);
    // [02]Hours(23時)
    Wire.write(b);
    // [03]Day(月)
    // 1:日 2:月 3:火 4:水 5:木 6:金 7:土
    Wire.write(3);
    // [04]Date(31日)
    Wire.write(1);
    // [05]Month(12月)
    Wire.write(1);
    // [06]Years(2017年)
    Wire.write(0x20);
 
  // I2Cスレーブへの送信完了
  Wire.endTransmission();

//*/  //INIT end *********

while(1){

  // レジスタのアドレスを先頭にする
  Wire.beginTransmission(ADDR);
    Wire.write(0x00);
  Wire.endTransmission();

  // I2Cスレーブに8byteのレジスタデータを要求する
  Wire.requestFrom(ADDR, 8);
 
  // 8byteのデータを取得する
  for (ii = 0; ii < 8; ii++) {
    while (Wire.available() == 0 ) {}
    data_read[ii] = Wire.read();
  }


        ii=2;
        while(1){
            Serial.print(ch_hex(data_read[ii]));
            ii--;
            if(ii==-1){break;}else{Serial.print(":");}
        }
        Serial.println("");

 
  delay(1000);

}//while

} //loop

```

H 0-23>0
M 0-59>22
00:22:00
00:22:00
00:22:01
00:22:02
00:22:03
00:22:04
00:22:05
00:22:06
Vue使う際の始動手順

こっちもReact同様、やるときいつも「あーなんだっけ」となるので、後で見返したりうっかり忘れたりした時のためにまとめておきます

## TL;DR
Vue使ってプロダクト作ったりする際の、サーバ起動あたりのコマンド軽くまとめ

## 前提条件（環境）
・Windows10
・npm

### 結論だけ
PowerShell開いて、プロジェクトのディレクトリ置きたいディレクトリに`cd`とかで入って以下のコマンド

```
vue create 作りたいプロジェクト名
cd 今作ったプロジェクト名
npm run serve
```
これを実行することで、 `http://localhost:8080/` （環境により違うかも）で作ったページが見れる
URLは`nupm run serve`したときに出てくる

## 詳細な過程

### Windows PowerShellを起動
コマンド叩いて実行する必要があるので、Windows環境ゆえWindows PowerShellを起動する必要があります
（Macだったらコマンドプロンプト、また使用するIDEによってはIDE上でできることも）
なので、検索欄なりスタートメニューなりからWindows PowerShellを起動します

### 対象のディレクトリに移動
起動コマンドについては、 `vue create 作りたいプロジェクト名` で用意し、作っているVueプロダクトのあるディレクトリで起動する必要があります
そのため、まずcdコマンドで対象のディレクトリ（ `package.json` のあるところ）に移動します

### コマンド実行制限の部分解除（場合による）
セキュリティのために、Set-ExecutionPolicyコマンドレットによってスクリプト実行の制限がなされていることがあります（「~ cannot be loaded because running scripts
is disabled on this system.」「このシステムではスクリプトの実行が無効になっているため、～を読み込むことができません」とか出てきたらこれ）
その場合は、以下のコマンド叩いてスクリプト実行の制限を、とりあえずローカルのファイルからは許可するように「RemoteSigned」に設定し、制限を部分解除すれば実行できるようになります

```
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
```
やり終えたら

```
Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope Process
```
あたりで戻しておくと安全かもしれません
（状態に関しては `Get-ExecutionPolicy` コマンドで確認可能。今回の本題とは外れるので詳しく調べたい場合はググって）

### サーバ起動
頻出なのでわざわざ言うことは無いと思う以下のコマンドで起動します

```
npm run serve
```
yarn使ってる場合はまた変わってきます（ `yarn run` とか）

### ページ確認
ここまでやれば `http://localhost:8080/` （環境により違うかも）にアクセスすることで、対象Vueプロダクトのページが開きます
アクセスするURLについては、`npm run serve`した際に提示されます
あとは確認しながらVuetいじってください



こっちも多分自動化する手段とかはありそう
zipメソッドを使って複数の配列を同時に取り出す

##複数のタグを同時に表示させたかった
タグ付け機能を複数実装し、同じページに表示させようとした際に便利なメソッドを見つけたので備忘録として残しておく。

##zipメソッドの使い方
zipメソッドを使うことで、複数の配列から同時に取り出すことができる。

```ruby
tag1 = ['test1', 'test2', 'test3']
tag2 = ['テスト1', 'テスト2', 'テスト3']

tag1.zip(tag2) do |tag1, tag2|
  puts tag1
  puts tag2
end
```
上記のように記述すると以下の実行結果となる。

```
test1
テスト1
test2
テスト2
test3
テスト3
```
vSphere系でやポートを指定した疎通確認

# vSphere系でやポートを指定した疎通確認

個人的な備忘のために投稿
業務でvSphere系、特にvCenter(vCSA)やUsageMeterを触っているときに443ポートで疎通確認が必要になった。
`ping`はNW機器で疎通不可
`telnet`でできればよかったのだが、vCSAやUMには入っていなかったため、`curl`と組み合わせることで実施。

```
$curl -v telnet://<IP or FQDN>:443
```

telnetがある環境なら以下でできる

```
telnet <IP or FQDN> 443
```