OmniAICreator/Qiita-1.07M huggingface dataset:
Lobeの機械学習で洗濯物が出ているかどうかを判別する画像認識モデルを作成する

Lobeというソフトを使うととても簡単に機械学習の分類器が作れます。
Lobe上での分類器だけなら、文系どころか、小学生でも作れるんじゃないかと思います。

今回は洗濯物があるかどうかを写真から判断するため画像認識モデルを作りたいと思います。
写真を撮りまくるやり方は前記事を参照ください。

https://qiita.com/tosshie/private/a3e451910857571b3fdd

#### 前提
* 教師データとなる写真がたまっていること（最初は10枚ぐらい写真があればいいと思います。精度が低ければ写真を追加していけば上がると思います）

#### モデル作成
* tourを一度見ておくことをおすすめします
    * https://www.lobe.ai/tour
* lobeインストール
    * 以下のページのDownloadから情報を入力してDownloadしてインストールです
    * https://www.lobe.ai/
* インストールしたら右上のimport -> images で写真を選択
    * 写真の枚数が少なければLabel付けは後からやれますが、写真の枚数が多いときは、同じLabelをつけたい写真だけをimportするのをおすすめします
* importできたら、label付けをします
    * 私は、deteru, nai, mienaiの3種類のlabelにしました
        * deteru: 洗濯物が出ている写真
        * nai: 洗濯物が出ていない写真
        * mienai: 暗くて写真から洗濯物があるかどうか判別できない写真
* label付けをしていると途中でtrainが走っているのがわかると思います
* trainが終わってピコン!と言ったら、何枚か追加して正しく認識するかテストしてみましょう。結構うまく予想できてびっくりした記憶があります

#### モデルのexport
* LobeのUserの上部のExportからTensorFlow Lite(オレンジ色のやつ)を選択
* フォルダを選択して実行（最適化の選択肢は実施で実行しています。違いは理解していないです。）
* 出てきたファイルをzipで固める（フォルダ名の空白だけ削除してからzipしています）
* zipで固めたファイルをRaspberry piへ転送
* Raspberry pi上でunzip

#### tfliteのインストール
* Tensorflow Liteのインストールをしないと出力されません
* 以下のページを参照しています

https://www.tensorflow.org/lite/guide/python

```
pip3 install https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl
```

#### 実行
* unzipの中のexampleディレクトリ内の `tflite_example.py` に写真ファイルを引数にして実行すると、予測結果が出力されます!
* nai, deteru, mienaiの3つのlabelの予測確率が出力されています

```
$ python3 tflite_example.py /<写真が保存されているフォルダ>/<写真ファイル>.jpg
Predicted: {'predictions': [{'label': 'nai', 'confidence': 1.0}, {'label': 'deteru', 'confidence': 3.381147769920452e-24}, {'label': 'mienai', 'confidence': 0.0}]}
```

#### tflite_example.py のパス変更
* rootでcronを回すときのために相対パスを絶対パスに変更します
* 以下のページを参照させていただきました

https://qiita.com/akahira/items/3ba553dabe6442a26e84

``` before.
class TFLiteModel:
    def __init__(self, model_dir) -> None: 
<snip>
        with open(os.path.join(model_dir, "signature.json"), "r") as f: <<< ここ
            self.signature = json.load(f)
        self.model_file = "../" + self.signature.get("filename")        <<< ここ
<snip>
```

``` after.
class TFLiteModel:
    def __init__(self, model_dir) -> None: 
<snip>
#        with open(os.path.join(model_dir, "signature.json"), "r") as f:
        with open("/<tflite_example.pyの1個上の階層>/signature.json","r") as f:
            self.signature = json.load(f)
#        self.model_file = "../" + self.signature.get("filename")
        self.model_file = "/<tflite_example.pyの1個上の階層>/saved_model.tflite"

<snip>
```

----------
next actionはこちらです

https://qiita.com/tosshie/items/0b5856d06d6bfc228d41

2021年3月から始めたスマートホーム化はこちらに一覧化しています（2021年7月時点）

https://qiita.com/tosshie/items/82dcc6405925b12d2fd1
AWS Configの結果をSNS Topic通してメール通知するCloudformationサンプル

作ったのでメモとして残しておきます。

# Cloudformation

```yaml
Resources:
  AwsConfigSnsTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: yourtopic
      TopicName: YourTopicName
      Subscription:
        - Endpoint: yourmail@example.com
          Protocol: email
        
  ConfigRulesChangedNotifyEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.config
        detail-type:
          - "Config Rules Compliance Change"
        detail:
          configRuleName:
            - !Ref MyConfigRule
          newEvaluationResult:
            complianceType:
              - NON_COMPLIANT
      State: "ENABLED"
      Targets:
        - Id: 1
          Arn: !Ref AwsConfigSnsTopic
          InputTransformer:
            InputPathsMap:
              awsRegion: "$.detail.awsRegion"
              resourceId: "$.detail.resourceId"
              awsAccountId: "$.detail.awsAccountId"
              compliance: "$.detail.newEvaluationResult.complianceType"
              rule: "$.detail.configRuleName"
              time: "$.detail.newEvaluationResult.resultRecordedTime"
              resourceType: "$.detail.resourceType"  
            InputTemplate: "\"On <time> AWS Config rule <rule> evaluated the <resourceType> with Id <resourceId> in the account <awsAccountId> region <awsRegion> as <compliance> For more details open the AWS Config console at https://console.aws.amazon.com/config/home?region=<awsRegion>#/timeline/<resourceType>/<resourceId>/configuration\""

  AwsConfigSnsTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      Topics:
        - !Ref AwsConfigSnsTopic
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow  
          Principal:
            Service: events.amazonaws.com
          Action:
            - sns:Publish
          Resource: !Ref AwsConfigSnsTopic

  MyConfigRule: 
    Type: AWS::Config::ConfigRule
#以下省略
```

# ポイント
## メッセージの整形
ここの内容を元にCloudformationでInputTransformerを設定しています。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/config-resource-non-compliant/

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-inputtransformer.html

## FailedInvocationsでSNSメッセージが飛ばない
SNSのアクセスポリシーで `events.amazonaws.com` からのPublish権限を付けてあげると上手くいきます。GUIから設定すると自動で設定されるので気付かなかったです。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudwatch-lambda-not-triggered/

https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudwatch-receive-sns-for-alarm-trigger/
PHP 複数の値を返す関数を定義する

# 目的

- 複数の値を返す関数を定義する方法をメモ的にまとめる

# 情報

- 筆者は下記サービスを使って記事内で紹介するソースの動作確認を行った。
    - [https://paiza.io/ja](https://paiza.io/ja)

# 方法

- 下記のように戻り値を配列状にして上げることで複数の値を返す関数を定義する事ができる。

    ```php
    function returnStr()
    {
        $str_1 = '１つ目の文字列';
        $str_2 = '2つ目の文字列';
    
        return [$str_1, $str_2];
    }
    ```

- 下記のように記載することで戻り値を配列状に取得する。

    ```php
    function returnStr()
    {
        $str_1 = '１つ目の文字列';
        $str_2 = '2つ目の文字列';
    
        return [$str_1, $str_2];
    }

    $returnStrArray = returnStr();

    var_dump($returnStrArray);
    ```

- 下記のようにlist戻り値の取得にlist関数（厳密には関数ではない）を用いるとそれぞれの戻り値各々を別々の変数へ格納する事ができる。

    ```php
    function returnStr()
    {
        $str_1 = '１つ目の文字列';
        $str_2 = '2つ目の文字列';
    
        return [$str_1, $str_2];
    }

    list($returnStr_1, $returnStr_2) = returnStr();

    var_dump($returnStr_1);
    var_dump($returnStr_2);
    ```

# 参考文献

- [https://www.php.net/manual/ja/function.list.php](https://www.php.net/manual/ja/function.list.php)
Unity 2D スプライトの大きさを取得する

##0.0 はじめに
スプライトの大きさをSpriteRendererを使って取得します。






##1.0 準備
四角いスプライトを１つ用意しました。




<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/35ea7816-c9ac-5efa-85d9-190c9e2138d4.png" width="300">
























横が1のサイズ、縦が2のサイズ、中心は(-0.5, 0.2)です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/d572bf9a-85f3-0f4f-a311-9ed809a701ce.png)





























<br>
＜参考情報＞
使用した四角のスプライトは100 x 100 px（ピクセル）の画像です。この画像の設定（Sprite Mode）でPixels Per Unitを100に設定しています。これで100 pxはワールド座標で１の大きさに相当します。
用意した四角は中心が(-0.5, 0.2)の位置で横の長さが1、縦が2なので、右上の角は（0.0, 1.2）の位置にあります（これがbounds.maxに相当します）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/a4a2dd7e-154b-c174-e88d-376272332e8b.png)































## 2.0 Spriteのサイズを取得する
SpriteRendererのboundsが使えます。サイズや場所はワールド座標です。

```C#:Test.cs
GameObject sqObj = GameObject.Find("Square"); // 目的のスプライトのオブジェクトを取得
SpriteRenderer sqSr = sqObj.GetComponent<SpriteRenderer>();//目的のスプライトのSpriteRendererを取得
Debug.Log("四角のサイズは " + sqSr.bounds.size + " です"); // 四角のサイズは (1.0, 2.0, 0.2) です
Debug.Log("四角の横の長さは " + sqSr.bounds.size.x + " です"); // 四角の横の長さは 1 です
Debug.Log("四角の縦の長さは " + sqSr.bounds.size.y + " です"); // 四角の縦の長さは 2 です
Debug.Log("中心からの距離は " +sqSr.bounds.extents+ " です");//中心からの距離は (0.5, 1.0, 0.1) です
Debug.Log("中心の座標は " + sqSr.bounds.center + " です");//中心の座標は (-0.5, 0.2, 0.0) です
Debug.Log("右上の座標は " + sqSr.bounds.max + " です");//右上の座標は (0.0, 1.2, 0.1) です
Debug.Log("左下の座標は " + sqSr.bounds.min + " です");//左下の座標は (-1.0, -0.8, -0.1) です
```

👍**ポイント**
sqSr.bounds.max.x (sqSr.bounds.min.x)、sqSr.bounds.max.y (sqSr.bounds.min.y)にてx座標、y座標を取得出来ます。
今更ですが、オブジェクト指向が理解しづらい理由

オブジェクト指向が理解しづらい理由

最近気づいたのは、ほとんどの人がプログラミング視点で見ているせいではないかなと考えるようになりました。

プログラムは目的ではなく手段です。
本当の目的は業務であり、システム開発の目的は現実社会の業務をコンピュータへ代替させることです。
つまりプログラムの手段的視点ではなく、もっと上位の目的視点でオブジェクト指向を観察すれば、カプセル化やポリモーフィズムがどんな目的で存在しているのかが見えてくるはずです。

例えば、運送業務をオブジェクト指向で実現するとした場合
まずは、実世界の業務を観察し、行為ではなく実体を見つけます。
例えば、こんな感じになります。
・商品
・配送センター
・トラック
・お客様
これらはすべてカプセル化されたオブジェクトに相当します。

次に、これらのオブジェクトの「関係」を観察します。
その時に使用する概念は「機能」です。
機能は実体が活動する行為で表せます。
例えば、以下のようになります。
・商品は配送センターに集約、保管され
・お客様からの注文で
・トラックでお客様宅へ配送される
ただ、実際には商品にもたくさん種類があり、種類ごとに扱いが変わります。
それらすべてを最初から盛り込むと非常に複雑になり、理解しづらくなります。
そこで、まず、概要設計段階では、その辺を無視して単に商品として定義します。
これが、業務レベルの抽象化です。

実装する場合は、商品オブジェクトは抽象クラスになるでしょう。
ただ、設計レベルでもこの段階で抽象的なオブジェクトとして扱うことで、設計から実装にフェーズが変わっても、これまでの方式のように視点を変換する必要がなくなります。つまり、現実社会をそのまま実装しやすくなるというわけです。

また、詳細レベルのフェーズに入った時には、商品としての基本部分は親クラスとして定義し、商品毎に異なる部分はポリモーフィズムで定義します。
これが、実装レベルの抽象化です。

このように、機能レベルでオブジェクト指向を観察すると、その目的が明確になります。
そして、機能設計が終わった段階で、すでにプログラムレベルでの構成はできているので、あとは、個別のオブジェクトに閉じて淡々と実装すればよく、他のオブジェクトとの複雑な関係はインターフェースで吸収することで、汎用的な部品としてシンプルな単一オブジェクトを扱うことができます。

最後に、この機能をインターフェースとして定義します。
機能も概要レベルでは抽象度は高くシンプルですが、詳細レベルでは細かなオブジェクト間の関係性を記述することになり、概要レベルでは抽象クラスとして定義します。

つまり、抽象度が高いものは業務担当者向け、抽象度が低いものはプログラマー向けとして分業化が可能になります。
そして、従来のように、概要設計と詳細設計で記載概念が変わるのに対して、オブジェクト指向では抽象度が変わっても、その記載概念（アーキテクト）は変わらないので、シームレスで一貫したシステム開発が可能になります。

そして、バグが一番発生しやすい変換作業が軽減できるので、信頼性も向上します。
mysql8でJSON_ARRAYAGGの結果をDistinctしたい

## 環境
mysql 8.0

## やりたかったこと
mysql8のsqlにおいて、`GROUP BY`して集約されたデータをjson形式にして、さらにdistinctをかけたかった。jsonで集約するのはJSON_ARRAYAGG関数を使うことができる。
例えば以下を実行すると

```sql
select u.sex, JSON_ARRAYAGG(u.name) from user u group by u.sex
```

userテーブルの中身を適当に脳内で補完してもらうと結果はこんな感じになる。

|u.sex|u.name|
|:--|:--|
|男|鈴木,佐藤,山崎,鈴木,鈴木,佐藤,高橋|
|女|鈴木,滝,山中,山中|

で、このままだとnameが重複してるのでdistinctした結果がほしいと思って

```sql
select u.sex, JSON_ARRAYAGG(distinct u.name) from user u group by u.sex
```

としてみたのだが、distinctが効かない。。

## 解決法
`group_concat`であればdistinctは効くので、それとconcatを組み合わせて無理矢理jsonにするのがよいっぽい。

```sql
select u.sex, concat('[', group_concat(distinct u.name),']') as name from user u group by u.sex
```

自分が実際業務で使ったのはこれにJSON_OBJECTを絡めた、以下のようにjsonをまるっととってくる方式を採用した。

```sql
select
	u.sex ,
	concat('[', group_concat(distinct JSON_OBJECT('id', u.id, 'name', u.name)), ']') as name
from
	user u
group by
	u.sex
```

## 感想
JSON_ARRAYAGGでdistinct効かないのはmysqlの仕様なのか？バージョンアップでいつか直るといいなぁ。
AWS Health とは

## 勉強前イメージ

サービスのhealth？
稼働状況？
cloudwatchと似てるようなやつかな

## 調査

### AWS Health とは

AWSのサービスで利用できるサービスの情報を提供するサービスでの
再起動が必要なリタイアなどのスケジュールや障害情報を提供するサービスになります。

### 例としては・・・

EC2インスタンスやRDSなどのリタイアなどがあります。
今はないですが、使用しているEC2インスタンスの再起動が必要になることがあります。
その際に以下のEC2のイベントに記載されるのですが、そちらの通知のことです。
メールなどでも通知はありますが、見落としがちなので別で通知を飛ばすことも出来ます。

![1イベント _ EC2 Management Console - Google Chrome 2021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/2e302bfd-aa86-f7e4-ecc9-88313609a1e4.png)

### 通知

CloudWatch EventsとAWS healthを連携させることで、
SNS通知をさせることが出来ます。

## 勉強後イメージ

あれ、通知させることできるのね
いつも見逃しそうになる

## 参考

- [AWS HealthでEC2の予定されたイベントの通知にアクションを設定する #reinvent](https://dev.classmethod.jp/articles/define-actions-when-ec2-scheduled-changes-triggered/)
[Windows] Anacondaで作成したPython環境使って、Pycharmでプロジェクトを作成する

#前置き
意外にピンポイントで説明したサイトがなかったので書く。
Anaconda, Pycharmのインストール方法を扱うサイトは無限にあるので略

#手順
## Anacondaで環境を作成する
↓こんな感じで`MachineLearning`のenvを作ったとする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/9d340d90-4921-76ba-57b5-3992decffada.png)

## 作成した環境のpathを調べる
https://docs.anaconda.com/anaconda/user-guide/tasks/integration/python-path/
にある通りanaconda promptを開いて以下のように実行する

```
> activate MachineLearning
(MachineLearning) > where python
C:\Users\実行環境のユーザー名\AppData\Local\conda\conda\envs\MachineLearning\python.exe
```

## Pycharmでプロジェクトを作成する
Existing interpreterで調べたpathを入れてCreateボタン押せばOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/cd890647-bccf-b66a-58c5-8b62fa2579f3.png)
【Laravel 8.x】フォームリクエストによるバリデーションで403エラー時の凡ミス解決

##目的
フォームリクエストによるバリデーション実装時、
動作を確認すると「403 THIS ACTION IS UNAUTHORIZED.」と403エラーが表示される。
403エラーを解消し、正常に処理が実施されるようにする。

##環境
OS: Windows 10 home
CPU: AMD Ryzen 2700X
GPU: NVIDIA GTX 1060
RAM: 16GB 2666Mhz
PHP: ver 8.0.3
Laravel: ver 8.45.1
MySQL(MariaDB): ver 15.1

##403エラー時のフォームリクエスト
```Request.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ImageRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
     return [
            'image' => 'required|mimes:jpg,jpeg,png|max:20480',
            'title' => 'required|min:2|max:100',
         ];
    }
    }
}

```

##結論
フォームリクエストのauthorizeメソッドがfalseになっていることで
403ステータスのHTTPレスポンスを自動的に返されていただけだった:head_bandage:
falseをtrueに変更することで正常な処理が行われました。
node.jsでfetchを使用できるようにする

こちらのサイトを参考にしました
○yarnを使用する
https://qiita.com/suisui654/items/1b89446e03991c7c2c3d
○Node.jsでfetchを使えるようにする
https://morizyun.github.io/javascript/node-js-npm-library-node-fetch.html
○node-fetch モジュールを使用して HTTP 通信を行う
https://maku77.github.io/nodejs/net/node-fetch.html

○注意点
node-fetchを使うには
const fetch = require('node-fetch');
をはじめに宣言する
Excelのデータをまとめて別ファイルに保存したい

##はじめに
Excelで下記のようなことをしたいなと思った。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/7a332737-9c1c-6970-28d0-6c03ff07cfd7.png)

Excelでそのままやってもいいけど、せっかくだからpythonで自動化できないかトライしてみた(このデータ数なら、自分で1つずつやった方が早いような...)。

##環境(Colabratory)
windows 10
Python 3.7.10
pandas 1.1.5

##内容
```python
#colabratory上でのファイルアップロード
import pandas as pd
from google.colab import files
files.upload()
```
```python
#データ表示(SHIFT-JISで日本語対応)
df = pd.read_csv('/content/data.csv',encoding='SHIFT-JIS')
df
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/8a28d8a3-04cb-8243-64d3-f7e8218c58d5.png)

データは90個あることがわかる。今回は値の列だけ取り出して実施する。
90÷5=18なので、最後に18個のデータがcsvに保存されていたら成功。

```python
#値の列だけを切り取り
df1 = df.iloc[:,1]

#5個ずつ値の平均を取り、リストに入れ込む
x=0
mean_number = []

while x+5<=len(df1): 
  number = round(df1[x:x+5].mean(),2) #小数点2桁で表示
  mean_number.append(number)
  x+=5

#リストの数字をcsvに保存
df_mean = pd.DataFrame(mean_number, columns = ['平均値']) 
df_mean.to_csv('/content/data2.csv',encoding='SHIFT-JIS')
```
csvファイルが保存されたので、本当にできているか確認してみよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/f4c11d46-15ed-f573-5bcd-5e16f06e8229.png)


ちゃんと18個数字があるので、成功したようだ。多分正しくできてるはず。

##まとめ
やりたいことはできたので満足(時間はちょっとかかったけど)。
やってて画像だけでなく、作成したファイルもアップしたいなと思った。GitHubも勉強しなければ…:tired_face:
地図アプリの不具合を修正

#### [前回](https://qiita.com/UpTheChels/items/67bea30460a1c87a37e7)までの問題点の修正
携帯上でアプリを実行してみると、以下の問題が発生した。
・ドラッグで地図上のカメラの位置を変更
→自己位置更新の際に呼ばれる関数が呼ばれ？、カメラが自己位置に戻る。

#### 修正案
- 自己位置が更新されたと判定される精度を下げて対応。
現在設定している精度は以下の通り、再構精度
`locationManager.desiredAccuracy = kCLLocationAccuracyBest`
これを以下に変更し、更新される精度を100mとした。
`locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters`
結果は変わらず。

- ドラッグが始まったタイミングで、カメラが自己位置に戻る処理を通らないようにする。

delegateを設定し、マップ上をタップした時に呼ばれる関数内に処理を記載

```swift
class ViewController: UIViewController,GMSMapViewDelegate

// ViewDidLoad
mapView.delegate = self

func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
    NSLog("タッチを検知しました。")
    // To Do
}
```

ドラッグの時は呼ばれないので却下。

- <del>`OnCameraMoveStarated`なる、カメラ位置が移動した時に呼ばれるメソッドがあることを[発見](https://qiita.com/amay077/items/2b13c915183fa500e430)</del>
アンドロイドだけだった。

- ちゃんとドラッグ開始を検出する関数も用意されてました。

```swift
func mapView(_ mapView: GMSMapView, willMove gesture: Bool){
    NSLog("ドラッグを開始しました。")
    // Todo
}
```

これで、カメラが自己位置に戻ってしまう問題が解決。
逆に、カメラを自己位置に戻すための処理を追加する。
ボタンを配置して、押すとカメラが自己位置に戻るようにした。

```swift
hereButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.width-80 ,y: UIScreen.main.bounds.height-80  ,width: 60, height: 60))
hereButton.backgroundColor = .lightGray
hereButton.layer.cornerRadius = 30.0
hereButton.setTitle("◉", for: .normal)
hereButton.setTitleColor(.white, for: .normal)
hereButton.addTarget(self, action: #selector(pushHereButton), for: .touchUpInside)
self.view.addSubview(hereButton)

@objc func pushHereButton(_ button: UIButton) {
    // ToDo
    camera = GMSCameraPosition.camera(withTarget: myPos,zoom: ZOOM)
    self.mapView.animate(to: camera)
}
```

適当にカメラを移動させて、右下のボタンを押下
![スクリーンショット 2021-07-03 22.36.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391844/7638df01-6368-560c-dc20-640d09759ed3.png)

LGTM!
![スクリーンショット 2021-07-03 22.36.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391844/a72db057-371e-3cc3-0a39-7812dce34b43.png)
WindowsでBluetoothのオンオフをショートカットする（razer synapse マクロ）

アクションセンターを開き、下のタイルで 右クリック > 編集
Bluetoothを左上に配置する。
タスクバーにBluetoothアイコンをおいておくとオンオフの状態がわかる。

上の設定をした状態で、`win+a`>`shift+tab`>`space`>`win+a`
を押していくとBluetoothを有効化できる。

次はこれをマクロで定義する。

synapseで下のxmlファイルをインポートし、キーに割り当てる。
（画像に示してあるように、＋をクリックしてでインポートできる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276332/47f18762-20b2-3dd2-5abc-d62ce03d436c.png)

```xml
<?xml version="1.0" encoding="utf-8"?>
<Macro xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Macro 1</Name>
  <Guid>50151930-af2e-474f-8a1e-88b7bf1a64f3</Guid>
  <MacroEvents>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>91</Makecode>
        <IsExtended>true</IsExtended>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>30</Makecode>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>30</Makecode>
        <State>1</State>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>91</Makecode>
        <State>1</State>
        <IsExtended>true</IsExtended>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>42</Makecode>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>15</Makecode>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>15</Makecode>
        <State>1</State>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>42</Makecode>
        <State>1</State>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>57</Makecode>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>57</Makecode>
        <State>1</State>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>91</Makecode>
        <IsExtended>true</IsExtended>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>30</Makecode>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>30</Makecode>
        <State>1</State>
      </KeyEvent>
    </MacroEvent>
    <MacroEvent>
      <Type>1</Type>
      <Delay>50</Delay>
      <KeyEvent>
        <Makecode>91</Makecode>
        <State>1</State>
        <IsExtended>true</IsExtended>
      </KeyEvent>
    </MacroEvent>
  </MacroEvents>
  <IsFolder>false</IsFolder>
  <FolderGuid>00000000-0000-0000-0000-000000000000</FolderGuid>
</Macro>
```
Ubuntu20.04でgoofysを使ってS3をマウントする

# はじめに

Gooofysは、AWS S3のバケットをPOSIX互換環境にマウントするためのGo言語のライブラリである。

https://github.com/kahing/goofys

本記事では、このgoofysをUbuntu20.04にインストールしてS3をマウントするまでの手順を示す。

# 環境

動作環境は以下の通り。

```bash
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

$ aws --version
aws-cli/2.2.1 Python/3.8.8 Linux/5.4.0-77-generic exe/x86_64.ubuntu.20 prompt/off
```

# 手順

[goofys](https://github.com/kahing/goofys)の公式サイトから [pre-built binaries](https://github.com/kahing/goofys/releases/latest/download/goofys) をダウンロードする。

なお、公式手順のgoコマンドでインストールする方法は、本記事執筆時点(7/2)では以下の通りエラーになる。

```bash:go-getで失敗
$ go get github.com/kahing/goofys
go: finding github.com/kardianos/osext latest
go: finding github.com/jacobsa/fuse latest
go: finding golang.org/x/sys latest
go: finding github.com/StackExchange/wmi latest
# github.com/kahing/goofys/api/common
go/pkg/mod/github.com/kahing/goofys@v0.24.0/api/common/conf_azure.go:272:34: accountsRes.Value undefined (type storage.AccountListResultPage has no field or method Value)
go/pkg/mod/github.com/kahing/goofys@v0.24.0/api/common/conf_azure.go:373:35: not enough arguments in call to client.ListKeys
	have (context.Context, string, string)
	want (context.Context, string, string, storage.ListKeyExpand)
```

ダウンロードしたpre-build binariesを適当なフォルダに格納し、rootユーザで実行権限をつけ、パスを通す。

```bash
$ ll /opt/goofys/goofys 
-rwxrwxr-x 1 root root 23M  7月  3 07:09 /opt/goofys/goofys*
```

マウントポイントのフォルダを作成し、S3のバケット名を指定して、マウントする。

```bash
$ mkdir -p /mnt/point/
$ goofys bucket_name /mnt/point/
```

マウントポイントの"/mnt/point"に適当なファイル"directory/to/file.tar.gz"をコピペして、数秒待つと、S3にアップロードされるr。

アップロードされたことはaws-cliのコマンドで確認できる。


```bash
$ aws s3 ls s3://bucket_name --recursive --human-readable --summarize
2021-07-03 08:03:25   49.7 MiB directory/to/file.tar.gz
Total Objects: 8
   Total Size: 49.7 MiB
```

# 参考文献

https://genzouw.com/entry/2019/03/07/080500/1091/
【R Markdown】追従メニューを設置する方法


R MarkdownファイルをHTMLファイルにKnitした際に、以下のようにメニューバーがサイドに表示され追従されるような設定方法を紹介します。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/8c23d361-8530-94ea-5c61-992461fb20e4.gif)



### BiocStyle

追従メニューを設置するには**BiocStyle**というパッケージを使用します。

まずはこのパッケージをインストールします。インストールはBiocManegerを用います。BiocManagerをインストールしてない方は、まずそれをダウンロードしてください。

```{R}
### BiocManagerを未インストールの場合
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

### BiocStyleのインストール
BiocManager::install("BiocStyle")
```

### 追従メニューの設定

次に、yamlヘッダと呼ばれるファイルの一番最初の部分を書き換えます。

Markdown形式で新規ファイルを作ると、yamlヘッダは以下のようになっていると思います。

```{R}
---
title: "Untitled"
author: "Fuki"
date: "7/3/2021"
output: html_document
---
```

これを以下のように書き換えます。

```{R}
---
title: "Untitled"
author: "Fuki"
date: "7/3/2021"
output: 
  BiocStyle::html_document:
    toc: TRUE
    toc_float: TRUE
---
```

output以下が変わっています。まず、outputの２行目でBiocStyleに変更し、３行目でメニューバーの設置、４行目でメニューバーの追従を指示しています。

あとはKnitをするだけです。

先程のような追従メニューが設置されます。スクロールに合わせて表示箇所がハイライトされます。

***

以上、R Markdownで追従メニューを設置する方法でした。
少しでも参考になれば幸いです。
javascriptによる価格フォームの記述から手数料と販売利益の算出方法その3


前回の入力時に発火するイベントの記述、valueの取得から販売手数料の計算と計算結果の表示を記述しました。

販売手数料の計算
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/1f8b83fa-0121-9cf8-4726-8dc5c609cfdb.png)

. innerHTMLメソッドで表示用のhtmlを作成させた
・価格を取得したpriceInputを引用し計算した
・小数点を切り下げるMath.floorメソッドを使用

販売履歴の計算
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/6a2f89fb-9024-0e6e-f1c6-435903051ecc.png)
・価格 - 手数料という計算においてddTaxDはhtmlごと使用されるので使えないので計算用のtaxValue作成


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/8989f443-2a33-b94d-1f67-5e20a87d03cf.png)

出来た...!!
分類モデルの評価-ROC曲線とAUC

## ROC(Receiver Operating Characteristic)曲線とは

___ROC曲線___は、縦軸に真陽性率(tpr: true positive rate)、横軸に偽陽性率(fpr: false positive rate)の値をプロットした曲線です。
___真陽性率___は、実際の正例のうちどれだけ正例を予測できたかの割合です。(＝再現率)
___偽陽性率___は、実際の負例のうち正例と予測されてしまった割合です。

予測確率を予測ラベルに変換する際の閾値を1.0と0.0の間で徐々に変化させ、真陽性率と偽陽性率の関係をプロットします。

## 閾値(Threshold)とは

ロジスティック回帰は予測確率を出力します。予測確率を予測ラベルに変換する際に使用する値が閾値です。
例えばスパムメールの分類で、閾値を0.5と設定した場合、
予測確率が0.5より大きい場合スパムであると判定します。
予測確率が0.5未満の場合本物メールであると判定します。

## ロジスティック回帰

```python
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4, random_state=42)

logreg = LogisticRegression()
logreg.fit(X_train, y_train)
y_pred = logreg.predict(X_test)

print(y_pred)
```

出力：

```text
[0 0 0 0 0 0 0 1 0 1]
```

ロジスティック回帰の閾値はデフォルト0.5です。

また、予測確率は以下のように計算できます。

```python
y_pred_prob = logreg.predict_proba(X_test)[:,1]
print(y_pred_prob)
```

出力：

```text
[0.39590165 0.23957606 0.20329823 0.22763991 0.42805118 0.48236847
 0.06612875 0.64996227 0.49846704 0.63918863]
```

## ROC曲線のプロット

```python
from sklearn.metrics import roc_curve

# 予測確率の計算
y_pred_prob = logreg.predict_proba(X_test)[:,1]
print(y_pred_prob)

# ROC曲線の値の生成：fpr、tpr、閾値
fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob)

# ROC曲線のプロット
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr, tpr, label='Logistic Regression')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/d28390c4-91c7-e481-79a8-d21509a46206.png)

## AUC(Area Under the Curve)とは

AUCは、ROC曲線の下部分の面積です。
AUCの面積が大きいほど機械学習の性能が良いです。

## AUCの計算

```python
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_val_score

y_pred_prob = logreg.predict_proba(X_test)[:,1]

# AUCの計算
print("AUC: {}".format(roc_auc_score(y_test, y_pred_prob)))

# AUCの計算（交差検証）
cv_auc = cross_val_score(logreg, X, y, cv=5, scoring='roc_auc')
print("5回の交差検証で計算されたAUC: {}".format(cv_auc))
```

出力：

```text
AUC: 0.8254806777079764
5回の交差検証で計算されたAUC: [0.80148148 0.8062963  0.81481481 0.86245283 0.8554717 ]
```

## 参考情報

* [ROC 曲線とAUC を用いて2値分類機械学習モデルの性能を計測・チューニングする](https://qiita.com/TsutomuNakamura/items/ef963381e5d2768791d4)
Ubuntu20.04にDesktop Widgetをインストールする

# はじめに

Ubuntuに、こんな感じ↓のDesktop Widgetをインストールする話。

![GNOME Widget](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/0b9d61bd-2f56-af33-801c-32670e844338.png)

これは、[The Circles - desktop widget](https://extensions.gnome.org/extension/3748/the-circles-desktop-widget/)というGNOME Shell 拡張機能のひとつで、時計、メモリ利用率、CPU利用率を表示できるもの。

# 環境

動作環境は以下の通り。

```bash
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

$ gnome-shell --version
GNOME Shell 3.36.9
```

# 手順

まず、GNOME Shell 拡張機能を画面で管理できるtweaksという拡張機能をインストールする。

```bash
$ sudo apt install gnome-tweaks
```


次に、Ubuntu オフィシャルのおすすめ拡張機能集をインストールする。

```bash
$ sudo apt install gnome-shell-extensions
```

次に、[The Circles - desktop widget](https://extensions.gnome.org/extension/3748/the-circles-desktop-widget/)が依存するライブラリをインストールする。

```bash
$ sudo apt install gir1.2-gtop-2.0 gir1.2-nm-1.0 gir1.2-wnck-1.0 gir1.2-clutter-1.0 gir1.2-gtkclutter-1.0
```

どこにも書いてないが、これをインストールしないとエラーが出てインストールできない。

最後に、Ubuntuでアプリを検索して、"Tweaks"を起動して、

![Screenshot from 2021-07-03 22-10-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/29f907ff-e834-8486-aebc-ac3a323c902c.png)

"拡張機能 > The circles - desktop widget"をONにする。

![Screenshot from 2021-07-03 22-06-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/4a04dbee-8968-9815-873b-8d1e86559dec.png)

すると、画面にウィジェットが表示された。

![GNOME Widget](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/0b9d61bd-2f56-af33-801c-32670e844338.png)


# 参考サイト

https://ubuntuapps.net/blog-entry-1141.html

https://itsfoss.com/gnome-shell-extensions/
【AWS】GETパラメーターを取得できない→CloudFrontの設定変更で解決

AWSにアプリをデプロイしたものの、GETパラメータを取得できていない問題に直面したのでその解決法をメモ代わりに残しておきます。
解決元になった記事を先に参照しておきます。
[CloudFront でクエリ文字列パラメータを転送するには](https://oji-cloud.net/2020/05/27/post-5040/)
ぶっちゃけこの記事見ればここから下は読まなくても大丈夫です
#結論:CloudFrontでクエリパラメータを転送するように設定
CloudFrontは、クエリ文字列の転送・キャッシュをしないようにデフォルトで設定されています。
そのため、CloudFrontの設定でクエリ文字列を転送するように設定すればOKです。

手順としては、
1. CloudFrontのディストリビューション選択、[Behaviors]タブ選択
2. 対象のcache behaviorを選択し、[Edit]
3. Query String Forwarding and Cachingの設定を “Forward all, cache based on all" に変更
4. 変更確定
5. ディストリビューションのStatusが"Deployed"に変われば完了
mac+VSCodeでElixir実行環境を作る

書籍『プログラミングElixir』に書かれたコードを実行できる環境を作ります。

## Elixirをインストール
環境はmacOS BigSur バージョン11.3.1です。

https://elixir-lang.jp/install.html
インストールページからディストリビューションmacOS(Mac OS X)の項目に記載されたコマンドを実施します。

macだとhomebrewでインストールできます。かんたんですね。

```
#　Homebrew を最新バージョンにアップデート
$ brew update

#　インストール
$ brew install elixir
```

ちなみにアンインストール。

```
$ brew uninstall elixir
```

## エディタ VSCodeをインストール

https://azure.microsoft.com/ja-jp/products/visual-studio-code/

Download Now ボタンからダウンロードします。
ダウンロードしたzipファイルを解答、Visual Studio Code.appをアプリケーションディレクトリーに移動します。

### エクステンションをインストール

開発に便利なエクステンションをインストール。
ブロックみたいなアイコンから必要なエクステンションを検索、インストールします。

![スクリーンショット 2021-07-03 19.55.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109744/c11a3fa7-fbae-37c5-88c5-fd7955a27a9e.png)

今回インストールしたエクステンション。

* vscode-elixir（Elixirのシンタックスカラー、コードスニペット、オートコンプリート）
* Thnder Client（REST API クライアント）
* GitLens（VSCodeのGit機能強化）
* Browser Preview（ブラウザ）

## VSCodeでターミナルを開く

メニューバーのTerminalから開くか、Macなら Ctrl+Shift+@ でターミナルウィンドウが開きます。

![スクリーンショット 2021-07-03 21.48.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109744/3d27d21d-d17f-a7d2-b3b2-d9408c31b334.png)

iexを起動する。

![スクリーンショット 2021-07-03 21.59.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109744/5c073dd5-7668-adba-517c-91649005eb4c.png)

これで最低限コードが実行できる環境ができました。
ターミナルはVSCodeでなくても、好みのターミナルを使うとよいと思います。

おつかれさまでしたー
Visual Studioのダークモードでrazorファイルが見にくいのを改善する

#1 初期状態でのrazorファイルの見え方
私はVisual Studioをダークテーマで使っているのだけれど、
razorファイルのコード部分が背景色が灰色になっていて見えにくい。
（最初からコード部分を選択しているか、検索条件に合致しているように見えてしまう。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441387/26535ee7-3829-bb20-79f9-677e650d0d12.png)

#2 コード部分の背景色が灰色にならないよう設定を変更

1.メニューバーの「ツール」を選択。
2.ツールの一番下の「オプション」を選択。
3.オプションが開いたら、左メニューから「環境」を開く。
4.環境の中の「フォントおよび色」を選択。
5.右側に表示項目のリストが現れるので「HTML Razorコードの背景」を選択。
6.背景色の「カスタム」を選択。
7.色の設定が表示されるので、明るさを__「28」__に設定。（最初は「75」になっている。）


あとは、開いた「色の設定」と「オプション」をそれぞれOKボタンで閉じれば設定が反映される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441387/1d994ca2-f7a4-59a4-8fa3-592a7a948e62.png)

#3 設定変更後のrazorファイルの見え方
コード部分の背景色が全体の背景色と一致してスッキリ見やすくなった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441387/c0e53c00-cdf2-e688-f777-747df8ce64ab.png)
javascriptによる価格フォームの記述から手数料と販売利益の算出方法その２

前回のファイル作成、ファイルの読み込み、ブラウザのロード時に発火するイベントの記述から、本イベントである販売手数料、販売利益を計算し算出する方法を記述しました。

手順その１

価格の値を入手するために必要な要素を取得する

＊必要な要素
・入力した金額の金額を入力する場所のidセレクタ
・販売手数料を表示する場所のidセレクタ
・販売利益を表示する場所のidセレクタ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/d5821e48-143d-b67b-97a7-cf1bcf3821c8.png)
取得したいidを探し出し...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/76f9685f-17a3-58fd-1184-2d368cdf68e0.png)

document.getElementById("取得したいid");
によりidを取得できる。


手順その2

入力するたびにイベントを発火できるようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/2fe2551e-79c2-8c66-e08d-9b7258a40119.png)

addEventListenerにinputを指定することで指定したセレクタに入力される度にイベント発火すようになる

手順その３

取得した価格のidから値を取り出す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/f199b8a4-40bd-22d8-adaa-390f3e190623.png)

.valueで
入力した価格のvalue属性（入力された値）を取得する
display: table;での要素の並び替えについて

#使い方
横並びにしたい子要素を持つ親要素に```display:table;```を記述し、子要素に```display:table-cell;```を記述することで適用させることができる。
内容はhtmlのtable要素を使用したテーブルレイアウトと同じでcssでできるようにしたものです。
高さを揃えた横並びのレイアウトや、縦方向の中央揃えがより簡単にできるようになる。

#コードの例

```ruby.rb
<div class="parent>
 <div class="child"></div>
 <div class="child"></div>
 <div class="child"></div>
</div>
```

```sample.css
.parent {
  display: table;
  width: 100%;
  border: 2px solid red;
  margin-top: 10px;
}
.child {
  display: table-cell;
  border: 1px solid blue;
}
```

display: table;は指定した要素分しか幅を広げないため、width100%と記述するなどして調整してあげると良い
Steam Web API で所有ゲームのジャンルを順位付けする

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248832/82069950-2b1c-8b1f-6097-7ff8d97c29d3.png)
標題通りの NodeJS スクリプトを作ったので投稿しておきます。
本来はそういうウェブサービスを作ろうと思ったんですが、Steam Web APIはブラウザから利用できないことを知り、あきらめた次第です（いちいちサーバ建てたくない病）。

```javascript
// `npm i --save node-fetch`
const fetch = require('node-fetch')

// Steam Web APIキー
// SEE: https://steamcommunity.com/dev/apikey
const steamWebApiKey = ''

// Steamニックネーム（e.g. `mimonelu`）
const nickname = ''

// 計上対象となる最短プレイ時間
const minPlayTime = 60

// Promise版JSON fetch
const fetchJson = (url) => new Promise((resolve, reject) => {
  console.log(`Access: ${url}`)
  fetch(url)
    .then((res) => res.json())
    .then((json) => {
      resolve(json)
    })
})

const main = async () => {
  // ニックネームからSteam IDを取得
  const userJson = await fetchJson(`https://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key=${steamWebApiKey}&vanityurl=${nickname}`)
  const steamId = userJson.response.steamid

  // 所有アプリケーションを取得
  const appListJson = await fetchJson(`http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=${steamWebApiKey}&steamid=${steamId}`)

  // 計上対象となるアプリケーションIDリストを生成
  const appIdList = appListJson.response.games
    .filter((app) => app.playtime_forever >= minPlayTime)
    .map((app) => app.appid)

  const genreObject = {}
  for (const appId of appIdList) {
    // アプリケーションのジャンルを取得
    // NOTICE: 情報量が大きすぎるので `filters=genres` で必要な情報のみ取得している　
    // NOTICE: `appids=111,222,...` というように複数のIDを指定可能だが機能しない模様
    const appDetailObjectJson = await fetchJson(`http://store.steampowered.com/api/appdetails?appids=${appId}&filters=genres`)

    if (appDetailObjectJson[appId].data.genres !== undefined) {
      appDetailObjectJson[appId].data.genres.forEach((genre) => {
        if (genreObject[genre.id] === undefined) {
          genreObject[genre.id] = {
            ...genre,
            count: 1,
          }
        } else {
          genreObject[genre.id].count ++
        }
      })
    }
  }

  // ジャンル配列の生成とソート
  const genreList = Object.values(genreObject)
  genreList.sort((a, b) => a.count < b.count ? 1 : (a.count > b.count ? - 1 : 0))

  // 出力
  console.log('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')
  console.log(`Nickname: ${nickname}
Number of owned games: ${appListJson.response.games.length}
Number of owned games (played over ${minPlayTime} minutes): ${appIdList.length}
Results:`)
  console.log(genreList)
  console.log('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')
}

main()
```

ポイントとしては、

* API キーが必要になるので、 https://steamcommunity.com/dev/apikey から取得してください。ドメインはご自由に。
* 最短プレイ時間を指定可能です。10分くらいしかプレイしていないゲームを計上しても意味がないので…。
* このままではデモ版とかデザインツールとかも含まれてしまいますが、そのあたりはがんばってください。

くらいです。

あ、あと全然関係ないんですが、Steamではよくレビューを投稿したりしているのでよろしくお願いします（？）
https://steamcommunity.com/id/mimonelu/
VPCについてまとめてみた

#はじめに
AWSを今年の春から学び始めたので少しずつアウトプットしていこうと思います。
今回は基本的なVPCについての内容をまとめます。

#前提知識
###リージョン
地域や国のこと。
各リージョン同士は分離されており、障害発生時に他のリージョンへの影響がないように設計されている。
現在日本には東京リージョンと大阪リージョンがあります。

###アベイラビリティーゾーン (AZ)
各リージョンに設置されているデータセンターのこと。
複数のAZにまたがってシステムを配置する構成をマルチAZという。
マルチAZは可用性の向上につながる。



#VPC 
VPC(Virtual Private Cloud)とは
AWS内部の論理的に分離された仮想ネットワークのこと。
VPCのアドレスの範囲を設定することで作成する。
デフォルトで一つ作成される。

###サブネット
VPC内のネットワークを小さなネットワークに分割したもの。
AZをまたがって作成することはできない。
IPアドレスの範囲を割り当てて作成する。
一つのVPC内で２００個まで作成することができる。

サブネットには以下2つの種類があります。
・パブリックサブネット → インターネットへの接続が可能なもの（インターネットゲートウェイへのルーティング有） 
・プライベートサブネット → インターネットへの接続が出来ないもの（インターネットゲートウェイへのルーティング無） 

###ルートテーブル
サブネットから外に出る通信をどこに向けて発信するか決めるルールのこと。
サブネットに関連付けて使用を行う。
最も明確なルールが優先されて適用される。(狭いIPアドレス範囲のルールが優先される)

###インターネットゲートウェイ
VPC内のAWSリソースとインターネットを繋げる。


###Nat gateway
プライベートサブネットのインターネット接続を可能にする。

###ENI(Elastic Network Interface)
IPアドレスを割り当てて、EC2インスタンス等
のインスタンスにアタッチすることができる。
アタッチできるのは同じAZ内のインスタンスのみ。
一つのインスタンスに複数のENIのアタッチが可能。


###Public IP アドレス
AWSのIPアドレスプールより割り当てられるIPアドレスでインターネットに通信できるアドレスのこと。
インスタンスが再起動、停止、終了した場合にこのアドレスは開放される。

###Elastic IPアドレス
インスタンスにアタッチが可能で、静的なIPアドレス。
インスタンスが再起動、停止、終了してもアドレスは変化しない。

###セキュリティグループ
インスタンス単位に設定するファイアーウォール
インバウンドとアウトバウンドのトラフィックルールの設定が可能。
ステートフル・インスペクション型
(送信したトラフィックについては、戻りのトラフィック考慮は不要)


###ネットワークACL
サブネット単位に設定するファイアーウォール
インバウンドとアウトバウンドのトラフィックルールの設定が可能。
ステートレス・インスペクション型
(送信したトラフィックについては、戻りのトラフィック考慮が必要)

#参考
[AWS CloudTech](https://aws-cloud-tech.com/)
[Amazon Virtual Private Cloud](https://aws.amazon.com/jp/vpc/)
[VPC のセキュリティグル-プ](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_SecurityGroups.html)
[ネットワーク ACL](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-network-acls.html)
[AWS リージョンとAZ](https://qiita.com/avicii2314/items/5e277517f1918fce413a)
【R初心者人向け】doParallelパッケージを用いた並列化の方法 〜NMDSを例に〜

# 並列化の書き方

**並列化**とは、複数のCPUを使って計算を同時に行うことで、計算時間を短くするプログラムの書き方です。今回は、Rの並列化パッケージである**doParallel**を用いて、シンプルな並列計算を行う方法をシェアします。

基本的な形は以下のようになります。

```{R}
library(doParallel)

cores <- detectCores()-1
cl <- makeCluster(cores)
registerDoParallel(cl)

## 100回のループの場合
result <- foreach(i=1:100) %dopar% {
 ## ここに並列化したい計算を入れる
}

stopCluster(cl)
```

では、順番に見ていきます。

### doParallelパッケージの読み込み

doParallelを読み込むと、foreachやparallelといったパッケージも自動で読み込まれます。

```{R}
## インストールしていない場合
# install.package("doParallel")

library(doParallel)
```

### コア数の取得

PCのコア数を自動で取得します。

```{R}
cores <- getOption("mc.cores",detectCores())
```

### クラスターの作成

```{R}
cl <- makeCluster(cores)
registerDoParallel(cl)
```

これでバックエンド側の設定は完了です。


### foreach

次にフロント側の記述です。foreach関数でループ計算を行いますが、その際に %do% の代わりに %dopar% を記述することで、並列化を行います。

```{R}
result <- foreach(i=1:100) %dopar% {
 ## ここに並列化したい計算を入れる
}
```

### 並列化の終了

最後に並列計算の終了を明示します。

```{R}
stopCluster(cl)
```

# 計算速度の比較

では、実例を用いて実際に並列化により計算時間が短縮されるかを見てみます。

今回は、veganパッケージを使ったNMDS（非計量多次元尺度法）という解析を例とします。NMDSとは、多変量のデータを、類似度をもとに２次元などの低次元の空間に配置する方法です。計算方法は違いますが、有名なPCA（主成分分析）と同じような次元圧縮の手法です。

そこで、多数の微生物種のデータを含む仮想のマイクロバイオームデータを作成し、NMDSにより二次元に展開します。NMDSでは、stress値と呼ばれる値が小さいほど当てはまりが良いとされています。そこで、set.seed値を1~100の中からstress値が最小になるようなseed値をループ計算により探索します。このループ計算を並列化する場合としない場合とで、計算時間を比較します。

### veganの読み込みと仮想データの作成

```{R}
## install.package("vegan")
## veganパッケージ
library(vegan)

## 仮想の community-by-species matrix　をランダムに生成
## 行が群集、列が種に相当
community_matrix=matrix(sample(1:100,25000,replace=T),nrow=50,dimnames=list(paste("community",1:50,sep=""),paste("sp",1:500,sep="")))

## 50行×500列の多次元データを作成した
## dim(community_matrix)
## [1]  50 500

## サンプルごとにリードのカウントの総数が異なるので、希釈（rarefy）することによりカウントを揃えています。

rared_matrix <- rrarefy(community_matrix, min(rowSums(community_matrix)))
```

### 並列化無し

まずは、並列化していないループ計算で、計算時間を測定します。計算時間の測定方法はいくつもありますが、ここではtictocというパッケージを使っています。

なお、foreachによるループの特徴として、forと違って出力が一つであるという特徴があります。何も指定をしないデフォルトではリスト形式で各計算結果が出力されますが、今回は行列形式の方が扱いやすいので、引数 **.combine =** に出力の仕方を指定しています。ここでは、結果を縦に結合していく、つまり行方向に結合していくために**'rbind'**を引数に渡します。


```{R}
install.package('tictoc')

## 並列化なし

tictoc::tic()
stress.value <- foreach(i=1:100,.combine = "rbind") %do% {
　set.seed(i)
　nmds<-metaMDS(data.micr,k=2,trymax=50)
　nmds$stress
}

grep(min(stress.value),stress.value)

tictoc::toc()
```

結果は

```{R}
> tictoc::toc()
51.699 sec elapsed
```

**約51秒**でした。

### 並列化あり

今度は、並列化ありのパターンで同じように測定を行います。

```{R}

## 並列化あり

tictoc::tic()
cores <- getOption("mc.cores",detectCores())
cl <- makeCluster(cores)
registerDoParallel(cl)

stress.value <- foreach(i=1:100,.packages='vegan',.combine = "rbind") %dopar% {
　set.seed(i)
　nmds<-metaMDS(data.micr,k=2,trymax=50)
　nmds$stress
}
grep(min(stress.value),stress.value)

tictoc::toc()
```

ここでは、**%do%**を**%dopar%**に変更することで並列化を実施しています。この時、ループの中で使用するパッケージを引数「.packages=''」で指定する必要があることに注意が必要です。library(vegan)をコードしていても、上記の「.packages='vegan'」の部分がないと

```{R}
## " 関数 "metaMDS" を見つけることができませんでした "
```

というエラーが出て、計算が進みません。

さて、並列化をしたときの計算時間は

```{R}
> tictoc::toc()
13.448 sec elapsed
```

**約13秒**でした。並列化なしの場合に比べて５分の１程度に短縮しています💪


***


以上、簡単なコードで並列化ができることを紹介しました。

少しでも参考になれば嬉しいです。
javascriptによる価格フォームの記述から手数料と販売利益の算出方法その１




今回RoRを使用したフリマアプリから値段フォームに記述した値段から販売利益と手数料を計算し、ブラウザに表示させる記述を書きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/7975e146-6f34-eef6-4ea2-8b588c30b7b2.png)


手順その１

算出させるためのjsファイル作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/1942732c-798e-8f75-2865-36a54f1aac6e.png)

・javascriptディレクトリ内に「price_input.js」ファイルを作成



手順その２

application.jsファイルに作成したｊｓファイルを読み込めるようにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/b85c6f2a-ad4b-8131-3bc1-7fa217193efc.png)


手順その３

イベントを起こすための起点としてページのロード時に起こすイベントを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650636/ced10568-21cf-8cac-9f5e-ff69d1b55b32.png)


今回の注意点

・application.jsファイルが入ったpacksディレクトリに入れてしまうとエラーを起こすのでjavascriptディレクトリ似直接作成する。

計算する本イベントのみ書いても対象を得られないのでロード時の
window.addEventListener('load', () => {});
は最初に記述する必要がある
Windows 11 を動かせる仮想化はHyper-Vだけではなかった

* 
VirtualBoxで色々試してみたが無理でした。セキュアブートの項目も見当たらず。

    * https://uupdump.net/ から取得できる `22000.65_amd64_ja-jp_multi_f19ccfd6_convert.zip` の`uup_download_windows.cmd`で作られるISOを使えばインストールできる様子。

* Hyper-Vは対応していた。(Windows 10 pro 21H1 にて確認)

https://news.mynavi.jp/article/20210630-1912120/

![win11.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/311afd39-d525-b0be-499d-f664f3cfb1d5.jpeg)


## Hyper-Vのメリット

CPU使用率が圧倒的に低い (VMWare、VirtualBoxと比較)

https://pmp-style.hatenablog.com/entry/VmHDDBench#%E3%81%BE%E3%81%A8%E3%82%81

## Hyper-Vのデメリット

* デュアルモニターにできない（？）
    * （VirtualBoxではできる。）


## Windows 10 Home でHyper-Vをインストールする方法

https://zeropasoakita.livedoor.blog/archives/37449396.html

```dosbatch:enable-hyperv.bat
pushd "%~dp0"

dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt

for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"
del hyper-v.txt

Dism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL
```

* `optionalfeatures.exe`でHyper-Vを有効にする

## Hyper-V

* `Hyper-V`をインストール
* `Hyper-V マネージャー`を起動
* クイック作成
* メモリが2048MBになっているので4096MBにする
* ISOファイルはSMBv1のサーバー上のものは利用できない様子。ローカルにコピーしておく

## vhdxの圧縮方法

* PowerShell を管理者権限で実行
* vhdxファイルがある場所で以下実施

```dosbatch
optimize-vhd -Path win11* -Mode Full
```
std::vectorチュートリアル

C++の標準ライブラリには`vector`という配列の便利なバージョンみたいなのがあります。
いきなり例を示していきます。以下では全て`iostream`と`vector`をincludeした上で試してみてください。

```C++
#include <iostream>
#include <vector>
```

vectorを作ってfor文で回してみる

```C++
std::vector<int> v = {2, 4, 6, 8, 10};
for (int i = 0; i < 5; ++i) std::cout << v[i] << "\n";
```

(ちなみに`std::vector<int> v;`と宣言すれば要素数0のvectorができます。)
`at`でも参照できる

```C++
for (int i = 0; i < 5; ++i) std::cout << v.at(i) << "\n";
```

`at`を使うと存在しない要素(i=8番目とか)を参照しようとするとちゃんとエラーメッセージを出してくれます。そのチェックのために少し動作が遅くなるけど。


vectorの末尾に値を加える

```C++
v.push_back(12);
for (int i = 0; i < 6; ++i) std::cout << v.at(i) << "\n";
```

要素数を知る

```C++
std::cout << v.size() << "\n";
```

1から100000までの自然数の中から7の倍数だけをvectorに詰めよう。

```C++
std::vector<int> v;
for (int i = 1; i <= 100000; ++i) {
  if (i % 7 == 0) v.push_back(i);
}
```

実はこれだと`push_back`の度にいちいちメモリを確保する動作が内部的に入って無駄に時間がかかります。先に必要な要素数に対応するメモリを`reserve`で予約しておこう。これで速くなります。

```C++
std::vector<int> v;
v.reserve(20000);
for (int i = 1; i <= 100000; ++i) {
  if (i % 7 == 0) v.push_back(i);
}
```

ここで`push_back`される要素の数は予約した20000より少ないですが大丈夫です。例えば10000要素分だけ`reserve`するとかでも大丈夫です。ざっくりとでOK。
このvectorの中から1000の倍数だけ出力してみましょう。

```C++
int length = v.size();
for (int i = 0; i < length; ++i) {
  if (v[i] % 1000 == 0) std::cout << v[i] << "\n";
}
```

for文の条件式で要素数分繰り返すような工夫をしているのは1つのポイント。
あと些細なことですがif文の条件式のところは`if (!(v[i] % 1000))`と書き換えても同じ結果になりますね。
(ちなみにさっきから改行で`"\n"`を使っていますが、これは`std::endl`よりもちょっと速いです。`++i`と前置インクリメントにしているのも一応速さを意識していますが、これは後置でもあまり変わらないかも)
`length`を定義せずにfor文のところで

```C++
for (int i = 0; i < v.size(); ++i) {...}
```

としたい人がいるかもしれませんが、for文の繰り返しの数だけ`v`のサイズを計算させることになってしまい処理が遅くなるのでやめておきましょう。

上記でfor文の条件式について色々書きましたが、vectorの要素を最初から最後まで見たい時は範囲ベースfor文を使ってみましょう。

```C++
for (auto&& x : v) {
  if (!(x % 1000)) std::cout << x << "\n";
}
```

こうすると`length`なんて定義しなくて良いしfor文の条件式についても悩む必要はなくなります。さらに、処理がとても速くなります。

ループの途中で例えば1000の倍数の時だけ要素の値を5に更新するとかもできます。

```C++
for (auto&& x : v) {
  if (!(x % 1000)) x = 5;
}
```

一方、このような値の書き換えをせずに先程のcoutの時みたいに単に要素を参照するだけならば、const修飾子を使うとさらに速く処理できるらしいです。

```C++
for (const auto& x : v) {
  if (not (x % 1000)) std::cout << x << "\n";
}
```

`!`を`not`に書き換えてみました。全く同じ動作をします。
vectorを空っぽにして最初の状態に戻すにはこうしましょう。

```C++
v.clear();
v.shrink_to_fit();
```
自作エラーの定義の仕方

# まずは定義

```python
class err(Exception):
    pass
```

Exceptionクラスを継承するだけで自作エラーが定義できます

# 自作エラーを発生させる

```python
class err(Exception):
    pass

raise err('エラーメッセージ')
```

raise エラー でわざとエラーを発生させることができます
すると

```
Traceback (most recent call last):
  File "Main.py", line 4, in <module>
    raise err('エラーメッセージ')
__main__.err: エラーメッセージ
```

こんな感じのエラーが表示されます


もちろんtry-exceptでエラーをキャッチすることもできます

```python
class err(Exception):
    pass

try:
    raise err('エラーメッセージ')
except err as e:
    print(e)
```

```python
エラーメッセージ
```

# オマケ

```python
class err1(NameError):
    pass

class err2(KeyError):
    pass

class err3(IndexError):
    pass

class err4(OSError):
    pass

class err5(SyntaxError):
    pass
```

Exception以外でもエラーであればなんでも継承することができます(なぜかSyntaxErrorも継承できる)

インデックスとか何も間違ってないのにSyntaxErrorが出てきたら怖いし夢に出てきそうなのでSyntaxErrorは継承しない方がいいと思います
Python モジュールの互換性を保つ方法

# はじめに
主な実行環境はPython3系を想定しています。
Pythonの互換性を保つ方法は様々ありますが、ここでは特にモジュールについての互換性の保ち方を記載します。

# モジュールがインストールされていない環境との互換性
インストールされていなくても動作に大きく影響しないモジュールがインストールされていない場合に、そのモジュールをインストールせずとも動作可能にするには以下のようにする。

```python
# not installed compatibility
try:
    from tqdm import tqdm
except ImportError:
    tqdm = lambda x:x

# example
for i in tqdm([1,2,3]):
    print(i)
```
tqdmモジュールがインストールされていない場合、```tqdm([1,2,3]) -> [1,2,3]```となり、プログレスバーは表示されないが、動作に支障はきたさない。

# Python2系との互換性
機能はほぼ同じだが、名前が異なっているモジュールをインポートする。

```python
# python version 2 compatibility
try:
    from urllib.parse import unquote
except ImportError:
    from urllib import unquote
```
メソッド名やクラス名が異なっている場合は、以下のように```as```を活用する。

```python
try:
    from A import B as C
except ImportError:
    from D import E as C
```
[Rails]Turbolinksをページごとに無効化する方法

## 環境
ruby 2.6.6
Rails 6.0.3

## はじめに
Railsでページ後にTurbolinksを無効化する方法について解説します。


## 本題

`application.html.erb`の`body`タグの一番上に以下を記述します。

```:app/views/layouts/application.html.erb
# ここから追加
<div 
  <% if content_for?(:body_attributes) %>
    <%= yield(:body_attributes) %>
  <% end %>
>
# ここまで

<%= render "layouts/header" %>
  <%= yield %>
<%= render "layouts/footer" %>

#閉じタグも忘れずに
</div> 
```
パーシャルを使ってる場合はしっかりとdivタグの下に記述してください

次にTurbolinksを無効化したい`view`に下記を追加します。

```:例(top.html.erb)
<% content_for(:body_attributes) do %>
    data-turbolinks="false"
<% end %>
```

以上で実装できます。
yahoo株式　ある特定銘柄をコマンドラインでみるシェル


xxxx.Tは、銘柄コードです。jqコマンドのインストールが必要です。

--- file ---
\#!/bin/bash
cur=$(curl -s https://finance.yahoo.co.jp/quote/xxxx.T|sed 's/[&;"]/\n/g'|grep stock_price|uniq|grep -o '[0-9]\+')
echo $cur
pre=$(curl -s https://finance.yahoo.co.jp/quote/xxxx.T|grep -m1 PRELOADED|sed s/window.__PRELOADED_STATE__//|sed s/=//|jq|grep closePrice|tail -1|grep -o '[0-9]\+')
echo $pre
echo $((cur-pre))
残プロ　第-32回　~HTMLの子要素を取得する~

# for文を意識したHTML

## task.csv

![task_csv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578927/0ab873e8-afc9-e231-b9c1-3ee24ad100a7.png)

## .html

前々回でjinja2によるテンプレートfor文を利用しました．
id指定の際，個別にするのでなくテンプレートを使用することで利便性が高まります．


~~~ html:
<tbody>
    {% for task in tasks_csv[1:] %}
    <tr id={{ task[0] }}>
        <th scope='row'>{{ task[1] }}</th>
        <td>{{ task[2] }}</td>
        <td>{{ task[3] }}</td>
        <td>{{ task[4] }}</td>
        <td>{{ task[5] }}</td>
        <td>
            <div class="form-group">
                <select class="form-control" onchange="replaceForm();">
                    <option value="">-</option>
                    <option value="Edit">Edit</option>
                    <option value="Delete">Delete</option>
                </select>
            </div>
        </td>
    </tr>
    {% endfor %}
</tbody>

<script>
    let row;
    let select;
    let col_1;
    let tasks = {{ tasks_csv|tojson }}
    let len = tasks.length

    function replaceForm(){
        for (let i=1; i<len; i++){
            row = document.getElementById(tasks[i][0]);
            console.log(row.children)
        }
    }
</script>
~~~

ここで注意なのですが，JavaScriptの関数内でjinja2のテンプレートは使用できません．新たに配列を用意しjson化したのち，代入することで利用できるようになります．