OmniAICreator/Qiita-1.07M huggingface dataset:
Node.js v12でnode-gypでのビルドが通らない場合、v10をインストールすればよい

Node.js v12@Windowsでnode-gypを用いたビルドで以下のようなエラーが出る場合、v10をインストールすればビルドできます
※この例では`winapi`のビルドで失敗の例

v12ではnode-gyp v5.0.5が強制インストールされてしまうことに由来したエラーと睨んでいます。
※なお、MSBuild Toolの2015,2017,2019いずれでもv12ではうまくいきませんでした

```
gyp ERR! build error 
gyp ERR! stack Error: `C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onExit (C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\lib\build.js:194:23)
gyp ERR! stack     at ChildProcess.emit (events.js:210:5)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12)
gyp ERR! System Windows_NT 10.0.18363
gyp ERR! command "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd C:\research\idle-poweroff\node_modules\winapi
gyp ERR! node -v v12.13.1
gyp ERR! node-gyp -v v5.0.5
gyp ERR! not ok 
```
TechCommit Advent Calendar 2019_13日目[新人エンジニアさんやプログラミング初心者の方がモチベを上げるお勧めな書籍３点]

こんにちは。TechCommitに参加して、早半年ほどが経過しました。
そのAdvent Calendarの13日が僕の番です。

が、最近は色々なPGの勉強のお話を聞く機会があり、
技術的な情報はたくさんあるけど、
メンタル的な部分の話は、難しいということを感じていました。

ので、今回はですね、
個人的に僕がお勧めしたい、モチベを上げるお勧めの書籍を紹介いたします。
有名な書籍ばかりなので、すでに読んでる方も多いと思いますがｗ

**その１**
**「プログラマーが知るべき97のこと」**

こちらの書籍は、有名も有名で、しかも無料で内容が公開しているため、
読んでいる方もたくさんいると思います。
しかし、何回読んでも良いものは良いですね。

プログラマとしての心構え、困難に出会ったときの乗り越え方など、
ベテランエンジニアの考え方や知見がちりばめられたエッセイとなっています。
プログラミングをしている人にとっては、力強いエールとなってくれることでしょう
無料なので、悩む前に読んだほうが得です。

以下は、無料公開されているサイトです

[プログラマが知るべき97のこと](https://xn--97-273ae6a4irb6e2hsoiozc2g4b8082p.com/)


**その２**
**「なぜ、あなたの仕事は終わらないのか？」**

マイクロソフトで超人的な腕を振るっていた、プログラマーの中島聡さんの
仕事に対する心構えの書籍です。

どうすれば、納期に余裕をもって作業できるのか？
どうすれば、後手後手にならずに緊急的な依頼に対応できるのか？
という部分にフォーカスし、その乗り越え方を伝授してくれています。

主に現役で頑張ってるエンジニア向けだとは思いますが、
仕事に対する考えたかは、どのような業種にも応用可能かと思います。

また、今の自分の仕事の方法、進め方に悩んでいる方の力にもなりますし、
エッセイとしても面白いです。
初学者の方にも今後のためになる内容ですし、仕事を頑張る人を応援する書籍なので、
モチベーションは上がりやすいでしょう。

以下はAmazonのKindleのリンクです

[なぜ、あなたの仕事は終わらないのか](https://www.amazon.co.jp/%E3%81%AA%E3%81%9C%E3%80%81%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AE%E4%BB%95%E4%BA%8B%E3%81%AF%E7%B5%82%E3%82%8F%E3%82%89%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B-%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89%E3%81%AF%E6%9C%80%E5%BC%B7%E3%81%AE%E6%AD%A6%E5%99%A8%E3%81%A7%E3%81%82%E3%82%8B-%E4%B8%AD%E5%B3%B6%E8%81%A1-ebook/dp/B01GPCKJWK)



**その３**
**「ピープルウェア」**

ピープルウェアとは、ハードウェア、ソフトウエアに並ぶ、
人が大事であるということを象徴する言葉です。
この書籍では、開発のプロジェクトでは、何よりもまず「人を大事にする」ことを訴えています。

書籍の主ターゲットは、管理者であるマネージャー向けの雰囲気ですが、
正直、プロジェクトで実際に開発するエンジニアが読むべき書籍です。
これを読むことにより、まず「一緒に開発するメンバーの大切さ」
そして、「そこで働く自分の大切さ」を感じることができるでしょう。

勘違いしてはいけないのは、「技術」は当然大事であり、
そこをおろそかにしてはいけません。
ただ、一緒に仕事をする仲間、そして自分という存在が、どれだけ重要であるか、
という点において、学ぶことができます。

そして、読めば読むほど、仕事中に怒鳴ったり、感情にまかせて相手を責めたりすることが、
どれほど愚かな行為であるかを、痛感することでしょう。

また、これを読むことにより、
人の扱いの悪いプロジェクト、
或いは、業種は違っても、あなたの職場で湧き上がる心のもやもやが、
すっきりすると思います（僕はしましたｗ）

チームは組織であり、会社も組織です。
組織においては、ITに限らず、人は大事なのです。

以下はAmazonのkindleのリンクです

[ピープルウェア](https://www.amazon.co.jp/dp/B00I96CJWO/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

だらだらと書き綴りましたが、
以上で記事の内容は終了です。
日々仕事をしながら、転職やスキルアップのために学習を続けると、
どうしても疲れや様々な葛藤から、モチベーションが失われていきます。

モチベの上げ方は人それぞれあるとは思いますが、
これらの書籍が、あなたの力になれば嬉しいです。

それでは、今後もお互い、プログラミングを楽しみましょう～！
Node.jsでローカルにある複数の画像をディレクトリを分けつつリサイズする

ディレクトリ毎に分けた複数の画像を一度にリサイズするべく、スクリプトを書きました。
元の画像の縦横比が全て揃っており、リサイズする画像も元の画像の縦横比を保ったままにすることを前提としています。

## 環境

* MacOS
* Node.jsのバージョン・・・12.8.1
* npmのバージョン・・・6.10.2

### 前提

以下がインストール済みであることを前提としています。

* Node.js
* npm(又はyarn)

## ディレクトリ構造

``` 
├── node-extensions
│   └── sharp.js ← 実行するスクリプトファイル。
├── node_modules/
├── package.json
├── src
│   ├── images
│   │   ├── gallery
│   │   │   ├── l ← 元の画像を入れるディレクトリ。この下に年月毎のフォルダを作成。
│   │   │   └── s ← リサイズ後の画像を入れるディレクトリ。スクリプト実行後に生成。
```

## パッケージのインストール・スクリプトの実行

### 必要なもの

* [sharp](https://www.npmjs.com/package/sharp)・・・画像のリサイズ
* [mkdirp](https://www.npmjs.com/package/mkdirp)・・・ディレクトリを生成

### スクリプトを書く

``` sharp.js
const sharp = require('sharp');
const fs = require('fs');
const fsPromises = fs.promises;
const glob = require('glob');
const path = require('path');
const mkdirp = require('mkdirp');

const RESIZE_WIDTH = 600; // リサイズ後の画像の幅

const ORIGINAL_IMG_DIR = glob.sync('../src/images/gallery/l/*/'); // 元画像を格納しているディレクトリ
const IMG_DATE_DIR = ORIGINAL_IMG_DIR.map(imgDirPath => imgDirPath.split('/', 6)[5]); // 日付のディレクトリ
const RESIZED_IMG_PARENT_DIRNAME = '../src/images/gallery/s/'; // リサイズ後の画像を入れるディレクトリ名
const RESIZED_IMG_DIR_ARRAY = IMG_DATE_DIR.map((name) =>
  RESIZED_IMG_PARENT_DIRNAME + name
); // リサイズ後の画像を入れるディレクトリ


/**
 * 画像をリサイズしてリサイズ後のディレクトリに格納する
 * @param {string} imgPath リサイズ前の画像パス 
 * @param {string} outputFilePath リサイズ後の画像パス
 */
function createResizeImage(imgPath, outputFilePath) {
  sharp(imgPath)
  .resize(RESIZE_WIDTH)
  .toFile(outputFilePath, (err) => {
    if ( err ) console.error(err);
    return;
  });
}

/**
 * リサイズ後の画像を入れるディレクトリを生成
 */
RESIZED_IMG_DIR_ARRAY.forEach((pathName) => {
  mkdirp.sync(pathName, (err) => {
    if ( err ) console.error(err);
    return;
  });
});


ORIGINAL_IMG_DIR.forEach((dirName, i) => {
  const resolvedPath = path.resolve(dirName);  
  fsPromises.readdir(resolvedPath)
    .then((files) => {
      console.log(files);
      files.forEach((file) => {
        createResizeImage(resolvedPath + '/' + file, path.resolve(RESIZED_IMG_DIR_ARRAY[i]) + '/' + file);
      });
    })
    .catch((err) => {
      console.log(err.message);
    });
});
```

### スクリプトを実行する

`node-extensions` のディレクトリまで移動して、以下を実行。

```
node sharp.js
```

`src/images/gallery/l/` の下に `201912/` というディレクトリの中に画像ファイルを入れている場合。
スクリプト実行後に `src/images/gallery/s/201912/` のディレクトリが生成されて、リサイズ後の同一ファイル名の画像が格納されます。
【Windows歴12年/Mac歴7年】が厳選する動画（再生,ダウンロード,変換）  PC版ソフト&サイト


長年PCを使ってきて動画のダウンロードに便利なソフト、サイトをまとめた。（メモ）
PC版

音楽編はこちら↓<a href="https://qiita.com/Koshi_VTuber/items/be7b0c41de066eadaa65">
【Windows歴12年/Mac歴7年】が厳選する音楽（再生,ダウンロード,変換） PC版ソフト&サイト</a>

#ダウンロード
YouTube
ClipConverter.cc: YouTube変換
https://www.clipconverter.cc/jp/

MP4 3GP AVI MOV MKV
MP3 M4A AAC


niconico
craving explorer
https://www.crav-ing.com

ニコニコ全盛期の頃からある、歴戦の戦士。
今でも強い。昔愛用していた。

nicozon: ニコニコ動画保存ツール
https://www.nicozon.net/

動画保存形式：.mp4

offliberty
http://offliberty.io/
音質指定は出来ないが、使える。

#再生
Windows
K-Lite Codec Pack
映画&ビデオ
Media Player Classic - Home Cinema（省略MPC-HC)
使いやすい方を使う。

Mac
VLC
Quicklook
（QuickTime）

#サムネイル表示
Icaros

#変換
Windows
- PremireProで書き出す

Mac
- QuickTimeで書き出す MP4→aac, mp3
- PremireProで書き出す
初心者によるプログラミング学習ログ 183日目

# 100日チャレンジの183日目

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

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

183日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>183日目<br><br>webサイトコーディング課題<br>ボタン位置、テキスト位置修正<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <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/%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%E3%81%A4%E3%81%AA%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/1205216973136642049?ref_src=twsrc%5Etfw">December 12, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
【2020年版】AWSのEC2にPython3をインストールする方法

先日、AWSのEC2にPython3をインストールする機会がありました。

その時に「AWS EC2 Python3」でGoogle検索したのですが、検索結果の上位に表示されたページの情報がいまいちでした。
具体的には、

- pyenv
- virtualenv

を使ってPython3の仮想環境を用意する方法が紹介されていましたが、 Python3の仮想環境を用意する方法は特別な事情がない限りは`venv`を使うべきです。
また、Python3をアプリ開発やデータ分析でガッツリ使う場合を除いては、そもそも仮想環境を用意する必要はないと思います。

Python3の仮想環境を用意する方法として`venv`を使う理由は、[Pythonの公式ドキュメントで推奨されている唯一の方法](https://docs.python.org/ja/3/library/venv.html)だからです。
`pyenv`を避けるべき理由は[この記事](https://qiita.com/shibukawa/items/0daab479a2fd2cb8a0e7)に詳しく書かれているので、興味のある方はこちらをご覧下さい。

また、[AWSの公式ドキュメント](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-linux-python3-boto3/)では`virtualenv`を使った方法が紹介されていますが、`virtualenv`が`venv`としてPythonの中に正式に取り込まれたPython3.3以降においては積極的に使う理由はないと思います。

ということで、改めてAWSのEC2にPython3をインストール方法を紹介したいと思います。と言っても、Pythonの公式ドキュメントで紹介されている方法に従うだけですが…。


# 前提
- OS
    - Amazon Linux 2 AMI
    - デフォルトではPython2系のみインストールされている
- インスタンスタイプ
    - t2.micro

# 手順
1. OSのシステムにPython3をインストール

    ```
    $ sudo yum update
    $ sudo yum install python3 -y
    ```

    Pythonを使う機会は限られており、Python本体やパッケージのバージョン管理が必要ない場合はこれで十分だと思います。
    一方、アプリ開発でそれ専用のバージョン管理をしたい場合や、データ分析で専用の環境を用意したい場合などは仮想環境の出番です。

2. venvを使って仮想環境のPython3をインストール

    ```
    $ python3 -m venv myenv
    ```

    上記のコマンドをホームディレクトリで実行すると、ホームディレクトリ配下に`myenv`というディレクトリが作成されます。`myenv`という名前は好きなように変更して構いません。


3. Python3の仮想環境を有効化

    ```
    $ source myenv/bin/activate
    ```

    上記のコマンドを実行すると、Python3の仮想環境が有効化されます。

4. Python3の仮想環境を無効化

    ```
    $ deactivate
    ```

    Python3の仮想環境を抜けたい場合は上記のコマンドを実行するだけです。また、環境をまるっと削除したい場合は`myenv`ディレクトリを削除すればOKです。

# 最後に
AWSのEC2にPython3をインストールする方法を紹介しましたが、少なくともLinux系のOSではそのまま当てはまる話しだと思います。
Pythonをほとんど使わない人はOSのシステムにインストールしたPython3を、Pythonをガッツリ使う人は`venv`を使って作成したPython3の仮想環境を使うと覚えておいて下さい。
Automatorで重複ファイルを定期削除する

> 2020/05/20 追記
> 本記事は、NorthDetail ブログにも投稿しています。
> https://www.northdetail.co.jp/blog/422/

# はじめに
こんにちは。iihara-tktsです。
私はファイル整理が苦手なので気づいたら重複ファイルがたくさん出来ているということが多々あったりします。
SSDが圧迫されてきたら削除はしているのですが、手動で削除している結構時間がかかったりします。
今回は、重複ファイルの削除をAutomatorを使って定期実行できるようにしたいと思います。

# Automatorとは？
<img width="115" alt="スクリーンショット 2019-12-12 19.17.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309766/df1a2f25-c575-6bb3-cdb6-43ca5d951c75.png">
Macにデフォルトで入っている作業を自動化してくれるアプリです。
>Automator は、簡単に作業を効率化できるパーソナル自動化アシスタントです。 Automator を使えば、単純なドラッグアンドドロップ操作で「自動化レシピ」を作成し、実行できます。 自動化レシピは、単純なタスクも複雑なタスクも、必要なときに必要な場所で実行してくれます。

# 事前準備
今回、ファイルの重複検出にあたり、fdupesコマンドを使ってファイルの重複を検出します。
Macではデフォルトでfdupesコマンドは使用できないので、[Homebrew](https://brew.sh/index_ja.html)を使用してインストールします。

```
$  brew install fdupes
```

# Automatorを設定
それでは、定期的に重複ファイルを削除してくれるようにAutomatorを設定しようかと思います。
Automatorを開いてカレンダーアラームを選択します。
<img width="1006" alt="スクリーンショット 2019-12-13 15.41.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309766/14f2f91f-250f-a330-9886-6b5eb0b7e9e7.png">

# シェルスクリプトを設定
削除する重複ファイルを削除するシェルスクリプトを設定します。
「シェルスクリプトを実行」を選択して、以下の画像のようにコードを入れます。


<img width="997" alt="スクリーンショット 2019-12-13 20.46.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309766/a5e7d469-ebd5-2791-53a1-6fcaf35e2f10.png">



Automator上でシェルスクリプトを実行しようとするとfdupesのパスが通っていないようなので以下の設定が必要になります。

```
export PATH=$PATH:/usr/local/bin
```

以下コマンドは事前準備で導入したfdupesのコマンドで重複ファイルで最初に検出されたものを除いて削除してくれます。

```
fdupes -frdN 重複ファイルを削除したいディレクトリのパス
```
また、今回はテスト用で作成したディレクトリ配下を指定していますが、重複ファイルでも中には削除していけないファイルもあるので、影響がないディレクトリで行いましょう。

# カレンダーの設定
Automatorの変更を保存するとカレンダーイベントが追加されます。
<img width="999" alt="スクリーンショット 2019-12-13 20.51.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309766/6ea1ac8a-21bb-2781-094e-a3ce66d5f5ec.png">


あとは、カレンダーから繰り返し設定を設定することで任意のタイミングで定期的に実行できるようになります。
<img width="929" alt="スクリーンショット 2019-12-13 20.53.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309766/b9b6aaf2-d850-61c1-9df5-a6844e201885.png">

# まとめ
今回は重複の定期削除を行いましたが、
Automatorでは他にも色々と設定することができます。
スクリプトを書かなくてもできることは多いのでMacを持っている方はぜひ触ってみてはいかがでしょうか。
JenkinsPipeline  gitからチェックアウトするスクリプト

gitからチェックアウト。

```
  stage('Checkout') {
    retry(3) {
      git(
        url: 'git@xxx.xxx:xxx/xxx.git',
        branch: 'develop',
        credentialsId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
      )
    }
  }
```
Twitter のツリーのテキストを Chrome のコンソールで取得しよう

![スクリーンショット 2019-12-13 20.49.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32871/856d8252-d573-172c-8eeb-faa61bd492a5.png)


Twitter の連続ツイートのテキストをプレーンなテキストでメモしたくなった時に、コピーが難しかったので作りました。


# ⚠注意点⚠
法と良識の範囲でのご利用をお願いします。


# スクリプト全体

```js
{
  const targetDom = document.querySelectorAll('div[lang="ja"][dir="auto"]');

  const checkLF = () => {
    if(navigator.platform.indexOf("Win") != -1) {
      return "\r\n";
    }else{
      return "\n";
    }
  };

  const logText = () => {
    if (!targetDom) {
      alert(`ツイートの取得に失敗しました`);
      return false;
    }
    const maxTweets = 30;
    const resultAlertText = `処理が完了しました。ログをご確認ください。`;
    let resultText;
    let lineFeedCode = checkLF();

    for (let i = 0; i < targetDom.length; i++) {
      const tmpText = targetDom[i].textContent;
      resultText = resultText + lineFeedCode + tmpText;
      if(maxTweets < i){
        resultAlertText = `処理が完了しました。ログをご確認ください。${maxTweets}ぐらい以降のツイートは取得していません。`;
        break;
      }
    }

    console.log(resultText);
    alert(resultAlertText);
  };

  logText();
}
```



# 使い方

1. Twitter の Web 版の画面を Chrome で開いてください。
2. console にコード全体をコピペして Enter キーを押してください。
3. コンソールにテキストが表示されます。適当にコピーしてご利用ください。



# Q & A

## 連続ツイートのテキストの一部しか取得できない。

環境によって違うようですが、一度に取得できるツイート数に上限があるようです。
適当に表示箇所を変更して再度お試しください。


## 日本語以外取得できない。Twitter にログインしていないと取得できない。

以下の部分を適切なセレクタに変更してご利用ください。

```
  const targetDom = document.querySelectorAll('div[lang="ja"][dir="auto"]');
```


## UI は作らないのか？

あまり簡単に使えるようにすると、いろいろと問題がありそうなので、あえて不便にしています。
RaspberryPiでPython SMBusライブラリのWriteメソッドのロジアナ解析

#概要
RaspberryPi上で動作するPythonで、i2cデバイスと通信をする際に使用できるSMBusライブラリのコマンドの一部をロジアナで見てみます。挙動の参考にしてみてください。

#ロジアナ解析

##write_byte_data(slave_address, command, byte_data)

```
write_byte_data(0x3e, 0xaa00, 0xaaff)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530581/57458995-3b0c-bc40-36c1-77626e41416c.png)

- slaveアドレスに続き、コマンド8bit、データ8bitがslaveデバイスへ送信されています。ソースでは故意に16bitデータを入力させましたが、上位8bitは無視されていました。



##write_word_data(slave_address, command, word_data)

```
write_word_data(0x3e, 0xaa00, 0xeedd)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530581/1eafcb3e-6ae2-a843-a0c4-02973a812080.png)

- コマンド8bit、データ16bitが送信されています。コマンドは下位8bitのみ、データはwordなので16bit分ですがLSB 7:0、MSB15:8の順に送信されています。




##write_i2c_block_data(slave_address, command, data[])

```
write_i2c_block_data(0x3e, 0xaa00, [0x01,0x02,0x03])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530581/95160b3c-d832-7d66-751f-cff2f6e0de29.png)

- データを配列で指定し、一気に送信しています。コマンドは0x00、データは0x01,0x02,0x03の三つになります。


##write_block_data(slave_address, command, data[])
```
write_block_data(0x3e, 0xaa00, [0x01,0x02,0x03])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530581/8381a941-fe50-7c24-d9a5-168900c6ad4a.png)

- 基本的に上のwrite_i2c_block_dataと同じだと思っていたのですが何故か引数で指定していない0x03が入ってしまい、原因不明です。分かるかたいらっしゃったらご教示いただけると助かります。
cargo bench結果をプロットするcargobench-plotを使う

Rustにはマイクロベンチマークを測定するための`cargo bench`があります。
私はマイクロベンチマーク好きなので、まずまずな頻度で`cargo bench`を実行します。
そういう時に結果をもうちょっといい感じに見えるようにしたいな、そのままブログに載せるためのチャートが欲しいよなぁとか思います。皆さんもそう思ったりしませんか？私は思いました。

なのでそんな人のためのツール [cargobench-plot](https://github.com/hhatto/cargobench-plot) を作りました。

## 使い方
インストール

```shell-session
$ cargo install --git https://github.com/hhatto/cargobench-plot.git
```

以下のような感じで実行することで`cargo-bench`の出力結果を受け取ってパースして、いい感じにプロットします。

```shell-session
$ cargo +nightly bench | cargobench-plot
```

## 出力されるチャート
以下のようなインタラクティブなチャートが入ったHTMLが出力されブラウザで見ることができます。

<img width="340" alt="スクリーンショット 2019-12-13 20.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1775/a85c17c4-52e0-5a9d-9881-182d8d9e2fa4.png">

いくつかサンプルを。
![woothee_all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1775/4c1c77fb-8422-979e-0f55-0a27bae28e6d.png)![woothee_part.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1775/eb68bb90-4b3e-0c21-b7e2-574f9f2489b4.png)
![keats_tera.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1775/7fa4d252-12d9-963f-f981-3b2ae311dc80.png)

あんまり見やすくなってない気も... :sweat: 

もう少し表示の仕方やコマンドラインオプションから表示に関する動きを変えることができる、みたいなところは工夫の余地がまだまだありそうです。

## 実装
プロットまわりは [vega_lite_3](https://github.com/procyon-rs/vega_lite_3.rs) クレートを使いました。若干クレート名がいけてない感じもしますが :sweat_smile:（個人の意見です。`_` なくていいのでは...） 使いやすさやビジュアライズのキレイさから選びました。

[Vega-Lite](https://vega.github.io/vega-lite/) をいい感じにラップしてくれてるみたいです。

柔軟にいろいろ設定できそうなので、もう少し見やすくする工夫をしたいと思います。

## 終わりに

よければ使ってみてください!!
twigでの文字連結

毎回調べて忘れてしまう。

通常phpでは「.」を使って文字連結をするがtwigでは「~」を使う。
普段はLaravel使っているのでbladeも例として記載。

以下はhoge-※.svgを10まで表示するさせる例

```twig
<ul class="tw-flex">
    {% for i in range(1, 10) %}
      <li>
        //twig
        <img src="{{ asset('assets/icon/hoge-' ~loop.index~ '.svg','theme') }}" class="tw-block tw-m-auto sm:tw-m-0" alt="">

　　　　　//blade
        <img src="{{ asset('assets/icon/hoge-' .loop.index .'.svg','theme') }}" class="tw-block tw-m-auto sm:tw-m-0" alt="">
      </li>
    {% endfor %}
  </ul>
```
【InfiniteWP】複数のWordpressサイトを一括管理の巻

#初めに
現在弊社では複数のWordpressサイトを抱えており
その管理を如何様にするか考えた結果、こちらのツールに行き着いた次第。



##InfiniteWPとは
<img width="1107" alt="Whatyoucando.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257884/728ceb9a-b9ac-8b07-e6b9-44ced995f1e0.jpeg">


複数のWordpressサイトを1つの画面で管理・操作できるwebアプリケーション

- **基本無料**
- プラグインやWordpressをワンクリックでバージョンアップ
- サイトデータのバックアップ
- サーバーステータスの監視
- 投稿の作成
- etc...

有償で機能追加も可能だが無料でも管理だけなら不足無し。
ヘルプのオペレーターも割と返事が早くて適切な回答をいただけたので
うまくいかない際も安心です。
#導入してみる
##当方環境
PC:mac
サーバー:AWS EC2、nginx、apache
##1.管理画面の構築
- 1-1.必要ファイルのダウンロード
    - https://new.infinitewp.com/install-options/
    - 左側のリストから`DIY - Manual Installation`を選択
    - `Download the IWP Admin Panel.`リンクからダウンロード
 
- 1-2.管理画面用ディレクトリ作成

```
# cd /var/www/html/
# mkdir -p infiniteWP/iwpdocs
```
- 1-3.ファイル設置、サーバー設定
    - scpコマンドで先ほどダウンロードしたzipファイルをサーバーにコピー
    - 解凍〜configファイル設定

```
# cd /var/www/html/infiniteWP/iwpdocs
# unzip /home/caad_admin/IWPAdminPanel_v*.zip
# mv IWPAdminPanel_v*/* ./
# rm -r IWPAdminPanel_v*
//インストール用のconfigファイル作成
# touch config.php
# chmod 666 config.php
```

- 1-4.データベース作成

```
mysql> create database infiniteWP;
mysql> grant all privileges on infiniteWP.* to iwp_admin@'%' identified by '任意のパスワード';
```

ローカルのhostsにサーバーIPとURLを追記後、ブラウザからアクセスする。

- 1-5.インストール〜ログイン
    - ライセンス規約画面で同意ボタンをクリック
    - データベース情報を入力
    - メールアドレスとパスワードを入力
    - インストール完了後Open my admin panelをクリック

※admin panelにアクセスできない、リダイレクトエラーになる場合、
config.phpに下記を追記

```
define('APP_HTTPS',0);
//これでエラーが出る場合は1にしてみる
```


##2.クライアントプラグイン導入〜サイト追加
- 2-1.IP制限をかけている場合は管理パネルが置いてあるサーバーのIPを許可させる

```
# vi /etc/nginx/conf.d/xxxx.conf
allow xxx.xxx.xxx.xxx;
```

- 2-2.対象サイトの管理画面にログインしプラグインをインストール
    - プラグイン>新規追加>`iwp-client`を検索しインストール>有効化
    - `Copy details`をクリックし情報をコピー
    - 管理パネル左下の`Add Website`をクリックし貼り付け、`Add Site`で追加

##こうして
一時の安寧が訪れた。
![InfiniteWP_adminpanel.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257884/1d14eb47-7abf-7e7a-580d-35d2231c7fb3.jpeg)

クライアントプラグインのアップデートも画面に表示してくれますし
こちらもワンクリックでアップデート可能です。便利。


##参考サイト
- [infiniteWPオフィシャルサイト](https://infinitewp.com/) 
- [infiniteWPサポート](https://support.infinitewp.com/support/home) 
- [TECH BLOG - 複数のwordpressを一括で管理するINFINITEWPプラグイン](https://www.startup-plus.com/techblog/post-880/) 
- [netamimi - 複数のWordPressサイトを一括管理できる「InfiniteWP」がスゴイ！](https://netamimi.com/158)
JenkinsPipeline 複数ノードでジョブを並列実行するスクリプト


TEMPフォルダの中身を削除するジョブを並列で実行するスクリプト。

```
def onlineComputers = []
stage("GetOnlineComputers") {
  onlineComputers = getOnlineComputers()
}


def builders = [:]
for (int i = 0; i < onlineComputers.size(); i++) {
	def onlineComputerName = onlineComputers[i].getName()
	builders[onlineComputerName] = {
		node(onlineComputerName) {
			stage('delete') {
				bat "if exist %temp% del /Q %temp%"
				bat "if exist %temp%\\* for /D %%1 in (%temp%\\*) do rmdir /s /q %%1"
			}
		}
	}
}
parallel builders

def getOnlineComputers() {
  def nodes = []  
  def allNodes = Jenkins.getInstance().getNodes()
  for (x in allNodes) {
    def node = x
    allNodes.each{node ->
      if (node.toComputer() && !node.toComputer().isOffline() && !node.toComputer().isTemporarilyOffline()) {
        nodes << node
      }
    }
  }
  return nodes
}
```
JenkinsPipeline オンラインのノードを取得するスクリプト


```
def getOnlineComputers() {
  def nodes = []  
  def allNodes = Jenkins.getInstance().getNodes()
  for (x in allNodes) {
    def node = x
    allNodes.each{node ->
      if (node.toComputer() && !node.toComputer().isOffline() && !node.toComputer().isTemporarilyOffline()) {
        nodes << node
      }
    }
  }
  return nodes
}
```
【Unity】Scene.buildIndexが-1になるのはDontDestroyOnLoadなScene

# 問題
スクリプトで生成されるGameObjectは、生成したSceneを破棄する時にまとめて破棄されてほしいので、`SceneManager.MoveGameObjectToScene(obj, SceneManager.GetSceneByBuildIndex(buildIndex));` として管理していたが、以下のエラーが出ることがあった。

```Console.
ArgumentException: GetSceneByBuildIndex: Invalid build index: -1
To add a scene to the build settings use the menu File->Build Settings...
```

調べてみると、DontDestroyOnLoad()としたGameObjectのsceneはbuildIndexが-1になる様子。

# 解決方法

buildIndexが負の場合は `DontDestroyOnLoad()` を `SceneManager.MoveGameObjectToScene()` の代わりに実行すればいいのだが、以下のように、sceneを丸ごと `SceneManager.MoveGameObjectToScene()` に渡しても大丈夫だった。

```buildIndexTest.cs
private void Awake()
{
    Object.DontDestroyOnLoad(gameObject);
}

private void Start () {
    var obj = new GameObject();
    Debug.Log(obj.scene.buildIndex);

    // buildIndexを経由すると以下のエラーになる
    // ArgumentException: GetSceneByBuildIndex: Invalid build index: -1
    // To add a scene to the build settings use the menu File->Build Settings...
    //var scene = SceneManager.GetSceneByBuildIndex(gameObject.scene.buildIndex);
    //SceneManager.MoveGameObjectToScene(obj, scene);
    //Debug.Log(obj.scene.buildIndex);

    SceneManager.MoveGameObjectToScene(obj, gameObject.scene);
    Debug.Log(obj.scene.buildIndex);
}
```

```Console.
1
UnityEngine.Debug:Log(Object)

-1
UnityEngine.Debug:Log(Object)
```
JenkinsPipeline 特定のラベルを持つノードを取得するスクリプト

labelsTextをジョブのパラメータとして指定して渡す前提。

```
includeLabels = params.labelsText.tokenize('\n')

def getTargetNodes() {
  def nodes = [:]
  def allNodes = Jenkins.getInstance().getNodes()
  for (x in allNodes) {
    def node = x
    def label = node.getAssignedLabels().find{assignedlabel ->
      includeLabels.find{includeLabel ->
        assignedlabel.getName() == includeLabel
      }
    }
    if (label) {
      nodes[node.name] = node
    }
  }
  return nodes
}
```
Codenize警察のいる生活

この記事は[くふうカンパニー Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kufu)の13日目の記事となります。

[DaVinciStudio](https://da-vinci-studio.com/)でSREをやっている横山です。
DaVinciStudioのSREは、くふうカンパニー各社のインフラ基盤の管理を行なっております。
そして、インフラ基盤の管理には[Terraform](https://www.terraform.io/)や[Codenize.tools](https://codenize.tools/)、[CloudFormation](https://aws.amazon.com/jp/cloudformation/)を使っています。
今回はこの管理ツールの運用について一筆書きたいと思います。

# TerraformとCodenize.toolsとCloudFormationについて
インフラのコード管理というと、概ねこれらの3ツールを利用されている方が多いのではないでしょうか？
雑に比較すると以下のような感じになります。

| 名称              |      いいところ      | 
|:----------------:|:-----------------:|
| Terraform        |  対応するリソースが豊富(AWS,GCP,datadog,Azure,GitHub、[ドミノピザ](https://ndmckinley.github.io/terraform-provider-dominos/)(嘘)などなど) | 
| Codenize.tools   |  Ruby DSL,<br>Rubyでプログラマブルにリソース定義できる|
| CloudFormation   |公式ツールという安心感。|

弊社では基本的にterraformを使い、新規で構築するものにはCloudFormationが使われることが多いです。
これはCloudFormataionでは既存のリソースのインポートができないという問題があったためです。
しかし、この問題は以下の通り、最近のアップデートで解消されました。今後は積極的に使っていこうと思っています。
https://aws.amazon.com/jp/blogs/news/new-import-existing-resources-into-a-cloudformation-stack/

# コード管理の辛さ
さて本題です。コード管理はこれらのツールを導入して終わりではありません。日々、運用していかなければなりません。
こんなこと、心当たりがありませんか？？
> うーん、、この検証のためのIAMロール、いちいちプルリク作ってコード変更するのめんどいな、とりあえず手動で作るか。うまく行ったら明日ちゃんとコード化しよ。

明日なんて永遠にこないのです。そのまま忘れ去られ時が過ぎ、、
次にIAMロールに変更を加えようとした人が`dry-run`した時に意図しない差分に気づくのです。。
これはとても悲しい。
手動作成を禁止して、厳格に運用すべきというツッコミはおっしゃる通りだと思います。
しかし、手動で作成できるゆるい運用もこれはこれでメリットがあると思っています。
ということで、このようなゆるさを保ちつつ、悲しい思いをする人が減るようにCodenize警察を作りました。

# Codenize警察
Codenize警察の中身はShellスクリプトです。
たとえば`hogehoge/hogehoge`レポジトリにコードがある場合、以下のようになります。
`GITHUB_TOKEN`、`SLACK_WEBHOOK_URL`は環境変数として渡します。

```bash
#!/bin/bash
set -x
function slack_notify_change_of () {
  payload="payload={'attachments':[{'color': '#e73613', 'text': '${1}の差分を検知しました。'}]}"
  curl -X POST --data-urlencode "$payload" $SLACK_WEBHOOK_URL
}

export AWS_REGION=ap-northeast-1
git clone --depth 1 https://$GITHUB_TOKEN@github.com/hogehoge/hogehoge.git

cd /opt/hogehoge
bundle install

cd /opt/hogehoge/codenize-tools
services=(roadwork)
for service in ${services[@]}; do
  bundle exec ${service} -a --dry-run | grep -e Create -e Delete -e Update
  if [ ${?} = 0 ]; then
    slack_notify_change_of ${service}
  fi
done

cd /opt/hogehoge/terraform
services=(cloudfront codebuild codecommit codepipeline datadog eip github iam kms lb s3 security_group vpc)
for service in ${services[@]}; do
  cd /opt/hogehoge/terraform/${service}
  terraform init
  terraform plan -detailed-exitcode -parallelism 50
  if [ ${?} = 2 ]; then
    slack_notify_change_of ${service}
  fi
done

```

あとはこのShellスクリプトを任意の環境で動かすだけです。
弊社ではECSやEKSを導入しているため、このスクリプトを配置したDockerコンテナをECS上で1日に1回実行(巡回)させています。
こうすることで差分がある時にSlackに以下のように通知され、コードに反映されていない変更が長期間放置されることがなくなりました。
※事情によりアイコン画像はお見せできません。
<img width="363" alt="スクリーンショット_2019-12-13_20_21_16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117895/8cd4aad7-ac9a-4046-99b9-e8ebc4f5773f.png">

# まとめ
こういったちょっとした**くふう**の積み重ねで暮らしを便利にしていきたいものですね。
[くふうカンパニー Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kufu)、明日の14日目は[matsuhisa_h](https://qiita.com/matsuhisa_h) さんの「地味な話」です。
そのPullRequestちょっと待った！

## はじめに
PullRequest・MergeRequestを出して開発メンバーからのレビューを受けて「うわ！なんでこんなしょうもない無駄なミスしちゃったんだろう」と悲しくなったことはありませんか？

私は数え切れないほどあります。

今日はそんなしょうもない無駄ミスをなくすために考えたことを紹介したいと思います。


## そのPullRequestをちょっと待つメリット
できた！！と思ってPullRequstを出す前に、一回深呼吸してもう一回考え直すメリットはたくさんあります。

### **1.開発メンバーの無駄な時間を奪わないで済む**

``` 
need_to_fix? ? 開発メンバーがこれはおかしいと思い、確認してコメントする : レビューOKにする
```
レビュアーからしたら圧倒的に「レビューOKにする」の方が短時間で済みます。
開発メンバーに迷惑をかけないためにもそのPullRequestはちょっと待つべきです。


### **2.リリースまでのスピードが速くなる**
これはしょうもないミスに関わらずですが、
`レビューを出す → コメントをもらう → 確認する → 修正する　→ もう一度見てもらう　→レビューOK`
の時間が勿体無いです。

`しっかり確認する → レビューを出す → レビューOK`
この3行程がいらなくなります。

レビューに割く時間を少なくすることでその分自身の開発に割く時間が増え、リリースできる実装物が増えます。
リリースできる実装物が増えるとサービスがよくなります。
自分が綺麗なプルリクエストを出すだけで結果サービスを改善するスピードが上がると思います。

### **3.メンタルを正常に保てる**
しょうもないミスをするとなんでこんなミスをしてしまったんだろうと悲しくなります。
悲しくなるとその気持ちが別のミスを誘発し、負のスパイラルに陥ります。

大元のミスがなくなれば、メンタルも正常に保たれさらにミスが減ります。

自分のためにもそのPullRequestはちょっと待つべきです。

## やってしまったしょうもない無駄なミス一覧

#### 1. **インデントズレ**
Lintやrubocopなどの静的解析ツールである程度のミスは防げますが、私がよくやってしまうのは
 **コピー&ペーストした後にインデントをしっかり確認しなかったため**を起きるミスです。
コピー＆ペーストした後はしっかりインデントを確認するクセをつけるべきです。

#### 2. 命名規則ミス
camelCase・snake_case・PascalCaseなどの命名規則が他のファイルと違い統一できていていないパターンです。新規のコンポーネントなど、1から書くときによくやってしまいます。

#### 3. 使っていないメソッドの消し忘れ
開発中にリファクタリングしたのはいいものの、不必要になったメソッドや定数を消し忘れてしまうパターンです。大規模な開発の時によくやってしまいます。

#### 4. めっちゃボタン連打できちゃう
クライアントでAPIを叩くボタンをレスポンスを待たず何度もリクエストが送られてしまうパターンです。ちゃんとテストしてないため起きます、レスポンスが来るまではボタンを押せないようにした方がいいです。

#### 5. 不適切なメソッド名
- スペルミス
- メソッド内の変更はしたけどメソッド名変えてない
- 英語としてわかりずらい

『プログラマが知るべき97のこと』という本の[名前重要](https://xn--97-273ae6a4irb6e2hsoiozc2g4b8082p.com/%E3%82%A8%E3%83%83%E3%82%BB%E3%82%A4/%E5%90%8D%E5%89%8D%E9%87%8D%E8%A6%81/
)というセンテンスを読んでから、コードを書くときもレビューするときも名前にしっかり注視するようになりました。

#### 6. サーバーサイドとクライアントでの値が違う
Vueのstateで状態管理をしている場合、APIを叩いてサーバーのデータは変えたけど、クライアント側は変わっておらずおかしな表示になってしまうことがあります。

#### 7. NULLチェック忘れ
null参照エラーを起こすため、しょうもないというか絶対ダメです。
これもしっかり起こりうるパターンを考えテストをすれば防げるものです。

しかしなんでもNULLチェックすればいいというものではありません。
[その「Nullチェック」必要ですか？ ～レビューで指摘を一つ減らすために～](https://qiita.com/teao26/items/3ace59deadad634dff4f)

#### 8. クォーテーションが違う
式展開するとき変数が無い時
rubyの場合、ダブルクォーテーションを使っていたり
JSの場合、バックスラッシュを使っていたり...

## しょうもない無駄なミスを防ぐには
#### Commitの前にDiffを確認
大体の問題はこれで防げる気がします。
確認のし忘れで無駄なミスが起きてしまうのです。

#### 静的解析ツール・エクステンションを大活用する
VisualStudioCodeのCode Spell Checkerや ruby-rubocopなど
使えるものはどんどん使っていきます

#### ラバーダッキング
ラバーダッキングとは
>主にプログラマの間で使われる言葉だと思うが、「ラバーダッキング」という問題解決手法がある。 ゴム製のアヒルのおもちゃに話しかけることで、頭の中で問題が整理されて解決を導く手法である。

差分を確認する際に、頭の中のアヒルに説明しながら確認します。
差分をズラーと目で追うより説明しながら確認した方が、「いや、待てよ...」と閃くきっかけにもなります

#### 反省
起きてしまった無駄なミスは反省します。
私は忘れてしまわないようにメモ帳に書いたり、Slackの自分のDMに書き留めて形に残すようにしています。
簡単にグーグルスプレッドシートを使ってメールの一斉送信をしてみた

#はじめに
特定のグループのメンバーそれぞれに同じ内容のメールを送りたい。

イベントの告知とか、
年末年始の挨拶とか、
退職時の挨拶とか。

Pythonとかプログラミングのことよくわからないし、
複雑なことをしたくないけど、
アドレスとか名前とか細かい部分は変えながら、
エクセルにまとめてある情報を使ってメールを一斉送信したい。

そんな時の簡単な方法として、
Googleのスプレッドシートでマクロを使ってメールを送信する方法をまとめた。

今回の方法からさらに応用したい人は、
参考ページを見てみてください

#必要なもの
Gmailのアカウント
Google Chrome

#方法
##スプレッドシートの作成
ChromeでGoogleのトップページかGmailのページの右上にある「・・・」メニューから、
「ドライブ」→「新規」→「Google スプレッドシート」を選択する。

シートの名前は適当に「一斉送信」とかで。

![ドライブ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/3bb19a49-9ad4-f51d-02c2-16c862efd492.png)

![新規.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/0009f308-ebcb-c949-c4dd-6f2879e15c7d.jpeg)

![名前.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/b1bc0766-ad2b-ac52-de1a-9c8239936e5e.jpeg)


##必要な情報を入力する
感覚的にはエクセルのシートなので、
名前とかメールアドレスとかいろいろ入れていく。

![一覧.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/7af46535-b610-7d35-072e-85e0bd6d960d.jpeg)


##マクロを作る
スプレッドシート内の「ツール」タブにて、
「スクリプトエディタ」を選択すると以下のような画面が出てくる。

![新規マクロ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/1a1dae74-75a8-6efe-03d4-3a408011821a.jpeg)



この中の関数を下記のように書き換える

```
function mailSend() {  //1行目を書き換え
  
 var mySheet=SpreadsheetApp.getActiveSheet();  //現在編集中のシートを取得
 var rowSheet=mySheet.getDataRange().getLastRow();  //入力したシートの最下列を取得
  
  for(var i=2;i<=rowSheet;i++){  //編集中シートの2行目の情報から取得する
   
  var strCompany=mySheet.getRange(i,1).getValue(); //会社(A列)
  var strEmail=mySheet.getRange(i,2).getValue(); //名前(B列)
  var strName=mySheet.getRange(i,3).getValue(); //メールアドレス(C列)
  var strFrom="hogehoge@hugahuga.co.jp"; //From欄(自分が使ってるメールアドレス)
  var strSender="piyopiyo"; //送信者の名前
  var strcc="foo@bar.co.jp"; //CCのアドレス
 

  var strSubject="Mail Send";  //メールのタイトル
  var strBody=strCompany + "\n" +  strName + " 様\n" + "\n" +"\
本文を入れてください" + "\n\n"+ "\
書き方はいろいろなパターンでできます";   //メールの本文
 
  GmailApp.sendEmail(  //メールの送信処理
    strEmail,
    strSubject,
    strBody,
    {
      from: strFrom,
      name: strSender,
      cc: strcc
    }
  ); 
  }
}
```

![スクリプト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/cdceaf1f-cc70-e1a1-4091-3bf8203c5105.jpeg)


『\n』は実際に表示されるメール内での改行を意味します。
『\』はスクリプト内だけでの見た目の改行を意味します。
『strBody』内での空白行は入れないでください。
エラーになって保存できなくなります。

必要な部分は適宜変更する。

スクリプトができたら「Ctrl」+「s」で適当な名前で保存する。

##メールを送ってみる
スプレッドシートの画面に戻り、「ツール」→「マクロ」→「インポート」を選択し、
上記で作ったスクリプトをインポートする。

![インポート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259343/352e74e4-7835-5701-c0ab-087d75321ec6.png)


インポート成功後は作ったマクロが選べるようになっているため、
実際に実行し、動くかどうか確認する。

初めて実行した場合はGmailアカウント使用の許諾を求められるため、
許可を選択する。

#参考ページ
[初心者でも簡単！Google Apps ScriptでGmailを操作してメールを送る方法](https://tonari-it.com/gas-gmail-sendemail/)
[Googleスプレッドシートで、一括送信メールを送る方法](https://liapoc.com/bulk-transmission.htm)]
[Google Apps Scriptで指定時刻にメールを送信するシステムを作ってみた](https://qiita.com/KentoDodo/items/4839af8700742a646cea)
paizaでkernel開発 その3

# 概要

paizaでkernel開発やってみる。
windowsでフロッピーイメージに、elfを入れる方法を考える。

# vectorのDiskExplorerを使う。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/34a09598-2a66-0e47-6718-0c94b7100f5d.png)


以上。
Antd の Uploadでファイル制御＆送信

#手動でUploadするファイルの制御（自分のStateで管理したい）

##Upload文

```react
<Upload {...props} customRequest={this.dummyRequest}>
</Upload>
```

###customRequestでuploadを騙す(実際あげてない）
```react:Upload.js
    dummyRequest({ file, onSuccess }){
        setTimeout(() => {
            onSuccess("ok");
        }, 0);
    }
```
###Fileあげる前にとリストから削除の制御(自分はUIDで指定して削除する）
```react
const props = {
    onRemove: file => {
        this.removeFromFileList(file.uid)
    },
    beforeUpload: file => {
        this.addToFileList(file)
        return false;
     }   
}
```

```react
addToFileList = file => {
    this.setState(state => ({
        fileList: [...state.fileList, file]
    })));

removeFromFileList = uid => {
    this.setState(state => {
        const newFileList = state.fileList.filter(file => file.uid !== uid);
        return{
            fileList: newFileList
        };
    });
```

##SpringにファイルとJSONをアップロードしたい時

###formDataでfileを入れたい時
```react:Form.js
const submitData = new FormData();

submitData.append("data", JSON.stringify(data));
const files = this.state.fileList;
```
####最初はこんな感じで試したが、なぜかcontrollerに届く時fileに何も入ってなかった
~~submitData.append("file",this.state.fileList)~~

####色々調べて、こんな風に入れたら成功しました
```react
files.forEach(file => {
    submitData.append("file", file)
});
```

##Fetch文（Content-Type指定しない）
```react
fetch(URL.SUBMIT, {
    method: "POST",
    body: submitData
})
```

#BackEndのControllerはこんな感じ
```java:FormController.java

@PostMapping(value= "/submit")
public void submitForm(@RequestParam("data") String data, @RequestParam("file") List<MultipartFile> file) throws JsonProcessingException {
    ///FormDataなので、中のjsonはStringの形式です、受け取った後対応するクラスに変換すれば良い
    MyForm form = new ObjectMapper().readValue(data, MyForm.class);
    this.myService.submitForm(data, file);
}
```


##参考したサイト
- [Managing File Uploads in React with Ant Design(英語)](https://levelup.gitconnected.com/managing-file-uploads-with-ant-design-6d78e592f2c4)
- [Ant-designのManual-Upload公式ソース](https://github.com/ant-design/ant-design/blob/master/components/upload/demo/upload-manually.md)
年末まで毎日webサイトを作り続ける大学生 〜56日目 Canvasを使って遊ぶ〜

##はじめに
こんにちは！@70days_jsです。

canvas内でボールが動き続けるものを作りました。
MDNにあるゲームを参考にしています。

今日は56日目。(2019/12/13)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day56.html

##やったこと
こんなことをやりました。（gif）↓
![test3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/4296efc5-02a9-1641-3baa-bf2b59d6862d.gif)

丸いボールがゆっくり動いています。
真ん中にある四角に入ると、ボールの色と大きさが変わり、軌道が消えます。
スペースキーを押すとボールのスピードが上がります。

html↓

```html
  <body>
    <div>
      spaceを押した回数（ペースアップ）: <span id="spaceClick">0</span>回
    </div>
    <canvas id="myCanvas" width="480" height="320"></canvas>
  </body>
```

canvasを使っています。

css↓

```css
canvas {
  background: rgba(255, 255, 255, 0.5);
  border: solid 1px black;
}
```

canvasのレイアウトを変えたぐらいです。

JavaScript↓

```javascript
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 5; //ボールの大きさ
var x = canvas.width / 2; //開始位置 X
var y = canvas.height / 3; //開始位置 Y
var dx = 1;
var dy = -1;
let color = "red";
let count = 0;
let spaceClick = document.getElementById("spaceClick");
document.addEventListener("keydown", space, false);

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
  ctx.rect(220, 140, 50, 50); //x, y , 幅、高さ

  if (x > 220 && x < 270 && (y > 140 && y < 190)) {
    randomBallSize();
    randomRGB();
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  }
  ctx.fillStyle = color;
  ctx.fill(); //実行
  ctx.closePath();
}

function draw() {
  if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
    dx = -dx;
  }
  if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) {
    dy = -dy;
  }
  drawBall();
  x += dx;
  y += dy;
  requestAnimationFrame(draw);
}

//setInterval(draw, 10);

function space(e) {
  count++;
  spaceClick.innerHTML = count;
  if (e.keyCode == 32) {
    let fugou = Math.sign(dx);
    if (fugou === 1) {
      dx++;
    } else {
      dx--;
    }
    let fugou2 = Math.sign(dy);
    if (fugou2 === 1) {
      dy++;
    } else {
      dy--;
    }
    console.log("fugou: " + fugou);
  }
}

function randomRGB() {
  let r = Math.floor(Math.random() * 256);
  let g = Math.floor(Math.random() * 256);
  let b = Math.floor(Math.random() * 256);
  let rgb = "rgba(" + r + ", " + g + "," + b + ", .5)";
  color = rgb;
}

function randomBallSize() {
  let ball = Math.floor(Math.random() * 8);
  ballRadius = ball + 3;
}

draw();
```

drawBall()関数でボールを描いています。
中にあるif文は

> if (x > 220 && x < 270 && (y > 140 && y < 190)) {

真ん中の四角の位置です。
この中に入ると

>   randomBallSize();
    randomRGB();
    ctx.clearRect(0, 0, canvas.width, canvas.height);

ボールのサイズを変更、色を変更、軌道を消します。

スペースキーの方はイベントリスナーで実装しています。

> document.addEventListener("keydown", space, false);

変数dxとdyは速さを調整する変数で、これら絶対値を上げていくことでボールの速度を速くしています。

最後に、

>   requestAnimationFrame(draw);

この関数↑でアニメーションのフレームレートを自動で判断しています。
setInterval()よりこっちの方が効率よくていいですね。


##感想
やっぱりゲームみたいな描画系はcanvasを使うべきなんだなと思いました。
canvasだとチャートとか、他にも色々作れそうなので勉強してみようかな。。

最後まで読んでいただきありがとうございます。明日も投稿しますのでよろしくお願いします。

##参考
1.[仕上げ - ゲーム開発 | MDN] (https://developer.mozilla.org/ja/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up)

MDNさん今回もお世話になりました！ありがとうございます！
レスポンシブ対応する

# レスポンシブ対応する
思ったよりめちゃ簡単だった．
## HTML
HTMLのヘッダーに以下を追記．

```html
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">
```
> width=device-width

でデバイスの幅を取得する．
## CSS
CSSに以下追記．
PC向けの場合

```css
@media screen and (min-width: 767px) { /*ウィンドウ幅が767px以上の場合に適用*/
 #hoge {
   hoge: foo;
 }
}
```

SP向けの場合

```css
@media screen and (max-width: 479px) { /*ウィンドウ幅が最大479pxまでの場合に適用*/
 #hoge {
   hoge: foo;
 }
}
```
CodeBuildでECR Push&ECS Deploy

こんにちわ。Patheeの廣瀬です

ECSのデプロイ、CodePipeline+CodeBuildのパターンはよく見るのですが、
コネヒトさんの[CodeBuildを使ったECSへのコンテナデプロイ](https://tech.connehito.com/entry/2019/06/17/180404)で、
`ecs-deploy `を使えば`CodeBuild`だけで完結できるのが良さげだなと思って取り入れてみました

## 環境
- Github
- AWS
  - ECS (Fargate)
  - ECR
  - CodeBuild

### CodeBuild設定
- イメージ: `aws/codebuild/amazonlinux2-x86_64-standard:1.0`
- ウェブフックイベント: PUSH 
    - 条件: タグ (`^refs/tags/release`など)

## buildspec.yml
```
version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
    commands:
      ## ecs-deployのインストール
      - yum install -y jq which
      - curl -OL https://raw.githubusercontent.com/silinternational/ecs-deploy/master/ecs-deploy
      - chmod +x ecs-deploy
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}

  pre_build:
    commands:
      ## ECRにログイン
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)

  build:
    commands:
      ## Dockerイメージのビルド
      - docker build -t $IMAGE_REPOSITORY_NAME:latest .
      - docker tag $IMAGE_REPOSITORY_NAME:latest $IMAGE_REPOSITORY_NAME:$IMAGE_TAG

      ## DockerイメージのECRへのプッシュ
      - docker push $IMAGE_REPOSITORY_NAME:latest
      - docker push $IMAGE_REPOSITORY_NAME:$IMAGE_TAG

      ## ECSへのデプロイ
      - ./ecs-deploy -n $ESC_SERVICE_NAME -c $ESC_CLUSTER_NAME -i $IMAGE_REPOSITORY_NAME:latest -r $AWS_DEFAULT_REGION -t 1200

```

### ポイント
- 環境変数として以下を設定
    - ESC_SERVICE_NAME
    - ESC_CLUSTER_NAME
    - IMAGE_REPOSITORY_NAME
- `ecs-deploy`を動かすのに`jq`・`which`が必要なのでyumでインストール  
※イメージがubuntuだったりすると微妙に違ってくるかも
- `ecs-deploy`のタイムアウトを長めに  
イメージサイズだったり設定で変わってくると思いますが

## Pros/Cons
元の記事で`CodeBuildの良さ`に触れられていますが、その他の部分での良し悪しをあげてみました

### Pros
- CodeBuildだけで完結する
    - 簡単
        - メンテが1箇所だけなので見通しが良い
        - タグ名をCodePiplineに渡すところでアーティファクトでつまずいたり、、、
    - CodePiplineの料金がかからない
        - 一つにつき固定で1$

### Cons
- ECSデプロイ部分に時間がかかる場合、高頻度に実施するとCodePipline使うよりも高くなるかも  
  https://aws.amazon.com/jp/codebuild/pricing/
- AWSコマンドで全部書けそう
    - とはいえ1行で済む簡便さ

## あと書き
既存プロジェクトはサクッとデプロイできるようになりましたが、
一方、新規に作る場合はGithubActionで済ませれば、CodeBuildはいらないかもです、、、
[GitHub ActionsからサクッとFargateにデプロイしてみた](https://dev.classmethod.jp/cloud/aws/github-actions-fargate-deploy/)
Cloud Build トリガー設定のブランチ、タグ名称設定は正規表現なので要注意

[VISITS Technologies Advent Calendar 2019](https://qiita.com/advent-calendar/2019/visits) 16日目は @overgoro56 が担当します。

みなさーん、お気をつけください！
Cloud Build トリガー設定のブランチ、タグ名称の設定は **正規表現** ですよー！ 
間違えて設定していると開発中のブランチを意図せずビルドしちゃうので要注意！
<img width="487" alt="スクリーンショット 2019-12-13 18.07.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89140/31cc1c38-5f80-07da-4550-39b99a504efe.png">
上記の設定です！
画面にも書いてあるしそんなの知ってるよって方も多いかもしれませんが、設定ミスってると事故るのでお気をつけください。


## 何が問題なのか

ここの設定で `master` と設定していると `master` ブランチだけでなく `hotfix/×××××-for-master` のようなブランチでもビルドされちゃいます。

画面に **正規表現** って書いてあるんだから当たり前ではありますが、Cloud Build の記事を見たりGoogle 画像検索してみると `develop` や `master` といった設定がされてしまっているものが散見されたので記事にしました。

## なぜ設定間違えが多いのか

過去の画面はこちらで現在の画面とは違いシンプル。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89140/a816cc98-7186-9c4b-7dc2-1c258416559f.png)
この設定は `develop` ブランチだけを対象にしたい場合には間違いです。
設定間違えが多い原因としては以下のようなことが考えられます。

- 現在の画面ほど正規表現推しではなかった
- 自分の記憶が確かならば `dev` と入力した時にサジェストされてたものは `develop` だったのでそのまま選んで入力完了してしまう場合が多い
- 導入したばかりの状態ではブランチの数が少ないために、 `次のブランチと一致します` に複数ブランチ表示されないので間違いに気づかない

ですので、過去に設定したことのある方、最近過去の設定を参考に設定をした方は設定の確認をお勧めします。

## 正しい設定

現在は以下のように正規表現でサジェストされるようになっています。
（おそらく設定間違えが多かったので変えたのだと思います。）
トリガー対象を`master` ブランチのみにしたい場合には `^master$` と設定しましょう。
<img width="471" alt="スクリーンショット 2019-12-13 18.36.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89140/892085fb-cabd-332f-22b2-26c145f9d2d8.png">

## 最後に

GCPはものすごいスピードで成長している最中で、こういう細かいことがあったりするので気をつけたい。
でも便利な機能も多く好きなので個人の開発でも使ってます。

今回はフロントエンジニアとしてUI/UXをちゃんと考えないといけないなと再認識。
ユーザーに共感してどうやって自分たちの製品を使うのか、ユーザーの考え方と行動を考えて物作りしていきたいと思いました。
【Unity】素早くUnity OculusQuest対応アプリを作ってみる/UnitySettingSwitcher使う版

せっかくUnitySettingSwitcher作ったので実際に使ってみるチュートリアルを書きました。
今回は新規にOculusQuest向けプロジェクトを作成する手順です。

# 前提

* 実行環境
  * Unity 2018.4.12f
      * Android 8.1(Oreo, 27) SDK (Android向けのビルド環境がセットアップ済であること)
  * macOS Catalina version 10.15.1
  * Oculus Quest
      * 開発者モードが有効になっていること
      * USBデバッグを許可していること
* 使用アセット
  * OculusIntegration v1.43
  * UnitySettingSwitcher v0.0.5 (https://github.com/uisawara/unity-settingswitcher/releases)
  * MiniJSON (https://gist.github.com/darktable/1411710)

# 手順

* プロジェクト作成・アセットインポート
  * 新規プロジェクトを作成
  * AssetStoreからOculusIntegrationをimport
  * MiniJSONをimport
  * UnitySettingSwitcherをimport
* プロジェクトの設定
  * 設定ファイル /Assets/Settings.xr.json を作成(内容は下方に記載)
  * 設定を適用
      * メニュー Window/UnitySettingsSwitcherウィンドウを開く(CMD+E)
      * "Reload"ボタンで設定ファルをリロード
      * "targets/vr-oculus"をクリックしてOculus向け設定を反映 (テンプレコピー→ボタン1クリックで設定が終わる)
* サンプルシーンの作成
  * /Assets/Oculus/VR/Prefabs/OVRCameraRigをHierarchyにD&Dして配置
  * OVRCameraRigをInspectorで開き OVRManagerのTarget DevicesにQuestを設定
* ビルドと実行
  * メニュー File/BuildAndRunでBuild Settingsウィンドウを開く
  * "Build And Run"ボタンクリックでアプリをビルド・実行

```/Assets/Settings.xr.json
{
  "settings": [
    {
      "name": "targets/vr-oculus",
      "player_settings": {
        "virtualRealitySupported": true,
        "VirtualRealitySDKs": "Oculus",
      },
      "editor_user_build_settings": {
        "androidBuildSubtarget": "ASTC"
      },
      "xr_settings": {
        "enabled": true
      },
      "android": {
        "minSdkVersion": "AndroidApiLevel22",
      }
    }
  ]
}
```

# 結果

これでいつもの青い空間がQuestで見られる筈

## 補足: UnitySettingSwitcherの導入で簡素になったところ

Settings.xr.jsonの設定テンプレートを使うことで以下の手順が簡略化されています。

* PlayerSettings
  * virtualRealitySupportedを有効に設定
  * VirtualRealitySDKsにOculusを追加
* EditorUserBuildSettings
  * "androidBuildSubtarget"に"ASTC"を設定
* android
  * "minSdkVersion"を"AndroidApiLevel22"に設定

あとQiitaに記事書くときUnityの設定変更していく手順を全部省略してSettingファイルの内容貼り付ければ
設定紹介できるのでそこ便利。。

## 引用

* OculusQuest向けのプロジェクト作成の手順については、こりんさん @korinVR の記事を参考にさせていただきました、感謝。
  * https://framesynthesis.jp/tech/unity/oculusquest/
* UnitySettingSwitcherについての紹介記事はこちら
  * https://qiita.com/sa_w_ara/items/127fb54b739dc74fe8e0
vagrantのprovisionでansibleのインストールに失敗する

ちょっとだけハマったので、備忘録。

### 環境
- Host: MacOSX
- Guest: ubuntu-18.04
- Vagrant 2.1.1

### 解決方法（2019/12/13現在）
Vagrantのバージョンアップ。
issueがあがっており、2.1.2で解決としてcloseされているので、
本日時点で最新の2.2.6へあげて無事解決。

- [Ansible Provisioner does not work with bento/ubuntu-18.04 #10158](https://github.com/hashicorp/vagrant/issues/10158)

### 現象
Provisionで失敗する。

```
==> default: Running provisioner: ansible_local...
     default: Installing Ansible...
 The following SSH command responded with a non-zero exit status.
 Vagrant assumes that this means the command failed!
 
 apt-get install -y -qq software-properties-common python-software-properties	
 
 Stdout from the command:
 
 
 
 Stderr from the command:
 
 E: Package 'python-software-properties' has no installation candidate
```
[with構文の理解・応用] Pythonの標準出力の出力先を柔軟に切り替える


Pythonの標準出力(printやsys.stdout)の出力先（file出力, console出力）をwith構文で適宜切り替えながら使う方法を紹介します。

# 動機
以下の様にすると標準出力の出力先を処理に応じて変更できますが、

```python
import sys
# 一時的にfile出力に変更
sys.stdout = open('out.log', 'a+')

...
sys.stdout.write('fugahoge')
...

# console出力に戻す
sys.stdout = sys.__stdout__
```
処理が終わった際に、元に戻す処理が手間なので何かないかなーと考えていて、with構文を使うとfile open()後のclose()が不必要になったことを思い出して、本記事を書くに至りました。

# 本記事に書いてあること
- 標準出力の変更法
- with構文の説明
- with構文での標準出力の出力先の変更法

# with構文
with構文は、以下の様なファイルの読み書きやtensorflowのgradient_tapeなど色々な場面で使われています。

```python
with open('', 'r') as f:
  f.read()
```
参考: [with構文(Python)](https://qiita.com/howmuch515/items/95efab2e61f735a150e3)
## with構文では何が起きているか
with構文を使うと何が起きているかというと、withの後にinstanseを指定（もしくは生成）すると、以下のような流れで処理が走ります。
1. そのinstanseの```.__enter__()```メソッドが呼ばれる
2. with構文内の処理がはしる
3. そのinstanseの```.__exit__()```メソッドが呼ばれる

### コード例
以下のようなコードを実行すると、

```python
class Logger():
    def setIO(self, *args, **kwargs):
        # TestIO instanseの生成
        return TestIO(*args, **kwargs)

class TestIO():
    def __enter__(self):
        print('enter')

    def __exit__(self, *args):
        print('exit')

logger = Logger()
with logger.setIO():
    print('---- in with syntax ----')
```
以下のように出力されます。

```:console
enter
---- in with syntax ----
exit
```

これで、```.__enter__()```メソッド -> with構文内の処理 -> ```.__exit__()```メソッド、の順に処理がはしっていることが確認できました。

参考: 
- [with構文とは何なのか - 年中アイス](https://reiki4040.hatenablog.com/entry/20130331/1364723288)
- [[Python] with構文で使用できるクラスを実装する](https://qiita.com/tchnkmr/items/c6b6480d236a51b91c17)
# 標準出力の出力先をwith構文で柔軟に切り替える
最後に、本記事の主題である「標準出力の出力先をwith構文で柔軟に切り替える」のコード例を紹介します。

```python
import sys

class SetIO():
    """with構文でI/Oを切り替えるためのクラス"""
    def __init__(self, filename: str):
        self.filename = filename

    def __enter__(self):
        sys.stdout = _STDLogger(out_file=self.filename)

    def __exit__(self, *args):
        sys.stdout = sys.__stdout__

class _STDLogger():
    """カスタムI/O"""
    def __init__(self, out_file='out.log'):
        self.log = open(out_file, "a+")

    def write(self, message):
        self.log.write(message)

    def flush(self):
        # this flush method is needed for python 3 compatibility.
        pass

print('before with block')

with SetIO('out.log'):
    # file出力に切り替え
    print('---- in with syntax ----')

print('after with block')
```
上記のコードを実行すると、
コンソールには、以下が出力されます。

```:console
before with block
after with block
```
そして、ファイル (out.log)には以下が出力されます。

```:out.log
---- in with syntax ----
```
上記の方法で標準出力先をwith構文を切り替えることができました。
# まとめ
出力先の変更は、組み込みのlogger moduleの名前空間を使えば可能ですが、細かく出力先をかえるには不便だと思っています。（loggerに精通していないだけの可能性はあります） 
そこで、本記事で紹介した手法が使える場面もあると考えています。
何かの参考になれば幸いです！

# Refs
- [with構文とは何なのか - 年中アイス](https://reiki4040.hatenablog.com/entry/20130331/1364723288)
- [[Python] with構文で使用できるクラスを実装する](https://qiita.com/tchnkmr/items/c6b6480d236a51b91c17)
- [with構文(Python)](https://qiita.com/howmuch515/items/95efab2e61f735a150e3)