OmniAICreator/Qiita-1.07M huggingface dataset:
WPF ButtonのContentsを改行させたいけどさせたくない

WPF Buttonをクリックした時にそのButtonのContentsをクリップボードに保存するコードを書いてました。
用途としては雛形の一覧みたいなのをページに列挙して、クリックする事でその雛形を取得するみたいな。わざわざButtonを使ってるのは、マウスオーバーで選択されてる箇所がはっきり判るからなんですが、Buttonをこんな使い方していいのかはちょっと判りません。背徳感ちょっとありますね。

```xmal:xmal
<Button Content="文字列" Click="Button_Click" />
```

```C#:code
private void Button_Click(object sender, RoutedEventArgs e)
{
	String tagString = ((TextBlock)((Button)sender).Content).Text;
	Clipboard.SetText(tagString);
}
```

みたいな感じの奴です。
ところがContents（コピーしたい文字列）が物凄く長くなってButtonの横幅がページに収まりきらなくなってしまったので、Contentsを改行したくなりました。

「WPF Button 改行」でGoogleって見ると,xamlでButtonタグに「xml:space="preserve"」を追記し、Contentsプロパティで改行個所に改行コード（`&#10;`など）を追記してやるとええぞという事が判りました。
早速xamlを変更です。

```xmal:xmal
<Button Content="文字列&#10;の続き" Click="Button_Click" xml:space="preserve"/>
```

実際のContentは文章なので非常に長いですが上記のような感じです。こうすることでButton表示時に文字列が改行されるのでページ幅からはみ出さないようにボタンを配置できました。

しかしです、このまま上記codeでButtonのContentsをクリップボードにコピーすると、コピーした文字列も改行されてしまいます。これは困る（´・ω・｀）

という訳でcodeの方も以下のように変更してみました。

```c#:code
private void Button_Click(object sender, RoutedEventArgs e)
{
	String tagString = ((TextBlock)((Button)sender).Content).Text;
	tagString = tagString.replace("&#10;", "");
	Clipboard.SetText(tagString);
}
```

replaceで `&#10;`を空文字列に置き換えようという作戦だったのですが、これが全然機能しない。エスケープ文字を削除する方法が全然判んないわけ。これはGoogleっても全然それらしい方法が見つかりませんでした。

ここでplanBです。先程ButtonのContentsを改行する方法を検索した際に、TextBlock設定する方法もあったのでそっちで試してみます。こっちはButtonの幅に応じて自動改行してくれるのでエスケープ文字を追加する必要がないから改行なしの文字列を取得できるはず……

```xmal:xmal
<Button Click="Button_Click" xml:space="preserve" Width="xxx">
	<TextBlock Text="文字列&#10;の続き" TextWrapping="WrapWithOverflow" />
</Button>
```

※実際のTextはもっと長いのでButtonのWidthで改行されます。

実際にxamlを書き換えた所意図通りの表示となりました。
しかし、予想されていましたがこのまま当該のButtonをクリックするとエラーとなります。そりゃそう。((Button)sender).ContentはTextBlockオブジェクトなんだからそのままstringに変換できるわけがない。
なんかうまい方法があるのかもしれないのですが、頭が悪いのでエラーが出たらtry..catchで処理すりゃええじゃん、とcodeを以下のように変更しました。

```c#:code
private void Button_Click(object sender, RoutedEventArgs e)
{
	string tagString;

	try
	{
		tagString = (string)((Button)sender).Content;
	}
	catch
	{
		tagString = ((TextBlock)((Button)sender).Content).Text;
	}

	Clipboard.SetText(tagString);
}
```

取りあえず意図通りに動作しているのでオッケーです(´^ω^｀)
第 7 回 PowerPlatform アンバサダー

 みなさま、こんにちは！日本マイクロソフトでカスタマーサクセスマネージャーをしております澤本です。今回は、Teamsプラットフォームにおいて、業務の最前線でDXを推進するアンバサダーについてお話したいと思います。

利活用を進めるIT担当者にとって、アンバサダーは、現場にソリューションを浸透させる上で大切な役割です。現場の様々な課題に対して、皆に納得行く考えや新しい業務のアプローチを示し推進させるのは、アンバサダーがあってこそ実現が出来ることであると思います。

では、どうやってアンバサダーを勧誘すれば良いでしょう？どの様な方々の協力が必要でしょうか。

一般的にアンバサダーは、基本やる気がある現場の方で、現在の状況を改善したいと強く願う方を対象にするのが良いとされています。下記の導入アダプションカーブで言うところの[イノベーター]、[アーリーアダプター]と言われるタイプの方々です。このタイプの人々は、常にリスクと向き合いながらも新しいやり方を模索しチャレンジされています。

![7.1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1549581/bace0a1d-9f6c-d8c8-6d1b-87e3ebeee1b3.jpeg)

更にMicrosoft 365では、管理センターにあるレポート機能が充実していますので、例えば既にMicrosoft 365を良く活用されているユーザーの皆さまにお声を掛けして座談会などを実施するだけで、現場のユーザーが考えている課題感や今後の活用の方向性などを把握することが容易に実現できます。 私が担当したお客様の多くでは、この様な現況をレポートで把握した上で座談会に持ち込むことで、部署や職種に対する利活用の方向性を見極め、適切な施策を現場に提供する最初のステップとして実施して頂いております。

良くお客様先で『アンバサダーは業務の負担になる』と言われるケースもありますが、そこは部門長の方やDX施策の一環としてきちんと認知される必要があります。また、ボランティアのアンバサダーにて実施を検討される場合においても、施策(キャンペーン)の期間を例えば3ヶ月間などに実施期間を固定して参加してもらうなど、アンバサダーのお仕事を受けてくださる方の心理的負担も考慮が必要になります。アンバサダーの方々の実現させたいことと、利活用の担当者が実現させたいこと両方が実現できるように施策をプランニングすることが重要です。

さて、現場で最先端活用を推進するアンバサダーに対して、本部側にも利活用の担当者と共に、業務の最適化をサポートする技術に明るい担当者が必要になります。どの様に最新テクノロジーを活用して現場のお困りごとを解決できるか考える担当者です。

マイクロソフトでは、様々な業務の現場と本部側の間をデジタル化することで、継続的に現場の課題を解決し業務を最適化させていく取り組み、このアプローチを**<u>デジタルフィードバックループ</u>**と表現しております。

![7.2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1549581/1910d787-a445-ed86-f3a2-899c88586b66.jpeg)

DXを推進することは、単に現在の業務をデジタル化するだけに留まりません。デジタル化した業務をさらにAIなどの力により分析させ、持続的かつ最適化を繰り返し図ることで業務がデジタル上で理想的に活用できるようになるのです。

今回はTeamsを中心とした業務のDX化の側面からお話し致しましたが、マイクロソフトでは、こういったデジタルフィードバックループを**［現場の業務］**だけではなく、**［お客様との関係］**であったり、**［社員との関係］**や**［製品やサービス］**の側面でも同様に適用すべきデジタル化の世界と考えています。

![7.3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1549581/5a9a6006-079d-e810-b97e-309256365b6f.jpeg)

少し話が拡散してしまいましたが、業務のデジタル化を考えた時、最先端業務を想像し実践できるアンバサダーとそれをサポートする本部側の組織は、今後デジタル時代に生きるどの企業にとっても大変有益な組織構成となってきます。デジタル時代の効果的な業務改善や浸透にアンバサダーチームを構築することを是非検討してみてください。

さて次回は、Teamsを業務で活用するための基盤づくり、Power Platformガバナンスについてお話したいと思います。

(本記事は2021年5月時点の情報に基づきます）

**[-- 目次に戻る --](https://qiita.com/Masa_Sawamoto/items/72cc8679a9b2ea812d70)**
パソコンのお引っ越し やることリスト

最近古いパソコンから新しいパソコンに置き換えたので、次回の移行作業の時のためにやったことをメモしておきます。

# やることリスト
基本的には古いパソコン内にある各種設定ファイルを、Googleドライブなどのオンラインストレージにアップロードして、新しいパソコンからダウンロードするだけになります。

基本的に、ファイルもしくはフォルダごとコピーしてアップロード・ダウンロードするだけなのでとても簡単です。

人にもよりますが、移行する必要があるのは大体以下の設定になるかなと。

- sshの設定
- エディタの設定
- ターミナルの設定
- 独自に設定したaliasや関数
- 画像などのファイル

## sshの設定

1. 古いパソコンでFinderを開いてホームディレクトリに移動
1. `[command] + [shift] + [.(ドット)]`で`.ssh`フォルダを表示
1. オンラインストレージの任意のフォルダにアップロード
1. 新しいパソコンからオンラインストレージにある`.ssh`フォルダをダウンロード
1. ダウンロードした`.ssh`フォルダをホームディレクトリに置く

### 注意点
フォルダをダウンロードする場合は、おそらくzipファイルなどの圧縮ファイルでダウンロードされるので、ダウンロード後に解凍してからホームディレクトリに配置してください。


## エディタの設定
ここで紹介するのはAtomエディタの設定方法です。2021年6月地点でも有効な手段でした。

https://www.yokoyan.net/entry/2018/08/16/181500

## ターミナルの設定
Macの純正ターミナルの設定です。

1. 古いパソコンでターミナルを開いて [環境設定] > [プロファイル] > 左側下部にある点3つのボタン > [書き出す...] を選択
1. 任意のファイル名で設定を適当なディレクトリに出力
1. 出力したファイルをオンラインストレージの任意のフォルダにアップロード
1. 新しいパソコンからオンラインストレージにあるファイルをダウンロード
1. 古いパソコンでターミナルを開いて [環境設定] > [プロファイル] > 左側下部にある点3つのボタン > [読み込む...] を選択
1. ダウンロードしたファイルを選択すれば設定が反映される


## 独自に設定したaliasや関数
やり方はssh設定の時と同じです。僕の場合はシェルにzshを使ってるので`.zshrc`を移行しましたが、人によっては`.bash_profile`だったりするので適宜読み替えてください。

また、git使ってるなら`.gitconfig`なども合わせて移管しておくといいかと思います。

1. 古いパソコンでFinderを開いてホームディレクトリに移動
1. `[command] + [shift] + [.(ドット)]`で`.zshrc`を表示
1. オンラインストレージの任意のフォルダにアップロード
1. 新しいパソコンからオンラインストレージにある`.zshrc`をダウンロード
1. ダウンロードした`.zshrc`をホームディレクトリに置く

## 画像などのファイル
そもそもですが、日頃からローカルではなくてオンラインに保存しておいて使うときだけダウンロードする方法をお勧めします。

1. 古いパソコンで移管したいファイルをオンラインストレージの任意のフォルダに全てアップロード
1. 新しいパソコンから使いたい時にダウンロードする


# まとめ
いかがでしたでしょうか。

この手順で移管作業を行えば、30分くらいでスムーズに新しいパソコンで開発作業を始められるかと思います。

作業してて思ったのが、日頃からローカルにはメモなども含めてファイルを保存しないように心がけようってことですね。
フロントエンドとは何かをざっくり理解する。(初心者向け)

#本記事の内容
本記事ではフロントエンドをざっくり理解する。短時間でざっくり理解することが目的の記事です。
※厳密に言えば謝っている部分もございますので、ご容赦ください。

#アジェンダ
1.フロントエンドとは何か？
2.DOMとは何か？

<details><summary>#1. フロントエンドとは何か。</summary>
一般的にフロントと言えば、ブラウザで動くものです。
Google Chromeやfirefoxのブラウザで記事を読んだり、記事にいいねができるのはフロントエンドのソースコードがあるからです。じゃあ、フロントエンドのソースコードって何か？？？と言うと、DOMなのです。
えっっ、DOMって何？って事をこれから説明していきます。</details>

<details><summary>#2. DOMとは何か？</summary>
Document Object Modelの略称でDOMと呼ばれています。
DOMの定義は下記サイトに記載されています。が、結局なんなの？ってことを書く記事なので、ざっくり書きます。
DOMとHTML、CSS、JavaScriptの3つからなるもの。ざっくり、下記のような画像のイメージです。
・HTML（記事の内容などを書くファイル）
・CSS(記事を装飾するファイル)
・JavaScript(イベントを発火するためファイル)
![IMG_1375.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/d23e272f-002a-fef8-4a2e-5671c8806e5c.jpeg)

</details>
【知らなかった】Vue.js　Nuxt.js　親からpropsで渡した値を子から更新する方法

#NGパターン

###親
```vuejs
<template>
  <div>
    <Children :message="message" />
  </div>
</template>

<script>
import Children from '~/components/Children.vue'

export default {
  components: {
    Children,
  },
  data() {
    return {
      message: 'メッセージ',
    }
  },
}
</script>

```

###子
```vuejs:Children.vue
<template>
  <div>
    <input type="text" v-model="message" />
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
    },
  },
}
</script>

```

上記の事をしたいが、どうしても以下エラーが出る...

```
Avoid mutating a prop directly since the value will 
be overwritten whenever the parent component re-renders. 
Instead, use a data or computed property based on 
the prop's value. Prop being mutated: "message"
...
```
propsの値を直接変更しないでね、って言ってます



# OKパターン

###親
```vuejs
<template>
  <div>
    <Children :message.sync="message" />
  </div>
</template>

<script>
import Children from '~/components/Children.vue'

export default {
  components: {
    Children,
  },
  data() {
    return {
      message: 'メッセージ',
    }
  },
}
</script>

```
- 親で.syncを使う


###子
```vuejs:Children.vue
<template>
  <div>
    <input type="text" :value="message" @input="inputMessage" />
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
    },
  },
  methods: {
    inputMessage(e) {
      this.$emit('update:message', e.target.value)
    },
  },
}
</script>
```
- 子では、v-modelは使用せず、inputイベントでupdate:props名

これで親と子のmessageが同期されて更新できます

知らなかったけど、めっちゃ便利

https://jp.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A3%BE%E5%AD%90
遠隔でJetsonの管理を実現する方法－アラート通知

#はじめに
[前回の記事](https://qiita.com/Koharu1993/items/5b5cdb179a62262b3ef4)ではコマンド送信機能をご紹介しましたが、
今回はアラート通知機能を皆様にご紹介していきたいと思います！
ぜひ最後まで見て頂けたら嬉しいです！


#Allxon DMSについて
Allxon Device Management Solutions (Allxon DMS) は、
多数のデバイスを容易に一元管理できるサービスです。
SIer企業及びサービスプロバイダ企業に対して、
シンプルにナビゲートしやすいデバイス管理サービスを提供します。
事業部をまたぐ多用なデバイス管理すらもひとつのAllxonアカウントから実行できるため、
デバイス上の問題解決のみならず、人件費と運用コストの大幅削減にも実現可能です。

#アラート通知機能について
管理中のデバイスに異常が生じたり、不正な接続や操作を検知、
または事前に設定した監視項目がしきい値を超過した場合に
担当者に対してプッシュアラートを送信します。
アラートは電子メール（SMTP）、LINEメッセージ、またはWebhookで受け取ることができます。
アラート項目やアラート受信者を設定する前に、
最初に任意の通知方法（SMTP、LINE、Webhook）の事前設定が必要です。

#アラート通知の設定手順
①サイドメニューの「アラート」をクリックしてアラートページを表示したら、
右上の「アラートチャンネル」ボタンをクリックします。
![01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1509678/ca414886-1935-23f9-40bd-43e6c186c42e.png)

②-1　メール(SMTP)設定
アラートメールを受信するには、所属組織のIT部署やSMTPプロバイダから入手したSMTP情報を入手してください。情報を入力したらSMTP設定が正常に機能しているかどうかを確認するためにDMSポータルから検証コードが電子メールで送られます。メールボックスを確認し、検証コードをメモしててください。
![02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1509678/94e19db8-83bf-0e90-1778-be24eee0db83.png)

②-2  Lineの設定
アラートチャンネルのページからLineによるアラート設定を行ってください。
![03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1509678/f0baa989-6415-1112-2464-67c42cf33620.png)

②-3　Webhookの設定
Allxon DMSポータルから　Webhookでアラートメッセージを送信できます。
Webhookはカスタムリクエストとコールバックを使用してアプリケーションが
相互に通信するのに役たちます。何か新しいことが起きたときに、
自動化された通知や情報を他のアプリケーションに送信することができます。
![04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1509678/0dff3c23-7972-8bb5-9555-ff87976b2d9d.png)

②-4　メール、Line、Webhookの詳細説明について
こちらの”**[マニュアル](https://app.hubspot.com/documents/7375543/summary/3800002)**”の40～44ページまでをご覧になって、操作してみて頂ければと思います。

③アラート項目とアラート受信者の設定
SMTP、LINE、Webhook の設定を行った後に、アラート項目とアラート受信者の設定を行います。
![05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1509678/354a7510-82f8-d30a-9b56-7a3cc686ce8a.png)

④アラートセンター
Allxon DMSでは、アラートセンターに送信されたすべてのアラートの記録を残すことができます。
これにより、デバイスの健康状態やパフォーマンスの履歴に関する情報を維持することができます。
「アラートページ」の右上のボタン「アラートセンター」をクリックします。
アラートセンターでは、各アラートの記録を見ることができます。
技術的な問題が解決されたかどうかについての一覧が
「アラート状態」に「トリガー」、「既読」、「解決」として表示されます。
![06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1509678/40253deb-e42f-de92-e24f-7685fd4d515e.png)


#終わりに
いかがでしょうか！とても簡単で便利ですよね！
また、すでにAllxon DMSをダウンロードした方に是非こちらの”**[マニュアル](https://app.hubspot.com/documents/7375543/summary/3800002)**”をご覧になって、
操作してみて頂ければと思います。
さて、次回はスクリーンショット取得の詳細設定をご紹介します。お楽しみにしてください。
毎週火曜日に記事を更新致しますので、
ご意見または感想がございましたら、ぜひコメント欄に書いて頂けると嬉しいです！
cloudflare + caddy v2で SSL mode full (strict) をする方法

# これをしたい

![SSL_TLS___mardigrasbeadsfactory_com___Account___Cloudflare_-_Web_Performance___Security.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/9034b8e8-1831-7aea-9c02-9d530ab18816.png)


## flexible（サイトに来る人 - SSL - cloudflare - plain - 自サーバー）

これだけでもまー良さそうではある。が、一応cloudflare自身もオススメしていないので、full (strict)に設定したい。

https://support.cloudflare.com/hc/en-us/articles/200170416-What-do-the-SSL-options-mean-

![Cursor_and_End-to-end_HTTPS_with_Cloudflare_-_Part_3__SSL_options_–_Cloudflare_Help_Center.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/b3883860-f411-e7ce-bfb0-706471647007.png)



> as a last resort （最終手段）

# それぞれの違い

![cf_ssl_settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/79d2eb57-7cf6-ee70-1eb9-0575f69e9edf.png)

- off 言うまでもなく何も防御なし
- flexible 見る人からcloudflareまではSSL
- full cloudflareから自サーバーまでもSSL（self-certificate）
- full(strict) cloudflareから自サーバーまでもSSL（certificateはcloudflareから）

# Caddyを使ってる

caddyは最初からlet's encryptでcertificateを用意してくれるので...cloudfareがドメイン管理してて、そっちでlet's encrypt使ってくれてるから、？？？
となる。

# 多分一番簡単なやり方

1. まず、間違いなく80と443ポートはファイヤーウォールから外れていることを確認
1. caddyはv2だ
1. cloudflareの自ドメインで、SSL/TLS→origin server→create certificateと行く
     ![SSL_TLS___mardigrasbeadsfactory_com___Account___Cloudflare_-_Web_Performance___Security-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/5da3df72-b31a-9cd8-9fe5-6673c3e28656.png)
1. 何もせずにcreateすれば15年持つcertificateが作れる
     ![SSL_TLS___mardigrasbeadsfactory_com___Account___Cloudflare_-_Web_Performance___Security-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/c8c49a6f-e2bf-d94b-9ebd-de953d6539c9.png)

1. 出てきたcertificateとprivate keyを各ファイルにする
    `/etc/ssl/certs/certificate.pem`
    `/etc/ssl/private/key.pem`
     ![SSL_TLS___mardigrasbeadsfactory_com___Account___Cloudflare_-_Web_Performance___Security-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/667b4640-ea2b-467f-b2f3-d371dfdf4cca.png)

1. Caddyfileを書き換える
1. `caddy run`する
1. cloudflareのSSL modeを`full (strict)`に切り替える（多分10秒ぐらいは待ったほうが良い）


# Caddyfileを書き換え

```
example.com {
  tls /etc/ssl/certs/certificate.pem /etc/ssl/private/key.pem
  respond "Hello, world!"
}
```

## 参考：

https://sammckenzie.be/en/blog/using-caddy-with-cloudflare/#using-cloudflares-origin-certificate
AWS LambdaでS3からHTMLファイルを取得して返す

色々と応用できそうなので残しておきます。

##環境

Python3.7
API Gateway プロキシ統合あり

##処理

``` Python3
import boto3
import os

# バケット名は環境変数から取得
BUCKET_NAME = os.environ['BUCKET_NAME']
s3 = boto3.resource('s3')
filepath = '/tmp/hogehoge.html'

def main(event, context):
    
    bucket = s3.Bucket(BUCKET_NAME)
    bucket.download_file('hogehoge.html', filepath)
    
    with open(filepath , encoding='utf-8') as f:
        html = f.read()
    
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "text/html"},
        "body": html
    }
```
[Ruby] 正規表現matchメソッドの応用②

##はじめに
前回の続き、matchメソッドの応用です。今回はメールアドレスのドメインの部分（＠以下）だけを抽出してみます。


##ドメイン部分を抽出する
何はともあれ、まずは例をみてみましょう。

```irb:ターミナル
irb(main):001:0> mail = 'hoge@tech-camp.com'
=> "hoge@tech-camp.com"

irb(main):002:0> mail.match(/@.+/)
=> #<MatchData "@tech-camp.com">
```

MatchDataで＠以下が抽出できていますね。

**・.**
**・+**

↑この表現が今回のポイントです。

##.

この表現はハイフンやピリオドなども含めた英数字のどの一文字にもマッチします。
例です↓

```irb:ターミナル
irb(main):001:0> 'hoge'.match(/./)
=> #<MatchData "h">
```

##+
これは直前の文字が一回以上繰り返すものにマッチします。
例です↓

```irb:ターミナル
irb(main):001:0> 'aaabb'.match(/a+/)
=> #<MatchData "aaa">
```

はじめの例を見てみましょう。

mail.match(/@.+/) となっていますね。
先ほどの.に+を組み合わせることでハイフンやピリオドを含んだ英数字の文字列を抽出しています。
つまりmatch(/@.+/)は「＠から始まる文字列でないと登録を認めない」という処理に応用ができます。

##最後に
基本的にユーザー登録のメールアドレス登録のバリデーションはdeviseが行ってくれるのであまり使う機会が少ないと思いますが、これらの使い方や、考え方というのはしっかり身につけておきたいです。
PythonでYahooファイナンスから株価データを取得してグラフ化する

# こんな感じになりました。

自然言語処理の新技術をリリースし、最近株価が爆上げ中の FRONTEO（マザーズ、証券コード：2158）の株価の折れ線グラフがこちらになります。
![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667942/3200a50b-00a2-9520-c993-27b46013faca.png)

5 分刻みのデータを 30 日分プロットしています。

赤実線が始値、青実線が終値、オレンジ点線が最高値、緑点線が最安値です。

たまに値がジャンプしたり途切れたりしているのは、Yahoo から取得したデータに欠損があるからです。非サポートの無料データなので、仕方ないですね。

# ソースコード

Github：https://github.com/hajime-f/yfinance

- Stock.py
- yfinance.py
- requirements.txt
- Makefile

の 4 つのファイルを下記のとおりに準備してコマンドを打つと、グラフが出力されます。

グラフを出力したい企業を変更する場合は、```code``` 変数に当該企業の証券コードを入れてください。

```python:Stock.py
import matplotlib.pyplot as plt
from datetime import datetime as dt
from yahoo_finance_api2 import share
from yahoo_finance_api2.exceptions import YahooFinanceError

class Stock:

    def __init__(self, code, p_day, p_minute):

        self.code = code
        self.p_day = p_day
        self.p_minute = p_minute

    # 銘柄コード code の株価データを取得する
    def fetch_stock_data(self):

        company_code = str(self.code) + '.T'
        my_share = share.Share(company_code)
        stock_data = None
        
        try:
            stock_data = my_share.get_historical(share.PERIOD_TYPE_DAY,
                                                 self.p_day,
                                                 share.FREQUENCY_TYPE_MINUTE,
                                                 self.p_minute)
        except YahooFinanceError as e:
            print(e.message)
            exit()
        
        return stock_data

    # リストに格納された int 型のミリ秒を datetime 型に変換する
    def convert_to_datetime_list(self, millisecond_list):

        return [dt.utcfromtimestamp(m / 1000) for m in millisecond_list]

    # 株価の折れ線グラフを描く
    def show_graph(self, stock_data):
        
        x_axis = self.convert_to_datetime_list(stock_data['timestamp'])
        y1_axis = stock_data['open']
        y2_axis = stock_data['high']
        y3_axis = stock_data['low']
        y4_axis = stock_data['close']

        plt.plot(x_axis, y1_axis, linestyle="solid")
        plt.plot(x_axis, y2_axis, linestyle="dashed")
        plt.plot(x_axis, y3_axis, linestyle="dashed")
        plt.plot(x_axis, y4_axis, linestyle="solid")

        plt.show()
```



```python:yfinance.py
from Stock import Stock

if __name__ == '__main__':
    
    code = 2158   # FRONTEO（証券コード：2158）
    p_day = 30    # 30 日分
    p_minute = 5  # 5 分刻み

    stock = Stock(code, p_day, p_minute)
    
    stock_data = stock.fetch_stock_data()
    
    stock.show_graph(stock_data)
```


```:requirements.txt
yahoo_finance_api2
matplotlib
```


```makefile:Makefile
all:
	python3 yfinance.py
install:
	python3 -m pip install -r requirements.txt
```


```bash:実行するコマンド
$ make install  # パッケージのインストール
$ make          # yfinance.py の実行
```

# Yahoo ファイナンスのデータについて

```yahoo_finance_api2``` を使えば API を利用できはするのですが、このサービスはすでに終了しており、サポートされていないので、データが欠損していたり不正確だったりすることがあるようです。

そのため、これを使って株を自動売買したり、不労所得を狙ったりするのは厳しいかなと思いました。。（←ちょっと考えてた）
【Java発展学習5日目】非標準ライブラリの利用とOSSライセンス

# クラスパス(class path)の指定
`クラスパス`を指定する方法は、以下の3通り。

> 1. 環境変数`CLASSPATH`に定義
> 2. `javac`・`java`コマンドの`-cp`オプションで定義
> 3. 1.や2.でのクラスパス指定がない場合、`カレントディレクトリ`が`クラスパス`として認識

なお、通常の`クラスローディング`対象は`クラスファイル`**のみ**であり、`JARファイル`は**対象外**として扱われる。

`JARファイル`内の`クラスファイル`を`クラスローディング`対象とする場合、`JARファイル`を`クラスパス`に指定する必要がある。
ただし、その場合は`カレントディレクトリ`が`クラスローディング`の**対象外**となるため、複数ディレクトリを`クラスパス`として指定する必要がある。

## VSCodeにおけるクラスパス指定
`Visual Studio Code`では`プロジェクトディレクトリ`が固定の`クラスローディング`対象となっているため、
`.classpath`ファイルに`<classpathentry>`タグを記述して`クラスパス`を追加する。

```xml:.classpath
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="lib" path="lib/">
    <classpathentry kind="lib" path="lib/commons-lang3-3.12.0.jar">
</classpath>
```

***

# ログ出力ライブラリ
[参考: ログ設計指針](https://qiita.com/nanasess/items/350e59b29cceb2f122b3)
一般的によく利用される`ログ出力ライブラリ`は、以下の通り。

|ライブラリ|内容|
|:--|:--|
|`java.util.logging`|`Java標準API`で用意された`ロギングライブラリ`|
|`Log4j`|`ASF(Apacheソフトウェア財団)`が開発した`ロギングライブラリ`|
|`Logback`|`Logbackプロジェクト`で開発された`ロギングライブラリ`|
|`commons-logging`|`ASF`が開発した`ログファサードライブラリ`|
|`SLF4J`|`QOS.ch`が開発した`ログファサードライブラリ`|

`ログ出力ライブラリ`で一般的に用いられるログレベルは、以下の通り。

|ログレベル|内容|
|:--|:--|
|`FATAL`|致命的なエラー|
|`ERROR`|エラー|
|`WARN`|警告|
|`INFO`|情報|
|`DEBUG`|デバッグ情報|
|`TRACE`|詳細情報|

***

# OSSライセンス
[参考: OSSライセンスの基礎知識](https://www.hibiyapark.net/app/wp-content/uploads/2018/05/c484e7e1251d2ed577a08fc47179d1e4.pdf)
`OSS(Open Source Software)`の多くが採用する`OSSライセンス`の種類は、以下の通り。

|厳格さ|カテゴリ|ライセンス|内容|
|:--:|:--|:--|:--|
|緩|パブリックドメイン<br>(public domain)|`Public Domain`|ソフトウェアの`著作権`を**放棄**|
|↑|非コピーレフト型<br>(non-copyleft)|`BSD`, `MIT`, `Apache`|`OSS`の`著作権表示`を義務化|
|↓|準コピーレフト型<br>(weak copyleft)|`LGPL`,`MPL`|**直接的**に利用した部分の`ソースコード開示`を義務化|
|厳|コピーレフト型<br>(strong copyleft)|`GPL`, `AGPL`|**間接的**に利用した部分の`ソースコード開示`も義務化|

## CC(Creative Commons)ライセンス
複数の`ライセンス規定`を組み合わせたライセンス。
以下の4つの`ライセンス要素`で構成される。

|要素|内容|
|:--|:--|
|`BY(Attribution)`|原作者の表記義務|
|`SA(Share-Alike)`|二次的著作物もライセンスを継承|
|`ND(NoDerivatives)`|改変禁止|
|`NC(Non-Commercial)`|商用禁止|

***

# 用語集

|用語|内容|
|:--|:--|
|ライブラリ(library)|複数の`クラスファイル`の集合。|
|バイナリモジュール(binary module)|`コンパイル`済みの`クラスファイル`。|
|JAR(Java Archive)|複数の`クラスファイル`を1つのファイルとして`圧縮(アーカイブ)`する形式。|
|クラスパス(class path)|`JVM`による`クラスローディング`**対象**となるパス情報。|
|ログファサード(log facade)|`ロギングシステム`の**切り替え**を行うフロントエンドシステム。|
|プロプライエタリ(proprietary)|`オープンソース`の対義語であり、「商用」と定義づけられる。|
|デュアルライセンス(dual lisence)|利用者が選択可能な`ライセンス`。`GPL・商用ライセンス`の組み合わせが一般的。|
|コピーレフト(copyleft)|`著作権(copyright)`とは対照的に、`二次的著作物`を許容する考え方。|
[tcl]autoproxyを利用したhttps通信

- tclを用いたprotocol処理の必要性が生じたため、方法を調査。
- 単純なhttp通信の際には**http**パッケージが存在するため便利だが、basic認証やhttps通信となると諸々の処理が必要となってくる。
- そのため今回は**autoproxy**パッケージを利用した方法を記録する。

## 環境
- Mac OS X 10.15.6
- Tcl 8.6
- tls
- tcllib

## 結果
- 簡単なhttps通信の例として、Qiitaの記事からタイトルと画像URLを取得してくる処理を記述する。
- 結果は以下。

```tcl:main.tcl
#!/usr/bin/tclsh
package require autoproxy
package require tls

# 引数なしエラー
if {$argc == 0} {puts stderr "no arg"; exit 1}

# 対象URL
set target [lindex $argv 0]

# 記事情報取得
proc detail_article {url} {
	if {$url == ""} {puts stderr "no url"; exit 1}

	# handler登録
	::autoproxy::init
	::http::register https 443 ::autoproxy::tls_socket

	# data取得
	set token [::http::geturl "$url.md"]
	set data [::http::data $token]
	::http::cleanup $token

	# title取得
	regexp -line {title: (.+)} $data -> title

	# 画像URL取得
	set image_matches [regexp -all -inline -line {!\[.+\]\((.+)\)} $data]
	set image_list [lsearch -all -inline -not $image_matches "!*"]

	# 結果
	puts "title $title"
	set i 0
	foreach {im} $image_list {
		incr i
		puts "image$i $im"
	}

}

detail_article $target
```

- 実行結果は以下。

```bash
$ ./main.tcl https://qiita.com/t_o_d/items/11f83e92ec9413eca127

title [Docker]Alpineでの容量可視化ツール「duf」の導入
image1 https://user-images.githubusercontent.com/44114228/105147795-01713700-5b45-11eb-8b31-dec0a03d4590.png
image2 https://user-images.githubusercontent.com/44114228/105148364-a2f88880-5b45-11eb-860f-98c16743a0c6.png
image3 https://user-images.githubusercontent.com/44114228/105148682-02569880-5b46-11eb-9f3a-d396d2981bf8.png
image4 https://user-images.githubusercontent.com/44114228/105148923-48136100-5b46-11eb-9c85-93657ee67f9e.png
```

## 補足

### handler登録
- https通信を利用する際には、httpパッケージの**register**関数を利用してプロトコルとソケットハンドラーを登録する必要がある。
- その際に以下の点に注意。
    - **autoproxyパッケージを利用する際には、`package http`の記述は不要。**
    - **`autoproxy::init`**でのプロキシパッケージの初期化を忘れない。
- **※ソケットのセキュリティ設定を変更する際には、`tls::init -tls1 1`のように追記。**

## 参考
- https://core.tcl-lang.org/tcltls/wiki/Documentation
- https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/http/autoproxy.md
Docker の Alpine で Bottle を使う

こちらと同様のことを行いました。
[AlpineでBottleを使う](http://kyamawork.info/post/0012/)

イメージの作成

```bash
docker run -dit -p 49153:3000 --name bottle_app alpine
```

Alpine に接続

```bash
docker exec -it bottle_app ash
```

```text
$ docker exec -it bottle_app ash
/ # 
```

必要なソフトのインストール

```text
/ # apk add python3 py3-pip tree
/ # pip3 install bottle
/ # mkdir /home/bottle
/ # cd /home/bottle
/home/bottle # 
```

次の２つのファイルを作成します。

```text
/home/bottle # tree
.
├── server.py
└── views
    └── sample.html
```

```py:server.py
from bottle import route, run, template
import random

@route('/')
def index():
	images = [
		"fmervo000001gsle.jpg",
		"rn2ola000000lk6e.jpg",
		"rn2ola000001gogf.jpg",
		"6fujishigai_s_s.jpg",
		"rn2ola000000lk6r.jpg",
		"5fujikawarakuza_s_s.jpg"
		]

	url_base = "https://www.city.fuji.shizuoka.jp/page/gazou/fmervo000001dsro-img/"
	url = url_base + random.choice(images)

	return template('sample', url=url)
#
run(host="0.0.0.0", port=3000, debug=True)
```

```html:views/sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<title>富士山</title>
</head>
<body>
<div class="container">
<p>富士山 航空写真</p>
<blockquote>
<img src="{{url}}" />
</blockquote>
<p>Courtesy: <a href="https://www.city.fuji.shizuoka.jp/page/gazou/fmervo000001dsro.html">富士市</a></p>
</div>
Jul/05/2021<br />
</body>
</html>
```

次のようにホストからコピーすることもできます。
CONTAINER ID は変更して下さい。

```bash
docker cp server.py 01dd1f42040a:/home/bottle
docker cp views 01dd1f42040a:/home/bottle/
```

CONTAINER ID の調べ方

```text
$ docker ps -a
CONTAINER ID   IMAGE     COMMAND     CREATED          STATUS          PORTS                                         NAMES
bbe3d679a9c4   alpine    "/bin/sh"   34 minutes ago   Up 34 minutes   0.0.0.0:49153->3000/tcp, :::49153->3000/tcp   bottle_app
```

サーバーの起動

```text
# python3 server.py 
Bottle v0.12.19 server starting up (using WSGIRefServer())...
Listening on http://0.0.0.0:3000/
Hit Ctrl-C to quit.
```

クライアントで
http://localhost:49153/
にアクセス

![bottle_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6c1e1ac4-eb71-b8d7-0841-3b4545a54fb3.png)
ポートフォリオサイトにゲストログイン機能の実装

ポートフォリオサイト制作時に、評価者の方が名前やパスワード、メールアドレスの登録などがめんどくさいだろうなと思い、ゲストログイン機能を実装しました。
（実際に新規登録が煩雑であれば、見られないこともあるそうです）

当記事はこちらを参考にしています。（めちゃくちゃわかりやすかったです）
[簡単ログイン・ゲストログイン機能の実装方法（ポートフォリオ用）](https://qiita.com/take18k_tech/items/35f9b5883f5be4c6e104)

#開発環境

> ruby 2.6.3
> Rails 5.2.6

#前提

deviseを使ったログイン機能が実装できている

モデル名、変数名等は適宜、ご自身の開発環境に変換してお考えください。

#ルーティング

ますはルーティングからです。
sessionsコントローラーのguest_sign_inアクションにpostでルーティングを設定します。

```config/routes.rb
:
# ゲストログイン用追加
  devise_scope :user do
    post 'users/guest_sign_in', to: 'users/sessions#guest_sign_in'
  end
:
```

# モデル

userモデルでゲストログインに使うようのメソッドを定義します。

ここでのポイントはfind_byではなく、`find_or_create_by!`を使っているところです。
一致するユーザーを探すか作るかしてくれるので、あらかじめゲストユーザーを作っておく必要もなければ、削除された場合でも問題なくログインができます。

```models/user.rb
# ゲストログイン用追加
  def self.guest
    find_or_create_by!(email: 'guest@example.com') do |user|
      user.name = "ゲスト"
      user.password = SecureRandom.urlsafe_base64  #パスワードはランダム
    end
  end
```

# コントローラー

モデルで定義した`guest`を使って`users/sessions_controller.rb`に処理を書いていきます。

sessions_controller.rbがない場合はdeviseコマンドでコントローラーを作ります。
controllers直下のusersフォルダが作られ、その中にsessions_controller.rbができます。

```
$rails g devise:controllers users
```

処理としてはコードを見れば理解できると思います。

```controllers/users/sessions_controller.rb
# ゲストログイン用追加
  def guest_sign_in
    # userにguestを代入
    user = User.guest
    # userでサインイン
    sign_in user
    # サインイン後の遷移先を指定
    redirect_to root_path, notice: 'ゲストユーザーとしてログインしました。'
  end
```

# ビュー

最後にビューにゲストログインボタンを設置します。

```erb:views/devise/sessions/new.html.erb
:
<%= link_to 'ゲストログイン（閲覧用）', users_guest_sign_in_path, method: :post, class:'btn btn-outline-success' %>
```

# まとめ

今回は簡単なゲストログイン機能を実装しました。

流れとしては、
ビューのゲストログインボタンを押す
→sessionsコントローラーのguest_sign_inが呼び出される
→guest_sign_in内でuserモデルのguestを呼び出す
→その後ログインし、リダイレクトする

こんな感じです。

ぼくはユーザーの削除機能もつけていないし、ゲストユーザーの情報を編集されてもよかったので、だいぶ省略して記事にしています。
もっと詳しく知りたい方は、ぼくが参考にした記事をご覧ください。

ぼくの[ポートフォリオサイト](https://oogiri-legendroad.com/)でも確認できるので、参考にしてみてください。
NiFi uuid関数は存在しない、UUIDを使うべき

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133516/5e4525cd-cc50-e428-677d-75b90c415840.png)


uuid()を使った時、上記エラーがあった。

UUID()にしたら治った
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133516/748e6ab2-5f3e-2e2a-93f8-bee2c66a239e.png)
AWSストレージサービスのそれぞれの特徴

#はじめに
AWSには様々なストレージサービスがあります。
一番よく聞くのは<b>S3</b>でしょう。他にも<b>EBS</b>や<b>EFS</b>などもストレージサービスに含まれます。
では、それらは一体なにが違うのでしょうか。

実はストレージ形式というのを意識すると、それぞれの違いのイメージが湧きやすいです。
ストレージ形式には大きく分けると<b>ブロックストレージ・ファイルストレージ・オブジェクトストレージ</b>の３種類があります。
それぞれのストレージ形式と、それらに相当するAWSストレージサービスについて特徴を書いていこうと思います。

#ブロックストレージとは（EBSに相当）
ブロックストレージは、物理マシンの記録領域をボリュームという単位で分割、さらにその内部を固定長のブロックに切り出して、そのブロックにデータを保存、管理するというストレージ形式です。
身近な例でいうとHDDやSSDなどがブロックストレージです。
我々がHDDやSSDを使っているなかでボリュームという単位を意識しなくていいのはファイルシステムのおかげです。
ブロックストレージを各OSに対応したファイルシステムにフォーマットすることで、我々は難しいことは考えずにファイルを保存したり呼び出したりできるわけです。
###EBS（Elastic Block Store）
AWSストレージサービスにおいてはと<b>EBS</b>がブロックストレージに当たります。

EBSはEC2インスタンスにアタッチ及びマウントして利用するストレージです。
EC2インスタンスのホストマシンとは別の外部マシンのリソースを使用しています。

EC2インスタンス作成の際、最低でも１つ以上のEBSをアタッチさせる必要があり、必ず１つはルートボリューム（ブートされる際に必要なOSが格納されているHDDまたはSSD）です。
後からEBSをアタッチした場合は<b>ファイルシステムをフォーマットしてマウントする</b>という作業が必要になります。
設定によってはインスタンス終了と同時に削除することも可能ですが、EBSだけを残すことも可能です。
また、インスタンスとEBSは同じAZに配置する必要があります。
さらに、１つのEBSに対して複数のインスタンスをアタッチすることはできません。

（インスタンスタイプによってはEBSではなくインスタンスストアというブロックストレージを選択することも可能です。インスタンスストアはEC2インスタンスのホストマシンに物理的にアタッチされたディスクをリソースとしています。また揮発性という特徴があり、インスタンスを停止・休止・終了した場合はデータは失われます。）</font>

https://aws.amazon.com/jp/ebs/?ebs-whats-new.sort-by=item.additionalFields.postDateTime&ebs-whats-new.sort-order=desc

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/InstanceStorage.html

#ファイルストレージとは（EFSに相当）
ファイルストレージにおいて、データは「フォルダ」や「ディレクトリ」といった形式で、階層的に管理、保存されます。階層的に保存されたデータには一意のパスを用いて、階層をたどっていく形でアクセスします。
ストレージにファイルシステムを組み込むことによって、ファイル単位でのデータの読み書きが可能になりました。

代表的な例はNFSサーバです。
NFS（Network File System）とは、その名の通りネットワーク越しにファイルにアクセスするための仕組みです。
NFSを使用すれば、ネットワークを介してファイルサーバー上のストレージ領域をローカルサーバーのハードディスクなどと同様に利用可能です。複数のサーバー間でのファイル共有が簡単に実現でき、複数のサーバーから共有しているファイルシステムに対して同時アクセスできるというメリットがあります。
###EFS（Elastic File System）
AWSにおいては<b>EFS</b>というサービスがあります。一言でいうと「<b>EFS=マネージドのNFSサーバ</b>」です。
VPC内に配置し、複数のAZまたはインスタンスへマウントすることが可能です。サーバ間でファイルを共有する場合に用いられることが多いです。

https://aws.amazon.com/jp/efs/

#オブジェクトストレージとは（S3に相当）
オブジェクトストレージはデータを「オブジェクト」という単位で扱う記憶装置です。

オブジェクトにはストレージシステムのなかで固有のID（URI）が付与され、データとそれを扱うためのメタデータによって構成されています。 メタデータは通常のファイルシステムでも作成日や作成者などの情報を持っていましたが、オブジェクトではデータの種類、保存期間やコピー回数など、より多くの情報を付加できます。

また、ディレクトリのような階層構造はなく、ストレージプールというオブジェクトの入れ物のみが作成され、メタデータによって管理されます。オブジェクト同士はフラットな関係で、データの移動で階層構造が変わることはありません。

###S3（Simple Storage Service）
AWSにおいてはS3が相当します。
ディレクトリ構造で管理するファイルストレージとは異なり、データサイズやデータ数の保存制限がないため、大容量データ（画像や動画ファイル）の保存に適しています。

S3の機能やオプションは非常にたくさんあり、ログファイルの保存から静的WEBサイトの公開などなど、様々な用途で使用されます。
気になる方はAWS公式サイトより調べてみてください。

https://aws.amazon.com/jp/s3/?nc=sn&loc=1


#さいごに
ここまでざっくりとまとめてみましたが、下記に記載した参考サイトでは図などを交えながらもっと詳しく説明されているので、気になった方はぜひ見てみてください！

#参考サイト
https://www.youtube.com/watch?v=TBjd2z62vCY

https://active.nikkeibp.co.jp/atclact/active/14/100700086/111700009/

https://www.fujitsu.com/jp/products/computing/storage/lib-f/tech/beginner/block/

https://www.fujitsu.com/jp/products/computing/storage/lib-f/tech/beginner/object-storage/

https://www.rworks.jp/system/system-column/sys-entry/21711/
Android Studio Arctic Foxで日本語が豆腐になる問題のwork around

※ Arctic Fox が Stable になりましたが修正されていませんでした…

Android Studio Arctic Fox (2020.3.1) Beta 5 時点で日本語が文字化けして豆腐になる問題があります。
IDE 側が修正されるとは思いますが、それまでの一時凌ぎになります。

Preference から Appearance & Behavior > Appearance で `Use custom font` を有効にすると(選択する Font が日本語に対応していれば)日本語も正しく表示されるようになります。

![スクリーンショット 2021-07-05 11.20.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/0e58da4a-baf2-a4ef-9d93-d2b006883fb0.png)


|Before|After|
|:--:|:--:|
| ![スクリーンショット 2021-07-05 11.32.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/25f83d5f-5445-e07f-93a7-fcfec640d357.png) | ![スクリーンショット 2021-07-05 11.29.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/4defff04-a541-9711-0240-b03b4a370958.png) |
マスタテーブルと非マスタテーブルをpandasで結合する

# pandasでマスタテーブルとマスタじゃないテーブル(トランザクション)をマージ(ジョイン)する
マスタテーブルとトランザクションテーブル(マスタではない記録保管用のテーブル)をジョインする方法が、案外わからなかったのでメモしておきます。
## 想定している状況
以下のように、商品のマスタテーブルdf_mと、その売上記録の一部df_tがあるとします。

```python
import pandas as pd

df_m = pd.DataFrame({'登録日': ['2021-05-10','2021-05-11','2021-05-30'],
                     '商品名': ['A', 'B', 'C'], 
                     '値段': ['1000', '1200', '1500'],
                     '発送元': ['倉庫A', '倉庫B', '倉庫C']})

df_t = pd.DataFrame({'登録日': ['2021-06-11','2021-06-09','2021-06-05','2021-06-02','2021-05-30','2021-05-30'],
                    '商品名': ['A', 'B', 'B','C', 'C', 'A'], 
                    '配送先': ['東京', '愛知', '兵庫','宮城', '大阪', '静岡']})

print(df_m)
#      登録日   商品名 値段  発送元
# 0  2021-05-10   A  1000  倉庫A
# 1  2021-05-11   B  1200  倉庫B
# 2  2021-05-30   C  1500  倉庫C

print(df_t)
#      登録日    商品名 配送先
# 0  2021-06-11   A   東京
# 1  2021-06-09   B   愛知
# 2  2021-06-05   B   兵庫
# 3  2021-06-02   C   宮城
# 4  2021-05-30   C   大阪
# 5  2021-05-30   A   静岡
```
"商品名"をキーに結合したい場合は、以下のように書きます。

```python
df_merge = pd.merge(df_t, df_m, on='商品名')
df_merge
```
出力：

|   | 登録日_x | 商品名 | 配送先 | 登録日_y | 値段 | 発送元 |
|::|:-:|:-:|:-:|:-:|:-:|:-:|
0|	2021-06-11|	A|	東京|	2021-05-10|	1000|	倉庫A|
1|	2021-05-30|	A|	静岡|	2021-05-10|	1000|	倉庫A|
2|	2021-06-09|	B|	愛知|	2021-05-11|	1200|	倉庫B|
3|	2021-06-05|	B|	兵庫|	2021-05-11|	1200|	倉庫B|
4|	2021-06-02|	C|	宮城|	2021-05-30|	1500|	倉庫C|
5|	2021-05-30|	C|	大阪|	2021-05-30|	1500|	倉庫C|

重複するキーが二つのテーブルにある場合、登録日_yというように列名が変わって複製されます。
同じ"登録日"という列名でも、今回のように意味の違う登録日である場合もあるため、pandasはデフォルトでは列名を変更して両列とも残してくれる仕様になっているのだと思います(たぶん)。
適宜、不要な列を削除したりリネームする等して対応します。

"how"オプションで、inner/outer/left/right ジョインの指定はできますが、マスタとトランザクションの結合であれば、デフォルトのinner joinで大丈夫です。

↓のように、on オプションを書き忘れると、df_tとdf_mに共通する列 ('登録日'と'商品名')両方が一致する行しか生き残らなくなるので注意。

```python
df_merge = pd.merge(df_t, df_m)
df_merge
# on で結合キーを指定しないと、df_tとdf_mに共通する列 ('登録日'と'商品名')両方が一致する行しかマージされない。
```
|登録日|	商品名|	配送先|	値段|	発送元|
|::|:-:|:-:|:-:|:-:|:-:|
|2021-05-30|C|大阪|1500|倉庫C|

##ちなみに
ここで、↓のように、マスターテーブルなのに重複のある、マスターテーブルもどきを誤って作ってしまったとします。

```python
df_dup_m = pd.DataFrame({'登録日': ['2021-05-10','2021-05-11','2021-05-15','2021-05-30'],
                         '商品名': ['A','A', 'B', 'C'], 
                         '値段': ['1000','2000', '1200', '1500'],
                         '発送元': ['倉庫A1','倉庫A2', '倉庫B', '倉庫C']})
```

これを以下のようにトランザクションと結合すると..

```python
df_t_merge = pd.merge(df_t, df_dup_m, on='商品名')
df_t_merge
#マスターテーブルに誤りがあり、商品名に重複がある場合(商品A)、重複した商品はマスターテーブルの格納順に列が付け足される。
```

	|登録日_x|	商品名|	配送先|	登録日_y|	値段|	発送元
|::|:-:|:-:|:-:|:-:|:-:|:-:|
0	|2021-06-11|	A|	東京|	2021-05-10|	1000|	倉庫A1
1	|2021-06-11|	A|	東京|	2021-05-11|	2000|	倉庫A2
2	|2021-05-30|	A|	静岡|	2021-05-10|	1000|	倉庫A1
3	|2021-05-30|	A|	静岡|	2021-05-11|	2000|	倉庫A2
4	|2021-06-09|	B|	愛知|	2021-05-15|	1200|	倉庫B
5	|2021-06-05|	B|	兵庫|	2021-05-15|	1200|	倉庫B
6	|2021-06-02|	C|	宮城|	2021-05-30|	1500|	倉庫C
7	|2021-05-30|	C|	大阪|	2021-05-30|	1500|	倉庫C

商品Aかつ配送先が東京の行と、
商品Aかつ配送先が静岡の行が、それぞれ2行に増えています。
また、それぞれの発送元が
「倉庫A1」→「倉庫A2」→「倉庫A1」→「倉庫A2」..というように、マスターテーブルの格納順になっています。
これをあえて応用すると、いろいろ便利かもしれません。
export default とexport constの違い

# はじめに
それぞれ以下の export になります。
・export default　→ **default export**
・export const 　→ **named export**

exportの書き方によって、import時の記載が変わってきます。
少し気になったので調べてみました。

# 書き方(export)
それぞれ以下のようなコードになります。（本記事はReactで記載します。）


## default export 

```Javascript:Test1Component.js
import React from "react";

const Test1Component = () => {
  return <div>Test1Component</div>;
};

export default Test1Component;
```

## named export
```Javascript:Test2Component.js
import React from "react";

export const Test2Component = () => {
  return <div>Test2Component</div>;
};
```


# 書き方(import)
import時には、{}がつくかつかないかの違いがあります。



## default export 

```Javascript:App.js
import Test1Component from "./components/Test1Component";
```

## named export
```Javascript:App.js
import { Test2Component } from "./components/Test2Component";
```

# 結論
default exportは、勝手に「default」という名前を付けてくれるnamed exportになるそう。
( default は予約後)
[JavaScript: Default Exportは、値を「default」という名前でNamed Exportしている](https://qiita.com/suin/items/b585ad68beec78099ee5)
[ES2015 (ES6) の import や export (default)（React基礎講座4）](https://qiita.com/ryosuketter/items/9588493b633069e06777)


__とりあえず以下を覚えておけば良さそう。__

* export default したものを import するときには {} を使わない
* 1 ファイル内で、1 export defaultのみ(通常は export は複数使用できる)
* なので、1ファイル1コンポーネントであれば、 export default を使う方がいい
githubでpull requestをmergeした際の作業メモ

# 目的

githubでpull requestをmergeした際の個人的作業メモ

# タスクリスト

- github上でmerge requestボタンで全commitをmergeするcommit作成
- この際にpushもされるのでmerge先にもうコードがある状態になる
- ローカルでは変更されていないがcheckoutでmerge先に切り替えると`Your branch is up to date with 'origin/main'.`とでる
    - これは最新のとずれているよという意味
- `git pull origin main`
- これで完了
email template マージフィールドのまとめ

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


+ [Lightning templateでIFを使う](https://qiita.com/Keiji_otsubo/items/4571b19004f5514c356c)

# PBの場合  {{{--}}} format のマージフィールドが機能しない

どうもPBから使う場合には機能しないようなことが報告されています。

:::note
Fawcett Jane
Hello I have had the exact same issue,  Lightning email templates work for using send list emails or individual email using the merge fields.  However if you want to use merge fields in a template via a process builder for example switch to a classic template unfortunately.

[Lightning Email Template Error for Process Email Alert: We don't recognize field prefix Recipient](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000A8taW)


こんにちは、まったく同じ問題が発生しました。Lightning メールテンプレートは、差し込み項目を使用して送信リストメールまたは個別のメールを使用する場合に機能します。ただし、たとえばプロセス ビルダーを介してテンプレートで差し込みフィールドを使用したい場合は、残念ながらクラシック テンプレートに切り替えてください
:::

#  {{{Recipient.FirstName}}}が機能しない

+ [The mobile survey sending functionality is active?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007YwGqr)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3c10e427-64eb-4772-11fa-d7d9cc048ad4.png)

:::note
Try using the following.
 
```
{{{Contact.FirstName}}}
``` 

https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000GeNIV
:::
MacでHHKBにBluetooth接続できないとき

## 背景
MacでHHKBにBluetooth接続できないとき、最終手段としてペアリング情報を全削除して再ペアリングを行うことで接続可能になります。
※下記内容はPFU公式HPにも記載があります。毎回忘れるので備忘録として記事を作成しました。

参考：[Bluetooth接続不具合の対処方法はありますか？](https://faq.pfu.jp/faq/show/3528?category_id=181&site_domain=hhkb)

##環境
PC: MacBook Pro 2020
OS: macOS Catalina (10.15.5)
HHKB: Professional HYBRID Type-S 英語配列（PD-KB800BS）

## 方法
1. HHKBの電源を入れる（青色のLEDランプが点灯する）。
1. 「Fn」キーを押しながら「Q」キーを押す(青色のLEDランプが点滅する）。
1. その状態でさらに「Fn」キーを押しながら「Z」キーを押し、日本語配列の場合は「BS」キーを、英語配列の場合は 「Delete」キー（英語配列でDIPスイッチのSW2あるいはSW3をONにしている場合は「`（~）」キー）を押す（橙色のLEDが点灯し、しばらくして消灯する）。
1. システム環境設定→BluetoothからHHKBを接続する。
【Docker】Cannot connect to Docker Deamon が出た時　　no.28

Cannot connect to Docker Deamonが出た時

色々試した結果、私の環境では以下のコマンドを使ってエラーを解決することができた(Windows10利用)

```
sudo dockerd
```

参考：
[stackoverflow](https://stackoverflow.com/questions/44678725/cannot-connect-to-the-docker-daemon-at-unix-var-run-docker-sock-is-the-docker)
Node.jsをバージョンアップしたのに「node -v」で前のバージョンが表示される時（Mac）


#Node.jsをバージョンアップしたのに反映されない？

https://qiita.com/Hide-Zaemon/items/cbb4497237843a729994

👆の記事を参考に、Node.jsのバージョンアップを試みた！！
Node.jsの推奨版を[こちら](https://nodejs.org/ja/)から確認して、参考にした記事の通り、コマンドを実行していく。

```terminal
$ brew update
// しばらく時間かかっても、気長に待つ、、、、

$ brew upgrade nodebrew

$ nodebrew ls-remote
// バージョンがずらりと並びます。

$ nodebrew install-binary v14.17.2
// 私が確認した時の推奨版はv14.17.2でした。

$ nodebrew list
// 利用可能なバージョンをリスト表示し、使用するバージョンを指定します。
 v10.16.0
 v14.17.2

$ nodebrew use v14.17.2

$ nodebrew ls
 v14.17.2

 current: v14.17.2
```

はい、ここまでは問題なく進みました。

**問題はこの次。。。**

```terminal
$ node -v
  v10.16.0
```

**え、、何で「v14.17.2」じゃないの？？？！！**
前のバージョンのままやん。。

#環境パスを通すといけた

https://tarovlog.com/2021/01/16/update-node-js/

👆の記事を参考に、下記のコマンドを実行。

```console
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zprofile
$ source ~/.zprofile
```

よくわかりませんが、これでバージョンアップができました:sweat_smile:

```terminal
$ node -v
  v14.17.2
```
liff.init()時のセキュリティ改善について


# 導入
LINE上でアプリを開発する際に、LIFFを使用している方が多いのではないでしょうか。
LINE上のユーザー情報などを取得する際には、liff.init()を実行するのですが、今まではアクセストークンなどの機密情報が含まれた状態のURLでしたが、今回のアップデートでliff.init()後に一時リダイレクト先URLから機密情報が除外されるように変更されました。
詳細については以下をご覧ください。

# LIFF v2.11.0アップデートについて
## liff.init()後に一次リダイレクト先URLから機密情報が除外されるようになりました

>セキュリティ上の観点から、liff.init()がresolveされたタイミングで、一次リダイレクト先URLからアクセストークンなどの機密情報を含むURLフラグメントが除外されるようになりました。そのため、メソッドチェーンのthen()メソッド内の処理では、機密情報を含まない一次リダイレクト先URLが現在のURLとして扱われます。

つまり、どういうことかというと

```Javascript
// ① URL上にアクセストークンなどの機密情報が含まれる
console.log(window.location.href);
// https://example.com/?liff.state=path#access_token=xxx&context_token=xxx&feature_token=xxx&id_token=xxx&client_id=xxx

liff.init({
	liffId: myLiffId
}).then(() => {
//	② URL上に機密情報が除外される
	console.log(window.location.href);
	// https://example.com/?liff.state=path
});
```

①のタイミングでURLを取得した場合、URL上にアクセストークンなどの機密情報が含まれ、セキュリティ上好ましくない状態です。

一方②は、liff.init()がresolveされたタイミング、つまり非同期処理の結果が成功（resolve）で返された際に、then()を使用したメソッドチェーンでの処理内ではURL上に機密情報が除外されるようアップデートされました。

## liff.init()について
LIFFアプリを作成するにあたり、必ず使用するのがこのメソッドです。

LIFFアプリを初期化することで、LIFF SDKの他のメソッドを実行できるようになります。

ちなみに、LIFFブラウザの場合、liff.init()実行時に自動でログイン処理が実行されますが、外部ブラウザ及びLINE内ブラウザの場合、liff.login()メソッドを実行して、ログイン処理を行う必要があります。

### リクエストの例

```Javascript
// Promiseオブジェクトを使用する方法
liff.init({
	liffId: myLiffId
}).then(() => {
	// ここからLIFF SDKを使用可能
}).catch((err) => {
	// エラー時の処理
});

// コールバックを使用する方法
liff.init({ liffId: myLiffId }, Callback, errCallback);
```

## liff.init()を実行した際の処理フロー

![liff.init().png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1457643/a8b40b7d-54f6-fc83-bb2f-beffb02719c1.png)

1次リダイレクト先URLは、ユーザーがLIFF URLにアクセスしたときに、LIFFサーバーから初めてリダイレクトされる先のURLです。ここにリダイレクトされた時に、liff.init()メソッドを実行します。

2次リダイレクト先URLは、liff.init()メソッドが実行された時に、ユーザーがリダイレクトされる先のURlです。ここにリダイレクトされたら、LIFFアプリのページを表示します。

こういったフローでLIFFアプリが起動されます。

## まとめ
v2.11.0のアップデートにより、liff.init()時のURLに機密情報が除外されるようになりました。それにより、セキュリティ上より安全に使用できるようになっています。ただし、liff.init()後のメソッドチェーン内での処理でなければいけないのは注意が必要です。

## 宣伝
パーソルプロセス＆テクノロジー株式会社（以下パーソルP&T）、システムソリューション（SSOL）事業部所属の髙井です。

私はモビリティソリューションデザインチームに所属しており、モビリティ（ここでは移動手段全般）に関するサービスを考えたり、アプリを構築したりしております。

いわゆる「MaaS」に取り組んでおります。

私たちが「MaaS」に取り組む中で、現在活用している、もしくは活用する予定の技術やサービスやとりあえず発信したいことなどなど、幅広くチームメンバーと共に執筆していきたいと思います。
メンバーごとに違った内容を発信していきますので、お楽しみに！

また、「MaaS」について詳しく知りたい方は、チームメンバーの吉田が記事を掲載しておりますので、
ぜひそちらをご覧ください。

「MaaSとは」でたどり着いて欲しい記事　（1/3 前編）
「MaaSとは」でたどり着いて欲しい記事　（2/3 中編）
「MaaSとは」でたどり着いて欲しい記事　（3/3 後編）

最後まで読んでいただき、ありがとうございました！
Macへのインストールの問題

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)

# データローダ

+ [Mac Os Big Sur ではデータローダが動かないようです 2020/11/19時点](https://qiita.com/Keiji_otsubo/items/a3bbecdafca2b66bac1d)
+ [Data Loader Mac Big Sur インストールエラー（再燃かな）](https://qiita.com/Keiji_otsubo/items/3b473642a3af8aa118eb)
+ [Can't download Data Loader on Mac M1](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V000077B5eC)
+ [macOSでローマ数字が入ったレポートをエクスポートすると文字化けする](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007akb4M)




# 【CLI】 Bad CPU type in executable

+ [I am getting an error "Bad CPU type in executable" on line 44 in node when installing CLI on my MacBook Pro with M1 Pro chip running Monterey version 12.3.1.](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000GgaAs)

+ [Install Cloud Foundry CLI in a M1 chip MacBook](https://stackoverflow.com/questions/72112287/install-cloud-foundry-cli-in-a-m1-chip-macbook)

With the release of v8.4.0 a few days ago the support for ARM based mac OS machines (e.g. M1) was added:

https://github.com/cloudfoundry/homebrew-tap/commit/69f268f18ea10a4c8e19c99a8bb209c1ebbcbe7d

It will still fail if you only tap it and leave out the version in your install command, so you'll need to enter:

```
brew install cloudfoundry/tap/cf-cli@8
```

+ [Bad CPU type in executable](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007A534v)

:::note
I've ended up re-installing the CLI using brew and that worked!
:::




# Node? version is 10.13.6 Symbol not found: ____chkstk_darwin

my mac version is 10.13.6
node version v16.17.0

+ [set up your salesforce dx environment](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000MhbKS)

+ [CLI for MacOS 10.13 ?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PeKCGSA3)

:::note
Please check this article.

https://stackoverflow.com/questions/74405288/command-line-tool-it-always-crashes-dyld-lazy-symbol-binding-failed-symbol-no
:::

+ [Facing an issue while installing salesforce CLI in Mac](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Yw5iD)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/79eeb26f-f39b-4273-0556-51079db00dac.png)

:::note
Please check, 

https://github.com/npm/cli/issues/672
https://stackoverflow.com/questions/46541371/npm-err-refusing-to-delete-code-eexist
:::


# LWC MacBook Pro running MacOS Sonoma 14.1.2 

+ [Command 'SFDX: Authorize an Og' resulted in an error - What's happening?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007TuIMA)

:::note alert
Command 'SFDX: Authorize an Og' resulted in an error
CLI Command process failed to start
:::
比較文でtrueやfalseと比べることにNGを出す理由

boolean literalとの比較 (`== false`)、私は通常NGとします（jsみたいな特殊な言語を除く）。

C言語時代はバグの温床、昨今の言語でも冗長表記として忌避されます(lint設定として用意されているのを目にします)。
冗長であることの問題は、結局のところひとつ余分な思考ステップが追加されるのでコードリーディングを少し遅くさせること、１ステップ分が不具合を生みやすくすること、と考えます。

__余分な思考ステップ__

言語を読み慣れてコードを英語的に読めるようになってくると、という前提付きですが、
boolean literalを使わない場合、「（比較の）対象が真の状態か、偽の状態か（または是か非か）」を直接思い浮かべるようになってきます。
一方boolean literalを使うと、1) 「比較の結果がtrue/falseであり」2)「なので対象はこの状態」という思考ステップをいつまでも強いるように感じます。

下記で私はそれを体感するのですが、いかがでしょうか。

```swift
assert(
  alice.has(hat) &&
  !alice.has(sunGlasses) &&
  alice.has(dresses) &&
  !alice.has(rings) &&
  alice.has(shoes)
)
```

```swift
assert(
  alice.has(hat) == true &&
  alice.has(sunGlasses) == false &&
  alice.has(dresses) == true &&
  alice.has(rings) == false &&
  alice.has(shoes) == true
)
```

__余談的考察と感想__

`if sum(a, b) == c` のような比較、これは「処理結果」を何かと比較するつもり、で書きます。
boolean literal を使って比較文を書くのは(`== true`)、同じ感覚で書いているのかな、と想像します。
「それとは別の感覚でも読み書きできるんですよ」、というのが伝わればいいな、というのが今回の記事に込めた希望です。
Google Cloud: 無償トライアルの申請

#はじめに
Google Cloudには、それぞれのサービスに無償枠がありますが、これを利用するためにはトライアル申請をする必要があります。本記事では、「Google Cloud無料プログラム(300$)」の申請方法について記述いたします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/44d13041-e949-187a-a954-8a717e0901a2.png)


<b>Google Cloudの無料プログラム</b>
https://cloud.google.com/free?hl=ja&skip_cache=true
https://cloud.google.com/free/docs/gcp-free-tier?hl=ja

なお、無料プログラムを利用するためには、「SMS受信」、及び、「クレジットカードの登録」、「個人情報（住所など）の入力」が必要です。

クレジットカード登録はあくまでGoogle Cloudのセキュリティのための利用であり、この無料プログラム申請だけでは、Google Cloudを誤って利用したとしても、（上限枠を使い切るだけで）課金されることはありません。

※ 本記事を参考にして申請されて、請求されたとしても、責任は負いませんので、その点はご了承ください。

手順は以下のとおりです
1. Googleアカウント（Gmail）作成
2. Google Cloud無料プログラム申請

１のGoogleアカウント作成については、ここでは記述しません。
ご自身のGmailアカウントを作成し、ご利用ください。

##申請手順

<b>1.[Google Cloud無料プログラム申請](https://cloud.google.com/free?hl=ja&skip_cache=true)のサイトより、「無料で使ってみる」をクリック</b>

<b>2.自分のアカウントを選択し、「続行」をクリック</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/f5b9d0fb-5747-6c11-4662-f93fb9795b69.png)

<b>3.自分の携帯番号を登録し、コード送信をクリック</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/b8b3105d-e3d0-c561-e8fe-7fe3a0cc72ce.png)
<b>4.SMSメールを受信するので、それを入力</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/a4bef2f5-b441-92b4-fdf8-967f20227577.png)
<b>5.クレジットカード情報、住所などを入力</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/2728c4eb-5ba6-e623-c26b-bd25cb06a2eb.png)
<b>6.今回無償枠を利用する理由などを適当に入力</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/06d3d50a-46b8-865a-9012-24ab893c908b.png)



<b>7. これで無料プログラムの申請の完了となります。</b>
[Google Cloudのコンソール画面](https://console.cloud.google.com/) から、サービスを利用してみましょう
CentOS RPMパッケージビルド手順

RedHat系ディストリビューションで使用されるRPMビルド手順の概要を説明します。対象の主なディストリビューションはCentOS、Fedoraです。

### 0.準備

パッケージビルドのオペレーションは全てrootユーザで実行します。

```
su root
```

RPMビルドに必要なツール類をインストールします。

```
dnf install rpm-build
```

### 1.ソースの入手と準備
CentOSのレポジトリからSRPMを入手して、パッケージのソースを入手します。ここでは、sysstatパッケージを例にとります。

```
dnf download --source sysstat
rpm -ivh sysstat-11.7.3-5.el8.src.rpm
```
SRPMのファイル名は、指定したレポジトリのバージョンによって変わります。
rpm -ivhコマンドで、/root/rpmbuild/SOURCES 配下にソースが展開されます。
また、/root/rpmbuild/SPECS 配下にビルド情報が格納されたSPECファイルが展開されます。

```ruby:/root/rpmbuild/SOURCES
sysstat-11.7.3.tar.xz
```

```ruby:/root/rpmbuild/SPECS
sysstat.spec
```

RPMビルドに必要な他フォルダは手動で作成します。

```
# cd /root/rpmbuild
# mkdir RPMS SRPMS BUILD
```


### 2.RPMビルド

sysstatパッケージのビルドを行います。

```
# cd /root/rpmbuild/SPECS
# rpmbuild -bb sysstat.spec
```

rpmbuildを実行すると、必要なパッケージが無いというエラーが出る場合は、そのパッケージをインストールしてから、再度rpmbuildを実行します。

```
エラー：ビルド依存性の失敗
　lm_sensors-devel は sysstat-11.7.3.5-el8.x86_64　に必要とされています

# dnf install lm_sensors-devel
(略)
# 完了しました!
# rpmbuild -bb sysstat.spec
```
Visual Studio に VSCode のショートカットキーを適用する方法

# Visual Studio の規定のショートカットキーは VSCode のショートカットキーと全く違う

VSCode や Atom でコーディングを始めた人は、Visual Studio を使わなければいけない場面が来た時に面食らう。　　
Visual Studio Code と Visual Studio って兄弟みたいな名前して、ショートカットキー違うの！？

例えば、コメントアウト(Windows の場合)

- VSCode: ```Ctrl + /```
- Visual Studio: ```Ctrl + k → +u```

例えば、カーソルのある行を1行下にコピー(Windows の場合)

- VSCode: ```Alt + Shift + Down```
- Visual Studio: ```Ctrl + c → Ctrl + v ```

Visual Studio の方が一手多い感じだし、全然VSCodeと違って覚えるの大変。（面倒！）

# Visual Stuido に VSCode の規定のショートカットキーを一括で適用しましょう

Visual Studioを開いて、メニューバーから ```ツール → オプション → 環境 → キーボード``` の順にクリック。
[次の追加キーボードマップスキームを適用(M)]で ```Visual Stuido Code``` を選択して ```OK``` をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188272/4246bf8d-b598-fe0d-7c42-26019fa72cd7.png)

以上