OmniAICreator/Qiita-1.07M huggingface dataset:
scpの代わりにrsyncでファイル転送を行う方法


##はじめに
なんでも昨年2019年4月17日のOpenSSHの公式リリースで、scpは非推奨とのアナウンスがあったそうで。先日誰かのtwitterを見て知りました。遅せぇよ俺。
OpenSSHの公式リリースを見ると、OpenSSH 8.0/8.0p1 (2019-04-17)のリリースノートに記載がありました。
https://www.openssh.com/releasenotes.html
https://www.openssh.com/txt/release-8.0
>The scp protocol is outdated, inflexible and not readily fixed. We
>recommend the use of more modern protocols like sftp and rsync for
>file transfer instead.

確かに。ファイル転送にはsftpやrsyncを代わりに推奨って書いてありますね。

Linuxでサーバを建てた時、パスワード無しログインに必要なauthorized_keysとか、自分のbash_profileをサーバへ送り込むのにscpを使っていましたが、これからはお作法としてはあまりよろしくない、ってことですね(そんな大事なファイルをscpとかネットワーク経由で送るってこともあまりよろしくないですが…)。
急にscpが使えなくなる、ってことはないでしょうけど、お行儀の良い手順として、rsyncでファイルを転送する手順を記録しておきます。

##環境
クライアント側はmacOS 10.13.6
サーバ側はUbuntu 20.04(VirtualBox)
サーバ側（送信先）でsshdが動作していることとします。
たまにmacとLinuxだとBSDとGNUのコマンドの違いでオプションが違っていることがありますが(dateコマンドで泣いた)、今回は両方とも当然BSDのscp(というかssh)なので、OSによる違いは無いと思います。


##今までのscpによるファイル転送

~~~
scp [転送するファイル] ログイン名@サーバアドレス:[サーバ側のコピー先絶対パス]
~~~

##scpの実行例
~~~
$ scp ./memo.txt hogehoge@192.168.0.12:/home/hogehoge/memo.txt
hogehoge@192.168.0.12's password: ※パスワード入力
memo.txt               100%   32    18.3KB/s   00:00 
~~~

##rsyncでファイルを転送する場合

~~~
$rsync -av ログイン名@サーバアドレス:[サーバ側のコピー先絶対パス]
~~~


ほとんど同じですね。~~ポイントはオプションに「-e "ssh"」を追加すること。~~
(ご指摘があり、rsync ver2.6.0以降では必要無いので修正します)
もし、サーバ側のsshのポート番号を変更している場合は「-e "ssh -p 2222"」という感じで、-eオプションでsshを指定、-pオプションでポート番号を指定してください。
~~rsyncのmanを見ると「-e, --rsh=COMMAND specify the remote shell to use」とあります。~~


一応、rsyncのオプションに指定した-avの説明

|オプション|説明|
|-----------:|:------------|
|**-a:**|**-rlptgoDと同じ(いろいろあるんですよねぇ。以下で説明)**|
|-r:|指定ディレクトリ配下をすべて対象とする|
|-l:|シンボリックリンクは、そのままシンボリックリンクとしてコピー|
|-p:|パーミッションをそのままコピー|
|-t:|タイムスタンプをそのままコピー|
|-g:|グループをそのままコピー|
|-o:|ファイル所有者をそのままコピー|
|-D:|デバイスファイルや特殊ファイルを保持(--devices --specialと同じ)|
|**-v:**|**verboseモード。動作状況を表示。**|

##rsyncの実行例

~~~~
$ rsync -av ./memo.txt hogehoge@192.168.0.12:/home/hogehoge/memo.txt
hogehoge@192.168.0.12's password: ※パスワード入力
building file list ... done
memo.txt

sent 160 bytes  received 42 bytes  134.67 bytes/sec
total size is 32  speedup is 0.16
~~~~

今回はファイル1個だけですが、本来の(？)rsyncの使い方である、同期をとるような場合は、ディレクトリのお尻にケツスラッシュが有ると無いとでは動作が大違いなので、こちらのサイトを参照して気をつけましょう。
（適当にディレクトリを指定すると、中身を転送先にブチまけて悲しい思いをします）

scpとrsyncでパスのケツスラッシュのありなしの挙動を毎回迷うのでメモ
http://oretachino.hatenablog.com/entry/2014/12/11/003815

追記
2020/06/07修正
ご指摘があり、rsyncの2.6.0以降ではsshがデフォルトのリモートシェルとなったので、「-e ssh」オプションは必要ないとのご指摘があり、実際に-eオプションは必要無いので修正しました。

rsyncのリリースノートにも記載がありました。
https://rsync.samba.org
>The default remote shell is now "ssh" unless you tell configure you want to make 
>something else the default.

2004年1月1日なので結構昔ですね。

2020/07/01修正
修正漏れがあったので直すついでにもう一度上記コマンドを別の環境で試したところ、動かない…

~~~~
rsync -av ./memo.txt hogehoge@192.168.0.51:/home/hogehoge/memo.txt
hogehoge@192.168.0.51: 
bash: rsync: コマンドが見つかりません
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
~~~~
「コマンドが見つかりません」ってrsync実行しているでしょ？
と思ったら、接続先にrsyncがインストールされてなかったというオチでした。
パスワードを入力した後ですからね、それりゃ手元の環境ではなく接続先ですよ。
備忘録)PowerShellでVimを使う

#実行環境
windows10
vim8.2.0577

#方法
1.vimインストール、[こちら](https://github.com/vim/vim-win32-installer/releases/tag/v8.2.0577)から
2.
powershellで以下のコマンドを実行
```> get-executionpolicy```
RemoteSignedが返ってきたらOK→Step3へ

RestrictやBypassの場合は
```set-executionpolicy remotesigned```
を実行

3.
```$profile```
を実行。設定ファイルの場所を確認
帰ってきたパスをエクスプローラーで開き、profile.ps1ファイルをエディタで編集

以下を追加
```set-alias vi 'C:\Program Files (x86)\Vim\Vim82\vim.exe'
set-alias vim 'C:\Program Files (x86)\Vim\Vim82\vim.exe'```

C:\Program Files (x86)\Vim\Vim82\vim.exeはvimをインストールした場所を入力。

4.powershellでvim or vi 実行
【python】雲を渡っていくゲームの最短ステップ数を求めるプログラム

#【python】雲を渡っていくゲームの最短ステップ数を求めるプログラム

▼設問

- ０または１が複数入ったlistが与えられる。
- ０は普通の雲。１は雷雲。
- インデックス番号が雲の番号になる。
- 雲を辿って最後のインデックス番号にたどり着けばゴール。
- 雲をたどるときにジャンプできるのは+１か+２。
- 雷雲は避ける。
- ゴールまでに必要な最短のジャンプ回数を求める（必ずゴールできる）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/3af58d7b-ae83-f4de-cf49-133c55af2457.png)

[URL](https://www.hackerrank.com/challenges/jumping-on-the-clouds/problem)

▼sample input

```python:
6
0 0 0 0 1 0
```

▼sample output

```python:
3
```

▼my answer

```python:
def jumpingOnClouds(c):
    i= ans = 0
    while i <= len(c)-2:
        #最終地点の１個前の場合
        if i+2 == len(c):
            ans += 1
            return ans
            
        #２個とばし可能か？
        elif c[i+2] != 1:
            i += 2
        else:
            i += 1
        ans += 1
    return ans

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')
    n = int(input())
    c = list(map(int, input().rstrip().split()))
    result = jumpingOnClouds(c)
    fptr.write(str(result) + '\n')
    fptr.close()
```



<br>
**・returnのあとに代入する式はかけない**
☓ return ans += 1
◯ return ans


**・len(c)**
要素の数を求める。※1以上
c[len(c)]は存在しない。


**・「!」**
!が前にくる
☓ a =! 3
◯ a != 3
[truncate]文字列が省略されているかをチェックする[JavaScript]

## 背景

文字列が長い時に、3点リーダーで省略したいというケースは結構あると思います。
その際に、css(text-overflow: ellipsis)で対応することもあるあるかなと(思っています。)

もし文字列が省略されたときに追加で処理を加えたいという場合はどうするかというのが今回のテーマです。

## 結論
scrollWidthとoffsetWidthを使います

### 以下、解説

#### 前提
こんなvueファイルがあったとします

```vue
<template>
  <div class="long-text">{{ longText }}</div>
</template>

<script>
export default {

  data() {
    return {
      longText:
        'ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんぁあぃいぅうぇえぉおかがきぎくぐけ'
    }
  }
}
</script>

<style>
.long-text {
  width: 200px;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
  background-color: pink;
}
</style>

```

こんな感じで表示されます(しっかり3点リーダーで省略されています)
![スクリーンショット 2020-06-06 11.05.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151354/91eb70bd-3dbf-fa9d-ef97-9e9a8cb2fa9e.png)

以下、文字列が省略されているかを確認するために試して、失敗例と成功例を記載します

#### 失敗例 DOMを取得して、実際の文字列(dataプロパティ)とDOM上の文字列の長さを比べたらいいのでは？

下のように$refsでDOMを取得してみました

```vue

<template>
  <!-- refを追加 -->
  <div ref="text" class="long-text">{{ longText }}</div>
</template>

<script>
export default {
  mounted() {
    // $refsでDOMを取得する
    console.log('this.$refs.text', this.$refs.text)
  },
  data() {
    return {
      longText:
        'ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんぁあぃいぅうぇえぉおかがきぎくぐけ'
    }
  }
}
</script>
```

まんま表示されてました。。。
lengthを使って文字列の長さを比べる方法では無理だなと判断しました。
![スクリーンショット 2020-06-06 11.12.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151354/cd5e9154-44fc-f2d5-27f4-99be2e86a562.png)

#### 成功例 lengthではなくoffsetWidthとscrollWidthを使う

$refsを使うところは変わらず、consoleでoffsetWidthとscrollWidthを確認してみます

```javascript
console.log('offsetWidth', this.$refs.text.offsetWidth)
console.log('scrollWidth', this.$refs.text.scrollWidth)
```

consoleで表示された値

![スクリーンショット 2020-06-06 11.15.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151354/6502c744-8920-cabd-746b-aab0bc64f7fd.png)

offsetWidthが表示されている幅で、scrollWidthが省略される前の実際の幅です
この値が合わないということは省略されていると判断していいと思います

## まとめ
省略されているときに何か追加処理することは結構あると思います。
省略される前の全文をポップアップで表示したいとか、prefixをつけたいとかとか
そんな時はぜひお試しくださいまし
TechAcademyが無料公開している「HTML・CSS入門講座」を受講する～HTML第1-3回～

# アジェンダ
* HTMLファイルに必要なタグ
* index.htmlについて
* HTMLファイルを作る
* 字下げについて

# HTMLファイルに必要なタグ
## doctype
HTMLファイルがどのHTMLバージョンで書かれているかを示すタグ。
タグで宣言する際は、doctypeの前に!を付ける必要がある。

HTML5の場合は、```<!doctype html>```

## html
このタグで囲われた内側が、HTMLの本文であることを示すタグ。
原則、上記のdoctype以外は全てこのタグの中に記述する。

htmlタグと同時に lang="" を記載することで、このHTMLファイルの文章がどの言語で書かれているかを指定できる。
日本語を指定する場合は、```<html lang="ja">```

## head
このタグで囲われた内側が、HTMLファイルを解釈する上で必要な情報であることを示すタグ。
Webページのタイトルや、メタデータを記述できる。

## body
このタグで囲われた内側が、HTMLファイルの本文であることを示すタグ。
Webブラウザで表示させる内容を記述する。

# index.htmlについて
Webサーバにアクセスした際、最初に表示されるHTMLファイルの名前。
絶対ではないが、一般的にはindex.htmlが主流。

# HTMLファイルを作る
HTMLファイルに必要なタグを書いて、HTMLファイルを作るとこんな感じ。

```html:index.html
<!doctype html>

<html lang="ja">
  <head>
  </head>
  <body>
  </body>
</html>

```

内容ないけどなんかカッコイイ！

# 字下げについて
HTMLのうち、「どこから」「どこまで」が「どのタグの内側か」をわかりやすくするために、__字下げ__を行う。
上記のindex.htmlで言うと、\<head>と\<body>は、\<html>タグの内側にあるので、一つ字下げを行っている。

必須の記法ではないが、HTMLファイルを見やすくするために心がけるべきだろう。

# おわりに
今回は、どの言語にもある「おまじない」に関する内容だった。
doctypeについてはおまじないとしか思っていなかったので、理解できてよかった。

次回 >> [ここ](https://qiita.com/MakoMakoMakotsu/items/5e18a300f8be9d947ee4)

## 参考
[1-3 HTMLの基礎構造（はじめてのHTML）](https://www.youtube.com/watch?v=LlnwZaYRFcQ&t=6s)
Nodeのバージョンを12に上げたら`Cannot find module '@babel/compat-data/corejs3-shipped-proposals'`というエラーが出て困った

Nodeのバージョンを12に上げた際、`Cannot find module '@babel/compat-data/corejs3-shipped-proposals'`というエラーが出たので解決法をメモ

結論

@babel/coreと@babel/preset-envのバージョンを以下に指定したら解消された。

"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.0",

参考にしたリンク
https://github.com/storybookjs/storybook/issues/10477
Raspberry Piのセットアップ（備忘録）

# Raspberry Piのセットアップ（備忘録）

## OSイメージの準備
https://www.raspberrypi.org/downloads/
Raspberry Pi ImagerをダウンロードしてRaspberry pi OSを選択。（楽になったものだ……）

## ヘッドレスセットアップの準備
### SSH
SDカードのルート直下に`ssh`（拡張子なし）というファイルを作成することでsshが有効化される。（デフォルトではsshは無効）

### 無線LANの定義
SDカードのルート直下にSSIDとパスワードを記載したwpa_supplicant.confというファイルを作成することで初回起動から無線LANへの接続設定ができる。wpa_passphraseが導入された環境であればnetwork={}の書式の部分をさくっと作ってくれる。（簡単な暗号化もしてくれるがあまり意味はない）

```sh:wpa_supplicant.conf
country=JP
update_config=1
ctrl_interface=/var/run/wpa_supplicant
network={
    ssid="SSIDNAME"
    #psk="平文のパスワード。削除可"
    psk=符号化したパスワード
}
```

# Raspberry piのOS上の設定
出来たmicroSDカードを挿し込んで起動する。

##SSHで接続
``ping 192.168.0.255``してから``arp -a``するなどしてRaspberry piが掴んだIPアドレスを探しだしたらSSHで接続。
b8-27-eb-から始まるMACアドレスがRaspberry pi。

デフォルトのID/PASS
user: pi
pass: raspberry

##何はなくともapt update

```
$ sudo apt update 
```

## Vimの導入
```
$ sudo apt --purge remove vim-common vim-tiny
$ sudo apt install vim
```

あとは適当な.vimrcを

```
$ cat <<EOS > ~/.vimrc
set nocompatible
set autoindent
set ruler
syntax on
set expandtab
set tabstop=2
set shiftwidth=2
EOS
```

## Python
Python3の開発用パッケージ導入

```
$ sudo apt -y install python3-dev
```

Python3用のpipを導入

```
$ sudo apt -y install python3-pip
```

確認

```
$ pip3 --version
pip 18.1 from /usr/lib/python3/dist-packages/pip (python 3.7)
```
## RPi.GPIOの導入
```
$ pip3 install RPi.GPIO
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting RPi.GPIO
  Downloading https://www.piwheels.org/simple/rpi-gpio/RPi.GPIO-0.7.0-cp37-cp37m-linux_armv7l.whl (69kB)
    100% |████████████████████████████████| 71kB 144kB/s
Installing collected packages: RPi.GPIO
Successfully installed RPi.GPIO-0.7.0
```
※後でサービスとかでGPIO使ったプログラムを動かすのであれば、sudoで入れたほうがいいかもしれない。

とりあえずこれぐらいあればベースになるだろうか。
SSHは鍵のみでログインするようにしたほうが良いね。
[.NET Framework] Controller の単体テストで FindPartialView を実行したい

既存の MVC Controller に対してテストコードを書く必要があって、その時にはまったこと。

## やりたいこと
- FindPartialView を（とりあえず）通したい

## 環境
- Windows 10 Pro
- Visual Studio 2019
- .NET Framework 4.7.2

## 最初に
Controller の中で
`ViewEngines.Engines.FindPartialView`
しているところがあり、単純にテストクラスで
` new TestController().Hoge()`
みたいに実行すると
**ControllerContext がない！**
とかいろいろ怒られる。

## Moq で何とかなる？
ControllerContext の Mock 作ればできるかも、と思ってやってみたものの、FindPartialView の実行に必要な ControllerContext の値が調べきれず。。
さらにいろいろ調べたところ、ViewEngines.Engines 自体に Mock の値を登録してしまうという記事を発見。

- https://stackoverflow.com/questions/23296937/how-do-i-mock-controller-context-in-my-unit-test-so-that-my-partial-view-to-stri

## やってみる
上記記事を参考に実装。

``` Test.cs
// RouteData
var routeData = new RouteData();
routeData.Values.Add("action", "[ActionName]");
routeData.Values.Add("controller", "[ControllerName]");

// ControllerContext
var mock = new Mock<ControllerContext>();
mock.SetupGet(m => m.RouteData)
	.Returns(routeData);

// View
var view = new Mock<IView>();
var viewEngine = new Mock<IViewEngine>();
var viewEngineResult = new ViewEngineResult(view.Object, viewEngine.Object);
viewEngine.Setup(e => e.FindPartialView(It.IsAny<ControllerContext>(), It.IsAny<string>(), It.IsAny<bool>()))
	.Returns(viewEngineResult);

// ViewEnginesの削除・登録
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(viewEngine.Object);

// Controller.ControllerContextにMockオブジェクトを設定
var controller = new TestController();
controller.ControllerContext = mock.Object;
```

実行時にエラーになるので、RouteData.Values に Controller の追加は必要。
Mock で生成した View と ViewEngine で作った ViewEngineResult を FindPartialView の戻りとして設定してあげる。さらに、ViewEngines.Engines に上記 ViewEngine を登録すればテスト実行可能。

## 改善の余地あり
上記コードだと、複数の FindPartialView があるときでも、常に同じ戻りとなる。
`e.FindPartialView(It.IsAny<ControllerContext>(), It.IsAny<string>(), It.IsAny<bool>())`
の第二引数を It.IsAny<string>() ではなく、指定可能にするような実装にしつつ、指定した値に対応した View を生成するようにすれば、いろいろなパターンに対応できそう。
Ruby で解く AtCoder ABC110 C 文字列操作

# はじめに
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

# 今回のお題
*[AtCoder Beginner Contest C - String Transformation](https://atcoder.jp/contests/abc110/tasks/abc110_c)*
<font color="green">Difficulty: 946</font>

今回のテーマ、文字列操作

異なる英小文字ですので、逆に考えますと重複を考慮するということで、重複した文字列と言えば**ハッシュ**。
コインの裏の裏が表であるように、ハッシュの逆の逆を調べます。
# Ruby
```ruby.rb
s = gets.chomp.chars
t = gets.chomp.chars
h = {}
g = {}
s.size.times do |i|
  if h[s[i]]
    if h[s[i]].count(t[i]) == 0
      h[s[i]] << t[i]
    end
  else
    h[s[i]] = [t[i]]
  end
  if g[t[i]]
    if g[t[i]].count(s[i]) == 0
      g[t[i]] << s[i]
    end
  else
    g[t[i]] = [s[i]]
  end
end
puts h.flatten(-1) == g.invert.flatten(-1) ? 'Yes' : 'No'
```
```hash.rb
h = {}
g = {}
s.size.times do |i|
  if h[s[i]]
    if h[s[i]].count(t[i]) == 0
      h[s[i]] << t[i]
    end
  else
    h[s[i]] = [t[i]]
  end
  if g[t[i]]
    if g[t[i]].count(s[i]) == 0
      g[t[i]] << s[i]
    end
  else
    g[t[i]] = [s[i]]
  end
end
```
文字列`s`から文字列`t`を見たハッシュ`h`と、文字列`t`から文字列`s`を見たハッシュ`g`を取得しています。

```flat.rb
puts h.flatten(-1) == g.invert.flatten(-1) ? 'Yes' : 'No'
```
`invert`でハッシュの逆（keyとvalueの入れ替え）を取得し比較します。
# Python
*[辞書のkeyとvalueを1行で入れ替える -Qiita](https://qiita.com/NLPingu/items/aa1106c626b5ca76431e)*にありますように、辞書の逆を求めるのが大変そうなので、***Python***はお休みします。~~機械学習に関係なさそうだし~~

*[Ruby 技術者認定試験 Silver](https://qiita.com/superrino130/items/0b22c639bacc43ec9282)*を勉強した時、`invert`や`flatten`なんて使わないよね、と思っていましたが、実際に使用することになりびっくり。
基礎学習って、必要ですね。


||Ruby|
|:--:|:--:|
|コード長 (Byte)|375|
|実行時間 (ms)|514|
|メモリ (KB)|22780|
# まとめ
+ ABC 110 C を解いた
+ Ruby に詳しくなった

参照したサイト
*[辞書のkeyとvalueを1行で入れ替える](https://qiita.com/NLPingu/items/aa1106c626b5ca76431e)*
*[instance method Hash#flatten](https://docs.ruby-lang.org/ja/latest/method/Hash/i/flatten.html)*
フォームに入力された開始時間、終了時間からJavaScriptを使って経過時間を算出する

画面で開始時間、終了時間を入力されると自動的に経過時間を計算する必要があるときってありませんか！？

開発者A「`<input type="time">`で開始時間、終了時間は入力できるようにしたけど、経過時間の計算処理はどうすれば？(心：自分で実装するのめんどくせーからネットにいいのねえかなー？)」
私「安心してください。ありますよ。」
ってな感じで使ってもらえればいいと思い、大した内容では無いですがQiitaに初投稿することにしました。


# 利用想定
- フォームに入力されたhh:mm形式の時間同士の経過時間を計算したい
- 開始、終了時間は同一日として扱うが、開始時間 > 終了時間の場合は終了日を翌日として計算したい

# 動作確認環境
- OS : windows10
- ブラウザ：Google Chrome(81.0.4044.138)

# 実装
時分入力フォーム「starttime」「endtime」から時間を取り出し経過時間「elapsetime」に入力する

- 方法1

時間のみの情報を一旦Date型にし[Date - Date = 経過ミリ秒]となる事を利用して経過ミリ秒
を算出、経過ミリ秒→経過時分(hh:mm)を算出する

``` method1.js
function setElapseTime() {
	const starttime= document.getElementById("starttime").value;
	const endtime= document.getElementById("endtime").value;
	document.getElementById("elapsetime").value = calElapseTime(starttime, endtime)
}

function calElapseTime(starttime, endtime) {
	//引数が時間形式(hh:mm)でない場合は計算しない
	if (!isFormatHHMM(starttime) || !isFormatHHMM(endtime)) return "";

	//経過時間算出のために一旦日付型に変換する
	//前提として同一日の時間入力同士の計算なのでDate化する際の日付は固定
	const wd = "2000/01/01";
	const startDate = new Date(`${wd} ${starttime}`);
	const endDate = new Date(`${wd} ${endtime}`);

	//開始時間 > 終了時間の場合、日を跨いでいるとして扱い、終了日に+1日する
	if (startDate > endDate) endDate.setDate(endDate.getDate() + 1);

	//終了日(終了時間) - 開始日(開始時間)を行い経過時間(ミリ秒)を算出
	const elapseMs = endDate - startDate;

	//経過時間(ミリ秒)をhh:mm形式の文字列にして返却する
	return msToTimeString(elapseMs);
}

//文字列が時間形式(hh:mm)かどうかを判定する
function isFormatHHMM(str) {
	const fmt = RegExp("^([0-1][0-9]|2[0-3]):([0-5][0-9])$");
	return fmt.test(str);
}

//ミリ秒から時分文字列(hh:mm)を作成して返す
function msToTimeString(ms) {
	//1minute = 60000ms
	//1hour = 60minutes = 3600000ms
	const hour = Math.floor(ms / 3600000);
	const minute = Math.floor((ms - 3600000 * hour) / 60000);
	const hh = ("00" + hour).slice(-2);
	const mm = ("00" + minute).slice(-2);
	
	return `${hh}:${mm}`;
}
```

いかがでしたでしょうか。
そう、思いましたね？（少なくとも私は思いました）
同一日の時間計算するのに一旦Date型に変換するのって美しくなくね？って。
そう思ったあなたお送りするのが「方法2」となります。

- 方法2

時間情報をミリ秒に変換し[終了時間(ミリ秒) - 開始時間(ミリ秒)]で経過ミリ秒を算出した後、経過ミリ秒→経過時分(hh:mm)を算出する 

``` method2.js
//下記のメソッド内容は省略(方法1を参照してください)
function setElapseTime() {}
function isFormatHHMM(str) {}
function msToTimeString(ms) {}

function calElapseTime(starttime, endtime) {
	//引数が時間形式(hh:mm)でない場合は計算しない
	if (!isFormatHHMM(starttime) || !isFormatHHMM(endtime)) return "";

	//各時間をミリ秒に変換する
	const startms = timeStringToMs(starttime);
	let endms = timeStringToMs(endtime);

	//開始時間 > 終了時間の場合、日を跨いでいるとして扱い+1日(1d = 86400000ms)
	if (startms > endms) endms += 86400000;

	//終了時間を行い経過時間(ミリ秒)を算出
	const elapseMs = endms - startms;

	//経過時間(ミリ秒)をhh:mm形式の文字列にして返却する
	return msToTimeString(elapseMs);
}

//時分文字列(hh:mm)からミリ秒を算出して返す
//時分文字列形式ではなかった場合は0msを返す
function timeStringToMs(hhmm) {
	//1h = 3600000ms
	//1m = 60000ms
	let ms = 0;
	const ret = hhmm.match(/^([0-1][0-9]|2[0-3]):([0-5][0-9])$/)
	if (ret != null) ms = Number(ret[1]) * 3600000 + Number(ret[2]) * 60000;
	return ms;
}
```

いかがでしたでしょうか。
開発者A「ラッキー！やりたいこと全部やってくれてる。丸パクリー」
と使ってもらえたら幸いです。
どちらかというと自分で再度使うべきときに備えて残したというのが正しいかもしれませんが、、

Qiitaへの投稿は初となるため、読みやすいかはちょっとまだわかりませんが、
こうすれば良いや、間違いなどあればご指摘いただければ幸いです。
plasmノードを動かしてコントラクトをデプロイする

# やること
- plasmノードのソースコードをビルドして動かす
- UIから接続する
- スマートコントラクトを実装してデプロイする

# 環境
- AWS LightSail
- ubuntu18.04

# まずはgit clone
```
git clone https://github.com/staketechnologies/Plasm
```

# rustの環境構築
- ※割愛します。READMEに詳しく書いてあるので、参考にして下さい。

# ブランチを選択する
- 私は、テストネットである「1.0.0-dusty」を使わせて頂きました。

```
git checkout -b 1.0.0-dusty origin/release/1.0.0-dusty
```

# ビルド
```
cd Plasm
cargo build --release
```

# ノードの起動
- AWS上なので、localhost前提の起動は出来ません。
- ※正しいかは検証していないですが、以下のコマンドで起動しました。

```
./target/release/plasm-node \
  --port 30334 \
  --ws-port 9944 \
  --rpc-port 9933 \
  --rpc-cors=*  \
  --unsafe-ws-external \
  --unsafe-rpc-external \
  --dev
```

# plasmUIを準備する
- cloneする

```
git clone https://github.com/staketechnologies/apps
```

- yarn installする
- ※私の場合、yarnとnodeのバージョンが新し過ぎたので、それぞれバージョンダウンさせてinstallしました。
- ※バージョンダウン方法はこちらから。[node](https://qiita.com/realtakahashi/items/a398e83a961c8dcfa109)
、[yarn](https://qiita.com/realtakahashi/items/c66d242398abecae97dc)
- どこまでバージョンダウンするかは、READMEに書いてある最低のところまで一旦落として、yarn installを実行します。すると、nodeはバージョンXX以上が必要とか何回か言われるので、それに合わせ少しずつバージョンを上げて対応しました。


```
cd apps
yarn install
```

- 実行します。

```
yarn start
```

- 3000ポートで起動しますので、IP:3000でアクセス可能です。

# スマートコントラクトを作る
- ink!のセットアップしてビルドすると、以下のエラーになる・・・

```
cargo +nightly contract build
error: failed to get bitcode from object file for LTO (Bitcode section not found in object file)
```

# 一旦、今回はここまで
- 使わせて貰う側として、一生懸命ついていきます。
- 素晴らしいアプリだと思うので、応援していきます。
さくらエディタの複数マクロのロジックを一つのファイルにまとめる方法 　その２

# はじめに
以下の記事で紹介した方法では、Editorオブジェクトにアクセスできないという致命的な問題があるので別の方法を考えました。

https://qiita.com/takahasinaoki/items/c161f5996832033fe31a

# 方法
ラッパー用のvbsファイルに本体のファイルをincludeします

本体のサンプル

```vb:Test.vbs
Option Explicit
Sub Test1()
    Call MsgBox("Test1が実行されました")
End Sub

Sub Test2()
    Call MsgBox("Test2が実行されました")
End Sub
```

ラッパー用のファイルのサンプル

```vb:Test1.vbs
Option Explicit
Dim objShell, objFSO
Set objShell = CreateObject("WScript.Shell")
Set objFSO   = CreateObject("Scripting.FileSystemObject")
objShell.CurrentDirectory = objFSO.GetParentFolderName(Editor.ExpandParameter("$M"))
With objFSO.OpenTextFile("Test.vbs")
    ExecuteGlobal .ReadAll
    .Close
End With

Call Test1()
```

```vb:Test2.vbs
Option Explicit
Dim objShell, objFSO
Set objShell = CreateObject("WScript.Shell")
Set objFSO   = CreateObject("Scripting.FileSystemObject")
objShell.CurrentDirectory = objFSO.GetParentFolderName(Editor.ExpandParameter("$M"))
With objFSO.OpenTextFile("Test.vbs")
    ExecuteGlobal .ReadAll
    .Close
End With

Call Test2()
```

# ラッパー用のファイルをマクロに登録します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/f7c8d0dc-40de-0f26-1351-855b1f6ce28f.png)
[.NET Core] Shift-JIS を扱う

.NET Core 3.1 で Shift-JIS エンコードを利用しようとした際に調べたこと。

## やりたいこと
- .NET Core 3.1 で Shift-JIS を扱いたい

## 環境
- Windows 10 Pro
- Visual Studio 2019
- .NET Core 3.1

## 最初に
何も考えずに
`Encoding.GetEncoding("Shift_JIS");`
のようにして実装したところ、以下エラーが発生。

```
System.NotSupportedException: 'No data is available for encoding 932. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.'
```

## 調査
改めて .NET のエンコードについて調べてみる。

- .NET で文字エンコーディング クラスを使用する方法
  - https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/character-encoding

.NET で使用できる標準の文字エンコーディングは、ASCII、UTF-7、UTF-8、UTF-16、UTF-32。
上記以外のエンコードを使用するためには、コードページのエンコードプロバイダーへの登録が必要となる。

- Encoding.RegisterProvider
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.text.encoding.registerprovider?view=netcore-3.1
- CodePagesEncodingProvider
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.text.codepagesencodingprovider?view=netcore-3.1

## コード追加
ということで、Shitf-JIS エンコード処理の前に、以下コードを追加。

`Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);`

無事に実行できた。
オフラインどう書く第13回問題の解答

問題はこちら->http://nabetani.sakura.ne.jp/hena/ord13blocktup/

すぐ思いつくのは、床につながっているマスを探索して印をつけておく方法ですが、
横一行づつ下から処理する方法で解いてみました。
まずレンガのあるマスを'1'として90度右に倒したようなリストのリストを作ります。(make/3)
（最上位のリストが左側の壁を表す）
次いで容器の底のブロックのないマスを'0'にします。(solve/5の2節目)
その上からは、容器の左壁のブロックのないマスを'0'とし、(solve/5の1節目)
左から右へ下から上へ一マスずつ調べて、(solve/5の3節目)
マスの値が'1'（壁）の場合、
　　まだ前のマスの値が決まっていなければ水なので前のマスの値を'2'とします。
マスの値が'1'でない場合、
　　横に'1'を挟まず二つ以上繋がっているマス（上下のリストの同じ位置）は同じ変数にし,
　　　　　（どこかで変数に値が入ると全て同じ値になります）
　　容器の下側（リストの一つ前の要素）を見て'0'だったら'0'にします。
最後にfindallで'2'を集めてリストにし,その長さを水の入る量とします。(solve/2)

```Prolog
%SWI-Prolog (7.6.4,7.4.2)
%start.
%:-initialization(start).   %ideone

find(L,N,M,V):-nth1(M,L,L1),nth1(N,L1,V).

makeL([],_,[]).
makeL([H1|T1],M,[H2|T2]):-
     makeL(T1,M,T2),M1 is M-H1,length(L1,M1),length(L2,H1),
     maplist(=('1'),L2),append(L2,L1,H2).

solve(L,R):-
     length(L,M),max_list(L,N),makeL(L,N,L1),solve(L1,M,N),
     findall(A,(member(L3,L1),member(A,L3),A=='2'),R2),length(R2,R),!.

solve(_,_,0):-!.
solve(L,M0,N):-
     N1 is N-1,solve(L,M0,N1),solve(L,M0,N,M0,_).
solve(L,_,N,1,V):-
     !,find(L,N,1,V),(var(V)->V='0';true).
solve(L,M0,1,M,V):-
     !,M1 is M-1,solve(L,M0,1,M1,_),find(L,1,M,V),(var(V)->V='0';true).
solve(L,M0,N,M,V):-
     M1 is M-1,solve(L,M0,N,M1,V1),find(L,N,M,V),
     (V=='1'->(var(V1)->V1='2';true);
     ((not(V1=='1')->V1=V;true),N1 is N-1,(find(L,N1,M,'0')->V='0';true))).
start:-str(S),
     split_string(S,"\n,\s","\s",L),pre(L).

pre([]):-!.
pre([_,B,C|T]):-
     atom_chars(B,L),maplist(atom_number,L,L1),solve(L1,R),disp(R,C),pre(T).

disp(R,C):-number_string(R,S),(S==C->write("pass ");write(" fail ")),writeln(S),!.


str("0  83141310145169154671122         24
1       923111128       45
2       923101128       1
3       903111128       9
4       3       0
5       31      0
6       412     1
7       3124    3
8       11111   0
9       222111  0
10      335544  0
11      1223455321      0
12      000     0
13      000100020003121         1
14      1213141516171819181716151413121         56
15      712131415161718191817161514131216       117
16      712131405161718191817161514031216       64
17      03205301204342100       1
18      0912830485711120342     18
19      1113241120998943327631001       20
20      7688167781598943035023813337019904732   41
21      2032075902729233234129146823006063388   79
22      8323636570846582397534533       44
23      2142555257761672319599209190604843      41
24      06424633785085474133925235      51
25      503144400846933212134   21
26      1204706243676306476295999864    21
27      050527640248767717738306306596466224    29
28      5926294098216193922825  65
29      655589141599534035      29
30      7411279689677738        34
31      268131111165754619136819109839402       102").
```
【Ruby/Rails】aliasを使う。rubocopに怒られない方法で！

# 環境

- ruby 2.6.6
- Rails 5.2.3
- [rubocop 0.82.0](https://github.com/rubocop-hq/rubocop)

# 問い

`alias`を使うべきか`alias_method`を使うべきか、`symbol`で定義すべきかしないべきか。

# これが答えだ！

`alias`を使い、`symbol`を**使わない**。

### インスタンスメソッド

```ruby
  def existing_method
    ...
  end

  alias alias_method existing_method
```

### クラスメソッド

```ruby
  def self.existing_method
    ...
  end

  class << self
    alias alias_method existing_method
  end
```
【python】谷の数を数えるプログラム　

#【python】谷の数を数えるプログラム　

▼設問

- 高さ0地点からスタート
- Uだと1上に。Dだと1下に進む。
- 終了は必ず高さ0地点になる。
- スタートから終了までの谷の数を求める。

[url](https://www.hackerrank.com/challenges/counting-valleys/problem)

▼sample input

```python:
8
UDDDUDUU
```

▼sample output

```python:
1
```

```:進んだ道のイメージ
_/\      _
   \    /
    \/\/
```

▼my answer

```python:
def countingValleys(n, s):
    #UとDを1と-1に変換
    ss = list(map(int, (s.replace("U","1 ").replace("D","-1 ").split())))

    #谷になる条件（0->-1の発生回数を求める）
    x=0
    ans=0
    for i in ss:
        if x==0 and x+i < 0:
            ans+=1
        x += i
    return ans

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')
    n = int(input())
    s = input()
    result = countingValleys(n, s)
    fptr.write(str(result) + '\n')
    fptr.close()
```

<br>
・avid hiker
avid：熱心な
hiker：ハイカー

・meticulously
細心の注意を払って
He tracks his hikes meticulously.
ハイキング(hikes)を細かく記録。

・topography
地形
Paying close attention to small details like topography.


<br>
##for文を一文にする。

▼my answer（ifを一文化）

```python:
def countingValleys(n, s):
    #UとDを1と-1に変換
    ss = list(map(int, (s.replace("U","1 ").replace("D","-1 ").split())))

    #ifを一文で書く
    x = ans=0
    for i in ss:
        ans += 1 if x==0 and x+i < 0 else 0
        x += i
    return ans
```

`[Trueの場合の式] if [条件] else [Falseの場合の式]`

※elseのあとにpassが使えない。
→ 0でそれっぽく動いた。


<br>
更に簡略化すべく、内包表記でトライしてみようとしたものの、for文の中に式が複数ある場合の内包表記の書き方がわからず、、
Ruby on Rails チュートリアル Windows での実施時の困ったメモ

[Ruby on Rails チュートリアル：実例を使って Rails を学ぼう](https://railstutorial.jp/) を Windows で実行している時に困ったことのメモをまとめていきます。

# 第３章にて成功するはずのテストが失敗する

[3.3.1 最初のテスト](https://railstutorial.jp/chapters/static_pages?version=5.1#sec-our_first_test)でGET が成功するか見るだけのテストなのに Permission エラーで失敗

```
E

Error:
StaticPagesControllerTest#test_should_get_help:
ActionView::Template::Error: Permission denied @ rb_file_s_rename - (C:/environment/sample_app/tmp/cache/assets/sprockets/v4.0.0/99/99m8UCKl4j8IpsVOK8ltLHyNh8Ae0nHw3GBkC34V_co.cache.68827840.15592.375890, C:/environment/sample_app/tmp/cache/assets/sprockets/v4.0.0/99/99m8UCKl4j8IpsVOK8ltLHyNh8Ae0nHw3GBkC34V_co.cache)
    app/views/layouts/application.html.erb:8
    test/controllers/static_pages_controller_test.rb:10:in `block in <class:StaticPagesControllerTest>'


rails test test/controllers/static_pages_controller_test.rb:9

.

Finished in 0.474810s, 4.2122 runs/s, 2.1061 assertions/s.
2 runs, 1 assertions, 0 failures, 1 errors, 0 skips
```

[Ruby on Rails - stylesheet_link_tag がエラーになる｜teratail](https://teratail.com/questions/56995) を参考に以下のコマンドを実行したら、解消した。

```
> rails tmp:cache:clear
> rails assets:precompile
```

# Guard を実行すると警告が表示される

```
  Please add the following to your Gemfile to avoid polling for changes:
    gem 'wdm', '>= 0.1.0' if Gem.win_platform?
```

書かれている通り、Gemfile に

```Gemfile
gem 'wdm', '>= 0.1.0', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
```

を追加して、

```
bundle install --without=production
```

を実行してから、Guard を再起動した。

```
bundle exec guard
```

ちなみに wdm は、`Windows Directory Monitor` の略のようです。

# 参考リンク

- [yasslab/sample_apps: Railsチュートリアルの各章が終わった状態を集めたリポジトリです。](https://github.com/yasslab/sample_apps)
- [【Railsチュートリアル】S3に画像をアップロードする設定【13章課題】 - Qiita](https://qiita.com/ryuchan00/items/8e414562b7122e7ec4fb) @ryuchan00 さん
- [Ruby - Railsチュートリアル13章 ArgumentErrorでherokuにデプロイできない｜teratail](https://teratail.com/questions/280923)
ゼロから始めるLeetCode Day48 「26. Remove Duplicates from Sorted Array」

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

その対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイト。

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

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

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

前回
[ゼロから始めるLeetCode Day47 「14. Longest Common Prefix」](https://qiita.com/KueharX/items/b97dbbcb697585924d30)

今はTop 100 Liked QuestionsのMediumを優先的に解いています。
Easyは全て解いたので気になる方は目次の方へどうぞ。

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

# 問題
[26. Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)
難易度はEasy。

問題としては、ソートされた配列が与えられます。
その配列から重複した要素を削除し、書く要素を1回だけ表示し、新しい長さを返す、という問題です。


>Given nums = [1,1,2],

>Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.

>It doesn't matter what you leave beyond the returned length.

>Given nums = [0,0,1,1,1,2,2,3,3,4],

>Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.

>It doesn't matter what values are set beyond the returned length.


#解法

```Python
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        n = 0
        for i in range(1,len(nums)):
            if nums[n] < nums[i]:
                n += 1
                nums[n] = nums[i]
        return n+1
# Runtime: 84 ms, faster than 77.52% of Python3 online submissions for Remove Duplicates from Sorted Array.
# Memory Usage: 15.6 MB, less than 35.88% of Python3 online submissions for Remove Duplicates from Sorted Array.    
```

最初から要素を舐めていき、それぞれのnumsのインデックスと用意した`n`を比較し、 処理をしていく、という手法で書きました。
特に捻って書く必要もないですし、オーソドックスな処理と言えるのではないでしょうか。

この問題は配列とfor文とif文の使い方を学ぶには良い問題だと思うので、興味を持った初心者でも解けそうな感じなのでお勧めしやすいのではないでしょうか。

今回はここまで。お疲れ様でした。
gobuffaloのテーブル名にはデフォルトで"s"がつく前提になっている

# 結論から
- gobuffaloで使うテーブル名には末尾に"s"がいる。
- 例を言うと「商品」を格納する構造体「product」を実装して、テーブルに格納する場合、テーブル名は「products」である必要ある。※デフォルトでは。

# テーブル名を自分の好きにカスタマイズする方法
- 該当のmodel.goでTableName 関数をオーバーライドする
- 以下は例です。

```
package models

import (
	"encoding/json"
	"time"

	"github.com/gobuffalo/pop"
	"github.com/gobuffalo/validate"
	"github.com/gofrs/uuid"
)

// Test is used by pop to map your .model.Name.Proper.Pluralize.Underscore database table to your go code.
type Test struct {
	ID        uuid.UUID `json:"id" db:"id"`
	Messsage  string    `json:"messsage" db:"messsage"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

// ★★★ここでテーブル名を指定することが出来ます。
func (t Test) TableName() string {
  return "testTest"
}

// String is not required by pop and may be deleted
func (t Test) String() string {
	jt, _ := json.Marshal(t)
	return string(jt)
}

// Tests is not required by pop and may be deleted
type Tests []Test

// String is not required by pop and may be deleted
func (t Tests) String() string {
	jt, _ := json.Marshal(t)
	return string(jt)
}

// Validate gets run every time you call a "pop.Validate*" (pop.ValidateAndSave, pop.ValidateAndCreate, pop.ValidateAndUpdate) method.
// This method is not required and may be deleted.
func (t *Test) Validate(tx *pop.Connection) (*validate.Errors, error) {
	return validate.NewErrors(), nil
}

// ValidateCreate gets run every time you call "pop.ValidateAndCreate" method.
// This method is not required and may be deleted.
func (t *Test) ValidateCreate(tx *pop.Connection) (*validate.Errors, error) {
	return validate.NewErrors(), nil
}

// ValidateUpdate gets run every time you call "pop.ValidateAndUpdate" method.
// This method is not required and may be deleted.
func (t *Test) ValidateUpdate(tx *pop.Connection) (*validate.Errors, error) {
	return validate.NewErrors(), nil
}

```
Splunkでサマリーインデックスを作る

サマリーインデックスは、検索結果を別のインデックスとして保持してくれる。

デフォルトのソースタイプ_stash_を使うかぎりは、別途ライセンス料金は取られない。

https://docs.splunk.com/Documentation/Splunk/latest/Knowledge/Usesummaryindexing

コマンドは`collect`

https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Collect

ただ、ログに`addinfo`と同じ_info_min_time_等の結果がついてくるので、気になる人は気になるみたい。`addinfo`はリンク参照

https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Addinfo

#実験

```configuration:props.conf
[summeries]
TRANSFORMS-info_del = info_del
```

```configration:transforms.conf
[info_del]
REGEX = (?m)([^,]+,).*\s*(count=\d+)
FORMAT = $1$2
DEST_KEY = _raw
```

を準備して、

```sql:making_summery_index.spl
| tstats count where index=_internal by _time span=12h
| collect sourcetype=summeries
```

```bash:result
_time	count
2020/06/04 21:00	344
2020/06/05 09:00	24292
2020/06/05 21:00	104435
```

をサマリーインデックス化

`_time`をログに載っけたかったので、`|collect addtime=true`のデフォルト設定を利用している。

#結果

```bash:index=summary
06/05/2020 21:00:00 +0900,count=104435
06/05/2020 09:00:00 +0900,count=24292
```

`_time`のあと`info_min_time=` ,`info_max_time=` ,`info_search_time=` が続くので、 _transforms.conf_で`_raw`を消している。

#一般化
```configration:transforms.conf
[info_del]
REGEX = (?m)([^,]+,)[^,]+,[^,]+,[^,]+,\s*(.*)
FORMAT = $1$2
DEST_KEY = _raw
```

一般化するとこんな感じだと思う。

ただ、もちろん**別途ライセンス計算に計上される**

#まとめ
最初`|collect addtime=`の挙動を調べるため、やっていました。

`[stash]`のスタンザに設定すれば、ライセンスの話とかなんとかなりそうですが、`$SPLUNK_HOME/bin/splunk cmd btool props list stash --debug`の結果が沢山あって、自分では`etc/apps/{appname}/local/`配下に設定しても上手く行きませんでした。

上手く行っている方がいたら、やり方を教えてください。
【python】ペアになる靴下の数を求めるプログラム　

#【python】ペアになる靴下の数を求めるプログラム

自分用のメモです。

▼設問

- 任意の数の整数が含まれるlistがある。
- list内の値は靴下の色の番号を表す。
- 同じ色が２つ揃うと１セット。
- セットの数を求める。

[url](https://www.hackerrank.com/challenges/sock-merchant/problem)

▼sample input

```python:
9
10 20 20 10 10 30 50 10 20
```

▼sample output

```python:
3
```


▼my answer

```python:
def sockMerchant(n, ar):
    pair=0
    for i in set(ar):
        pair += int(ar.count(i)/2)
    return pair

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')
    n = int(input())
    ar = list(map(int, input().rstrip().split()))
    result = sockMerchant(n, ar)
    fptr.write(str(result) + '\n')
    fptr.close()
```


**・int()**
小数点以下は**切り捨て**

**・countメソッド**
`オブジェクト.count(i)`
 オブジェクトの中に、iが何個入っている数を返す。

文字列でも使える。

```python:
aaa = "あいうえおあいうえおあい"
aaa.count("あ")
```


<br>
##内包表記を使ってシンプルにする

▼my answer(内包表記)

```python:
ar=[10,20,20,10,10,30,50,10,20]

def sockMerchant(n, ar):
    return sum([int((ar.count(i))/2) for i in set(ar)])

sockMerchant(9, ar)
```

- 内包表記の中で「+=」などの代入は使えない。
- [ ]の場合、list型が帰ってくる。
- sum(list)でlistの各要素の合計値が返る
google formに値をprefillした状態になるようURLパラメータをつけて叩く

なんてことはないのですが、googleformを使ってwebでアンケートをとる際に、prefillした値を入れておきたい時にどうしたらいいかのメモ。

# やり方
まずは作成したgoogleformのサイドメニューから「事前入力したURLを取得」
![スクリーンショット 2020-06-06 7.18.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214667/8a4de114-9b32-6cd9-263b-5a11a06bf05a.png)

prefillしたい項目に適当な値をぶっ込んで「リンクを取得」を押します
![ef218d507889e2e337a9a3c13d010841.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214667/ed98f4ee-5a4e-7733-c57c-d3efaef8abd2.png)

そうするとリンクをコピーするよう言われるので、クリップボードにコピーします
![e1a7e9126567257aec8171457fb19eed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214667/f6546304-6619-d888-e829-567aa40408bc.png)

そうするとコピーした内容が下記のように出てくるはずです。「entry.1234567890=hogehoge」がprefill目的の対象です

```
https://docs.google.com/forms/.../viewform?usp=pp_url&entry.1234567890=hogehoge
```

あとは各自の実装によると思いますが、hogehogeの前までと実際に入れ込みたい値をURLとして加工してlinkに与えるだけです。
（下記の例ではわかりやすさのために、パラメーターごと直書きし、格納済みの任意の値（@feedback_id）をくっつけています）

```sample.html.slim
  - feedback_url = "https://docs.google.com/forms/.../viewform?usp=pp_url&entry.1234567890=" + @feedback_id
  = link_to feedback_url, style: "..." do
    | アンケートに回答する
```

（なお注意として、googleformの「送信」>「（リンクボタン）」>「URLを短縮」で、短縮URLを得ることができますが、こちらはパラメーターをそのままくっつけることはできません。）
React で useState でのデータ更新を行う場合に Map オブジェクトを経由させてみる

# React で useState でのデータ更新を行う場合に Map オブジェクトを経由させてみる

- データをオブジェクトで扱う場合に `useState` を使う
- 特定のプロパティへの更新は `setData({ ...data, key: value })` などによりできる
- テキスト入力の場合には入力のたびに再レンダリングが行われるため [use-debounce](https://github.com/xnimorz/use-debounce) により更新頻度を絞り込む
- 更新頻度を絞り込むと複数の要素をまたいだ素早い入力が最後の更新以外を無効化してしまうケースがある

## 事例

[useState のセッターを直接使う場合と Map オブジェクトを経由させる場合 (CodeSnadbox)](https://codesandbox.io/s/update-using-map-ukxd2)

(画像です)
![update-using-map](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116435/345cfe40-5cd4-a3bc-15c2-4512c30ab96d.png)

### useState のセッターを直接使用して更新

上記においてデータ更新を行う `setData` を直接実行する `updateDirectly` を使用しているほうは
`type1`, `color1` を連続してクリックすると片方しか更新されません。

```js:update-directly
  // setData により値を直接更新する
  const [updateDirectly] = useDebouncedCallback(value => {
    setData({ ...data, ...value });
  }, 1000);
```

これは `useDebouncedCallback` により `data` への更新を `1 秒` 遅延させており、
その範囲内で複数の更新が行われた場合に最後のものしか反映されないためです。

### Map オブジェクトを経由して更新

一方 Map オブジェクトを使用する `updateMap` + `updateWithMap` のほうでも同一の遅延を行っていますが
連続の入力でも `type2`, `color2` の両方が更新されます。

```js:update-with-map
  // 再レンダリングでされても保持されるよう useState で Map オブジェクトを保持
  const [updates] = React.useState(new Map());
  // Map 経由で値を更新する
  const [updateWithMap] = useDebouncedCallback(() => {
    const diff = {};
    updates.forEach((value, key) => (diff[key] = value));
    setData({ ...data, ...diff });
  }, 1000);
  // Map の更新
  const updateMap = value => {
    Object.keys(value).forEach(key => updates.set(key, value[key]));
    updateWithMap();
  };
```

`updateDirectly` との違いとして

- Map オブジェクトである `updates` への更新 (`.set()`) では遅延させない
- `data` を更新する際には変更を集約した `updates` を使用

更新を行う際にレンダリングを行わない変更が可能な Map オブジェクトを使用することにより
全ての更新を反映しつつ遅延を実現しております。
さくらエディタの複数マクロのロジックを一つのファイルにまとめる方法

# vbsファイルの引数でマクロの挙動を分岐させます
サンプル

```vb:Test.vbs
Option Explicit
Select Case Wscript.Arguments(0)
Case "1"
    Call Test1
Case "2"
    Call Test2
End Select
Call MsgBox("パターン1を終了します")

'または以下でもＯＫ
Dim Func
Set Func = GetRef("Test" & Wscript.Arguments(0))
Call Func
Call MsgBox("パターン2を終了します")

Sub Test1()
    Call MsgBox("Test1が実行されました")
End Sub

Sub Test2()
    Call MsgBox("Test2が実行されました")
End Sub
```

# ダメな例
マクロの登録画面で直接引数を指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/06788aba-fc5c-ac48-7f4a-b6bc11045108.png)

実行時はエラーになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/90418a62-b2ad-9228-7459-f40502934c1a.png)
※もう1つの問題として、Test.vbsが実行できたとしてもWscriptオブジェクトが参照できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/9f141386-534f-30ed-8153-d41a07a2ada7.png)



# 実行可能な例
ラッパー用のvbsファイルを作成します

```vb:Test1.vbs
Dim objShell
Set objShell = CreateObject("WScript.Shell")
objShell.CurrentDirectory = CreateObject("Scripting.FileSystemObject").GetParentFolderName(Editor.ExpandParameter("$M"))
Call objShell.Run("Test.vbs 1",,True)
```

```vb:Test2.vbs
Dim objShell
Set objShell = CreateObject("WScript.Shell")
objShell.CurrentDirectory = CreateObject("Scripting.FileSystemObject").GetParentFolderName(Editor.ExpandParameter("$M"))
Call objShell.Run("Test.vbs 2",,True)
```

上記のファイルをマクロに登録します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/f7c8d0dc-40de-0f26-1351-855b1f6ce28f.png)


# 問題点
Test.vbsファイル内では、Editorオブジェクトにアクセスできないため、使用はかなり限定されます
※この問題を解決する別の方法を考えました

https://qiita.com/takahasinaoki/items/7c7554beb95f32227589
Raspberry Pi4のUSB(HDD)起動設定

**2021/04/16 bootloader更新に伴い手順を修正**
**現在(2021年4月)でもstockしてくれる方がいるので最新内容に更新**
(古い内容は要らないと思うので整理してあります)


### 0. USBで起動したい!!

基本的には、**[ここ](https://www.tomshardware.com/how-to/boot-raspberry-pi-4-usb)**の通りに実施して問題なく設定できます。

が。。。`rpi-update`は開発者が使うべきコマンドとのことで、単純にマネをしてはいけないようです。

ということで、本記事の内容を参考にして頂ければ幸いです。

## 1. Raspberry Pi OS 64bit版を導入(必須ではありません)

**私はOSインストールからやり直すか！と考えたので下記のイメージとツールを利用しました**

- [2021年3月4日版のイメージファイル](https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2021-04-09/2021-03-04-raspios-buster-arm64.zip)
- [Raspberry Pi Imager](https://www.raspberrypi.org/downloads/)

入手してmicroSDに書きこみ、Raspberry Pi4を起動する。

**※そのままだとブートローダーは古いままなのでUSB起動しない**

## 2. ブートローダー書き換え
下記コマンドでブートローダーを書き換え。

```shell
$ sudo apt update
$ sudo apt full-upgrade

# 下記コマンドで設定ファイルを書き換える(2021年現在では不要かも)
$ sudo sed -i /etc/default/rpi-eeprom-update -e "s/beta/critical/"
# # beta版を使う場合には下記コマンドを実行する
# $ sudo sed -i /etc/default/rpi-eeprom-update -e "s/critical/beta/" 

# bootloader の存在確認
$ ls /lib/firmware/raspberrypi/bootloader/stable/pie* -la
-rw-r--r-- 1 root root 524288  4月 24  2020 /lib/firmware/raspberrypi/bootloader/stable/pieeprom-2020-04-16.bin
～省略～
-rw-r--r-- 1 root root 524288  3月 19 02:01 /lib/firmware/raspberrypi/bootloader/stable/pieeprom-2021-03-18.bin

# 最新の安定版は pieeprom-2021-03-18.bin なので、これを利用する。
$ sudo rpi-eeprom-update -d -f /lib/firmware/raspberrypi/bootloader/stable/pieeprom-2021-03-18.bin
```

#### 上記の設定が終わったら、ひとまず再起動。

```shell
$ sudo reboot now
```

*(追記)*
*再起動後、bootloaderがmicrosdを探しているような表示となり焦ってしまいました*
*放置や再起動を繰り返したら正常に起動するようになりました。*



## 3. ブートローダーの確認
先ほど書き込んだものが適用されているかな？

```bash
$ vcgencmd bootloader_version
Mar 18 2021 08:54:11
version 1b43d5b6fe5b71c300563afc0548122752a0618b (release)
timestamp 1616057651
update-time 1618532393
capabilities 0x0000001f
```
2021年3月18日(Mar 18)のモノで動いているようなので更新確認OK!

## 4. microSDの内容をHDDにコピー


SD Card Copierを起動する(`メニュー→アクセサリ→SD Card Copier`)

- Copy From DeviceはmicroSDを選択。
- Copy To DeviceはHDDを選択。
- New Partition UUIDs にチェックを付ける。

**Start**を押してコピーが完了したらシャットダウンし、microSDを外して終了です。

**やっとmicroSD破損の恐怖から解放される!!!**
docker-composeしたらalpine linuxのCDNが死んでるように見えて困った

# 事象
alpine linuxを用いてdockerコンテナを作成しようとしたところ、突然下記のように出るようになってしまいCDNが死んでいるのかと思われました。

```
WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz: could not connect to server (check repositories file)
WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpindocにe/v3.9/community/x86_64/APKINDEX.tar.gz: could not connect to server (check repositories file)
ERROR: unsatisfiable constraints:
```

ところが早速検索でヒットした[このあたり](https://qiita.com/kotauchisunsun/items/3f447283b52508f057b9)を見ると、CDNは死んでいない模様。

# 原因
どうやらdocker-alpineのissueでも昔から出ているようで、docker側のDNS解決の問題のようです。
[Repository problem? #279](https://github.com/gliderlabs/docker-alpine/issues/279)
[dl-cdn.alpinelinux.org errors #386](https://github.com/gliderlabs/docker-alpine/issues/386)

正確には、ホストOS側でデフォルトで有効になっているdnsmasqが原因であり、
dockerがデフォルト設定をコピーするとローカルにDNSがなくて困ってしまうので、パプリックなDNSを指定するようにしなければならないそう。 
なので、docker buildしたイメージの中で、/etc/resolv.confが下記のようになる。

```
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
search xxx.jp

nameserver 8.8.8.8
nameserver 8.8.4.4
```
dockerの[こちらのdoc](http://docs.docker.jp/engine/installation/linux/ubuntulinux.html#docker-dns)にそれっぽいことが書かれています。

# 解決策
手っ取り早くは、dockerを再起動する（ことによってデフォルトでパブリックなDNSを指定するようにdockerが設定されるたぶん）ようにissueには書かれていますが、私の環境では改善しなかったのでdockerを更新 + 端末ごと再起動 + イメージから作り直し をとりあえず試した段階で改善されました。

しかしそれでは気持ち悪いので下記の通り[先人の知恵](https://rabbitfoot141.hatenablog.com/entry/2018/11/22/191858)に乗っかりました。

「dockerのホストであるUbuntuでは、デフォルトでdnsmasq が有効になっていて、 /etc/resolv.confが下記のように自分を見る設定になっている。」
ならば /etc/resolv.conf に下記の通り書いてしまおうと。

```
nameserver 8.8.8.8
nameserver 8.8.4.4
```
を追記の上、Dockerを再起動すればDNS解決で失敗しなくなります。

# 参考にした記事
[Repository problem? #279](https://github.com/gliderlabs/docker-alpine/issues/279)
[dl-cdn.alpinelinux.org errors #386](https://github.com/gliderlabs/docker-alpine/issues/386)
[alpine linuxのapk updateが失敗して動かなくなったときの解決法](https://qiita.com/kotauchisunsun/items/3f447283b52508f057b9)
[Dockerコンテナ内から外部通信が向いたときにDNSが解決できない問題を解消する](https://rabbitfoot141.hatenablog.com/entry/2018/11/22/191858)
[systemd起動のDockerでdnsオプションを有効にする](https://qiita.com/hirosemi/items/0574a4b044f46c6ac5af)
[Docker が使う DNS サーバの設定](http://docs.docker.jp/engine/installation/linux/ubuntulinux.html#docker-dns)
Google Colabで使い捨て・書き捨てファイルを作成するときに便利な技 (scratchpad)

## 書き捨て用のColabのノートブックを一発で作成する

結論から最初に書いてしまうと、Googleにログインした状態で下記のURLを開くと、一度限りのColabのノートブックが作成されます。
(`scratchpad` というらしいです)
https://colab.research.google.com/notebooks/empty.ipynb

あとは自由に使って、用が済んだらそのままウィンドウを閉じるだけなので、便利！

ちょっとした作業をしたいだけなのにノートブックを作成するたびに`Untitled0.ipynb`, `Untitled1.ipynb`と、どんどん新しいノートが作られてしまい、後でまとめて削除する...という一連の手間がなくなるので、より気軽にColabを試せるようになります。

[こちらのYoutube動画の3:28あたり(Making the most of Colab (TF Dev Summit '20))](https://youtu.be/pnClcwTCyc0?t=208)で、そのためのTipsが紹介されていたので、メモとして残しておきます。
Node.js の Lambda 関数を ローカルでテストする （その２）

AWS のコンソールから、ダウンロードして解凍した index.js を実行する方法です。

![download_package.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/76c27478-5268-866a-d4a9-87b25557fa1f.png)


フォルダー構造

```text
$ tree example01/
example01/
├── index.js
└── test_local.js
```

```js:index.js
exports.handler = async (event) => {
    // TODO implement
    console.error("***** start example01 PM 18:49 ***")
    var rvalue = {}
    rvalue['key1'] = parseInt(event['key1'],10)
    rvalue['key2'] = parseInt(event['key2'],10)
    rvalue['key3'] = parseInt(event['key3'],10)
    rvalue['sum'] = rvalue['key1']+ rvalue['key2'] + rvalue['key3']
    rvalue['message'] = 'Hello from example01'

    const response = {
        statusCode: 200,
        body: JSON.stringify(rvalue),
    };
    console.error("***** end example01 ***")
    return response;
};
```

```js:test_local.js

#! /usr/bin/node
// ---------------------------------------------------------------
//	test_local.js
//
//					Jun/06/2020
//
// ---------------------------------------------------------------
var fs = require("fs")
var example01 = require('../example01')
// ---------------------------------------------------------------
console.error ("*** 開始 *** test_local.js ***")

const event = {
	"key1": 11,
	"key2": 21,
	"key3": 31
}

const context = ""

rvalue = example01.handler(event)
console.log(rvalue)

console.error ("*** 終了 *** test_local.js ***")
// ---------------------------------------------------------------
```

実行結果

```text
$ ./test_local.js 
*** 開始 *** test_local.js ***
***** start example01 PM 18:49 ***
***** end example01 ***
Promise {
  {
    statusCode: 200,
    body: '{"key1":11,"key2":21,"key3":31,"sum":63,"message":"Hello from example01"}'
  }
}
*** 終了 *** test_local.js ***
```
pipenv shellができなくなった時の対処法

# はじめに
macでpyenv+pipenvでPythonのバージョン管理・ライブラリ管理・仮想環境の管理をしているのですが、ある日pipenvの仮想環境をアクティベートしようとしたら以下のようなエラーが出てアクティベートできなくなりました。

```
$ pipenv shell
Traceback (most recent call last):
  File "/usr/local/Cellar/pipenv/2018.11.26_4/libexec/bin/pipenv", line 5, in <module>
    from pipenv import cli
ModuleNotFoundError: No module named 'pipenv'
```

pipenvが見つからないというエラーですが、pipenvそのものが格納されているディレクトリを見に行くと、正常にそこに存在しているのでこのエラーが出る原因が全くわからないのです。
このエラーは他のどのディレクトリの仮想環境をアクティベートしようとしても出て、pipenvが壊れたことを悟りました。原因に心当たりがあるとすれば久しぶりにmacを再起動したことです。未確認ですが、もしかしたら仮想環境から抜けられていないものが残っている状態で再起動してこうなったのかもしれません。ちなみに数日前に後輩もこの症状に陥り、原因不明はわからないまま大学の先生にサポートされながらpyenvもpipenvもインストールし直すことで解決していたので自分もやってみたら治りました。一連の作業を備忘録として残しておきます。

# 既存の環境を削除
まず、既存のpyenvとpipenvを削除していきます。ここで、ライブラリ管理をしているPipfile等は削除する必要はありません。Pipfileに記述されている情報を基にすぐ再構築できるように残しておきます。
この記事ではpyenv+pipenvの仮想環境の再構築を主眼に置いてるので、元々これらの環境を使用しており、PipfileやPifile.lock、.bash_profileやzshrcの設定を特にいじる必要がないという前提で書きます。

- 使用しているPythonのパスを確認
- pyenvに関するディレクトリを削除
- pyenvを削除
- pipenvを削除

```
$ which python
>>> /Users/xxx/.pyenv/shims/python
$ rm -rf /Users/xxx/.pyenv
$ brew uninstall pyenv
$ brew uninstall pipenv
```

# pyenv+pipenv, Pythonの入れ直し
ここからはツールの再インストールです。

```
$ brew install pyenv
$ brew install pipenv
```

- 元々使っていたバージョンを指定してPythonをインストール
- mac全体で3.7.5を使用するように設定
- Pythonのバージョンを確認（反映されていたら終わりかな？）

```
$ pyenv install 3.6.7
$ pyenv install 3.7.5
$ pyenv global 3.7.5
$ python -V
>>> Python 2.7.10
```

反映されていなかったのでどのPythonを使っているのか確認すると、macデフォルトのPythonを使っているようです。

```
$ which python
>>> /usr/bin/python
```

そういえば ```/Users/xxx/.pyenv/shims/python``` のようなパス指定でpyenvのPythonを使えるようにする為に```.bash_profile```に以下のような記述をしたことを思い出しました。zshユーザーは他のファイルです。

```
export PYENV_ROOT=${HOME}/.pyenv
if [ -d "${PYENV_ROOT}" ]; then
  export PATH=${PYENV_ROOT}/bin:$PATH
  eval "$(pyenv init -)"
fi
```

上記の設定をもう一度反映させ、改めてどのPythonを使っているか確認します。

```
$ source .bash_profile
$ which python
>>> /Users/xxx/.pyenv/shims/python
```
正常にpyenvのPythonを支えていることが確認できました。

# 仮想環境の再構築
ここからはpipenvで管理する仮想環境の再構築についてです。

- 元々使っていた、仮想環境を再構築したいディレクトリに移動
- Pythonのバージョンを指定してpipenv環境を作成
- 仮想環境のアクティベート
- 既存のPipfileを基にライブラリを一括インストール

```
cd 仮想環境を作りたいディレクトリ
pipenv --python 3.7.5
pipenv shell
pipenv install
```
以上で仮想環境の再構築は完了です。

# 最後に
冒頭に記述したエラーについて英語の文献も含めて検索しましたがなかなか同じ症状の人を見つけられず、未だに原因不明ではありますが、対症療法はあるので慌てず冷静に対処しましょう。

# 参考にした記事
[pipenvとpyenvを再インストールした](https://blog.ikappio.com/reinstall-pipenv-pyenv-and-remove-pyenv-virtualenv/)
[pyenvをちゃんと消してから入れ直す](https://qiita.com/yasudadesu/items/1177aa93229e7c4b7a45)
ルーター変更時の小技

# Tips
ルーターを買い替え時、端末が多いとWi-Fiを設定するために新しいSSIDとパスワードを入力するのは大変ですが、新しいルーターのSSIDとパスワードを旧ルーターのSSIDとパスワードと同じにすれば端末側の設定を変更しなくてもそのままWi-Fiが使え手間が減ります。

## My Accounts
<a href="https://github.com/mao2009"><img src="https://mao2009.github.io/qiita_template/GitHub-Mark-64px.png" width="50px"></a><a href="https://twitter.com/loach_mao"> <img src="https://mao2009.github.io/qiita_template/Twitter_Social_Icon_Circle_Color.png" width="50px"></a>