OmniAICreator/Qiita-1.07M huggingface dataset:
Redmineのチケット編集画面において開始日と期日の日付入力が行えない現象への暫定対処法

Redmineのチケット編集画面で「開始日」と「期日」の日付入力が行えない現象に遭遇したため、その対処方法のメモです。
対処方法としては暫定的な方法になりますが、同じ状況の方の参考になればと思います。
**※追記：どうやら `OSX(10.9.5)＋Firefox(69.0 64bit)` の場合のみ発生するようで、OSバージョンが古いことが原因である可能性が高いです。**

## 発生している現象

Redmineのチケット編集画面において、「開始日」と「期日」はポップアップ型のカレンダーで日付が選択できるはずであるが、カレンダーが表示されない。また、入力欄が操作できないため、日付の入力・変更が行えない。
![img001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61137/350ea7ab-5c40-3c09-9df9-b478102d522a.png)

## 動作環境のバージョン

以下の環境で現象が再現することを確認済み。

 * CentOS-7
 * Ruby2.6.5p114
 * MariaDB 5.5.64
 * Redmine-4.0.4(2019/10/06時点での最新版)

## 対処方法(暫定対処)

チケット編集画面のViewを修正することで対応。日付入力欄は `<input type="date" ...` の形のHTMLタグが生成される実装になっているが、これを `<input type="text" ...` となるように修正した。

```diff
$ svn diff
Index: app/views/issues/_attributes.html.erb
===================================================================
--- app/views/issues/_attributes.html.erb       (revision 18597)
+++ app/views/issues/_attributes.html.erb       (working copy)
@@ -52,14 +52,14 @@

 <% if @issue.safe_attribute? 'start_date' %>
 <p id="start_date_area">
-  <%= f.date_field(:start_date, :size => 10, :required => @issue.required_attribute?('start_date')) %>
+  <%= f.date_field(:start_date, :size => 10, :required => @issue.required_attribute?('start_date')).to_str.sub(/type=.*?date"/, '').html_safe %>
   <%= calendar_for('issue_start_date') %>
 </p>
 <% end %>

 <% if @issue.safe_attribute? 'due_date' %>
 <p id="due_date_area">
-  <%= f.date_field(:due_date, :size => 10, :required => @issue.required_attribute?('due_date')) %>
+  <%= f.date_field(:due_date, :size => 10, :required => @issue.required_attribute?('due_date')).to_str.sub(/type=.*?date"/, '').html_safe %>
   <%= calendar_for('issue_due_date') %>
 </p>
 <% end %>
```

上記の暫定対応を加えた後にRedmineを再起動することで、「開始日」と「期日」の入力欄がテキストフィールドとして表示されるようになるため、YYYY-MM-DDの形式で日付の入力・編集ができるようになります。
![img002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61137/3abe33bf-d182-809b-8cce-5fa9c8ea1738.png)

## まとめ

Redmineのチケット編集画面で開始日と期日の変更ができない現象への対処方法を紹介しました。
Redmineの[issues](http://www.redmine.org/project/redmine/issues)には該当するものは見つけられなかったので、もしかしたら何か設定の不備に起因する現象なのかもしれません。

## 参考URL
 * [SafeBuffer Objectにgsubを実行できるように対応](https://qiita.com/natsume/items/bbfc2165deff8c78514e)
 * [redmine.orgのissues](http://www.redmine.org/projects/redmine/issues)
 * [Redmine(リポジトリ)](http://svn.redmine.org/redmine/tags/)
AWS CDKで構築したVPCのテンプレートを眺めるだけの記事

早速眺めていきます。

# ソース
```cdk_stack.py
from aws_cdk import (
    core,
    aws_ec2 as ec2
)

class CdkStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        ec2.Vpc(self,"CDK_TEST_HIROGA")
```

`app.synth()` するところは省略。

# Overview
（アイコンが小さくて分かりづらい．．．）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/3ee2fa4b-5dc6-4d38-a307-8e8ab16e1d47.png)

* VPC: 1つ
* Subnet: Public2つ、Private2つ
* InternetGateway: VPCに対して1つ
* NatGateway: PublicSubnetごとに1つ、合計2つ
* EIP: NatGatewayごとに1つ、合計2つ
* ほか、RouteTable, Route, SubnetRouteTableAssociation


# VPC
* デフォルトのCIDR Blockは`10.0.0.0/16`。
* Nameの命名規則は、指定しない限り `スタック名`/`リソースのID`になるようだ。

```
  CDKTESTHIROGA2CBE18D7:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: cdk/CDK_TEST_HIROGA
    Metadata:
      aws:cdk:path: cdk/CDK_TEST_HIROGA/Resource
```

# Public Subnet
* ネットワークアドレスはデフォルトで18ビット。
* AZ IDはデフォルトで `apne1-az4` と `apne1-az1`[^1]
* `aws-cdk:subnet-name` は、既存のSubnetをCDKでimportする際に参照するための値。何も指定しないと `aws-cdk:subnet-type` とおなじになるらしい。[^2]
* `aws-cdk:subnet-type` はISOLATED, PRIVATE, PUBLICのいずれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/52cef5d2-467b-251f-7001-5ec65134fcef.png)

[^1]: こういう記事ではAZ IDを使ったほうがいいみたいですね。[クラメソさんブログ](https://dev.classmethod.jp/cloud/use-az-id-for-identify-az-crossing-over-account/)
[^2]: [Importing an existing VPC](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-ec2-readme.html#importing-an-existing-vpc)

```
  CDKTESTHIROGAPublicSubnet1SubnetEDE92B34:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/18
      VpcId:
        Ref: CDKTESTHIROGA2CBE18D7
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: cdk/CDK_TEST_HIROGA/PublicSubnet1
        - Key: aws-cdk:subnet-name
          Value: Public
        - Key: aws-cdk:subnet-type
          Value: Public
    Metadata:
      aws:cdk:path: cdk/CDK_TEST_HIROGA/PublicSubnet1/Subnet

```

# おまけ
今回作成したテンプレート

https://gist.github.com/hiroga-cc/5d5d33e2a677efce1a82c2f2d7cc9484
Splunk BOSS of the SOCを可視化（Sankey diagram）

.conf 2017 Splunk Championの中村さんの話を聞く機会があって、刺激を受けたのでやってみる。
中村さんの[.conf 2017の資料](https://conf.splunk.com/files/2017/slides/recruit-technologies-automated-its-cybersecurity-actions-using-splunk.pdf)も参考に。

最初はGOJASのSlackに上がっていた[Using data & Splunk ML Toolkit to predict crime](https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2018/october/using-data-and-splunk-ml-toolkit-to-predict-crime/)
[google翻訳](https://translate.google.com/translate?um=1&ie=UTF-8&hl=ja&client=tw-ob&sl=en&tl=ja&u=https%3A%2F%2Fwww.nccgroup.trust%2Fuk%2Fabout-us%2Fnewsroom-and-events%2Fblogs%2F2018%2Foctober%2Fusing-data-and-splunk-ml-toolkit-to-predict-crime%2F)をやろうとして断念
.conf 2018の資料は[ここ](https://static.rainfocus.com/splunk/splunkconf18/sess/1523465959599001PaI1/finalPDF/Splunking-Crime-Predicting-London-1509_1538797283343001YEzV.pdf)

## Sankey Diagram
ダウンロードは[ここ](https://splunkbase.splunk.com/app/3112/)、使い方は[ここ](https://docs.splunk.com/Documentation/SankeyDiagram/1.3.0/SankeyDiagramViz/SankeySearchDataFormat)

![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/07c29acd-ad62-870b-da54-4ccd5daaddbd.png)

```Splunk:SPL
index=botsv1 sourcetype=iis c_ip=40.80.148.42 sc_status=200
| stats count dc(cs_uri_stem) as uri by cs_method,cs_uri_stem
```
これも綺麗だけど、ＵＲＬの構成ごとに分けてみる。

![qiita2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/b19d4d48-4ac0-7936-bca8-2f4dccdc7b4e.png)

```Splunk:SPL
index=botsv1 (sourcetype=iis c_ip=40.80.148.42 sc_status=200) OR (src_ip=40.80.148.42 sourcetype=suricata eventtype=suricata_eve_http http.status=200)
| eval method=coalesce(cs_method,http_method)
| eval url=coalesce(cs_uri_stem,'http.url')
| eval url="/".method.url
| rex field=url max_match=6 "(?<uri>/[^/]+)"
| fields uri
| table _time,uri
| eval second_tmp=mvindex(uri,1,6)
| mvexpand uri
| streamstats count by _time
| eval second_uri=mvindex(second_tmp,count-1)
| eval uri=replace(uri,"/([A-Z]+)","\1")
| eval second_uri=replace(second_uri,"\?.+","")
| stats count  by uri,second_uri
```
####解説
```
... | stats <stats_function>(<size_field>) [<stats_function>(<color_field>)] by <source_category_field> <target_category_field>
```
Sankey Diagramの構成は上記のとおり。
今回は

|始め|終わり|大きさ|色|
|:-:|:-:|:-:|:-:|
|`uri`|`second_uri`|`count`| なし |
でフィールドを作った。

urlを要素に分けるまでは簡単だったけど、交互にするのがよくわからずハマった。

何とかなった方法として
`| eval second_tmp=mvindex(uri,1,6)`
でマルチバリューなURLを一つずらしてつくった。例として

|uri|second_uri|
|:-:|:-:|
|/POST<br>/joomla<br>/index.php|/joomla<br>/index.php|

`mvexpand uri`すると

|uri|second_uri|
|:-:|:-:|
|/POST|/joomla<br>index.php|
|/joomla|/joomla<br>index.php|
|index.php||
となる。
それを`streamstats`でつくったカウンターで`second_uri`の値を取り出していく。
`mvindex`のカウンターが__0__から始まるので`-1`

_method_は正規表現で取り出すために`/`をつけていたのを外して、
IDSのログにはクエリーがたくさん出ていたので、それを`replace`で消してあげた。
本来ならこれをよく調べなきゃいけないけど、今回は無視。

最後に`stats`でまとめて、表を作って`Visualization`

## まとめ
Sankey Diagramは`stats`で作らなくても表を作ればいい。

|始め|終わり|
|:-:|:-:|
|A|B|
|B|C|
|C||
の表を作るのが大変なので、`appendcols`や`append`で作ってもよかったと思う。

:sweat:大きさが`count`であればなおさらですね。
実際、順序関係はSplunk側でやってもらえるので大きさのところをしっかりやれば

|始め|終わり|
|:-:|:-:|
|B|C|
|A|B|
|C||
みたいなバラバラでもきちんと表示してくれる。

:cry: 簡単に作れるようになりたい。
【HTML5/資格】 HTML5プロフェッショナル　レベル１認定試験　受験記録

「HTML5プロフェッショナル　レベル１認定試験」を受けてきました。
無事合格できたので、私の学習方法・学習量など記載しておこうと思います。

※HTML5プロフェッショナル認定とは？？については、ここでは説明しませんので、
　公式HP(<a href="https://html5exam.jp/">html5exam.jp</a>)を参照して下さい。

#### HTML5/CSS3との距離感と、受験の目的
私は証券・金融系の基幹システムを取り扱うSIerで勤務していますが、中には個人投資家向けのWebサービスや、証券営業向けのSFAをWebサービスを提供していたりと、割と日々の業務の中でWebフロントサイドの開発でHTML5+CSS3,JavaScriptを取り扱うことが多いです。
ですが、開発にあたり事前に体系的な知識をつける研修がなく、「ネットなどで得た知識で組んでみて、動けばOK(ロジックの妥当性を評価しない)」という環境、というのが現実です。
「このままじゃ絶対マズい・・・」と思い、資格を取ることが目的というよりは「体系的な知識を身に付けたい。あわよくば、その証明となる資格があると嬉しい」と思ったのが、受験に向けて勉強しようと思った動機・目的です。
（とはいえ、おそらく年内で今の現場からは退職するのですが。）

#### 結果
合格ライン70点(1問1.67点、60問中４２問正解)に対し、得点は78点。合格でした。

#### 学習方法、学習量
私の場合、学習方法は大きく以下の2つでした。
といいながら、基本的には両方「問題集を解く」なので、２つの問題集を解きましたという意味になります。

#####1.HTML教科書 HTML5プロフェッショナル認定試験 レベル1 スピードマスター問題集 Ver2.0対応
公式から学習教材として挙げられている問題集です。

######良いと思った点
・解説が過不足ない
というか、自分にとっては、「１問に対してその１問分の解説がされている」と思いました。
なぜ問題の答えがその選択肢になるのか、なぜ他の選択肢を選んではいけなかったのか、が説明されており、その問題１問分の認識を確認するための内容としてちょうどいいボリュームだと思いました。

・問題のすぐあとに解答がある
これは人によって好みが分かれると思いますが、私の場合は、問題１問解くごとに解答・解説を確認したかったので、問題→解答が１セットになっているのはありがたかったです。

######悪いと思った点
・空白ページがやたら多い
中身のない、ムダな空白ページがやたら多く、そういったページがなければ厚さは半分程度になったんじゃないかと思うほどでした。解答・解説や次の問題を隠す意図がある改ページでもなさそうで、そういった空白ページが多いことで「中身が薄い」という印象にもなるような気がしました。

#####2.ping-t　最強WEB問題集HTML5プロフェッショナル認定資格 レベル1(v2.0)
webの学習サイト(?)ping-tで<b>有料で</b>配信されている問題集です。
かたちとしては、他の試験やサイトでもあるような一般的なweb問題集とそんなに変わらないと思います。

######良いと思った点
・理解度や学習量を管理しやすい
ただし、問題ごとに金銀銅でランク分けされており、最初はすべて銅からスタートするのですが、直近１回正解で銀→連続２回正解で金→不正解で銅に逆戻り、というシステムは割と独自かな、と。
基本的には、その仕組みのなかで「全問金にする」を目標に学習を進めていくことになると思います。
また、１０問単位でテストの出題数を設定することができ、１０分あるから２０問解こうとか、１時間あるから模擬試験形式(60問)でやろうとか、タイミングごとの時間やモチベーションで学習量が設定しやすかったです。

######悪いと思った点
・解答解説が冗長
例えば、htmlとcssを読んで特定の要素がどういう表示になるかを選択するような問題の場合、スタイルシートの適用の優先度や擬似クラス・擬似要素、そのcssの中身(rgbやtext-alignなど)がすべて解説として出てきてしまい、問題のキモとして抑えるべき部分がどこなのかが分かりづらいと思いました。

#####3.(おまけ)実際に出題されたHTML、CSSで画面表示させてみる
結局、実際に自分で書いて動かしてみるのが一番理解できるし、手を動かした分、記憶にも定着します。
HTMLやCSSならテキストエディタとブラウザがあればローカルで実行できますし。
なんなら私はあまり使ったことないですが、codepenみたいなサイトもありますよね。

#####学習量
よくこういったエントリで「何時間の勉強しました」みたいなコトが書かれているんですが、自分の場合はゲームしながらNetflix見ながら家事しながらでダラダラやってたので、正直、時間という尺度では学習量が測れません。
ただし、期間としては先々月末にPython3エンジニア認定基礎に合格してから準備を始めたので、「１ヶ月間、仕事から帰ってから問題集を解く程度の勉強でも、その内容がきちんとアタマに入っていれば合格できる」というコトは言えると思います。
（先月中旬までは転職活動もしていて、この受験対策は後回しであまりできていなかったので、実質的に準備期間は２週間程度だったかもしれません。）

####受験の感想
単純に知識が不足していた部分を除き、出題内容が難しい、というより、回答者を迷わせるような余計な文言が付いているものが散見された気がします。
（シンプルに問えば「サーバ内部エラー時のリターンコードは次のうちどれか」というところ、「サーバ内部エラー時のリターンコードで、CGIスクリプトでエラーが発生した際に返されるものは〜」みたいなオマケがついているせいで「あれ、５００でいい、、、よね？？」って思うような問題）

そういった問題が序盤で立て続けにあり、少し不安になりましたが、見直し時点で合格ラインを超えてる自信はあったので、ムリにアタマをひねって何とか正解させようとせず、記憶と直感で答えた選択肢のままにしておきました。

#####受験の結果、目的の「体系的な知識を身に付ける」は達成できたのか
かなり、きちんとした知識が身に付いたとは思います。
私の場合、特にスタイルシートの適用の優先度みたいな部分はきちんと理解していなかったので、そういった知識は今後「なんでこの画面のこの部分だけ意図した通りの表示にならないんだろう」といったようなコトに対応する際のスピードや方法に直接影響してくるかな、と思います。

今月後半はネスペ、11月にはG検定がありますが、何とか年度内にはレベル２も取りたいと思います。
初心者によるプログラミング学習ログ118日目

# 100日チャレンジの118日目。

Twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

118日目は、

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>118日目<br><br>UdemyでVue.js学習<br>v-ifとかv-elseとかレンダリングとか。<br>メンターさんの課題やるつもりが寝落ち…<a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1179506076376432640?ref_src=twsrc%5Etfw">October 2, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

```index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="main.css">
    <title>Document</title>
   
</head>
<body>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <div id="app">
    <p v-if="ok">OK!</p>
    <P v-else-if="maybeOk">maybeOk</P>
    <p v-else>Not OK...</p><!--V-ifの直後にこないとだめ-->
  </div>

 <script>
   new Vue ({
     el: '#app',
     data: {
       ok: false,
       maybeOk: true
     }
   })
  </script>
 </body>
</html>

```

V-elseは、v-ifの直後にこないと機能しないみたい
[Vim] コマンド1つで下部に高さ10のターミナルを生成

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241774/3bab642c-6f68-e269-b2a1-ea1b784435b8.gif)


# やったこと

現代のイケてるテキストエディタはコマンド一発で下部にターミナルを出せるエディタが
多い(VSCode, JetBrains, Spacemacs など)と思います。かっこいいです。Vimでもやりたい。

# コード

以下のコードにて、``s;`` で下部に高さ10のターミナルが生成されます。

```vim:init.vim
" 下部に高さ10のコマンドラインを生成
nnoremap s; :<c-u>sp<cr><c-w>J:<c-u>res 10<cr>:<C-u>terminal<cr>:<c-u>setlocal noequalalways<cr>i 
```

# 説明

1. ``:<c-u>sp<cr>`` ウィンドウを縦スプリット
2. ``<c-w>J`` ウィンドウを下に持ってくる
3. ``:<c-u>res 10<cr>`` ウィンドウを高さ10にリサイズ
4. ``:<c-u>terminal<cr>`` ターミナルを開く
5. ``:<c-u>setlocal noequalalways<cr>`` ウィンドウのサイズ自動調整無効化
6. ``i`` インサートモード

# その他

[ぼくがかんがえた使用プラグイン80個以上の最強init.vim](https://github.com/Cassin01/ReiwaVimConfiguration)
Red Hat Enterprise Linuxのメディアのパッケージ内容でローカルリポジトリを作成する方法

前回の[「インターネットに繋がらない環境でyumでApache Http Serverをインストールする手順（Red Hat Enterprise Linux編）」](https://qiita.com/yasushi-jp/items/a2b90a43dcba61d2e714)では、特定のパッケージのみダウンロードしローカルリポジトリを作成しましたが、今回は「Red Hat Enterprise Linux」のメディアに含まれているパッケージを全てローカルにコピーし、ローカルリポジトリを作成します。

# 前提条件
- VirtualBox6.0をインストール済み
- ホストOS：Windows7
- ゲストOS：RedHatEnterpriseLinix7.7
- ゲストOSにメディアのisoファイル（rhel-server-7.7-x86_64-dvd.iso）が存在すること


### 1. `rhel-server-7.7-x86_64-dvd.iso`をマウントする。

```
[root@RHEL-DEMO ~]# mount -o loop -t iso9660 /root/rhel-server-7.7-x86_64-dvd.iso /media
mount: /dev/loop0 is write-protected, mounting read-only
[root@RHEL-DEMO ~]#
```

### 2. パッケージを格納するディレクトリを作成

```
[root@RHEL-DEMO ~]# cd
[root@RHEL-DEMO ~]# pwd
/root
[root@RHEL-DEMO ~]# ls
anaconda-ks.cfg  rhel-server-7.7-x86_64-dvd.iso  yum
[root@RHEL-DEMO ~]# cd yum
[root@RHEL-DEMO yum]# ls
httpd_repo
[root@RHEL-DEMO yum]# mkdir -p all_repo/Packages
```

### 3. メディアのパッケージを全てコピー

```
[root@RHEL-DEMO yum]# cd all_repo/Packages
[root@RHEL-DEMO Packages]# cp /media/Packages/* ./
[root@RHEL-DEMO Packages]#
```

### 4. ローカルリポジトリを作成

```
[root@RHEL-DEMO Packages]# cd ../..
[root@RHEL-DEMO yum]# ls
all_repo  httpd_repo
[root@RHEL-DEMO yum]# createrepo all_repo
Spawning worker 0 with 5229 pkgs
Workers Finished
Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete
[root@RHEL-DEMO yum]#
```

### 5. リポジトリファイルを作成

```:/etc/yum.repos.d/all_repo.repo
[all_repo]
name=all_repo
baseurl=file:///root/yum/all_repo
enabled=1
gpgcheck=0
```

`enabled=1`としているので、yumコマンドで`all_repo`のリポジトリからインストールすることが可能となります。
なお、tarで固めて他のマシンへコピーすることも可能です。

以上
Ubuntu18.04+英字配列で日本語入力の切替を左右altで行う+caps lockを左ctrlと入れ替え

# 用意

## ディレクトリ作成
```
$ mkdir -p ~/.xkb/keymap ~/.xkb/symbols
```

## 現状設定書き出し

```
$ setxkbmap -print > ~/.xkb/keymap/mykbd
```

## ~/.xkb/symbols/myswap作成

```
partial modifier_keys
xkb_symbols "myswapkeys" {
  replace key <LCTL> { [ Caps_Lock ] };
  replace key <CAPS> { [ Control_L] };
  key <LALT>  { [ Hiragana ] };
  key <RALT>  { [ Katakana ] };
};
```


## ~/.xkb/keymap/mykbdのxkb_symbolsのincludeにmyswap(myswapkeys)追加

```
xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)" };
    xkb_types     { include "complete" };
    xkb_compat    { include "complete" };
#    xkb_symbols   { include "pc+us+us:2+inet(evdev)+ctrl(swap_lwin_lctl)+myswap(myswapkeys)" };
    xkb_symbols   { include "pc+us+us:2+inet(evdev)+myswap(myswapkeys)" };
    xkb_geometry  { include "pc(pc105)" };
};
```

~~※`+ctrl(swap_lwin_lctl)`はalt単体で推したときに問題にならないようにするためのworkaround~~

# システム反映

## .bashrcに追記

```
xkbcomp -I$HOME/.xkb ~/.xkb/keymap/mykbd $DISPLAY 2> /dev/null
```

## ~/.xkb/symbols/myswapをコピー

```
sudo cp -i ~/.xkb/symbols/myswap /usr/share/X11/xkb/symbols/
```

## /usr/share/X11/xkb/rules/evdev に追記

```
mysetting:myswapkeys = +myswap(myswapkeys)
```

## gnomeのシステム設定に反映

```
$ export GIO_EXTRA_MODULES=/usr/lib/x86_64-linux-gnu/gio/modules/ # workaround for the issue* 
$ gsettings set org.gnome.desktop.input-sources xkb-options "['mysetting:myswapkeys']"
```

### the issue*
```
$ gsettings set org.gnome.desktop.input-sources xkb-options "['mysetting:myswapkeys']"
GLib-GIO-Message: 02:13:03.500: Using the 'memory' GSettings backend.  Your settings will not be saved or shared with other applications.
```

## 再起動
## 設定保持確認
マイクロサービスの肥大化が止まらない

###はじめに
マイクロサービスアーキテクチャの開発を経験して感じたことを書き綴っています。

近年流行の兆しを見せているマイクロサービスアーキテクチャ。
DDDと相性が良いこともあってマイクロサービスアーキテクチャを採用している開発現場は非常に増えていると思います。


###マイクロサービスの概要
マイクロサービスの最大の恩恵は機能単位でサービスを提供することで、メンテナンス性や可用性の向上が見込まれる点です。

各サービス間の連携を疎結合にすることで依存関係を明確にしておくことが重要なのですが、この考え方がDDDのコンテキストマップとマッチすることから、DDDとセットで扱われることが多いと思います。

###やがて儚い幻想が壊される
ところが、各サービス間を疎結合に保つということがなかなか厄介になってきます。
例えば、リプレイス案件の場合であれば、現在のサービスをざっくりと（実はこれがいけないのですが）分析しドメインごとにマイクロサービス化してチームが結成される。
最初のころはドメイン分割してコンテキストマップで依存関係を明確にして設計＆開発が進むのですが、機能が増えてくると、どこのサービスの持ちものであるのかが難しくなってくる。
また、疎結合を保つためにイベントソーシングなどの手法を用いるケースも増えてくる。
同じ様なデータを各サービスが持つことも増えてきて、徐々に肥大化が始まってくる。

###陰謀論
こうした挫折を経験すると、このような思考が頭をよぎる。
そもそも、マイクロサービスは本当に良いモノなのか。
マイクロサービスとはAmazonやGoogleのビジネス戦略なのではないか。

###結局なにがダメだったのか考察してみる
最初に書いたのだけれど、マイクロサービスはDDDと相性が良いと思う。
DDDと相性が良いのでマイクロサービスはDDDと二人三脚で進めるべきなのではないか。
つまり、最初に細かく分割しすぎるのは良くないということ。
例えば、ユースケース駆動設計の手法を用いるのならば、ユースケース単位でドメイン分析を行い実装まで落とし込むことが可能である。

つまり、そのプロジェクトが最初にやらなければならないのはドメイン分割＆チーム割ではなくて、ユースケース（ユーザーストーリー）の洗い出しなのではないか。
言い方を変えてもう一度言うと、プロジェクトの最初期の段階では**似たように見える**機能を**無理やり**まとめてドメイン分けしてしまう必要はないのではないかということ。

いつ分割するのか。
初期リリースする機能のユースケースの分析（シーケンス）が終了したタイミング。
各ユースケースの依存関係やI/O、非機能要件がクリアになっているこのタイミングが理想的なんだと思った。
課題も勿論ある。
このタイミングでアーキテクチャ設計をして、マイクロサービス化して、サービスごとにチーム分けした場合、スケジュールはどうなっちゃうの？ということ。
そんなにゆったりしたプロジェクト存在しないよって言われそう。

10年後、マイクロサービスがどうなっているのか興味深い。
Android PAC利用時に一部Google製アプリがタイムアウトする件

#はじめに
Androidで「Proxy Auto-Configuration(PAC)」使用時に
Google PlayやYouTubeなど、一部のGoogle製アプリの通信がタイムアウトとなり、
使えない事象について、対処法をインターネット上で見つけたので備忘録。

#環境
- 使用端末OS：Android 8.0.0
- HTTPサーバ：Apache/2.4.18 (Ubuntu)(PACファイル配布用）
- プロキシサーバ：Squid Cache Version 3.5.12 (PACで指定するプロキシサーバ)

 ※今回の原因はAndroidに起因するもので、HTTPサーバやプロキシサーバは事象に直接関係はないが、関連環境として記載。

#対応
###設定の「電池の最適化」より「ProxyHandler」の最適化をオフにする
Settings > Battery > ︙(※1) > Battery optimization > "ProxyHandler" > Don't optimize > DONE
※1：画面右上の「︙(縦の三点リーダー)」ボタン

#原因
- Androidの機能として、PAC構成に従って適切なプロキシサーバへ通信を転送させるProxyHandlerがある。
- ProxyHandlerはバッテリの最適化がデフォルトで「適応」になっており、バックグラウンドでの実行が禁止されている。
- ProxyHandlerを経由して通信するアプリはProxyHandlerがバックグラウンドで実行されず、通信できないためタイムアウトとなる。
- Android Open Source Projectに事象を報告したがバッテリの最適化が適応状態であればバックグラウンドで実行されないのは意図した動作であるとして、修正はされず。

※Google ChromeはAndroidのデフォルトとは異なるPACの処理を行うためタイムアウトとならない！
（上記は参考サイトの要約）

#感想
Chromeでは意図した通りにPACが動作していたため、Google PlayやYouTubeのアプリでタイムアウトが発生するのは、PACの構成やプロキシサーバの設定が問題であると思い、中々ハマってしまった。


#参考
2019/Oct/06: https://www.ctrl.blog/entry/android-proxyhandler-battery-optimization.html
データベース基礎まとめ

#はじめに

データベースの基礎部分のまとめです。
(※　現在学習中の部分の情報を中心にまとめています。)


#1.　データベース（DB）とは？
###1.1 概要
- **決まった形式で整理されたデータの集まり。**

∟　複数のユーザーが情報を共有して使用できる。
∟　[取得・登録・修正・削除]などでき、効率よくデータを抽出できる。

**「図書館」**　のようなイメージで例えられる。


注※「データベース」という言葉はやや抽象的に使われ、会話の中では
DBMS(※後述)なども「データベース」と呼ばれたりもする。

>例：Aさん「データベース何使ってるの〜？」
　　Bさん「Oracle使ってますよ〜。」

など。

###1.2　データベースの種類
データベースはざっくりと以下の種類がある。

1.リレーショナル型(関係型)　　←略してRDB、現在の主流。
2.階層型
3.ネットワーク型
4.NoSQL

#2.　リレーショナル型データベース(RDB)について
データを **表(テーブル)形式** で管理するデータベース。
列と行を持つ、「Excel」のようなイメージ。


###2.1　テーブルとは

カラム（列）とレコード（行）で構成される表（テーブル）です。

![sampleTable.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396284/f5c7dbda-a27a-6924-5fd8-4fba3e02c1fd.jpeg)

###2.2　データ型

データ型とは、列に格納するデータを制限する方法。
整数、文字列など列に入るデータの種類を限定できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396284/d8c2dad1-b178-7aa0-e2b8-1257686dc2fb.png)

**■可変長、固定長ってなに？**

**可変長**・・・可変長とは文字数の上限を明示的に定義した文字列。

例えば文字数が「可変長で10文字」と定義されている場合、
10文字以内であればよいということになります。

**固定長**・・・固定長は文字数が明示的に定義されている文字列。

例えば文字数が「固定長で10文字」と定義されていている場合、
必ず10文字である必要があります。

#3.　データベース管理システム「DBMS」とは
　
**DBMS**　・・・　【Database Management System】の略称。

「DBの機能を提供するソフトウェア」のこと。
「RDB」の管理システムなら「**RDBMS**」という。

###3.1　RDBMS と NoSQL

「**NoSQL**」とは"リレーショナル型データベース以外のDBMSのこと"を指します。

■代表的なNoSQL
・ MongoDB   (MongoDB Inc.)
・ BigTable　(Google)
・ Cassandra (Apache Software Foundation)

　　
**NoSQLデータベースのメリット**

>・　データの格納および取得が高度に最適化されている
・　大規模データに対応できる
・　多種多様なデータに対して柔軟に対応できる

**NoSQLデータベースのデメリット**

>・　データの整合性が確保されない
・　登録済みデータの加工は基本的に不可能、可能でも最小限
・　データの並べ替えには注意が必要

###3.2　DBMSとデータベースの違い
前述のように、
OracleやMySQLも便宜上「データベース」と呼ばれるような場合も多いが、
厳密には、「DBMS(RDBMS)であってデータベースではない」というのが正しい区分。
　　　　
データベースが **図書館** なら、
DBMSは、 **そこで働く職員さん** のイメージ。


　　

![データベース (4).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396284/14c522b9-6c22-e48a-0046-3b6407091ecd.jpeg)


#4.　SQLとは？

「SQL」はRDBを操作するための言語。
RDBを扱うとき、SQLを知らなければ何も操作ができないのです！(^^;;

※SQLのもう少し詳しい説明については別でまとめました。
→[SQLまとめ(分類まで)](https://qiita.com/matsukei/items/3f3813424447a00ab5cc)


#5.　まとめ
　　
以上、データベースについて、ざっくりとまとめてみました。
　　　
間違ってる点などあれば修正いたしますので、ご指摘いただけると幸いです！(^_^;)
昔、自作のCSSで作ったサイトをBulmaに切り替える(簡単なBulmaの使い方)

# 初めに
昔、若気の至りで作成したCSS/HTMLで作成したサイトをBULMAに切り替えてみた備忘録

# 結論
やっぱり、デザインに関しては中途半端にチャレンジするのであればあるものを実装したほうが良いと思いました。
切り替え自体も1時間程度で終了しましたし、スッキリしました。

## 変更前

<img width="1576" alt="スクリーンショット 2019-10-06 0.55.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/f55b6fb6-0284-b71c-7ff3-335eb1b2bb4c.png">

## 変更後

<img width="1444" alt="スクリーンショット 2019-10-06 0.57.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/b6375dd7-a12b-376a-79f4-e59cbfbb217c.png">

# 手順

旧式のHTMLサイトとCSSを用意しました。
今回のサイトはCSSが該当HTML内に入っていたため1ファイルでしたが…

## 1,既存のCSSを全削除
不用意に残っていると悪さをしそうなのですべて削除しました。

## 2,`Bulma`を読み込ませる

ヘッダー部に下記の1行を入れます。

```HTML
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
```

## 3,ベースをどのように書くか調べる

とりあえず、全体構成が最初であるため `Bulma`の`Layout`を参照します。
この中の、`Container`を参照し `body`要素直下に埋め込みます。
こんな感じですね。

```html
  <body>
    <div class="container">
      <div class="notification">
      </div>
    </div>
  </body>
```

## 4,タイトルをどうするか考える

タイトルに関しては[hero](https://bulma.io/documentation/layout/hero/)というのがあったのでこれを利用しました。
こんな感じに記載すれば綺麗になりました。

```html
<section class="hero is-info">
    <div class="hero-body">
    <div class="container">
        <h1 class="title">
        hasito.com
        </h1>
        <h2 class="subtitle">
        しがないサラリーマンプログラマ
        </h2>
    </div>
    </div>
</section>
```

## 5,全体構成を考える

次に、現状の構成から大きく変えない方法で少しみてみたところ…
[tiles](https://bulma.io/documentation/layout/tiles/)がそれっぽいのでこれをそのまま流用しました.

こんな感じの構成です。
<img width="1172" alt="スクリーンショット 2019-10-06 1.13.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/fcf57afb-f68c-62b1-582c-8c22da4e38fd.png">

該当の要素に各コンテンツを埋め込んでいくだけですね。
完成は下記になります。

https://hasito.com

# 悩んだ所
そこまでなかったので備忘録的に書いておきます。

## `Hero`と`tiles`の間にmarginが生まれない
正規な解決方法があるのでしょうけど、すぐに探せなかったため改行で逃げています…

## `tiles`が最も長い要素に依存する。
例えば横軸で長い要素が1個あると、他の要素も長く取ろうとして不格好になります。
私サイトはTwitterが長さ指定無しだったため6000px程度になりかなり見にくくなってしまいました。
Twitterの埋め込みは`data-height="x"`で高さを指定できるため、これで解決しました。
AndroidStudioで端末の画面を録画する

## はじめに
Androidアプリを開発していくうちに、ここの動作誰かに見て欲しいなーって思ったことはありませんか？
そんな方のために、簡単に端末の画面を録画できる方法を書いていきたいと思います。
Androidアプリの開発環境はほとんどの割合でAndroidStudioだと思われるので、AndroidStudioの機能の中で録画の方法となります。

## 録画方法
まず端末をパソコンに繋いで、アプリを起動させます。
その後、Lagcatの左側にあるScreen Recordのボタンを押します(画像参照/画像一番下)。

<img width="46" alt="スクリーンショット 2019-10-06 0.29.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298324/25b98deb-a7e3-a311-5b06-d2e0065ad71e.png">

押した後はbit rateと解像度(幅と高さ)を指定することができます。
デフォルトではbit rateは4、解像度は端末の状態に合わせられます。

<img width="555" alt="スクリーンショット 2019-10-06 0.30.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298324/f80fe001-165a-06ca-b363-32f6bedc713c.png">

ここまで設定し、Start Recordingを押すと録画が開始し、Stop Recordingを押すと録画が終了します。
その後は任意のフォルダに保存し、録画した画面を再生することができるようになっています。
Windows EventLogをElasticSearchにimportする(のを100倍早くする)

# Overview
[Windows EventLogをElasticSearchにimportする](https://qiita.com/sumeshi/items/491891d83c3aca224880)
という記事をちょっと前に書きました

[EvtxtoElk](https://github.com/dgunter/evtxtoelk)はとても素晴らしいライブラリなのですが, 
Windowsの巨大なイベントログをインデックスしようとするとアホみたいに時間がかかって死にそうなので高速化を図ります。**(僕のケースでは30分ほどかかっていました)**

結論からいうと, **EvtxtoElkの高速化は(コスト的に)無理**なので偉い人が作ったパーサを利用して自分で書きました。

**2020/06/12 追記:**
  機能追加しました :sushi:
  [Windows EventLogをjson形式に変換する](https://qiita.com/sumeshi/items/f3e87f0412f9b05f85a3)

# Usage
https://github.com/sumeshi/evtx2es

pipでインスコします。
`pip install evtx2es`

コンソールからも使えます。

```bash
$ evtx2es /path/to/your/file.evtx
```

Python製なのでスクリプトからも呼べて安心！
100ファイル読みたいときとかも楽チンですね！:kissing_heart:

```py
from evtx2es import evtx2es

if __name__ == '__main__':
    filepath = '/path/to/your/file.evtx'
    evtx2es(filepath)
```

# Evaluation
評価にはJPCERT/CCが提供しているLogonTracerというツールのsampleを使いました。
だいたい30MBくらいのSecurityログです。

https://github.com/JPCERTCC/LogonTracer

速度の計測にはtimeコマンドを用いました。
もっと厳密な図り方もできますが, どうせ計測環境によって変わるしいいよね。

## EvtxtoElk
```bash
$ time python elk.py
321.95 user 0.11 system 5:30.77 elapsed 97%CPU
```

## Evtx2es
```bash
$ time python es.py
4.94 user 0.06 system 0:11.84 elapsed 42%CPU
```

約320秒から5秒になりました。

大体64倍の高速化ができました！<font color="lightgrey">100倍は嘘です！！ごめんなさい！！！</font>
CPU使用率も下がってるのも嬉しいです:sunglasses:

# Optimize

最初はWindowsのクソデカいファイルだからこんなもんかな〜と思ってたんですけど, ElasticSearchのインデックスってそんなに遅くない**ハズ**なんですよね。
なのに遅いってことは, どこかで足を引っ張っている存在がいるということです。

ならそこを高速化してあげれば早くなるはず！と思って取り掛かりました。
アプローチとしては

- Python部分を書き直す
  - numbaで実行時コンパイルを行う
  - Cythonを使ってC言語のライブラリをコンパイルする

- それ以外の言語を使う
  - 遅い部分だけ別の言語で書く
  - 速い言語でPythonライブラリを作る

などいくつかあります。下に行くほど黒魔術感が増します。

以下に高速化の手順を書いていきます...といっても僕がしたことはほとんどなくて, 
**卍最強Evtxパースライブラリ卍** を使っただけです。

https://github.com/omerbenamram/pyevtx-rs

## Profiling
Pythonみたいな速度の遅い言語を使う人はよくやると思うんですが, 
むやみやたらに高速化するよりボトルネックを探して重点的に高速化したほうが効果が高いことが多いです。

そのために, line_profilerというものを使います。

> [Pythonのline_profilerとmemory_profilerの紹介](https://qiita.com/aratana_tamutomo/items/aa3b723a3dd7a44e45d6#100%E5%9B%9E%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E5%B9%B3%E5%9D%87%E8%A6%8B%E3%81%A6%E3%81%BF%E3%82%8B)

詳しい説明を書いてくれている方がいらっしゃるのでおまかせします。(助かりました！ありがとうございます！)

line_profilerで行単位でEvtxtoElkのコードを分析した結果, EvtxtoElkは無実だということがわかりました :joy:

じゃあ何が悪かったかというと, 依存ライブラリの[python-evtx](https://github.com/williballenthin/python-evtx)のようです。
(※ このライブラリは非常に有用ですが, 今回のユースケースでは間違った選択だった. ということです.)


## Development
ならpython-evtxをCythonで高速化しようと思ったのですが, ソースコードをひと目見てやめました。作業量にリターンが見合いません。

しかたないからRustあたりでパーサを書くか〜とも思ったのですが, ふとこんな考えが頭をよぎりました。

(もう誰かつくってるのでは？)

**https://github.com/omerbenamram/pyevtx-rs**

じゃあelasticsearchとの接続部分だけ書けばいいじゃん！と思ってつくってついでにパッケージ化しました。

修士の研究で使うから作ったけどせっかくなら使ってもらえるとうれしいです！ :sushi: 


お わ り

<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

ちなみに

```
$ evtx2es hoge.evtx --size=10000
```

とかしましたがあんまりはやくなりませんでしたざんねん

ElasticSearchはバッファサイズで劇的に早くなるわけではないのでそこそこの値にしておくのが良いと思います。
どっちかというとMappingTypeを最適化したほうがパフォーマンス良かったりします(_allを無効にする, not_analyzedなフィールドを設定するなど...)
【React】 FormでEnterキーを押した時にSubmitされるのを防ぐ

Reactで作成したForm内でEnterキーを押すと、勝手にSubmitされてしまい、画面がリロードされて困ったのでメモです。

```React:Form.js
handleSubmit(e) {
    e.preventDefault();
  }

render() {
  return(
    <div className="search-item">
      <form
        className="search-item__form"
        onSubmit={e => this.handleSubmit(e)}
      >
        <input
          type="text"
          className="search-item__item-search-field"
        />
      </form>
    </div>
  )
}
```

HTMLではformタグの中にonSubmit="return false;"と記述すればSubmitされることはないのですがReactでは思うように動作しないため、
上記のようにe.preventDefault();を使うとエンターキーを押してもSubmitされるのを防ぐことができます。
Raspberry Pi 3 Model B+に最新のNode.jsとnpmをインストールする

# 環境
```
cat /etc/debian_version
10.4

cat /etc/issue
Raspbian GNU/Linux 10 \n \l
```

# インストール方法

公式にやり方が書いていました。
https://github.com/nodesource/distributions

```
curl -sL https://deb.nodesource.com/setup_14.x | bash -
apt-get install -y nodejs
```
※root権限で実行

# バージョン確認

```
node -v
v12.11.1

npm -v
6.14.5
```

npmは最新バージョンが入ったが、nodeが最新バージョンになっていない。

# nodeを最新バージョンに切り替える

nodeバージョン管理システム「n」をnpmにてインストールし、最新バージョンに切り替える。
[tj/n: Node version management](https://github.com/tj/n)


```
echo "N_PREFIX=$HOME/.n" >> .profile
echo "export PATH=$N_PREFIX/bin:$PATH" >> .profile
source .profile
npm install -g n
```

最新nodeに切り替え

```
n latest
```

バージョンを確認

```
node -v
v14.5.0
```

最新バージョンが入りました。
お疲れ様でした。
Python3で家庭用ネットワークカメラからJpeg画像をダウンロードしPILで表示する

#はじめに
Python3で家庭用のネットワークカメラからJPEG画像をダウンロードして、そのまま保存しないでPILで表示するためのメモ。
IO DATAのQwatchシリーズのカメラはAPIの仕様がメーカーからダウンロードでき、JPEG画像をHTTPで取得することが可能。
今回ダウンロードしたカメラの画像をどこかに保存するのではなく、すぐに画像処理に使いたいのでダウンロードしてPIL形式で受けるようにしてみた。

#環境
Python 3.7.4
カメラ：TS-NA220W (IO Data)


```python:sample.py
#!/usr/bin/env python
# coding: utf-8

# カメラの設定
IMG_URL = "http://192.168.XXX.XXX:XXXXX/snapshot.jpg"
USER = "YOUR NAME"
PASS = "YOUR PASSWORD"

import io
import base64
import requests
from PIL import Image

# JPEGをダウンロードしPIL形式で返す
def download_pil_image(url, user, pwd):
    # BASIC認証用のヘッダを作成
    userpass = base64.encodebytes(('%s:%s' % (user, pwd)).encode("utf-8"))[:-1]
    headers = {"Authorization": "Basic %s" % userpass.decode("utf-8")}
    
    # 引数のURLにアクセスしデータをダウンロード
    res = requests.get(url, headers=headers)
    
    # PIL形式に変換
    img_bin = io.BytesIO(res.content)
    pil_img = Image.open(img_bin)

    return pil_img

# 呼び出し部分
try:
    # カメラ画像を読み込む
    img = download_pil_image(IMG_URL, USER, PASS)
    img.show()
except Exception as e:
        print(e)
-cpオプションにプロパティファイルのパスを指定したにも関わらず、クラスパスとして認識されない

# 環境

この記事は以下の環境で、稼働確認を実施しました。

```
C:\>java -version
openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.3+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.3+7, mixed mode)
```

# 事象

以下の`Main.java`はクラスパス上に存在する`queen.properties`を読み込んだのち、その内容を整形して表示するものです。

```java:Main.java
import java.io.IOException;
import java.util.Properties;

public class Main {
    public static void main(String[] args) {
        try (var in = Main.class.getClassLoader().getResourceAsStream("queen.properties")) {
            var properties = new Properties();
            properties.load(in);

            for (var key : properties.stringPropertyNames()) {
                var value = properties.getProperty(key);
                var message = String.format("key=`%s` value=`%s`", key, value);
                System.out.println(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

なお`queen.properties`の内容は次の通りです。

```queen.properties
queen.vocal  = Freddie Mercury
queen.guitar = Brian May
queen.bass   = John Deacon
queen.drum   = Roger Taylor
```

さて`Main.java`を`javac`によりコンパイルして、`Main.class`を生成し、以下の通り実行したところ、エラーが発生し、想定通りの挙動を見せませんでした。

```
C:\>java -cp properties\queen.properties; Main
Exception in thread "main" java.lang.NullPointerException: inStream parameter is null
        at java.base/java.util.Objects.requireNonNull(Objects.java:246)
        at java.base/java.util.Properties.load(Properties.java:403)
        at Main.main(Main.java:8)
```

__このケースでは`properties`ディレクトリに格納された`queen.properties`をクラスパスに追加したいという意図がありました。そのため、クラスパスを指定する`-cp`オプションに`properties\queen.properties`を指定したのですが、うまく動作しなかったようです。__

# 原因と対策

ワイルドカード(`*`)を利用する場合などを別にすると、クラスパスへの指定方法はおおよそ次のようなルールになっているようです。

- jarファイルやzipファイルはファイル名を指定する。
- それ以外はディレクトリ名を指定する。

propertiesファイルをクラスパスに指定したいというのが今回の要望でした。したがって、クラスパスの指定方法としては後者が正解です。そこで、`-cp`オプションにファイル名ではなく、ディレクトリ名を指定したところ、想定通りの挙動になりました。

```
C:\>java -cp properties; Main
key=`queen.guitar` value=`Brian May`
key=`queen.drum` value=`Roger Taylor`
key=`queen.vocal` value=`Freddie Mercury`
key=`queen.bass` value=`John Deacon`
```

# 参考

[「クラス・パスの設定」](https://docs.oracle.com/javase/jp/8/docs/technotes/tools/windows/classpath.html)
【超重要!!】GitHubから外部参照する方法

## 1.GitHubから外部参照する方法
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/37dabbe4-9847-1e8c-2efa-908a59637df2.png)

[画像のリンクはこちら](https://github.com/ryomeblog/CSS_Test)

1. 参照したいGitHubのサイトへアクセスする。
2. 上記の画像を参照し、URLを  `https://①.github.io/②/③` とすると参照できる。

## 2.外部参照の確認

```html:test.html
<!DOCTYPE html>
<html>
    <head>
        <!-- 付加情報 -->

        <!-- タイトル -->
        <title>タイトル名</title>
        <!-- 文字コード -->
        <meta charset="utf-8" />
        <!-- 外部ファイル -->
        <link type="text/css" rel="stylesheet" href="https://ryomeblog.github.io/CSS_Test/style.css">
    </head>

    <body>
        <!-- コンテンツ -->
        <h1>Hello</h1>
    </body>
</html>
```
上記はGitHubから `CSSを外部参照` したhtmlの具体的な記述例です。
中身の文をコピーして、文字コードは `UTF-8` を指定し、ファイル名を `test.html` でデスクトップに保存するとブラウザではこうなります↓↓

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/d66aba2a-92d9-2f88-1594-5987e0c3d080.png)

画像のようになれば成功です。

## 3.GitHub
GitHubにソースコードを公開しています。

https://github.com/ryomeblog/qiita/tree/master/%E3%80%90%E8%B6%85%E9%87%8D%E8%A6%81!!%E3%80%91GitHub%E3%81%8B%E3%82%89%E5%A4%96%E9%83%A8%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
Mavenを依存ライブラリをダウンロードする用途のみで使う

まあ、前口上は省いて、WindowsでMavenリポジトリにあるライブラリを依存関係を含めて一式ダウンロードする手順。

１．OpenJDKを持ってきて展開。
https://jdk.java.net/13/
のzipファイルをダウンロードし展開。jdk-13フォルダをC:\にコピーして、「C:\jdk」にリネーム。

２．Apache Mavenを持ってきて展開。
https://maven.apache.org/download.cgi
のzipファイルをダウンロードし展開。apache-maven-x.x.xのフォルダをC:\にコピーして、「C:\maven」にリネーム。

３．コマンドプロンプトを起動してmavenのbinに移動。
```> CD C:\maven\bin```

４．JAVA_HOMEを設定。
```> SET JAVA_HOME=C:\jdk```

５．pom.xml作る。
「Mavenリポジトリからダウンロードしたいライブラリをここにコピペ」のところにMavenリポジトリで手に入るスニペットをコピペ。
例はSpring Data Core 2.1.11。
https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons/2.1.11.RELEASE

```> notepad pom.xml```

```xml:pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>id</groupId>
<artifactId>dl</artifactId>
<version>1</version>

<dependencies>
<!-- Mavenリポジトリからダウンロードしたいライブラリをここにコピペ -->

<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-commons</artifactId>
    <version>2.1.11.RELEASE</version>
</dependency>

</dependencies>
</project>

```

６．mvn実行する。
```> mvn dependency:copy-dependencies```

７．「.\target\dependency」に依存関係込みでライブラリ一式がダウンロードされるので、それをアプリのlibディレクトリなりにコピーする。

```
C:\maven\bin>dir .\target\dependency
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は 9281-A910 です

 C:\maven\bin\target\dependency のディレクトリ

2019/10/06  00:46    <DIR>          .
2019/10/06  00:46    <DIR>          ..
2019/10/06  00:46            41,139 slf4j-api-1.7.26.jar
2019/10/06  00:46           673,979 spring-beans-5.1.10.RELEASE.jar
2019/10/06  00:46         1,301,116 spring-core-5.1.10.RELEASE.jar
2019/10/06  00:46         1,176,955 spring-data-commons-2.1.11.RELEASE.jar
2019/10/06  00:46            23,764 spring-jcl-5.1.10.RELEASE.jar
               5 個のファイル           3,216,953 バイト
               2 個のディレクトリ  80,748,457,984 バイトの空き領域

```

以上。
googlecolabを使ってみる

- 少し前に書いた記事が発掘されたの挙げとこう！
- まぁそんな感じ

# googleCoLabって
- googleがやってる無料の計算システム（ただし制限あり）
    - ９０分ルールと１２時間ルールがあるらしい[参考リンク](https://qiita.com/tomo_makes/items/b3c60b10f7b25a0a5935#2-%E3%82%B7%E3%83%A3%E3%83%83%E3%83%88%E3%83%80%E3%82%A6%E3%83%B3%E3%81%BE%E3%81%A7%E3%81%AE%E6%AE%8B%E6%99%82%E9%96%93%E3%81%AF90%E5%88%86%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A812%E6%99%82%E9%96%93%E3%83%AB%E3%83%BC%E3%83%AB)
- 家にGPUマシンおけないよとかいう人は、お手軽に使えます。
- 記述法は、jupterNotebook形式です。

# 使い方
- 画面はこんなかんじ
![main](https://github.com/kapibarasyun/til/blob/image/googlecolab/main.png?raw=true)
- とりあえず、コードを書く場所に順番にコードを書いて行く感じ
- 基本コードはpython3&切り替えるとmarkdownでコメント~~もどき~~もかける

## ファイルのやり取りは？
- 直接ファイルをアップロードするかgoogledriveへアップロード
- まずは、かんたんな直接アップロード方法
1. メイン画面のところの黒丸のところクリック
![upload](https://github.com/kapibarasyun/til/blob/image/googlecolab/kokodayo.png?raw=true)
2. そこに直接ドラッグアンドドロップ
![upload](https://github.com/kapibarasyun/til/blob/image/googlecolab/drive.png?raw=true)

`注意`
Driveに置くとアップロードしたデータは消えないが普通にアップロードするとデータがログアウトするたび消えるので再度アップロードが必要

- googleDriveつなげ方
    - 以下のコードを実行

```bash 
from google.colab import drive
drive.mount('/content/drive')
```
- ここでgoogledrive認証があるので認証を行う．認証コードをコピペして次実行

`注意`
ここでも一旦ログアウトや長時間使わないと接続が切れますので，コードを実行し直して再度認証してください

## ディレクトリ移動方法＆apt&pipのやり方は
- 基本のpwdは以下にしめす場所

```bash
/content
#移動を行うときは
!cd /content/hogehoge
```
- !を頭につけることでコマンドが実行できます．
- ここでは試しにmecabの環境をつくる
- 参考サイト[ColaboratoryでMeCabを使えようにする。](https://qiita.com/pytry3g/items/897ae738b8fbd3ae7893)

```bash
!apt install aptitude
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xzutils
file -y
!pip install mecab-python3==0.7
```
`注意`
ここでも長時間ログインしなかったり接続が切れると再度リセットです．もう一回**再生ボタン**みたいなのを押して実行し直してね
Effective Java 第3版 85項 Javaのシリアライズよりも代替手段を選ぶ

Javaでシリアライズを扱う機会があったので、Effective Java 第3版 12章を読みました。
まとめを記載します。

##シリアライズ/ディシリアライズ(Serialize/Deserialize)とは
オブジェクトをバイトストリームとして符号化する、また反対にオブジェクトを再構築する手法。
Javaのフレームワークでは、オブジェクトにSerializableインターフェースを実装することによって容易に実装できる。

例えば、以下の様にUserをシリアライズ化した場合、インスタンス化されたUserオブジェクトは```ObjectInputStream#readObject()```を呼び出せば、容易にディシリアライズされる。

```
public class User implements Serializable {
    private static final long serialVersionUID = 199035831519635924L;
    private String name;
    private String cardNumber;

    public User(String name, String cardNumber) {
        this.name = name;
        this.cardNumber = cardNumber;
    }
}
```

## シリアライズの危険性
シリアライズは便利だが、上記の例では、どこからでもUserインスタンスはディシリアライズできるということにもなる。

こうしたコードは、リモートコード実行(RCE)やDoS攻撃などの攻撃の弱点になってしまう。
さらに、RMI,JMX,JMSといった、よく使われているJavaのサブシステム、およびサードパーティーのライブラリにもシリアライズは使用されているため、**攻撃対象領域**は広くなってしまう傾向にある。
（こうしたライブラリや製品など様々な場所で使われているJavaのシリアライズ可能な型を持つメソッドを**ガジェット**と呼ぶ。こうしたガジェットを組み合わせることで(ガジェットチェーン)、攻撃者はネイティブコードを呼び出せてしまう。)

また、ガジェットなしでも、シリアライズ技術を利用し、DoS攻撃が仕掛けられるで「ディシリアライズ爆弾」なども作ることができてしまう。
これは、インスタンスのディシリアライズをする場合、そのフィールドや要素のハッシュコードを計算する必要があることを悪用し、例えば深い入れ子構造になっているHashSetインスタンスなどを作成してディシリアライズさせることで、莫大な計算時間を掛けさせる攻撃手法である。


## ディシリアライズ攻撃に対する対応策

最善策は、システム内で一切のディシリアライズを行わないこと。
世の中には、クロスプラットフォーム構造化データ表現(≠シリアライズシステム)があり、これらを利用することで、シリアライズ以外の方法で、オブジェクトとバイトシーケンス間の変換を安全に行うことができる。
こうした表現は、基本データ型と配列のみをサポートし、Javaのシリアライズよりもはるかに単純である。

主なものに、JSONとprotobufがあり、これらは**言語中立**である。
・JSON→Webでよく使われる軽量のデータ交換フォーマット。JavaScript用に開発され、テキストで人間が読める形式でデータ表現ができる。
・protobuf→Googleにより、C++様に開発された。バイナリ形式で、より効率的である。

次に、既存のJavaシステムを開発している場合などで、シリアライズの利用が避けられない場合の策としては、信頼していないバイトストリームのディシリアライズは、一切行わないこと。
（特に信頼していない元からのRMI要求を受け付けないこと）
→Javaのセキュアコーディングガイドラインにて、「信頼されないデータのディシリアライズは、本質的に危険であり、避けるべきである」という記載があり、ガイドライン全体で唯一大文字・太字・斜体・赤字で強調記載されている。
[Secure Coding Guidelines for Java SE](https://www.oracle.com/technetwork/java/seccodeguide-139067.html)

シリアライズが避けられず、データの安全性を確保できない場合は、Java9で導入された```ObjectInputFilter```を使用することも必要。
これにより、データストリームに適用されるフィルタ処理を、ディシリアライズ前に実行できる。
なお、フィルタ方法には以下の二種類がある。
ブラックリスト・・・デフォルトでクラスを受け入れ、潜在的に危険なクラスを拒否する方法
ホワイトリスト・・・デフォルトでクラスを拒否し、安全なクラスを受け入れるする方法

ブラックリストは、新たな脅威に対応できないため、***ホワイトリストを選ぶこと***
(Serial Whitelist Application Trainerとよばれるツールを使うと、ホワイトリストを自動準備し、過剰なメモリ使用や、深い構造のオブジェクトを防いでくれる。ただし、防ぐことができないディシリアライズ爆弾などの攻撃もある。)

## 参考図書
[Effective Java 第3版](https://www.amazon.co.jp/Effective-Java-%E7%AC%AC3%E7%89%88-Joshua-Bloch/dp/4621303252/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)
Goの関数とメソッドについて

##関数とメソッドは違うもの

###関数
関数は以下のような形で書ける。

`func 関数名（引数） 戻り値 {}`
例

```go
func add(a,b int) int{
  return a + b
}
```

###メソッド
メソッドとは**レシーバーと関連づけられた関数**。

レシーバーとは
関数を紐づけるもの。
例えば、以下の`(s example)`の部分。

```go
type example string

func (s example) sum() int{
  return s + 1
}
```

exampleと紐づいているので、exampleを宣言すれば`sum()`も呼び出せる。

```go
type example int

func (s example) sum() int {
	return int(s + 1)
}

func main() {
	var e example = 1
	out := e.sum()
	fmt.Println(out)
}
```
マルチ機能時計を作る(ESP32+LEDMatrix)

#はじめに

LEDマトリクスモジュールを使って、マルチデジタル時計を作りました。


##日付表示・温湿度表示
タッチセンサーで右のネジ部を１回タッチで日付、２回タッチで温湿度表示。
![temperture.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/97577d4d-6f30-ee50-8d8a-95f369dbcd41.gif)

##時報
サンプルにパックマンがあったので時報で使ってみました。
インベーダーもあります。ソース内でお好みの方で。
![pacman.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/69b05376-ef72-14f4-10a8-a65e42adb4a1.gif)

#仕様
* デジタル時計
* 日付表示
* 温湿度表示
* タッチセンサー切り替え
* アニメーション

#ハードウェア 
* ESP-WROOM-32 DevKit（[Amazon](https://www.amazon.co.jp/gp/product/B0718T232Z/)）
* マトリクスモジュール（[Amazon](https://www.amazon.co.jp/gp/product/B06XQXN53V)）
* 温湿度センサーモジュール（AM2320：[秋月電子](http://akizukidenshi.com/catalog/g/gM-08663/)）
* ユニバーサル基板、ワイヤー、金具等、入れ物
* 母艦（Windows10）

#配線
ハンダ付けは必要ありません。パーツをワイヤーで繋ぐだけ。

| ESP32(GPIO) | MaxtriModule |
|:-:|:-:|
|5V |VCC|
|27|CLK|
|12|DIN|
|14|CS|
ESP32のGPIOのピンの特にこだわりはありません。配線したときに並んでいるものを使うために上記のようにしただけです。

| ESP32(GPIO) | Touch sensors |
|:-:|:-:|
|T4| ワイヤーで外出し|
ESP32はタッチセンサーを装備しています。どのタッチセンサーピンを使っても構いませんが、位置によっては干渉を起こすかもしれませんので、色々試してみてからお使いください。

| ESP32(GPIO) | AM2320 |
|:-:|:-:|
|3.3V |VDD|
|26|SDA|
|GND|GND|
|GND|SCL|
 温湿度センサーAM2320 ですが、single bus 方式で使いましたので、SCL は GND に繋いでいます。


左端にあるのが AM2320 、右端にあるネジがタッチセンサーです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/f18027c7-6c00-b30f-85dd-4dec926cc020.png" width=70%>

#ケースと格納
ケースはかなり悩んで色々買ってしまいました。
結局ダイソーの[クリアケース](https://lipscosme.com/posts/495294)に落ち着きました。こいうのってセンスが出るんですよね・・・。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/ec52cc3a-1d00-722c-dd6f-ee45aeea6aa1.png" width=70%>
配線をちゃんとして自作ケースを作った方が早いんじゃないかと悩みました。


#MAX7219用ライブラリ
いよいよ本題です。このLEDMatrixのドライバとして使われているのが MAX7219 です。
そして MAX7219 の制御用にライブラリが公開されています。
MD_MAX7219：https://github.com/MajicDesigns/MD_MAX72XX
これを利用したアニメーションライブラリが MD_Parola です。
MD_Parola：https://github.com/MajicDesigns/MD_Parola
今回はこれらを使いました。

#ソース
こちらに置いておきます。
https://github.com/nori-dev-akg/LED-Matrix-MultiClock

#最後に
実際には下のように使っています。
次回はせっかくのESP32なので通知メッセージを流したりできるように改修します。
またLEDの色が赤でないものを購入したいと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/4ba7d734-3673-a58f-4176-b60de15bb71d.png" width=70%>
AmazonLinux2にDockerとdocker-composeをインストールする

# 環境
- AmazonLinux2

# 手順
1. Dockerインストール

    ```
sudo amazon-linux-extras install docker -y # sudo yum install docker -y
sudo systemctl enable docker
sudo systemctl start docker
    ```

2. 初期設定（sudoなしでdockerコマンドを実行する）

    ```
sudo gpasswd -a $USER docker
sudo systemctl restart docker
exit # 再ログインすると反映される
    ```

3. docker-composeインストール
バージョンは[ここ](https://github.com/docker/compose/releases)から選ぶ

    ```
curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
    ```
firestore+nuxt入門

# この記事の目的

firebaseのfistoreの読み書きの基本をまとめる

# firestoreのデータモデル

https://firebase.google.com/docs/firestore/data-model

![memo-61.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193389/dad6098d-af51-1d43-bf3b-a574cdc5060b.jpeg)

* コレクション・・・tableのようなもの
* ドキュメント・・・レコードのようなもの
* データ・・・値のようなもの

# 読み書きの仕方

https://firebase.google.com/docs/firestore/quickstart

```javascript
var db = firebase.firestore();
// dbに初期化したfireastoreを代入
db.collection("users").add({
    first: "Ada",
    last: "Lovelace",
    born: 1815
})
.then(function(docRef) {
    console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
    console.error("Error adding document: ", error);
});
// addでusersコレクションにデータをいれていく
```

thenは処理が成功した際の処理。chatchは失敗してエラーが出た際の処理。

## データの書き込み

https://firebase.google.com/docs/firestore/manage-data/add-data

* データベースの作成
* ルールの作成
* firestoreの初期化
* addでcollectionの追加

### 書き込み（set、add、update）

* set・・・データを追加、もしすでにデータがあったら上書き
* update・・・既存のデータを更新
* add・・・新しいドキュメント、データを追加する

## データの取得

https://firebase.google.com/docs/firestore/query-data/get-data
【初心者向け】JavaとKotlinの違い

###Kotlinとは
- Kotlinは、JetBrains社が作っているJVM上で動作する言語。
- Kotlinは、Javaと完全に相互運用が可能である。あるクラスをJavaで書いて、それを継承したクラスを Kotlinで書いて、さらに継承したクラスをJavaで書くことができる。
- Javaで書かれていたプロジェクトに、追加開発分だけ Kotlin で書くことでき、導入しやすい。

###変数宣言
- Java

           String str = "aaa";
- Kotlin

           var str: String = "aaa"

final な変数を宣言するには val 、変更可能な変数を宣言するには var を使います。

###if文
- Java

         String foo = bar < 10 ? "abc" : "xyz";
- Kotlin

         var foo = if (bar < 10) "abc" else "xyz"
if や else ブロック内の結果を直接代入することができます。

###for文

- Java

             for (int num : numbers) {
                System.out.println(num);
             }
             for (int i = 0; i< 5; i++) {
                System.out.println(i); 
             } 

- Kotlin

           for (num in numbers) {
              println(num)
           }
           for (i in 0 until 5) {
              println(i)
           }
kotlinは inを使う。

###コンストラクタの呼び出し
- Java

        Foo foo = new Foo();
- Kotlin

        var foo = Foo()
kotlinでは、newは不要である。
備忘録：AndroidをPCで操作できるmobizenの設定で躓いたポイント

目的：AndroidをPCで操作するためにmobizenをインストールした。このとき、いくつかの躓きポイントがあったので、備忘録として残す。

# 前提
PC: Windows10
タブレット: Android(バージョン6.0.1)
ソフト: mobizen mirroring(バージョン2.21.16.47)
　　　　※mobizenブラウザ版ではなく、mobizen PC版を使用

# 躓きポイント
- mobizenの非対応タブレットの場合、mobizenブラウザ版やwifi接続を利用すると、タブレットの画面をクリックできないなどの制限があるため、「mobizen PC版」および「USB接続」する必要がある（ブーステッドモード）。
- USBケーブルはデータ転送用であること
- USB接続したら、タブレット側で「MNP」設定(ファイル転送用)を選ぶこと
- タブレットは「開発者向けオプション」から「USBデバック」をONにしておくこと
- キーボード設定：PCからタブレットを操作する際、キーボード配列がタブレットの設定と異なるため、正しくキーボード入力できない。　
　⇒　対策：半角/全角キーを押して日本語入力を選択すると、キーボード配列の設定を「mobizen mirroring」にするようポップアップで促されるので、ポップアップのショートカットから、タブレットの設定画面「言語と入力」に移動し、「mobizen mirroring」を選択する。 ⇒　これにより、PCのキーボード配列が有効になる。

# まとめ
- ネット上では、mobizenのインストール方法を丁寧に公開しているサイトが多数あるので、そちらを参照した。
- ここでは、mobizenインストールから設定までで自分が困った点と対処法を備忘録として残した。
Vimが喋った

ども、Vimゴリラです。

# はじめに
以前、Vimの翻訳プラグイン[translate.vim](https://github.com/skanehira/translate.vim)を作ってからブラウザで翻訳する機会がほとんど無くなりました。
普段は日本語と英語を交互で翻訳することが多く、ふと英語の発音をVimで聞けたらいいなぁと思い、5分くらいでぱぱっと作りました。

# どんな感じ？
こんな感じです。Qiitaは動画を載せられ無いのでツイートの方で見て頂ければと思います。
https://twitter.com/gorilla0513/status/1180480069371719680?s=20

# 導入
READMEを参照してください。
<a href="https://github.com/skanehira/say.vim"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/skanehira/say.vim.png" width="460px"></a>

1点注意ですが、このプラグインは内部で`say`コマンドを使用していて、このコマンドはMacOSにしかないため、Mac以外はこのプラグインを使えないです。

# 使い方
とても簡単です。`:Say` を実行するだけです。
もちろん選択したテキストを翻訳することもできます。

また`:Say "my name is gorilla"`といった感じで引数を渡すことで、
引数のテキストを読み上げてくれます。

# ボイスの変更
vimrcに次のように設定を書くことで変更できます。

```vim
let g:say_voice = 'Kyoko'
```

デフォルトのボイスは英語の`Alex`になっています。`say`で使用できる言語は日本語や中国語、韓国語などがあります。
詳しくはREADMEを参照してください。

# 仕組み
Vimで`say`コマンドを非同期で実行しているだけです。
メインの処理はたったこれだけ。

```vim
function! say#say(start, end, ...) abort
	let text = join(getline(a:start, a:end), "\n")
	if a:0 != 0
		let text = a:1
	endif

    let voice = get(g:, 'say_voice', 'Alex')
	let cmd = ['say', '-v', voice, text]

	call job_start(cmd, {
				\ 'err_cb': function('s:err_cb'),
				\ })
endfunction
```

`getline`を使用して、選択した範囲のテキストを取得しています。
そして引数がある場合は、引数を優先するようにしています。

`job_start` で`say`コマンドを非同期で実行させています。
とても簡単ですね。

# 最後に
ぱぱっと作ったので、何か便利な機能を思いついたら改良していきたいと考えています。
欲を言えば他のOSでもテキストを読み上げる方法があれば、インターフェイスをきちんと固めて対応したいと考えています。

もしこの方法で実現できるといった情報があればぜひコメントを頂けると助かります。