OmniAICreator/Qiita-1.07M huggingface dataset:
Python2.7 とPython3.6が同居しているAmazon Linux （≠Amazon Linux 2）環境でCertbot-autoを動かす

#想定読者
- この記事を誰かが読むことはあまり想定していません。下記のような人が検索の末にたどり着いて、正しい情報源に近づくための道しるべになればいいかな、と思っています。
    - Linuxには詳しくない、Pythonもよくわからない、https接続できるサイトを安価に運営する必要からAWS（Amazon Linux）、Let's Encryptの組み合わせを使っている人
    - 見よう見まねでコマンドをコピペしているが、内容を理解できていない人
- 私自身が↑こういう人なので、記事内容の正確さは保障できません。あらかじめお詫びしておきます。

#Let's encryptからのメール
- 2020年1月にLet's Encryptから「Update your client software to continue using Let's Encrypt」というタイトルのメールが着信した。
    - ACMEv1プロトコルを使って証明書を更新しているようだが、もうすぐ使えなくなるよ
    - ACMEv2に対応したクライアント（ https://letsencrypt.org/docs/client-options/ ）に切り替えないと証明書の発行ができなくなるよ

#Let's Encryptとcertbotの関係、certbotとcertbot-autoの関係
- Let's Encryptは「公共の利益のために運営されている、フリーで自動化されたオープンな認証局」でInternet Security Research Group（ISRG）がサービスを提供している（https://letsencrypt.org/ja/about/ ）
- Certbotクライアントは、電子フロンティア財団（EFF）が提供しているACMEクライアント。
- Let's Encrypt/ISRGが提供しているわけではない。Let's EncryptのウェブサイトではCertbotを推奨しているが、他のクライアントソフトウェアも多数紹介されている。（ https://letsencrypt.org/ja/docs/client-options/ ）
- Certbotの旧称はLet's Encryptクライアントで、EFFのリリース（ https://www.eff.org/deeplinks/2016/05/announcing-certbot-new-tls-robot ）を見る限り、フリーのSSL証明書発行を目指していたEFF/Mozilla/研究者たちによるプロジェクトから認証局としてのLet's Encryptが分岐した模様。
- で、Certbot-autoはCertbotのラッパーで、Certbotの実行と依存関係管理を行う。←ここをよく理解せずに、かなり無理やり導入したCertbotを直接叩いて実行していた（＝約2年間バージョンアップせず）のが、今回苦労した原因。

#Certbot-auto最新版の取得、実行→エラー
- Certbot-autoの導入手順については多数記事があるのでそちらを参照ください。私は「AWS EC2のAmazon LinuxでLet's Encryptのサーバ証明書を取得する（ https://qiita.com/kanehara/items/a2c322acc3d2a96ff42d ）」を参考にしました。
- で、実行するとなんかエラーが出る。
    - Certbot-autoの実行時にAmazon Linuxをサポートしていないので云々と出るので、--debugオプションをつける
- Pythonのバージョンが古いせいかと思い、Python3.6をインストールするも、Certbotの初回実行時にPython2.7の環境を構築しようとして失敗する。
- /usr/bin/virtualenvが/usr/bin/virtualenv-2.7のシンボリックリンクになっていることが問題と判断。
    - Pythonは複数バージョンがインストールされていることを前提に、仮想環境を構築してバージョンを使い分けることが一般的、らしい。
    - 結果、仮想環境ソリューションもまた複数が乱立（と言ったらきっと怒られる）していて、このソリューションはこのバージョンでは使える使えない、であるとか、このソリューションは非推奨になって久しい、などの情報もまた多い。
    - そもそも「Amazon Linuxではpython2系を置いておかないとまずい」という記事を複数目にしたため、Python3.6を追加でインストールしている。
    - Amazon Linux 2であればこの問題が起きないのでは、と、1インスタンス立ち上げてみたのは秘密だ。
    - でもAmazon Linux 2でもCertbotを動かすのは一筋縄ではいかないらしい。
        - 古い記事「Amazon Linux2でLet's Encrypt使おうとしたらコケた話（ https://qiita.com/MysteriousMonkey/items/f26316447c1ff390ce21 ）」
        - 新しい記事「Amazon Linux2とLet's EncryptでSSL対応サーバを0から爆速構築（ https://qiita.com/MysteriousMonkey/items/4d3d857c0e68d4bfff39 ）」

#とりあえず解決（後で問題が起きるかも）
- /usr/bin/virtualenvが/usr/bin/virtualenv-2.7のシンボリックリンクになっているのが問題なので
    - virtualenv-3.6をインストール
         - 参考記事：「AmazonLinuxでデフォルトで使えるpython36-virtualenvパッケージを使ったPython3.6 venv環境の構築（ https://www.saintsouth.net/blog/construct-python36-venv-by-virtualenv-on-aws-amazon-linux/ ）」
         - シンボリックリンクの張り替え
         - Certbot-autoの実行
         - ウェブサーバーの再起動

```
sudo yum install python36-virtualenv
sudo unlink /etc/alternatives/virtualenv
sudo ln -s /usr/bin/virtualenv-3.6 /etc/alternatives/virtualenv
sudo certbot-auto renew --debug
sudo service httpd restart
```

#以上
- 後で問題が起きたら更新します。
[漏洞通告]jackson-2642/jackson-databind && Fastjson SSRF(服务器端请求伪造)

### 漏洞描述
近日,亚信安全网络攻防实验室跟踪到jackson-databind新增一个黑名单类,由threedr3am提交.该类来源于JDK,不需要依赖任何jar包,该类主要可用于SSRF(服务器端请求伪造).SSRF漏洞的危害,本文不多作赘述.

### 漏洞编号
Jackson内部编号2642

### 漏洞威胁等级
中危

### 不受影响范围
jackson-databind >= 2.9.10.4
jackson-databind >= 2.10.0
### 漏洞验证
这里选用2.9.10.2且请求dnslog作为例子

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/98b0361b-be7e-ce82-f1aa-c64f1b599016.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/c278632b-69ef-ac65-32a7-ff41bcc0963b.png)

在fastjson1.2.66(最新版)中开启autotype以后,同样受影响

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/c04bfef8-0bca-e9bd-2f2c-e96a0c499262.png)

### 修复建议
1.更新jackson-databind到最新版本
2.在fastjson中禁用autotype

### 时间轴
[0] 2020/03/04 Jackson官方关闭该漏洞
[1] 2020/03/08 亚信安全网络攻防实验室分析&复现该漏洞并发布漏洞通告

### Reference
https://github.com/FasterXML/jackson-databind/issues/2642
VuexのStoreをモジュールで分割する

# はじめに
vuexをいじっていく上でAPIをいじってstoreに格納する物が多い時、または多くなりそうな時
<strong>可読性、拡張性の点からstore/index.jsにごちゃごちゃ書くのではなくstoreごとに別ファイルにしよう</strong>
ただ、そのまま思うように書いていったらいろいろつまずいたので、今つまずいた！って人に読んでもらいたい。

# モジュールで分割する時詰まったこと

- mutationが読み込めない
- actionが読み込めない
- gettersがうまくstateを取れなくてundefinedになってしまう

#### 上記３つを修正する

## mutation、actionが読み込めない
<br>

思うように書いて行ったらこの２つがエラーメッセージが出てきた

```
[vuex] unknown mutation type: (mutation名)
[vuex] unknown action type: (action名)
```

これの原因のコードは
#### actionを動かすコードにあり！！ (this.commit, this.dispatch)

```vue.js
- this.commit('mutation名')
+ this.commit('module名/mutation名', Response)

- this.$store.dispatch("action名");
+ this.$store.dispatch("action名/mutation名");
```

###<strong><font color="Red">module名も必要みたい</font></strong>


これでmutation,actionは読み込める！


## gettersでうまくstateを取れなくてundefinedになってしまう

問題はここ

```vue.js
  computed: {
    変数名() {
      - return this.$store.getters.getters名；
      + return this.$store.getters["module名/getter名"];
    }
  }
```

少し見たことない書き方だったので見たときこれでできるのかと思ったけどこれでいいみたい
これで解決。

ちなみに、
####<font color="Red">getterを書く所はcomputedにしよう</font>
dataプロパティは値を変化することができるデータ。処理上変化されている場合がある。
computedプロパティはsetterがない場合、read onlyになるため変更の可能性を考慮せずに済む。

stateを変化できるのはmutationだけっていうルールを守ろうってハナシ！！
未経験SESはやめとけ！現場でテスターと雑用しかやらされなかった話

■雑用
・設計書と実装の乖離の調査。
運用中の設計書と実装の乖離があるから上司から調査して「直せ」と言われる。
ついでにあとで参画する人が見やすいように書き方の統一されてない箇所の修正もやらされる。
・パフォーマンスが悪い箇所の調査。
ログからやたら処理に時間が食ってる箇所を洗い出せと言われる。報告すると上司に３つ４つ機能をピックアップされて、「直せ」と言われる。
チューニング前後の計測するからと言ってそれ専用のバッチを作れと言われる。
「バッチは作ったこと無い」とやんわり言うと「やれ」と言われてネットで調べながら作らされる。それをまとめた資料まで作らされる。

■テスター
・設計書を見させられてテスト観点表を作成。
設計書見てての誤字脱字・実装漏れを発見して報告すると「直せ」と言われて直す。
・バグがあったら報告する
「直せ」と言われる。
・結合試験のフェーズでも観点表を作らされる。
「業務も流れもわからないから無理です」というと「やれ」と言われる。
設計書みまくったり、上司や別会社のパートナーの人に必死に聞き取りしてテストシナリオを作って報告するも
パターンが足りないと何度も突き返される。

おしまい
three-vrmのboneの名前と動く場所

#はじめに
three-vrmをご存じでしょうか。
pixivさんから出てるthree.jsのvrmローダーです。
簡単に触ってみたい方は以下のページで詳しく書いてますので是非触ってみてください。
[【three-vrm】せっかくなのでTypeScript+webpack+three.jsに入門して、Web上でVRMモデルを表示してみる](https://qiita.com/drumath2237/items/2d43d7e3beb7024285ae)
とてもわかりやすいです。
これを機にtypescriptを少し触れるようになればいいなと個人的に思ってます。

#本編
これを触ってると色々なポーズをさせていきたくなると思います。
調べるとボーンの一覧表が出てきました。
[Enumeration HumanoidBoneName](https://pixiv.github.io/three-vrm/docs/enums/vrmschema.humanoidbonename.html)
ヒュー英語だぜ!!!
流石グローバル化が進んでるぜ!!

というわけで日本語特化型エンジニアはgoogle翻訳にかけます。
読めるものもあれば中には...
>LeftLittleIntermediate → 左インデックス中級

なんだよ左インデックス中級って。

困ったのでそのまま検索にかけてみる
[HumanBodyBones.LeftLittleIntermediate](https://docs.unity3d.com/jp/460/ScriptReference/HumanBodyBones.LeftLittleIntermediate.html)
>これは左小指第二指骨のボーンです。

なるほどUnityでの名前と対応してるのか。
しかしUnityは触ったことがないので馴染みも何もありません。
というわけで一覧表にしてみました。どうぞ。

##一覧表

| three-vrm | 場所 |
----|---- 
| Chest | 胸 |
| Head | 頭 |
| Hips | 尻 |
| Jaw | 顎 |
| LeftEye | 左目 |
| LeftFoot | 左足 |
| LeftHand | 左手 |
| LeftIndexDistal | 左人差し指第三指骨 |
| LeftIndexIntermediate | 左人差し指第二指骨 |
| LeftIndexProximal | 左人差し指第一指骨 |
| LeftLittleDistal | 左小指第三指骨 |
| LeftLittleIntermediate | 左小指第二指骨 |
| LeftLittleProximal | 左小指第一指骨 |
| LeftLowerArm | 左ひじ |
| LeftLowerLeg | 左ひざ |
| LeftMiddleDistal | 左中指第三指骨 |
| LeftMiddleIntermediate | 左中指第二指骨 |
| LeftMiddleProximal | 左中指第一指骨 |
| LeftRingDistal | 左薬指第三指骨 |
| LeftRingIntermediate | 左薬指第二指骨 |
| LeftRingProximal | 左薬指第一指骨 |
| LeftShoulder | 左肩 |
| LeftThumbDistal | 左親指第三指骨 |
| LeftThumbIntermediate | 左親指第二指骨 |
| LeftThumbProximal | 左親指第一指骨 |
| LeftToes | 左つま先 |
| LeftUpperArm | 左上腕 |
| LeftUpperLeg | 左太もも |
| Neck | 首 |
| RightEye | 右目 |
| RightFoot | 右足 |
| RightHand | 右手 |
| RightIndexDistal | 右人差し指第三指骨 |
| RightIndexIntermediate | 右人差し指第二指骨 |
| RightIndexProximal | 右人差し指第一指骨 |
| RightLittleDistal | 右小指第三指骨 |
| RightLittleIntermediate | 右小指第二指骨 |
| RightLittleProximal | 右小指第一指骨 |
| RightLowerArm | 右ひじ |
| RightLowerLeg | 右ひざ |
| RightMiddleDistal | 右中指第三指骨 |
| RightMiddleIntermediate | 右中指第二指骨 |
| RightMiddleProximal | 右中指第一指骨 |
| RightRingDistal | 右薬指第三指骨 |
| RightRingIntermediate | 右薬指第二指骨 |
| RightRingProximal | 右薬指第一指骨 |
| RightShoulder | 右肩 |
| RightThumbDistal | 右親指第三指骨 |
| RightThumbIntermediate | 右親指第二指骨 |
| RightThumbProximal | 右親指第一指骨 |
| RightToes | 右つま先 |
| RightUpperArm | 右上腕 |
| RightUpperLeg | 右太もも |
| Spine | 背骨 |
| UpperChest | 上胸(Unity該当なし) |

## 名前がめんどくさい
「ピザって10回言ってみ??」
「ピザピザピザピザピザピザピザピザピザピザ」
「じゃあここは?」
「エルボゥ!!」
「LowerArmじゃ二度と間違えるなクソが」

と言ったように少し名前に癖があります。
これは覚えるしかありません。
しっかし指もめんどくさいことになってますね

| three-vrm | 場所 |
----|---- 
|Thumb|親指|
|Index|人差し指|
|Middle|中指|
|Ring|薬指|
|Little|小指|
|Proximal |第一指骨|
|Intermediate |第二指骨|
|Distal|第三指骨|

ところで第〇指骨ってどこなんでしょう?
[ 第1指骨 ] [検索]
google「馬のやつやで」

ん～わけわからんから自分で調べるか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/17e73b7a-45b9-9ea4-99ad-2a58442edec3.png)

というわけで調べた結果です。
図が汚い?うるせーしらねー!!

#まとめ
今のところ動かしたい部分をちょっとずつ動かすしかない感じですかね。
関節を動かすというよりは腕とかの骨を動かす感覚の方が近いのでしょうか?
解説サイトがまだ少ないので手探りでしかできないのが難点ですね。
いずれ日本語の解説サイトが出来ることを祈って。
Ruby FizzBuzz

IT未経験のスクール生が学んだことをアウトプットします:sunglasses:

FizzBuzzは非常に有名なプログラミングの問題です。
私もRubyの勉強やり始めた時にこの問題と遭遇しました。
プログラミング初心者の方は特に覚えておきたい問題です。

#FizzBuzz問題

1〜100までの数字をターミナルに出力してください。ただし、「3の倍数」のときは数字の代わりに文字列でFizzと、「5の倍数」のときはBuzz、両方の倍数である「15の倍数」のときはFizzBuzzと出力してください。

####1から100までの数字を出力させる

1〜100まで出力させるからといって以下のように順番にputsで出力しようとしては効率が悪すぎます。

<font color="Blue">良くない例</font>

```saple.rb
def fizz_buzz

puts 1
puts 2
puts 3
(中略)
puts 99
puts 100
```
一定の処理を繰り返す時には***while***文を使います。

##while文

while文は繰り返し処理を行う文法の1つです。

```sample.rb
  while 条件式 do
    # 処理
  end
```
条件式を元に繰り返すかどうかを判定します。条件式がtrueの時は処理を繰り返します。
1~100まで出力、つまり数字が100以上になるまでは処理を繰り返すので、条件式は以下のようになります。

```sample.rb
num = 1
while (num <=100) do
end
```
1から始まるのでnum=1を定義します。while文の中に書いてしまうとnumを判別できなくなりエラーが起こるので注意しましょう。

次にwhile文の中身である処理を記述しましょう。処理は問題文にある通り、「3の倍数」のときはFizzと、「5の倍数」のときはBuzz、両方の倍数である「15の倍数」のときはFizzBuzzと出力、です。

##if文
「3の倍数の時は」や「5の倍数の時は」など条件によって処理が別れる時はif文を使います。
条件が複数の時はelsifを使います

 <font color="Fuchsia">書き方</font>

```sample.rb
  if 条件式1 
    # 条件式1が真(true)のときに実行する処理
  elsif 条件式2 
    # 条件式1が偽(false)のとき、かつ
    # 条件式2が真(true)のときに実行する処理
  elsif 条件式3
    # 条件式1が偽(false)のとき、更に
    # 条件式2が偽(false)のとき、かつ
    # 条件式3が真(true)のときに実行する処理
  else
    # 条件式1と条件式2がどちらとも偽(false)のときに実行する処理
  end
```

今回の問題に当てはめるとこうなります。

```sample.rb
  def fizz_buzz
    num = 1
    while (num <= 100) do
      #15の倍数の時(もしnumを15で割った時の余りが0なら)
      if (num % 15) == 0
        puts "FizzBuzz"
      #3の倍数の時(numを3で割った時の余りが0なら)
      elsif (num % 3) == 0
        puts "Fizz"
      #5の倍数の時(numを5で割った時の余りが0なら)
      elsif (num % 5) == 0
        puts "Buzz"
      #それ以外の時
      else
        puts num
      end
    end
  end
```
最後に処理が終わるごとにnumを1ずつ増やさなければいけません。増やさないとnumが1のままで、
永遠に1だけが出力されます。

<font color="DarkOrange">完成コード</font>

```sample.rb
 def fizz_buzz
    num = 1
    while (num <= 100) do
      if (num % 15) == 0
        puts "FizzBuzz"
      elsif (num % 3) == 0
        puts "Fizz"
      elsif (num % 5) == 0
        puts "Buzz"
      else
        puts num
      end
      # numを1ずつ増やす　num +=1(自己代入演算子)でもOK
      num = num + 1
    end
  end
  #メソッドの実行
  fizz_buzz
```
DiscordBOTをPythonで作るときの個人的によく使うテンプレート（備忘録）

# 前提
```:環境
Python 3.6.6
Discord.py-1.2.5
```
```:ディレクトリ構造
├ cogs
│   └ mainCmd.py
└ main.py
```
# コード
```python:main.py
import discord
from discord.ext import commands
import traceback 

DiscordBot_Cogs = [
    'cogs.mainCmd'
]

class MyBot(commands.Bot):
    def __init__(self, command_prefix):
        super().__init__(command_prefix)
        for cog in DiscordBot_Cogs:
            try:
                self.load_extension(cog)
            except Exception:
                traceback.print_exc()

    async def on_ready(self):
        print('BOT起動')

if __name__ == '__main__':
    bot = MyBot(command_prefix='!?')
    bot.run('TOKEN') 
```
```python:mainCmd.py
from discord.ext import commands

class MainCmdCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    async def cmd(self, ctx):
        await ctx.send("コマンドを受信しました。")

def setup(bot):
    bot.add_cog(MainCmdCog(bot))
```
# 説明と注意書き
## main.py
```python
DiscordBot_Cogs = [
    'cogs.mainCmd'
]
```
`DiscordBot_Cogs`というリストの中に`'cogs.mainCmd'`を入れる。
コマンド用Pythonファイル（コグ）を追加するときはリストの書き方に従って

```python
DiscordBot_Cogs = [
    'cogs.mainCmd',
    'cogs.exampleCmd'
]
```
とする。
`cogs`はフォルダ名で`mainCmd`は拡張子なしのファイル名。

```python
for cog in DiscordBot_Cogs:
    try:
        self.load_extension(cog)
    except Exception:
        traceback.print_exc()
```
先ほどのリストをfor文で回してtry&exceptを使ってコグを登録する。（ファイル名が間違っていたりしてファイルが存在しなかった場合にエラーが出る。）

```python
if __name__ == '__main__':
    bot = MyBot(command_prefix='!?')
    bot.run('TOKEN') 
```
BOTのコマンドで頭に付ける文字（MonsterBOTだと`!?`、Minecraft風に言えば`/`）
## mainCmd.py
```python
@commands.command()
async def cmd(self, ctx):
    await ctx.send("コマンドを受信しました。")
```
`!?cmd`と打つだけでそのチャンネルで`コマンドを受信しました。`とBOTに送らせるコマンド。

これに引数を使うときは以下のようにすればよい。

```python
@commands.command()
async def cmd(self, ctx, *args):
    if len(args) == 0:
        await ctx.send("引数が存在しない。")
    if len(args) == 1:
        await ctx.send("引数が１つで **" + args[0] + "** である。")
    if len(args) == 2:
        await ctx.send("引数が２つで **" + args[0] + "** と **" + args[1] + "** である。")
```
あとは増やしていけばよい。
ROCm 向け iterative sparse matrix solver rocALUTION のメモ

https://github.com/ROCmSoftwarePlatform/rocALUTION

いろいろライブラリがぽこぽこ湧いてきて, ROCm はよくわからない構成になっている感があります.

すでに疎行列ライブラリは rocSparse (cuSparse の ROCm 版?)がありますが, rocALUTION はそのラッパーのようなものでしょうか?
CUDA には cuSolver がありますが, 対応するもの(?)として rocSOLVER https://github.com/ROCmSoftwarePlatform/rocSOLVER があるので rocALUTION の存在が謎です.

ただ, コードはよくかけているようで, 他の ROCm ライブラリに比べて, ビルドはすんなりとおります.

API もそんなにややこしくないので, GPU (疎)行列計算ライブラリとして利用しやすそうな雰囲気があります.
とりあえずぱぱっと使えて, GPU で高速化(されるはず)された行列ソルバーほしいときに良さそうです.

double 精度も対応しています.

gfx803(fiji, polaris)以降対応なので, 現状(2020/03 月), 倍精度で活用するには実質 Radeon VII 一択でしょうか.
AWS SAA(SAA-C01)取得までのメモ

AWSがこれだけ普及しているのに、全く知らないのはエンジニアと呼べるのかい？と思い、SAA取得を決意！
クラウド・サーバ・ネットワークに関する知識もほぼ皆無な状態でしたが
１ヶ月半学習し、なんとか合格
全セクションにおいて「十分な知識を有する」でした

学習の流れは、大まかに以下２つになります
1.Udemy学習教材
これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座（初心者向け22時間完全コース）
→セール期間であれば1200〜1500円で購入できます(量・質共に参考書より圧倒的にコスパが良い)
AWS何それ？レベルの人でもハンズオン形式で学習するので、知識が無くても問題なく進めていけますが
分からない用語はちゃんとググりましょう（22時間の倍はかかると思って！）
実際に手を動かすことで、イメージができるようになるので、大幅に理解できるようになります
模擬試験1〜3を９0%以上取れるようになるまでレッツチャレンジ！

2.WEB問題集
AWS WEB問題集で学習しよう(https://aws.koiwaclub.com/)
→1.Udemy学習教材の模擬試験の正答率が90%達成できていれば、#82から学習で良いです
解説もわかりやすく、本番に近いレベルになっています（かなり類似している）


合格したので、AWSの気になった機能について、試験範囲ガーとか気にせず深掘りできるようになった
これが一番嬉しい！
dbm

#書き込めるのは、バイトか文字列のみ

```py
import dbm

#r:読み込み専用、w:書き込み専用、c:読み書き両方
with dbm.open('cache','c') as db:
    db['key1']='values1'
    db['key2'] = 'values2'
    #db['key3']=1

with dbm.open('cache','r') as db:
    print(db.get('key1'))
```
出力：

```text
b'values3'
```
コードレビューのLGTMをカッコよく出してみる

# 今日の目標

チーム開発でコードレビューは大切です

でもまだまだレベルの高いコードレビューをできるかどうか　それはちと難しい

だから　チーム開発なんかでも　つい　「LGTM！」を連発してしまいます。

これではちと　
#味気ないのでは？？？？

ということで　

プルリク出した人が　ガンダムファンなら

![LGTM](https://i.lgtm.fun/mrn.png) 

北斗の拳が好きなら

![LGTM](https://i.lgtm.fun/mmx.png)

子猫好きなら

![LGTM](https://i.lgtm.fun/44e.gif)

そして　もののふ　なら
![LGTM](https://i.lgtm.fun/mvb.png)

こんな感じで　ちょっとした工夫で　チーム開発も盛り上がるんではないでしょうか？

# 参考サイトはこちらです

https://lgtm.fun/

乃木坂もありますw　


## では　チーム開発は楽しんでなんぼなんで　遊び心を持ってやりましょ〜〜〜〜

ひがきけいた
Twitter: https://twitter.com/keitah0322
Github : https://github.com/higakikeita
huggingface/transformersのBertModelで日本語文章ベクトルを作成

事前学習済みBERTから日本語文章ベクトルを作成する方法を紹介します。

## 環境
- Python (3.6.9)
- PyTorch (1.3.0)
- [transformers](https://github.com/huggingface/transformers) (2.5.1)

## 手順
### 1. モデル読み込み
```py

import torch
from transformers.tokenization_bert_japanese import BertJapaneseTokenizer
from transformers import BertModel 

# 日本語トークナイザ
tokenizer = BertJapaneseTokenizer.from_pretrained('bert-base-japanese')
# 事前学習済みBert
model = BertModel.from_pretrained('bert-base-japanese')
```

### 2. 入力データの準備
今回は3文を格納したリストを用意

```py
input_batch = \
    ["すもももももももものうち", 
    "隣の客はよく柿食う客だ",
    "東京特許許可局許可局長"]
```

### 3. 前処理（単語Id化, Padding, 特殊トークン付与)

[batch_encode_plus](https://huggingface.co/transformers/main_classes/tokenizer.html#transformers.PreTrainedTokenizer.batch_encode_plus)を使えば、文章リストからモデル入力用のミニバッチへ前処理してくれます。
`pad_to_max_length`はPaddingのオプション。

```python
encoded_data = tokenizer.batch_encode_plus(
input_batch, pad_to_max_length=True, add_special_tokens=True)
```

**結果**
辞書型を返却するので注意が必要です。
`input_ids`が単語ID化したものです。

```py
{'input_ids': [[2, 340, 28480, 28480, 28, 18534, 28, 18534, 5, 859, 3, 0],
  [2, 2107, 5, 1466, 9, 1755, 14983, 761, 28489, 1466, 75, 3],
  [2, 391, 6192, 3591, 600, 3591, 5232, 3, 0, 0, 0, 0]],
 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]]}
```

ちなみに、どのようにトークナイズされたか確認すると以下のにようになります。

```py
input_ids = torch.tensor(encoded_data["input_ids"])
tokenizer.convert_ids_to_tokens(input_ids[0].tolist())
```

**結果**

特殊トークンがきちんと付与されています。

```py
['[CLS]', 'す', '##も', '##も', 'も', 'もも', 'も', 'もも', 'の', 'うち', '[SEP]', '[PAD]']
```

### 4. BERTで文ベクトル化
さきほどのtensor化した`input_ids`をBERTへ入力します。

[公式ドキュメント](https://huggingface.co/transformers/model_doc/bert.html#transformers.BertModel)によると、モデルはタプルを返却する。
1つ目の要素が最終層の隠れ状態ベクトルになるので、`outputs[0]`で取り出す。

```py
outputs = model(input_ids)
last_hidden_states = outputs[0]
print(last_hidden_states.size())
# torch.Size([3, 12, 768])
```

出力ベクトルのサイズを見てみると、（ミニバッチサイズ, 系列長, ベクトル次元数）になっています。
**入力したテキストの先頭に付与されている`[CLS]`から文ベクトルを作りたい**ので、以下のように取り出します。

```py
sentencevec = last_hidden_states[:,0,:]
print(sentencevec.size())
# torch.Size([3, 768])
```

これで完成です。

## 参考ページ
- https://github.com/huggingface/transformers
- https://github.com/cl-tohoku/bert-japanese
全PullRequestコンフリクト地獄

こんばんは、おささです😚

今回のお題

#### 「コンフリクト地獄」

でございます。

そうです、GithubにPullRequestとして上げたブランチが　**全部**　コンフリクト起こしているんです。

### 流石に走馬灯が見えました。

コンフリクトを起こしていたファイルは、VScodeのconfig/db配下にある***「schema.rb」***ファイルです。

### 経緯からご説明します。

1. チーム開発でDB設計後、**各テーブルに分けて**brunchを作って作業をした
2. migrationをしたあとに**必ず変更がかかる**schema.rbファイルの存在を知らず、各brunchのschemaファイルがその時点で相違していた
3. そのことに気づかず、各テーブルをそれぞれが作業しGithubにあげたため、**全brunchで**schemaファイルのコンフリクトが起きた

以上が、ざっくりとした全貌です。

多分この記事を検索して見られている方は、かなり焦られていると思いますが
### ご安心ください
簡単に直ります。

そもそもschemaファイルはmigration毎に変わるので、**サクッとリセットしちゃおう！**みたいな感じだそうな。

# 対処方法

1. GithubDesktopを最新の状態にしましょう！（master brunchを選択し、Fech origin!）
2. masterが最新になったら、コンフリクトを起こしているbrunchに切り替えましょう（Current brunchをコンフリクト起こしているbrunchへ！）
3. PCの左上「brunch」を選択し、 Update from master を選択
4. GithubDesktopにコンフリクトの窓が現れたと思うので、「Open in Visual Studio Code」を押しVScodeへジャンプ！
5. schemaファイルに、コンフリクト内容が嬉しくないカラフルさで出ていると思いますが、　command+a　で記述を全削除！
6. ディレクトリに移動したターミナルで、「rails db:migrate:reset」コマンドを実行！
7. schemaファイル内が更新され、GithubDesktopに戻るとコンフリクトが解消されていると思うので「Commit Merge」！
8. 変更を「Push origin」！

この作業で、**schemaファイルのコンフリクト**は解消することができます😄
もしコンフリクトを起こしている**schemaファイル**がいくつもある場合、コンフリクトを解消する順番とかはとくにないそうなので、Mergeしたい順に解消作業をしていけば良いかと思われます♪

あとは適宜、Github上でMerge、GithubDesktopでmasterにMerge等していただければ👍

### 以上、「全Brunchコンフリクトで地獄を見た」の回でした！

では、また👋
Ovtoにミドルウェア機能を追加しました

先日[Ovto](https://qiita.com/tags/ovto)の新バージョン0.6.0をリリースしました。本稿では0.6の目玉機能「Ovto::Middleware」について解説します。

## Ovto::Middlwareとは

昨年のアドカレで[書いた](https://qiita.com/yhara/items/01d0b4938d7b86d320d9)ように、これまでのOvtoはstateとactionの名前空間が1つしかなく、ある機能を複数のアプリ間で使いまわそうとしたときに取り回しがあまり良くありませんでした。

Ovto::Middlewareはこれを解決するためのもので、あるまとまったState, Actions, Componentの組を「ミドルウェア」として切り出すことができます。

## ミドルウェア

- 各ミドルウェアは名前を持ちます。名前に使える文字はRubyのメソッド名と同じです(つまりハイフン等は不可)。
- 各ミドルウェアはアプリと同様、State, Actions, Componentを持ちます。ただし名前空間はミドルウェアごとに固有なので、アプリや他のミドルウェアとの名前衝突を気にする必要はありません。
- ミドルウェアはアプリが`use`することで使用可能になります。
  - またはミドルウェアが別のミドルウェアを`use`することも可能です。

## 例

(https://yhara.github.io/ovto/docs/api/middleware.html の日本語訳です。)

```
# 1. ミドルウェア名を付ける
class MyMiddleware < Ovto::Middleware("my_middleware")
  def setup
    # アプリ起動時に行いたい処理
  end

  # 2. ミドルウェアのstate
  class State < MyMiddleware::State
    item :count, default: 0
  end

  # 3. ミドルウェアのaction
  class Actions < MyMiddleware::Actions
    def increment(by:)
      return {count: state.count + by}
    end
  end

  # 4. ミドルウェアのcomponent
  class SomeComponent < MyMiddleware::Component
    def render
      o 'span', state.count
      o 'button', onclick: ->{ actions.increment(by: 1) }
    end
  end
end

class MyApp < Ovto::App
  # 5. ミドルウェアを使うことを宣言
  use MyMiddleware

  class State < Ovto::State; end
  class Actions < Ovto::Actions; end

  class MainComponent < Ovto::Component
    def render
      o 'div.counter' do
        o MyMiddleware::SomeComponent
      end
    end
  end
```

## デモ

- https://yhara.github.io/ovto-ide/
- https://github.com/yhara/ovto-ide

Ovto::Middlewareの使用例です。昨年の春頃に「Smalltalkみたいな環境を作りたい」と思って作業していたものが例にちょうど良かったのでミドルウェア化しました。移動・リサイズ可能なウィンドウを`ovto_window`というミドルウェアとして実装しています。
Twitter、FaceBook、LINEのSNSシェアリンクを作る

とりあえずHTMLのシェアリンクの書き方を3つ書きます。
`[URL]`の部分をシェアしたいURLに置き換えてください。

# Twitter

```html
<a href="https://twitter.com/intent/tweet?url=[URL]">Twitter</a>
```

# FaceBook

```html
<a href="https://www.facebook.com/sharer/sharer.php?u=[URL]">FaceBook</a>
```

# LINE

```html
<a href="https://timeline.line.me/social-plugin/share?url=[URL]">LINE</a>
```

# 結果

<a href="https://twitter.com/intent/tweet?url=https://qiita.com/oblivion/items/cc7b4773b8305e93c049">Twitter</a>
<a href="https://www.facebook.com/sharer/sharer.php?u=https://qiita.com/oblivion/items/cc7b4773b8305e93c049">FaceBook</a>
<a href="https://timeline.line.me/social-plugin/share?url=https://qiita.com/oblivion/items/cc7b4773b8305e93c049">LINE</a>

# 参考文献

この記事は以下の情報を参考にして執筆しました。

- [【ソーシャルサービス】シェアURLまとめ](https://11-30am.com/38/?utm_source=qiita&utm_content=article#URL)
[Rails]ItemImagesテーブルとItemsテーブルを別けた際のテーブルの紐付けから複数画像アップロードまで

##Gemのインストール
```ruby:Gemfile
gem 'carrierwave'
gem 'rmagick'
```
画像投稿機能に関わるgemのインストールをお忘れなく。
gem'rmagick'は画像のリサイズなどに使用します。

##前置き
```ruby:terminal
rails g uploader images
```
リサイズなど画像の設定をする為のファイルが生成されます。

```
app/uploaders/images_uploader.rb
```

##モデルとの紐付け
imageが存在するモデルをItem_Imageモデルとしています。

ItemImagesテーブルとItemsテーブルは**1対多**の関係にあります。
画像は沢山のItemを持っているからです。
![2020-03-07 23.14のイメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565275/db656bca-1303-2818-9728-b4888509091d.jpeg)



```ruby:item.rb
class Item < ApplicationRecord
  has_many   :item_images 
  accepts_nested_attributes_for   :item_images
end
```

ネストさせるパラメータ(item_imageモデル)の親のモデルクラスであるitemモデルに**accepts_nested_attributes_for**を記述します。引数にはネストの子のモデルをシンボルで指定してあげます。
has_manyなので複数形で記述します。
こうすることで **item_images_attributesメソッド**がItemモデルに追加されました。
後ほど使用します。

```ruby:item_image.rb
class ItemImage < ApplicationRecord
    belongs_to :item 

    mount_uploader :image, ImageUploader
end
```
ItemImagesテーブルに追加したカラムの名前をmount_uploaderに指定します。

##Itemsコントローラーの設定
```ruby:items_controller.rb
def new
  @item = Item.new
  @item_image = @item.item_images.build
end

```
formで使用する@itemをnewメソッドで生成し、
**buildメソッド**でitemモデルに紐付くitem_imageモデルを生成しています。
buildメソッドは慣習的に、関連するモデルを生成するときは、buildを使うようです。
ここで生成したインスタンス変数@item_imageはcreateメソッドで使用します。



##Formの作成
```html:new.html.haml
= form_with(model:@item, locale: true , id: 'new_item') do |f|
 　= f.fields_for :item_images do |i|
　　　= i.file_field :image, multiple: true, class: 'image-upload-dropfile-hidden', id:"image-label",type: 'file', name: "item_images[image][]"
```

1つのアップローダーで複数の画像を選択する為には、**multiple: true**を記述する必要があります。
multiple: trueを記述した際、params内は配列として渡されるので、コントローラー側で配列の中身を取り出す処理が必要になります。

##ストロングパラメーター
```ruby:items_controller.rb
private

  def item_params
      params.require(:item).permit(item_images_attributes: [:id, :item_id, :image])
  end
```

今回コードが冗長になる為、itemsテーブルの他のキーのpermitの記述は抜いています。
ここで登場です、item_images_attributesメソッド。
item_images_attributesをpermitに加えると、コントローラで入れ子のitem_imagesの属性を@item.item_imagesとして扱えるようになります。
配列内にはitem_imagesテーブルのキーを記載しています。


##Formに入力したデータの保存

```ruby:items_controller.rb
def create
    if @item.save

      params[:item_images]['image'].each do |img|
        @item_image = @item.item_images.create(:image => img, :item_id => @item.id)
      end

      redirect_to item_path(@item.id)
    end
  end
```
念押しです。先ほどの@item_imageはcreateアクションで保存の処理を行うために、newアクションでインスタンス生成しました。
multiple: trueで複数の画像を渡しているので、params[:item_images]['image']の中身は配列であり、each文で一つ一つの要素に@item_image取り出す処理を行います。
これでDBにItemモデルと紐づいた画像が登録されます。
mksのプログラミング勉強記録（html、css、dockerなど様々書きます）

#3月8日進捗
・某オンラインプログラミング課題にてgitHubのログイン機能の実装が成功
・dockerのコマンドを一覧にまとめた。
・<img width="1792" alt="スクリーンショット 2020-03-08 0.40.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579630/9a101807-1ca1-bad6-581c-e34a7ea237ed.png">

##取り組んだこと
wordpressのorgのダウンロード
dockerの作成
dockerのnginxの実行
dockerコマンドをまとめ。
laravelの勉強
"Import CSV with 1 Select" チャレンジ - 解説

# ループなしでCSVをJSONにするチャレンジ
2020/3/6 にJohn LiuからツイートされたPower Automateに関するチャレンジの解説です。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">FRIDAY <a href="https://twitter.com/MSPowerAutomate?ref_src=twsrc%5Etfw">@MSPowerAutomate</a> CHALLENGE TIME<br>Import CSV with 1 select<a href="https://twitter.com/hashtag/FlowFam?src=hash&amp;ref_src=twsrc%5Etfw">#FlowFam</a> <a href="https://twitter.com/mofumofu_dance?ref_src=twsrc%5Etfw">@mofumofu_dance</a> <a href="https://t.co/WOvLnXUTji">pic.twitter.com/WOvLnXUTji</a></p>&mdash; John Liu 劉 (@johnnliu) <a href="https://twitter.com/johnnliu/status/1235846758107729920?ref_src=twsrc%5Etfw">March 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

列の数が分かっている場合には、Apply to eachのループを利用することなく、Selectアクション1個でCSVからJsonを作れます。
※以前の投稿 [こちら](https://qiita.com/h-nagao/items/4c9cfa65f80792258cf9)では、任意のN列に対応するためにLoopを一個つかっていました。でもNが分かっていればSelect一個で対応可能です。

# Flow
全体は以下のようになります。
簡単のため、4行ｘ2列のCSVですが、500行だろうが、10列だろうが、構成は同じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/ddee4ec1-7836-8088-1ac6-833d78f3f392.png)

順番に見ていきましょう。

## Compose lines
1 Selectでと言いながら、わかりやすさのために1個Composeアクションを挟んでいます。
ここでのインプットは

```
split(outputs('Compose'),decodeUriComponent('%0A'))
```
やっているのは、最初に定義した4x2のCSVを改行コード(LF)でsplitしています。改行コードが```decodeUriComponent('%0A')``` です。
この結果まずは、5個の文字列からなる配列が得られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/970fa4f5-8f37-73b5-88cc-f90f011cb8c2.png)
ヘッダーが配列の0番目ですね。

## Select
あとはほとんどお分かりかと思いますが、**range()**を対象にSelectをして、各行をカンマでSplitして格納という操作をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/c8192081-849d-0b47-f648-c6df1ecf8823.png)
range(....)の結果は、ここでは[1,2,3,4]になります。
Mapの中で、*item()*と書くと、この1~4のいずれかになります。これを利用して、
Compose linesの0番目(最初の行)でkey:valueの**key**部分をつくり、1番目以降、item()番目でvalueを作る
という操作をしています。

結果は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/8ea3ea87-8b2d-5c44-04ac-c04d7489a7ff.png)

# 補足
500行、10列のCSVで試してみました。結果は0秒で終わっています。これなら、例えばOneDrive上のCSVをPowerAppsのデータソースにするのも気軽にできそうですね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/52101c81-3866-a264-3f53-280f4663e3ae.png)
ssh環境の設定メモ


# Client側での鍵生成と転送
```
ssh-keygen -t ed25519  -C "kanai-x1-carbon-2018"
ssh-copy-id -i id_ed25519.pub kanai@www.hogetan.net
ssh kanai@www.hogetan.net
```

# Windowsでのssh-agent
```
sc config ssh-agent start=auto
sc start ssh-agent
ssh-add  c:\Users\kanai\Documents\x1.priv
```

# Unixでのssh-agent
```
eval `ssh-agent`
# Agent pid 138
ssh-add
# Enter passphrase for /home/kanai/.ssh/id_ed25519:
# Identity added: /home/kanai/.ssh/id_ed25519 (kanai-nw6-x1-2019-ubuntu)
```
あたまのなかの整理メモ(Java - データ型編)

# My Java環境

* java11

# Javaのデータ型

 * プリミティブ型
 * 参照型

## プリミティブ型(値そのものを使う、`null`は代入できない。)

 * boolean(初期値は`false`)
 * char
 * byte
 * short
 * int
 * long(`l`をつける。`long value = 10l;`)
 * float(`f`をつける。`float value = 10f;`)
 * double

## 参照型(インスタンスへの参照を扱う)

 * オブジェクト型
 * 配列型
 * 列挙型

##　n進数

 * 2進数(`0b`はじまり。`int value = 0x0101`)
 * 8進数(`0`はじまり。`int value = 077;`)
 * 10進数(特記なし。`int value = 10;`)
 * 16進数(`0x`はじまり。`int value = 0x1B;`)

## アンダースコアを使用した数値表記

 * 先頭と末尾での使用NG(`int value = _123;`や`int value = 123_;`はNG)
 * 記号の前後での使用はNG(`int value = 12_.3;`や`float value = 123_f`や`int value = 0x_0100;`はNG)
 
```java

int value = 123_456;
System.out.println(value);
```

表示結果は

```
123456
```


## 識別子の命名規則

 * 予約語の使用はNG
 * 記号はアンダースコア(`_`)と通貨記号はOK、ハイフン(`-`)の使用はNG
 * 数字から始まるのはNG(`int v123;`はOK)

## 型推論(`var`)

型推論はコンパイル時に行われる。

### OK

 * 以下のようなローカル変数
 
```java
var value = 123;
var value = method();
var value = new ArrayList<>();
```

### NG

* メンバ変数
* メソッドの引数宣言(`public method(var value){...}`はNG)
* 以下のようなローカル変数

```java

var value;
var value = null;
var value = {1, 2, 3};
var value = ラムダ式
```

 * 2つのクラスに互換性がない場合

```java

var classA = new ClassA();
classA = new ClassB();
```

## mutable(可変)とimmutable(不可変)

### mutable
* StringBuilderクラス　
* など

### immutable
 * Stringクラス
 * LocalDateクラス
 * など

## 型の範囲

byte < short < int < long < float < double

ばいしょいろふだ

## 型変換

`大きい`から`小さい`は明示的にキャスト。

```java

int value1 = 123;
short value2 = (int)value1;
```

## 同一性と同値性

* 同一性(同じインスタンスを参照) ・・・ `==`で判定
* 同値性(同じ値) ・・・ `equals`で判定
投稿したユーザーのみ編集・削除を許可したい

##投稿したユーザーのみ編集・削除
【例】モデルをTweetとします。

```app/views/tweets/index.html.erb
〜省略〜
<% if user_signed_in? && current_user.id == tweet.user_id %>
            <li>
              <%= link_to '編集', "/tweets/#{tweet.id}/edit", method: :get %>
            </li>
            <li>
              <%= link_to '削除', "/tweets/#{tweet.id}", method: :delete %>
            </li>
          <% end %>
〜省略〜
```
上記で「ユーザーがログインしている」かつ「投稿したユーザーである投稿だけに許可」となります。
current_user.id == tweet.user_idにより、ログイン中ユーザーのidと投稿したユーザーのidが一致すれば、編集・削除の表示を許可しました。
user_signed_in?はユーザー登録しているか?
currentは現在なのでcurrent_user.idはログイン中
tweet.user_idはどのユーザーのidか
&&は"かつ"==は"等しい"という意味です。
showアクションにも記述します。
【例】

```app/views/tweets/show.html.erb
〜省略〜
<% if user_signed_in? && current_user.id == tweet.user_id %>
            <li>
              <%= link_to '編集', "/tweets/#{tweet.id}/edit", method: :get %>
            </li>
            <li>
              <%= link_to '削除', "/tweets/#{tweet.id}", method: :delete %>
            </li>
          <% end %>
〜省略〜
```
さっきのとは少し違いcurrent_user.id == @tweet.user_idという条件を含むif文で、未ログイン時や自分の投稿ではない時は非表示となるように記述しました。
Pythonでスクレイピングしたテキストを、Googleスプレッドシートに入れる

## 参考サイト
https://yokonoji.work/python-scraping-6
https://qiita.com/akabei/items/0eac37cb852ad476c6b9

## 使ったライブラリ
requests
BeautifulSoup
oauth2client
gspread

## 実装
### サービスアカウントキー
Googleスプレッドシートにアクセスするためのサービスアカウントキーは、参考サイトに書いてあるとおりなので、ざっくりで書きます。m(_ _)m

↓サイトにて、
https://console.developers.google.com/cloud-resource-manager

↓を実行
- プロジェクトを作成
- Google Drive API 有効
- Google Sheets API　有効
- サービスアカウントキーを作成 （JSONダウンロード）

### スプレッドシート作成
- スプレッドシート作成
- 「共有」から、ダウンロードしたJSONに書いてある「client_email」のアドレスを共有

### プログラム作成
```sample.py
import requests
import gspread
from bs4 import BeautifulSoup
from oauth2client.service_account import ServiceAccountCredentials

url = "<取得するサイトのURL>"
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
elements = soup.select('<取得したいタグ>')#select()メソッドを使っているので、「CSSセレクタ」で書ける

scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('<ダウンロードしたJSONファイル名>', scope)
gc = gspread.authorize(credentials)
wks = gc.open('<スプレッドシートの名前>').sheet1

for index, e in enumerate(elements):
    num = index + 1　#スプレッドシートの番号に「0」が無いので先に1をプラス
    wks.update_acell('A'+str(num) , e.get_text())
```
Rust の dbg! マクロはリリースビルドでも普通に動く

[AtCoder Beginner Contest 158](https://atcoder.jp/contests/abc158)
に参加されたみなさま、お疲れさまでした。

D問題で以下のような問題が出題されました。

## D - String Formation

### 概要

英小文字からなる文字列 $S$ がある。
$S$ に対して、与えられた $Q$ 回の操作を順番に施す。操作は以下の3種類のうちいずれかである。

＜操作＞
1. 文字列 $S$ の前後を反転する
2. 文字列 $S$ の先頭に文字 $C_i$ を追加する
3. 文字列 $S$ の末尾に文字 $C_i$ を追加する

$Q$ 回の操作の後、最終的にできる文字列を求めなさい。

### 制約

- 文字列 $S$ の長さは $10^5$ 以下
- $S$ は英小文字からなる
- $1 \leq Q \leq 2 \times 10^5$
- $C_i$ は英小文字

# コンテスト中の思考

順番に操作を処理していくけど、文字列の反転操作は愚直に毎回実行するとコストが大きそう。
「反転フラグ」みたいなものを用意しておいて、「今、文字列は反転状態なのか？そうでないのか？」を仮想的に扱えるようにすればよさそう。
例えば、「反転フラグ」が `true` の状態で `先頭 に x を追加する` という操作を行うのと、「反転フラグ」が `false` の状態で `末尾に x を追加する」という操作を行うのは、等価とみなせる！

これをコードに落とし込めば、計算量的には $O(Q)$ でいけるはず。
先頭に追加したり末尾に追加したりするから、 `Vec` じゃなくて `VecDeque` を使うことにだけ注意しよう。

# 実装

コンテスト中の自分は上のような思考を辿り、以下のように実装をしました。


```rust
fn main() {
    let S: String = read();
    let S: Vec<char> = S.chars().collect();
    let Q: usize = read();
    let query = read_vec2(Q as u32);
    use std::collections::VecDeque;
    let mut S: VecDeque<_> = S.into();
    let mut reverse = false; // 反転フラグ

    for i in 0..Q {
        let q = &query[i];
        dbg!(&query[i], &q);
        if q[0] == '1' {
            reverse = !reverse;
        } else {
            let f = q[1];
            let c = q[2];
            if (!reverse && f == '1') || (reverse && f == '2') {
                // 反転フラグが立っていない状態で先頭に追加するのと、反転フラグが立っている状態で末尾に追加することが等価
                S.push_front(c); 
            } else if (!reverse && f == '2') || (reverse && f == '1') {
                // ↑の反対、末尾に追加するパターン
                S.push_back(c);
            }
        }
    }
    let ans: String = if reverse {
        // Q 回の操作を終えたあと、反転フラグが立っているならば、実際の反転処理を行う
        S.into_iter().rev().collect()
    } else {
        S.into_iter().collect()
    };
    println!("{}", ans);
}

```

テストケースも無事にパスし、ノリノリで提出をしました。
（なお、[tanakh/cargo-atcoder](https://github.com/tanakh/cargo-atcoder) を使用して、ローカルでビルドしたものを提出しています。）

# 提出結果

<img width="1106" alt="スクリーンショット 2020-03-07 23.42.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151210/37f2216f-95a5-301a-e61d-0abe6294378d.png">

.......なんで❗️❓❗️❓❗️❓❗️❓

# コンテスト終了後

Rust の文字列操作は実はめちゃくちゃ重たいのか…？ `VecDeque` は重いのか？？ `.rev()` が重いとか？？
など、あらゆる可能性を考え、疑心暗鬼に陥っていました。

Rust の標準ライブラリのドキュメントをチェックしていき、[std::dbg - Rust](https://doc.rust-lang.org/std/macro.dbg.html) にたどり着いた自分の前に、この文章が現れました。


>The dbg! macro works exactly the same in release builds. This is useful when debugging issues that nly occur in release builds or when debugging in release mode is significantly faster.

———— **dbg! マクロってリリースビルドでも動くのか！！！！！！！！！！！！**

# 再提出

デバッグ用に

```rust
dbg!(&query[i], &q);
```

を書いていたのですが、これはリリースビルドでは無効化されるものだと勝手に思い込んでいました。
`dbg!` を消して提出したところ、50ms で AC しました。
（ `dbg!` 高々20万回実行するだけでめちゃくちゃ時間かかるんですね……）

コンテスト中の最初の提出で通っていればギリギリ水色パフォが出ていたものの、この `dbg!` による TLE のせいで茶色パフォになってしまいました。

`dbg!` はリリースビルドでも動く、って常識なんでしょうか？
僕と同じ被害に遭う方を少しでも減らせれば幸いです。
【自分用】git pull　３つの使い方

自分用です。ただのメモです。

##### git pullどんな時に使う？
リモートリポジトリのコードをローカルに持ってきたい時。
ローカルで新しくリポジトリを作って作業したい時。
など




##### git checkout masterの前提で以下３ついずれかのやり方でできる
（内容は同じ）

```
$ git pull origin master
// origin 上の master ブランチを、現在チェックアウトしているブランチ（= master）に取り込む
```
```
$ git fetch origin master
// 指定したリモートブランチの最新状態を、リモート追跡ブランチに反映する
```
```
$ git merge FETCH_HEAD
// 更新されたリモート追跡ブランチを、現在のローカルブランチにマージする
```
chat-space終了

挙動確認
グループ名が左に寄ってなかった
_message.scssでh1にしていたのを.group-info__box__group に変えたら左に寄った

Editボタンを押すと、参加以外のメンバーが表示される
（どのグループのEditボタンを押しても同じメンバーが表示されています）
_main_chat.html.hamlでedit_group_path(current_user)を
= link_to "Edit", edit_group_path(@group), class: 'btn'に変えて修正。

再起動しないと本番環境には反映されない


Nginxの再起動
リモートのターミナル
1 sudo service nginx restart

Unicornの再起動
リモートのターミナル
1. > ps aux |grep unicorn
2. # Unicornのプロセスidを確認する
3. > kill -9 （unicornのプロセスid

ローカルのターミナル
1 > bundle exec cap production deploy

個人アプリ作りたいものは見つかったが、どうしていいかわからない
とりあえず何もしないのはもったいないので基礎カリキュラムのMVSの復讐、改めて見るよくわかる！
Thymeleafで開発中にHTML内のth属性にwarningがついてしまう

# 現象
eclipseやSTSでSpring boot + Thymeleafで開発しているとき、HTML内のth属性にwarningがついてウザい。
![warning.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371795/0f198573-fa18-b9a2-687d-76dc84eeb290.png)

# 環境
Spring Tool Suite 3

# 原因
htmlの属性に`xmlns:th="http://www.thymeleaf.org"`を書き忘れている。

```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <title>Hello</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>Hello SpringBoot Sample</h1>
    <h1 th:text="${message}"></h1>
  </body>
</html>
```

# 対策
## パターン1：HTML属性にxmlnsを書く
HTMLタグのxmlns属性を書いて、th属性があることをエディタに知らせる。

```html:sample.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Hello</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>Hello SpringBoot Sample</h1>
    <h1 th:text="${message}"></h1>
  </body>
</html>
```

## パターン2：th属性ではなく、data属性形式で書く
th属性ではなくdata属性の記述方式で書く
HTML5対応したい場合はこちら。個人的にはこちらを押したい。

```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <title>Hello</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>Hello SpringBoot Sample</h1>
    <h1 data-th-text="${message}"></h1>
  </body>
</html>
```
ゴルーチンを使ってwindows用のtouchコマンドを作ってみた

# 概要

windowsでtouchが使えないので、以下の機能を持つtouchコマンド作ってみた。

 1. 複数ファイルを一度に作る    (例) touch file1 file2 file3
 2. 既存ファイルは上書きしない

[githubレポジトリ](https://github.com/youk-h/golang-cli/tree/master/touch)

## mainコード

<details><summary>mainコード</summary><div>

```main.go

package main

import (
	"errors"
	"flag"
	"os"
	"sync"
)

func main() {
	flag.Parse()
	execute(flag.Args())
}

func execute(fileNames []string) {
	wg := sync.WaitGroup{}
	for _, name := range fileNames {
		wg.Add(1)
		go touch(name, &wg)
	}
	wg.Wait()
}

func touch(fileName string, wg *sync.WaitGroup) {
	defer wg.Done()

	if fileExists(fileName) {
		return
	}

	createFile(fileName)
}

func fileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		return false
	}
	return true
}

func createFile(fileName string) error {
	if file, err := os.Create(fileName); err == nil {
		file.Close()
		return nil
	}
	return errors.New("")
}


```
</div></details>

## testコード

<details><summary>testコード</summary><div>

```main_test.go
package main

import (
	"os"
	"sync"
	"testing"
)

func TestFileExists(t *testing.T) {
	const fileName = "file"

	if exist := fileExists(fileName); exist != false {
		t.Fatalf("it should return false because %s doesn't exist", fileName)
	}

	// setup for test
	file, err := os.Create(fileName)
	if err != nil {
		t.Fatalf("test setup failed")
	}
	defer os.Remove(fileName)
	defer file.Close()

	if exist := fileExists(fileName); exist != true {
		t.Fatalf("it should return true because %s exists", fileName)
	}
}

func TestCreateFile(t *testing.T) {
	const fileName = "file"
	err := createFile(fileName)
	defer os.Remove(fileName)

	if _, e := os.Stat(fileName); e != nil {
		t.Fatalf("it should create %s", fileName)
	}
	if err != nil {
		t.Fatalf("it should return nil becuase file is created now")
	}
}

func TestTouch(t *testing.T) {
	const fileName = "file"
	wg := sync.WaitGroup{}

	wg.Add(1)
	go touch(fileName, &wg)
	defer os.Remove(fileName)
	wg.Wait()
	if !fileExists(fileName) {
		t.Fatalf("it should create %s", fileName)
	}

	wg.Add(1)
	go touch(fileName, &wg)
	wg.Wait()
	if !fileExists(fileName) {
		t.Fatalf("it should remain %s", fileName)
	}
}

func TestExecute(t *testing.T) {
	fileNames := []string{"file1", "file2", "file3"}

	execute(fileNames)
	defer func() {
		for _, name := range fileNames {
			os.Remove(name)
		}
	}()
	for _, name := range fileNames {
		if exist := fileExists(name); exist != true {
			t.Fatalf("it should create %s", name)
		}
	}
}

```

</div?</summary>
Codeforces Round #626 B. Count Subrectangles 行列に含まれる面積kの長方形の個数

https://codeforces.com/contest/1323/problem/B

# 題意
- 0と1だけで構成される配列a,bから作られるcがある。(要素は$a[i] * b[j]$によって生成される)
- このcの中に面積kの四角形が何個存在するか？

# できる行列cの理解を深める
```Python
a = [0,1,1,1,1,0,1]
b = [0,1,1,0,1,1,1]
c = []
for i in range(len(a)):
    l = []
    for j in range(len(b)):
        l.append(a[i] * b[j])
    c.append(l)
from pprint import pprint
pprint(c)
```

としてみると

```
[[0, 0, 0, 0, 0, 0, 0],
 [0, 1, 1, 0, 1, 1, 1],
 [0, 1, 1, 0, 1, 1, 1],
 [0, 1, 1, 0, 1, 1, 1],
 [0, 1, 1, 0, 1, 1, 1],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 1, 1, 0, 1, 1, 1]]
```
が得られ、個々には、`4 x 2, 4 x 3, 1 x 2, 1 x 3`の四角形が存在する。これは、配列a,bにおける連続した1の数の組み合わせに他ならない。行列a,bを見ると、aは[4,1]でbは[2, 3]で上記の四角形はまさにこの積である。

# 面積kの四角形の数え方について理解する
kの約数をxとすると、$x \times k/x$ の四角形を考えればよい。次に例を挙げる。
- k = 4の場合、約数は[1,2,4]であるため、1x4, 2x2, 4x1の四角形を考えればよい。
- k = 12の場合約数は[1,2,3,4,6,12]であるため、1x12, 2x6, 3x4, 4x3, 6x2, 12x1の四角を考えればよい。
- k = 13の場合、素数なので、1x13と13x1
を考えればよい。

# ある四角形x, y の中に四角形lx, lyは何個存在できるか？
$(x - lx + 1) * (y - lx + 1)$個。ただし、$x-lx$や$y-lx$が負の数となるときは存在できない。これは3x3の四角形の中に、2x2や1x3や1x2が何個存在するかを書くとわかるはず。

# 実装する
基本的には、上記を実装すればよい。つまり、
- 行列a,b から1の連続する数をカウントし、作られる四角形(x, y)をすべて列挙する
- 面積kとなる四角形が作れる組み合わせ(lx, ly)をすべて列挙する
- すべての行列cの四角形(x,y)に対してすべての面積kの四角形(lx, ly)が何個存在するかをカウントする
のだが、愚直に実装するとTLEする。aとbの長さが40000のため、[0 1 0 1]などの入力があると、20000 x 20000の四角形ができてしまう。

そこで、作られる三角形は列挙せずに(x,y,数)でカウントする。例えば、a=[1,1,0,1,1], b=[1,1,0,1,1]なら、

```
[[1, 1, 0, 1, 1],
 [1, 1, 0, 1, 1],
 [0, 0, 0, 0, 0],
 [1, 1, 0, 1, 1],
 [1, 1, 0, 1, 1]]
```

となり、2x2の四角形が4つできるが、これは、la=[2,2], lb=[2,2] という連続する1の数のリストの積だが、
la = (2: 2個), lb = (2: 2個）と格納しておくことで、2x2の三角形は2個x2個と計算できる。これにより、間に合う。

# コード
```Python
def make_divisors(n):
    divisors = []
    for i in range(1, int(n ** 0.5) + 1):
        if n % i == 0:
            divisors.append(i)
            if i != n // i:
                divisors.append(n // i)
    return divisors

n,m,k = map(int, input().split())
data = input().split()
datb = input().split()

divs = make_divisors(k)
rects = []
# 面積kの四角形(x,y)を列挙
for x in divs:
    rects.append((x, k // x))

from collections import Counter, defaultdict

# 配列a,bから連続した1の長さの個数をカウントする辞書を生成
# [1,1,1,0,1,1,1,0,1,1] -> [3,3,2]の長さなので -> {3:2, 2:1}という辞書になる
da = defaultdict(int)
db = defaultdict(int)
cnt = 0
l = len(data)
for i in range(l):
    if data[i] == "1":
        cnt += 1
    if data[i] == "0" or i == l - 1:
        da[cnt] += 1
        cnt = 0

cnt = 0
l = len(datb)
for i in range(l):
    if datb[i] == "1":
        cnt += 1
    if datb[i] == "0" or i == l - 1:
        db[cnt] += 1
        cnt = 0

# 数える
res = 0
for lx in da:
    for ly in db:
        for x, y in rects:
            # aとbから作られるx*yの四角形の数
            reccount = da[lx] * db[ly]
            #print("{0} x {1} count = {4}, find {2} x {3} rect".format(lx, ly, x, y, reccount))
            cx = lx - x
            cy = ly - y
            if cx > -1 and cy > -1:
                # 作れるなら足す
                cannum = (cx + 1) * (cy + 1) * reccount
                res += cannum
print(res)
```
https://codeforces.com/contest/1323/submission/72671380
本番環境でトラブルを起こさないための手順作成TIPS

１年目のインフラエンジニアです。本番環境での設定変更等を行うための手順作成時の注意点やよく使うコマンドをまとめます。
※随時更新予定

# 本番作業の流れ
1. 変更が入る設定ファイルをバックアップ
 - **エラーや予期しない結果となった場合に、切り戻しが必要なため**
 - 設定変更時からの差分比較の実施にも使用する  
2. 設定変更
    1. 設定ファイルを変更し、意図した箇所が変更されているか、バックアップした設定ファイルと差分比較して確認する
    2. サービスの再起動などにより、設定反映を実施する
3. 動作確認  
設定変更が意図した通りに反映されているか、問題が発生していないかを確認


```:Webページを移行する場合
作業日バックアップ用のディレクトリを作成
# mkdir -v /var/tmp/`date +%Y%m%d`backup
mkdir: created directory `/var/tmp/20200307backup'

httpd.confをバックアップ
# cp -av /etc/httpd/conf/httpd.conf /var/tmp/`date +%Y%m%d`backup
`/etc/httpd/conf/httpd.conf' -> `/var/tmp/20200307backup/httpd.conf'

DocumentRootを移行
# vim /etc/httpd/conf/httpd.conf

設定変更部分の差分確認
# diff -U0 /var/tmp/`date +%Y%m%d`backup/httpd.conf /etc/httpd/conf/httpd.conf 
--- /var/tmp/20200307work/httpd.conf	2020-02-24 10:40:22.515205375 +0000
+++ /etc/httpd/conf/httpd.conf	2020-03-07 14:33:18.297797548 +0000
@@ -120 +120 @@
-DocumentRoot "/var/www/html"
+DocumentRoot "/var/www/html_after"

設定エラーがないことを確認
# httpd -t
Syntax OK

サービスを再起動して設定を反映
# systemctl reload httpd.service

サービスの正常性確認
# systemctl status httpd.service

移行後の新ページが表示されていることの確認
# curl http://localhost
```
# TIPS
## カレントディレクトリを変更する
pwdとセットで実施し、移動していることを確認する

```
# cd /etc/httpd/conf/;pwd
/etc/httpd/conf/
```
## ファイルをコピーする
### cpオプション
- -a (--preserve=all)  
コピー元の情報を保持してコピーする(パーミッション、オーナー、タイムスタンプ等)
- -v (--verbose)  
実行していることを説明する

```:cp
# cp -av /etc/httpd/conf/httpd.conf /var/tmp/20200307backup/
`/etc/httpd/conf/httpd.conf' -> `/var/tmp/20200307backup/httpd.conf'
または
# cp -a /etc/http/conf/httpd.conf /var/tmp/20200307backup/
# ls -l /var/tmp/20200307backup/
```

## ファイルを移動する
コピー元ファイルのメタ情報を保持するために、mvを使用せず、cpを使用
[Linuxでのファイルの入れ替え（mvコマンド vs cpコマンド）](https://www.greptips.com/posts/792/)

```:移動
# cp -av /usr/local/bin/test.sh /usr/local/sbin/
`/usr/local/bin/test.sh' -> `/usr/local/sbin/test.sh'
# rm -i /usr/local/bin/test.sh
rm: remove regular file ‘/usr/local/bin/test.sh’? y
```
## 複数ファイルを削除する
```:/home/work/配下のtestから始まるファイルの削除
# ls /root/work/（参考）
/root/work/sample  /root/work/test0  /root/work/test1  /root/work/test2

rmで削除する前に同じパスで削除対象のファイルに間違いがないかを確認
# ls /root/work/test*
/root/work/test0  /root/work/test1  /root/work/test2

# rm /root/work/test*
rm: remove regular empty file ‘/root/work/test0’? y
rm: remove regular empty file ‘/root/work/test1’? y
rm: remove regular empty file ‘/root/work/test2’? y
nodejsのfsモジュールの使い方

fsモジュールの使い方をまとめました。

# 前提条件
- npmがインストールされていること

# 同期と非同期
同期処理と非同期処理の2つのファイル処理が出来ます。
`Sync`と付けると同期処理で、付けないと非同期で処理されます。

| 同期 | 非同期 |
| ----- | ----- |
| statSync | stat |
| readFileSync | readFile |
| copyFileSync | copyFile |
| unlinkSync | unlink |

- **同期**は処理を完了するまで後続の処理を止める
- **非同期**は処理の完了を待たずに後続の処理を行う

## 設定
`mkdir`コマンドと`touch`コマンドでファイルを作成します。

```shell
$ mkdir dir && touch test.js dir/test.txt
```

```javascript:test.js
const fs = require('fs')

try {
  fs.statSync('dir/test.txt')
  console.log('同期処理')
} catch (err) {
  console.log(err)
}

fs.stat('dir/test.txt', (err) => {
  if (err) throw err
  console.log('非同期処理')
})

console.log('後続の処理')
```

## 実行
`node`コマンドを実行します。

```shell
$ node test
```

## 出力結果
```console
同期処理
後続の処理
非同期処理
```

# 使い方
## ファイルの存在確認
ファイルが存在していればオブジェクトを取得出来ます。
`isDirectory`メソッドでディレクトリかどうかも確認が出来ます。

```javascript
const fs = require('fs')

try {
  const dir = fs.statSync('dir')
  const file = fs.statSync('dir/test.txt')
  console.log(dir.isDirectory())
  console.log(file.isDirectory())
} catch (err) {
  console.log(err)
}
```

**実行結果**

```console
true
false
```

## ファイル一覧を取得

```javascript
const fs = require('fs')

try {
  console.log(fs.readdirSync('dir'))
} catch (err) {
  console.log(err)
}
```

**実行結果**

```console
[ 'test.txt' ]
```

## ファイルの読み込み

```javascript
const fs = require('fs')

try {
  console.log(fs.readFileSync('dir/test.txt', 'utf8'))
} catch (err) {
  console.log(err)
}
```

```text:dir/test.txt
Hello world!
```

**実行結果**

```console
Hello world!
```

## ファイルの書き込み
ファイルが存在しなければ新規作成して、存在する場合は上書きします。

```javascript
const fs = require('fs')

try {
  fs.writeFileSync('dir/test2.txt', 'Hello world!!', 'utf8')
} catch (err) {
  console.log(err)
}
```

**実行結果**

```text:dir/test2.txt
Hello world!!
```

## ファイルの追記

```javascript
const fs = require('fs')

try {
  fs.appendFileSync('dir/test.txt', 'Hello overwrite!', 'utf8')
} catch (err) {
  console.log(err)
}
```

```text:dir/test.txt
Hello world!!
```

**実行結果**

```text:dir/test.txt
Hello world!!
Hello overwrite!
```

## ファイルの複製

```javascript
const fs = require('fs')

try {
  fs.copyFileSync('dir/test.txt', 'dir/test2.txt')
} catch (err) {
  console.log(err)
}
```

## ファイルの削除

```javascript
const fs = require('fs')

try {
  fs.unlinkSync('dir/test.txt')
} catch (err) {
  console.log(err)
}
```

# 参考文献

この記事は以下の情報を参考にして執筆しました。

- [パス操作(path)とファイル操作(fs)](https://www.wakuwakubank.com/posts/663-nodejs-fs-path/)
Pythonスクリプトをコマンドラインツールとして実装する時の引数の管理方法

コマンドラインの引数を利用する方法は標準のライブラリだと以下の2つ？

* `sys` モジュールの `sys.argv` で引数を参照する方法
* `argparse` モジュールで本格的に実装する方法

`sys.argv` は、シンプルに引数を参照できるくらいかな

* [Python: コマンドライン引数とは？（超基礎） - Qiita](https://qiita.com/orange_u/items/3f0fb6044fd5ee2c3a37)

折角なのでちゃんとした実装をしてみるために、いくつかの参考ページを拾っておく
まずは公式ドキュメント「Python 3 ドキュメント」

* [argparse --- コマンドラインオプション、引数、サブコマンドのパーサー](https://docs.python.org/ja/3/library/argparse.html)
* [Argparse チュートリアル](https://docs.python.org/ja/3/howto/argparse.html)

一通り、`argparse` を使う方法は、以下のページが良さそう

* [Python argparseの使い方 - Qiita](https://qiita.com/dodo5522/items/6ec2b6d83287add6c185)

以下、パイプでファイルを引数で渡す処理のことが書かれていて内容把握したかったが、今ひとつ書いてあることがよくわからなかった...

* [pythonでコマンドライン引数を使うサンプル - Qiita](https://qiita.com/stkdev/items/e262dada7b68ea91aa0c)

具体的には、以下のような疑問

`sys.stdin.isatty()` で標準入力があったかどうかを判定するとあるが... 標準入力で受け取ったデータは1つ目の引数に入るのか？

実行例もあるが、`argparse.ArgumentParser().parse_args()`で標準入力の値を取得した際にそれを特定するキーは何になるのか...

とりあえず、「パイプでファイルを引数で渡す処理」は直近で必要なコマンドには必要ないから一時保留

以下のページは、サクッと使い始めたい時の一通りの書き方と、よくある使い方も書かれていて実用的な紹介記事

* [ArgumentParserの使い方を簡単にまとめた - Qiita](https://qiita.com/kzkadc/items/e4fc7bc9c003de1eb6d0)

よくある使い方とは...

* 省略形式の引数の定義の方法と、プログラム内での参照方法
* 初期値の設定方法
* 引数で指定される値の型の指定方法
* 引数の設定をTrue/Falseとして扱う方法(仕様としては、型の指定方法に含まれる内容)

標準のモジュール以外にもコマンドプログラムを補完するようなモジュールがいくつかある模様

* [ConfigArgParse](https://github.com/bw2/ConfigArgParse)
    * [python ConfigArgParse メモ ~まだ引数と設定ファイル別々に管理しているの？~ - Qiita](https://qiita.com/etoy/items/39bd5fb743fc516962e4)
* [Pythonコマンドライン解析ライブラリの比較(argparse, click, fire) - Qiita](https://qiita.com/ikura1/items/e94d82692a7a101fde53)
    * [GitHub - pallets/click: Python composable command line interface toolkit](https://github.com/pallets/click)
    * [GitHub - google/python-fire: Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.](https://github.com/google/python-fire)

このほか、実際に実装を進める中で必要になったのが、以下

* ssh/scp の処理
* 別階層の自前ライブラリを取り込む方法

長くなりそうなので、とりあえず、基本的なコマンド作成の時の調査結果ということで、以上