OmniAICreator/Qiita-1.07M huggingface dataset:
Expo * FirebaseのAuth認証のDocsでエラーが出たので修正案


Expo上のReactNativeで、FirebaseのAuth認証を使ったアプリ開発をしようとしていたのですが、
公式Docsが少なく、いろいろ手こずったので、初動だけ備忘メモしておきます。


#ExpoとReactのバージョン
```
"react": "16.13.1",
"expo" : "4.3.2"
```

#Firebase上であらかじめユーザーを一つ作っておく

GUIでポチポチ作れます。
![20211003_Qiita投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292076/d7a28f1a-d176-aac4-a097-ba6fe2f9d9d5.png)

#Firebaseを参照する
Signinメソッドだけ（Signupメソッドも同様のため）
問題点はimport箇所。公式Docsに書いてあるimportが使えなかったため、色々試した結果、これで通りました。

```Typescript:firabase.tsx
import firebase from "firebase/app";
import "firebase/auth";
import Constants from "expo-constants";

firebase.initializeApp(Constants.manifest.extra.firebase);

export const signin = async (email: string, password: string) => {
    try {
        const userCredential = await firebase
            .auth()
            .signInWithEmailAndPassword(email, password);
        console.log(userCredential);
    } catch (err) {
        console.log(err);
    }
};
```

#Loginする
最初にレンダリングしたときに、ログインしてみる。

```Typescript:AuthScreen.tsx
import React, { useEffect } from "react";
import { StyleSheet, SafeAreaView, Text } from "react-native";
import { signin } from "../lib/firebase";

export const AuthScreen: React.FC = () => {
    useEffect(() => {
        signin("XXXXX", "YYYYYY");
    }, []);

    return (
        <SafeAreaView style={styles.container}>
            <Text style={styles.text}>ログイン中...</Text>
        </SafeAreaView>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: "#fff",
        alignItems: "center",
        justifyContent: "center",
    },
    text: {
        marginTop: 16,
        fontSize: 12,
        color: "#888",
    },
});

```

UserCredentialが返ってきて、問題なくログイン成功

```
Object {
〜〜〜
    "isNewUser": false,
    "providerId": "password",
〜〜〜
  "operationType": "signIn",
  "user": Object {
〜〜〜
    "email": "XXXXX",
    "isAnonymous": false,
〜〜〜
    "providerData": Array [
      Object {
        "displayName": null,
        "email": "XXXXX",
〜〜〜
      },
    ],
〜〜〜
}
```


#公式Docs

1　Expo公式ドキュメント　Firebase認証

https://docs.expo.dev/guides/using-firebase/

2 Firebase公式ドキュメント　Webアプリにおける認証

https://firebase.google.com/docs/auth/web/start?hl=ja

#終了
[Rails]has_one_attachedもしくはhas_many_attached

##初めに
####この記事の対象者
アプリケーションに画像を添付したいヒト用

####環境
・Macbook Air (Retina, 13-inch,2019)
・プロセッサ 1.6GHz デュアルコアIntel Core i5
・メモリ　8GB 2133 Mhz LPDDR3
・MacOS Big Sur　バージョン 11.5.2

####記事の目次
**１）なにができるか**
**２）前提条件**
**３）どうやってつかうか**
**４）最後に**

##なにができるのか
####画像を追加できるようなシステムを利用して、画像を添付させることができる

##前提条件（詳しくは→作成中）
**１）画像を追加できるようなシステムを作る**
####(例：商品のテーブル）
![producttablesample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/4e9f3cd6-5421-76b9-67a1-a87565289f3a.png)
####（例：画像１枚追加システム）
![oneimagesystem.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/71a13369-7afc-a859-8206-7f40885eca5d.png)
####（例：画像複数枚追加システム）
![manyimagesystem.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/2adf303a-a9a2-e7ab-38af-b2afaa6ff16f.png)
####（フォーム内を保存させる設定）
![createactionsample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/ce248ac1-af8a-c8d8-16d7-9acb8b235cba.png)

**２）表示させたい場所を作る**
![addingimagesystem.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/64205400-e905-7bd2-6646-8d5b0bb752e6.png)


##どうやって使うのか
####userが画像追加システム記入後、createアクションでDBに保存するとき画像も一緒にという設定をmodelに書く！今回の場合はproductのviewｓでフォームを使って画像を保存しているから→→→model:productにアソシエーションを組む。

**（注意）複数枚の場合はimage→imagesとなる**

**1)画像が一枚の場合**

```ruby
has_one_attached :image
```


**２）画像が複数枚の場合**

```ruby
has_many_attached :images
```

##最後に
**今まで、アソシエーションを組むときは他モデルと他モデルで組んでいたのに画像のモデルは無いのにどうやって関連付けるのだ？って混乱してしまったけどDBに保存はされないが関連付けされたモデルと手をつないでいる状態と考えるようにしました。**

**ココまで読んでくださいましてありがとうございました！**
S3のアプリケーションコンテンツの保存

# アプリケーションコンテンツの保存

## アクセスコントロールリスト
- 静的Webサイトで活用する際に、パブリック公開する

## バケットポリシー
- アクセスコントロールリストより詳細なアクセス権限を設定

## 署名付きURL
- オブジェクトをURLを知っていれば誰でもダウンロードできる設定
- AWS SDKの各言語でコードを記述して生成

## CORS(Cross-Origin Resource Sharing)
- 静的Webサイトなどで他のバケット(ドメイン)のオブジェクトを使用する際に使用
WebDAVとは

## 勉強前イメージ

FTP的な機能もあるみたいな話だった気がする

## 調査

### WebDAV とは

HTTPの拡張で、サーバ内のファイルやディレクトリの管理を直接行うことができる機能になります。
よくwebサーバとファイルをやり取りする手段で使われるのがftpですが、それを代替できるのがWebDAVになり、
サーバのファイルをローカル端末のようにブラウザ上で編集・更新出来ることで利便性が高まります。

### WebDAVのメリット

- シンプル

httpベースなので構成がシンプルで、
webコンテンツのアップロードを容易にWebDAVで実装できます。

- セキュリティ向上が容易

セキュリティの向上はhttpと考え方を流用可能で、80番ポート・443番ポートを使用するため、FTPなどと比較すると接続許可するポートは少なくて良いです。
また、firewallやルーターの設定を気にすることなく利用できます。

- OSや実装に依存しない

httpの拡張なので特定のOSなどに依存する仕組みはなく、
複数のOS上で実装が可能です。

## 勉強後イメージ

## 参考

- [WebDAVとは？](https://academy.gmocloud.com/keywords/20170310/4148)
- [技術仕様徹底解説](https://atmarkit.itmedia.co.jp/ait/articles/0109/22/news002.html)
EC2にデプロイしたロゴ画像が表示されない

件の[ポートフォリオ](https://qiita.com/ryo1103/items/973d05c52b2adb3e84b2)を作成後、`heroku`にてデプロイし次に`AWS`へのデプロイに挑戦しました。
その際に`app/assets/images`下にあるロゴ画像が表示されなかった時の対処の話です。（下記参照）
![スクリーンショット 2021-09-03 19.00.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748419/be2d3a51-3d89-cf7b-c4ac-b0fe72935d1b.png)

# 目次
1. `heroku`でも起きていた現象
1. `AWS`では、原因が異なる
1. 今回の解決策

## herokuでも起きていた現象

- 画像が読み込まれない現象は`heroku`の初期でも起きていました。
- 原因はプリコンパイル関連でサクッと解決。
    - 【参考】 [【Heroku】本番環境でアプリに導入している画像が表示されない場合の対応方法(Ruby on Rails)](https://note.com/become_engineer/n/n845339e9d128) 

## AWSでは、原因が異なる

```読み込みミスした記述.
 <%= link_to root_path, class: "navbar-brand" do %>
    <img class="logo"src="/assets/images/ロゴ.png">
 <% end %>
```
- 検証の`console`には`404`が表示されていたのでパスが違うみたい
- 色々渡り歩くき、以下の内容を見つける
  - 参考：[[Rails]本番環境で画像が表示されないエラーについて](https://qiita.com/yamato1491038/items/7f80e642ac373733bf96#%E5%8E%9F%E5%9B%A0)

> 本番環境では、画像もコンパイルされ、画像ファイル名が変わりディレクトリも変わってしまいます！

- `assets_path`が有効らしいと判明


## 解決策
- [Railsガイド](https://railsguides.jp/asset_pipeline.html#:~:text=%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%A8CDN%E3%81%AE%E8%A8%AD%E5%AE%9A%E5%AE%8C%E4%BA%86%E5%BE%8C%E3%80%81%E4%BB%A5%E4%B8%8B%E3%81%AE%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%82%92%E6%8C%81%E3%81%A4Web%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%97%E3%81%9F%E3%81%A8%E3%81%97%E3%81%BE%E3%81%99)を参照し,`assets_path`の使い方を見る。
- `iimage_tag`と`assets_path`で組める。
完成コードは以下

```.erb
　<%= link_to root_path do %>
　　　<%= image_tag asset_path('ファイル名.png') %>
　<% end %>
```

これで`local`も`production`も無事表示されました。
Windowsでpipenv

venvに引き続きこっちも簡単な導入方法の記載

# 環境
Windows10
python 3.9.4

# コマンド

## pipenv インストール
``` shell
python -m pip install pipenv
```

## pipenv プロジェクト化

※プロジェクトにしたいフォルダに事前に移動して

``` shell
python -m pipenv --python 3.9
```

## パッケージインストール
``` shell
python -m pipenv install [packege]
```

例）

``` shell
python -m pipenv install algorithms
```

## プロジェクト環境に入る
``` shell
python -m pipenv shell
``` 

※powershellだと、仮想環境に入ったときにプロジェクト名が出ないためわかりにくい、、
※cmdだと先頭にカッコ書きでプロジェクト名がつくためわかりやすい

# 補足
一応、pipenvのプロジェクトでインストールしたパッケージがプロジェクト外で使えないことは確認しています
MacでChrome/Profile/FileSystemの不要なデータを削除する方法メモ

# 概要
Macでストレージの空きを増やすためにデータ量の多いディレクトリを調べていたところ、 `/Library/Application Support/Google/Chrome/Profile 1⁩/File System` が大きかったため、削除する手順をメモしておく。

# FileSystemの中身は何か
Chromeの拡張機能で使用するデータらしい。
インストールしている拡張機能のいずれかでキャッシュしているデータが多いなどが原因で、FileSystemが肥大化するものと思われる。
FileSystem直下のディレクトリは、例えば `000` などの数字がディレクトリ名となるが、その下にはキャッシュした画像ファイルが並んでいたりする。

# 削除手順
数字のディレクトリの中身をざっとみたところ、自分の場合はGoogleスライドのキャッシュ（主に画像）が原因だとわかったため、Googleスライドのキャッシュを削除して対応した。
具体的な手順は以下の通り。

## 1. 適当なスライドを開いて、左上の鍵マークから「サイトの設定」を開く
|![手順1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304453/2c05f215-923f-05f5-1255-430f25967838.png)|
|:-:|

## 2. 「データを削除」を押す
|![手順2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304453/1b07992b-ba58-f107-1581-7827860017de.png)|
|:-:|

# docs.google.comのデータとは
おそらく拡張機能の「Google オフライン ドキュメント」でローカルにダウンロードしたキャッシュのことだと思われる。
そのためGoogleオフラインドキュメントを無効化しないと、再度Googleドキュメントを開いた際にキャッシュされてしまうため注意。
eclipseで作業中のprojectがwindowsエクスプローラに表示されない

#背景 ― back ground ―
windows10，eclipse，springBootでjavaのアプリケーションを作成中のこと。
途中まで作成したらworkspaceのフォルダごとコピーし、
複製したフォルダの名前を適当に変え、それを新たなworkspaceとして作成を続ける、ということを繰り返した。
###なぜそんなことをした？
途中で変なになったら戻れるように履歴を残したかった。gitにするのがめんどかった。
それまでは同じ履歴を残すにも、プロジェクトを新しいworkspaceにインポートしてたが、
上記の様にworkspaceのフォルダごとコピーするとプロジェクトをインポートせずに作業ができたので、
これは楽でいい、と

#起きちったこと ― incident ―
eclipse上で引き続き作成していた所（当然のことながらeclipseのパッケージ・エクスプローラには表示されている）、
windows10のエクスプローラでworkspaceの中を見ても、いるはずのプロジェクトが表示されない。
（windows10のエクスプローラの機能「隠しファイルの表示／非表示」とは無関係）
eclipseのプロジェクトをインポートする機能を使っても、（インポート可能なプロジェクトとして表示されるはずが）表示されない。

#解決  ― solution ―
eclipseのパッケージ・エクスプローラで、問題のプロジェクトのプロパティ・ダイアログを表示させると、
ロケーションのパスが何代か前のコピー元workspaceのパスではないか。
（プロジェクトのプロパティ・ダイアログを表示させるには、
eclipseのパッケージ・エクスプローラでプロジェクト名を右クリック
→ メニューから『プロパティ』を選択）
そしてどうやらその何代か前のコピー元workspaceから、workspaceのフォルダごとコピーするということを始めていた。
何代か前のコピー元workspaceをeclipseで開き、問題のプロジェクトを見ても、作成を止めた以降の更新はされていない様子。
しかしwindows10のエクスプローラでそのプロジェクトを見ると、さっきまでやってた更新がされてる！

そこで、まず問題のプロジェクトをeclipseのパッケージ・エクスプローラから削除し、
つぎに（windows10のエクスプローラ上で）何代か前のコピー元からコピーしてきたプロジェクトを作業中のworkspaceに置いて、
最後にeclipseでインポートしたら表示される様になったし、これまでの更新も失われなかった（よく見てないけど多分）。

workspaceごとコピーしちゃうと中のプロジェクトはシャローコピー（浅いコピー）となり、
参照元が更新されていた、という話だね。
履歴を残すというのもできてなかった訳で、まあ楽しようとして結局回り道。なんともシャローなことやってたね。ww
負け惜しみを言えばこういうのは確実に勉強にはなる。
今後もやはり履歴を残したいので
(1) おとなしくプロジェクトをインポートするか、
(2) git導入だな。
触感デバイス開発モジュールをArduino MKR ZEROで使う

#・はじめに
ビット・トレード・ワンから販売されている触感デバイス開発モジュール(https://btoshop.jp/products/hapstak) はi2s規格の音声再生によりマイコンボードと接続して簡単に触覚作品を作ることができるモジュールです。マイコンボードは M5 ATOM シリーズと Arduino MKR ZERO であればボードのピンにそのまま接続して動かすことができます。
Arduino MKR ZEROを使って触感デバイス開発モジュールを動かしてみたいと思います。

#・Arduino Maker Zeroのセットアップ
ボードマネージャーから「Arduino SAMD boards」をインストールする必要があります。
１．	ツール＞ボード＞ボードマネージャーを選択
２．	Zeroと検索するとArduino SAMD boardsが出てくるのでそれをインストールします。
３．	ツール＞ボード＞Arduino SAMD＞Arduino MKRZEROを選択
これでArduino maker zeroに書き込むことが可能となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1703667/10f939ac-0191-54e2-2538-240d61c2e357.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1703667/7d737a06-9432-3ded-375d-764e16cbc39f.png)


音声処理に関わるArduinoのサンプルが紹介されているサイト(https://tigoe.github.io/SoundExamples/) からI2S, the Inter-IC Sound Protocol>WAV file playback with potentiometer volume controlを開きます。このGitHubに公開されているコードをダウンロードします。(ダウンロードはこの上流のSoundExamplesから行うことができます。ダウンロードしたファイルの中から ArduinoSound_Examples> WaveVolumeControl> WaveVolumeControl.inoを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1703667/3a5b9ffb-e890-9889-9e64-169f6ddbf2ba.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1703667/8b7375f0-2ad2-f442-5635-a7a1aa270191.png)

WaveVolumeControl.ino を実行するためにArduinoSoundというライブラリーが必要です。
そこでライブラリーを管理＞ライブラリーマネージャーからこのライブラリーを検索してインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1703667/8af54d96-b4d4-8860-395a-49cdaa1e0d84.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1703667/d2d319bf-373f-60e5-0169-f2baae8e9499.png)

WaveVolumeControl.ino では Arduino のアナログ入力 A0 の入力値に応じて音の大きさをコントロールするものなので、ここではしたから4行目の
  AudioOutI2S.volume(loudness);
を
  AudioOutI2S.volume(100);
に変更して常に最大のボリュームで音が鳴るようにします。

このプログラムを Arduino MKR ZERO に書き込むことによって、Arduino MKR ZERO に挿入されたSDカードのルートある"SOUND.WAV"という音声ファイルで触感デバイス開発モジュールを振動させることができます。
※挿入するSDカードのファイルシステムはFAT16、FAT32である必要があります。
[Rails]アソシエーションについて

##初めに
####この記事の対象者
**railsでのプログラミングがはじめまして人向け**

####環境
・Macbook Air (Retina, 13-inch,2019)
・プロセッサ 1.6GHz デュアルコアIntel Core i5
・メモリ　8GB 2133 Mhz LPDDR3
・MacOS Big Sur　バージョン 11.5.2

####記事の目次
**１）modelってなんだ？**
**２）modelですること[基本]**
**3）最後に**

##modelってなんだ？
**主にデータベースへ情報を保存したり、保存する情報にルールをつけて制限する場所**
**→model名と同じテーブルへと情報が保存される**
**→(例えば)保存するデータは半角英数字であるべきとルールをつければ、一致できない場合保存不可能になる**

##modelですること[基本]
####アソシエーションを組む(関連付け)
**複数のテーブルがある場合、アソシエーションを組むことでお互いの情報を共有できるようになる！**

**belongs_toの場合（単対単）**
![belongs_to sampleer .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/b104a1f9-9655-de8f-1778-7a579ae47841.png)

```
（BモデルがAモデルに所属しているとき！）
(table:authorから見て)belongs_to: books
(table:addressから見て)belongs_to: usersｘ
```


**has_oneの場合（単対単）**
**（例：通販サイト）**
![er_has_onesample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/c34a7ba1-9a13-ed0c-6a17-638173b28930.png)

```
(BモデルがAモデルを一つだけもっているとき！)
(table:productsから見て)
belongs_to :user
has_one :payed_history

(table:usersから見て)
has_many :products
has_many :payed_histories
has_one :order

(table:ordersから見て)
belongs_to :payed_history

(table:payed_historyから見て)
belongs_to :product
belong_to :user
has_one :order
```

**has_manyの場合（単対多）**
**注意：has_manyを使う場合、対象となるテーブルは複数形となる**

```
（上記の通販サイトER図を参考に→user一人に対して多数の商品を持つの関連付け）
has_many :products
```

##最後に
この他にもアソシエーションは存在するが、この３つをよく使っている。記事を書いて、ちょっとよくわからないところがあるきがするが一度投稿して時間をおいて理解を深めたら再度編集しようと思ってます。。

ココまで読んでくださいましてありがとうございます！
フルトラ時に左足つま先が上に折れ曲がることへの対応例（ VRChat ）

:::note
下記のように修正したアニメーションを作成することで改善しますが、今度は移動時のモーションが床を滑るようなものになってしまいます。
諸々解決するにはきちんと歩行モーションを作成しないといけないようです。
:::
(2021.11.29 追記)
修正したアニメーションを用意しました。[こちら](https://minadukitei.booth.pm/items/3463812 "無料あり】フルトラでしゃがんでも爪先が上に曲がらないように頑張る移動アニメーション【SDK3専用】")からダウンロードできます。
自然なアニメーションではないと思いますが、修正アニメーションの作成が面倒な方はご利用ください。
(2021.11.29 追記ここまで)
# はじめに
どうも。「バーチャルためにならない改変お姉さん」の水無月せきなです。
今回はVRChat のアバター、特にフルトラ（フルボディトラッキング）時において顕在化する問題への対応についてです。

# 環境
VRChat : VRChat 2021.3.4p2
SDK    : VRCSDK3-AVATAR-2021.09.03.09.25_Public
Unity  : 2019.4.30f1
OS     : Windows 10 ( 20H2 )

# フルトラで床に座っているとつま先が上に折れ曲がる
下の写真をご覧ください。
![VRChat_1920x1080_2021-10-02_20-57-44.193.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/eaf08deb-138c-b4d9-6754-5c406b6ce1fd.png)
__つま先がありえないくらいに折れ曲がっています。__
Twitterでも同様の呟きを見ることができるかと思います。また、回避策として、移動モーションをフルトラ時に再生しないようにするような方法が紹介されていたのを見た記憶があります。
しかし、移動モーションを再生しなければ発生しないのであれば、移動モーションに問題があるのでは？　と引っかかりました。

# 対応
結論から言えば、やはり移動モーションが原因でした[^1]。
![Proxy_animation.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/f2076c49-9544-6848-e68e-df5b6c6989eb.png)
こちらは VRChat のデフォルト移動モーションの一つ、proxy_low_crawl_Still というアニメーションのプレビューです。
見事に左足のつま先が曲がっています。
おそらく、つま先が地面に接している状態の表現（つまり本来は自然なモーション）だと思うのですが、修正します。
![Tab_Animation.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/a58a54e9-5f60-b465-df68-b97ad0916732.png)
アニメーション内の ` Left Toes Up-Down ` の値を `0` にすれば、曲がらなくなります。
![Fixed_Animation.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/f8d5537b-f663-14b7-3944-20bbb73ccf50.png)
厄介なのは、修正するアニメーションは ` proxy_low_crawl_Still ` だけではありません[^2]。
移動モーションはブレンドツリーになっており、他のモーションでも ` Left Toes Up-Down ` は使われています。` Crouching ` だけでなく `Prone` で使われているアニメーションもです。
また、左右の移動はミラーで実装されているため、右足側も設定し直しておいた方が良いかと思います。

という訳で、対象アニメーションは

* proxy_crouch_still
* proxy_crouch_walk_forward
* proxy_crouch_walk_right
* proxy_crouch_walk_right_45
* proxy_crouch_walk_right_135
* proxy_low_crawl_still
* proxy_low_crawl_forward
* proxy_low_crawl_right

対象プロパティ（値を０に設定）は上記のアニメーション内の

* Left Toes Up-Down
* Right Toes Up-Down

です。修正したものを設定すれば完了です。
![VRChat_1920x1080_2021-10-02_20-58-21.164.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/10c0e430-0f15-d1b2-f11f-cad4f591f16f.png)
これでフルトラでしゃがんでもつま先が曲がりません[^3]！

# おわりに
既に他の方が言われているような気がするのですが、パッと見た限りでは見つからなかったので書きました。
修正した Animator Controller を配布しようかとも思ったのですが、VRChat のデフォルトから変える箇所が少なく、配布にあたって問題が無いか確信がありませんでしたので、記事で述べるにとどめておきます。

[^1]: モデルによって曲がり方に違いがある気がするので、より根本的な原因は別なところにあるかもしれません。
[^2]: このアニメーションと Prone で使用している `~_Still` を修正すればだいぶ改善しますが、移動した際に一瞬屈曲することがありました。
[^3]: フルトラで気付いただけで、デスクトップモード時にもなっていたのかなとは思います。
M5Stack Core2: LED の使い方

こちらのページを参考にしました。
[[M5Stack Core2 for AWS] ArduinoでLED (Adafruit NeoPixel フルカラーLED) を点灯してみました](https://dev.classmethod.jp/articles/m5stack-core2-for-aws-arduino-sk6812/)

![IMG_20211003_150743.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/5e76a2c0-6681-06fd-1a85-46f56ef7fbfd.jpeg)

![IMG_20211003_150019.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/03088b67-43d0-100e-af3d-ecb1f3a21b83.jpeg)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/e9c155bd-d67b-5ea4-6cb3-ef5e76b0a066.png)

```text:led01/led01.ino
// ---------------------------------------------------------------
/*
	led01.ino

						Oct/03/2021
*/
// ---------------------------------------------------------------
#include <M5Core2.h>
#include <Adafruit_NeoPixel.h>
#define PIN 25 
#define NUMPIXELS 9 //LEDの数を指定
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //800kHzでNeoPixelを駆動

int icount = 0;
// ---------------------------------------------------------------
void setup() {
	Serial.println("*** setup *** start ***");

	pixels.begin(); //NeoPixelの初期化

	M5.begin();
	M5.Lcd.setTextSize(3);
}

// ---------------------------------------------------------------
void loop() {
	Serial.println("*** loop *** " + String(icount));
	pixels.clear(); // NeoPixelのリセット
 
	for(int it=0; it<9; it++){
	int jt = it -1;
	if (jt < 0)
		{
		jt = 8;
	  	}

	if ((it % 3) == 0)
		{
		pixels.setPixelColor(it, pixels.Color(0, 150, 0));
		}
	   else if ((it % 3) == 1)
		{
		pixels.setPixelColor(it, pixels.Color(0, 0, 150));
		}
	else
		{
		pixels.setPixelColor(it, pixels.Color(150, 0, 0));
		}

	pixels.setPixelColor(jt, pixels.Color(0, 0, 0));
	pixels.show();	 //LEDに色を反映
	M5.Lcd.setCursor(0, 0);
	M5.Lcd.printf("LED Sample %d",it);
	delay(2000);
	icount++;
	}
}

// ---------------------------------------------------------------
```

Arduino IDE 2.3.4 で確認しました。
javaで2つのSetの要素を足したい時の書き方あれこれ

2つのSetの要素を足したい時があり、その時に実装悩んだので共有です。
オススメ度順に上から並べています。

## GuavaのIterablesを使う

一番スッキリしてる気がする

```java
return Sets.newHashSet(Iterables.concat(hashSet1, hashSet2));
```

https://guava.dev/releases/21.0/api/docs/com/google/common/collect/Iterables.html#concat-java.lang.Iterable-java.lang.Iterable-

## それぞれStreamにしてからStream.concat()でつなげる

王道な気がする

```java
return Stream.concat(
    hashSet1.stream(),
    hashSet2.stream())
    .collect(Collectors.toSet());
```

## SetのStreamをflatMapでStreamをつくる

ちょっとぱっと見わかりにくい気もする

```java
return Stream.of(hashSet1, hashSet2)
    .flatMap(Collection::stream)
    .collect(Collectors.toSet());
```

## Set.addAll()を使う

戻り値がbooleanなのが残念・・・
`return set1.addAll(set2);`みたいな感じに書きたかった。

```java
Set<String> result = new HashSet<>();
result.addAll(set1);
result.addAll(set2);
return result;
```

# 補足：速度検証

それぞれの速度を検証してみました。
100個のランダムな1000以下の数字のStringのSetを足しています。
1000000回演算を行って、平均から時間を取得しています。

```
5240ns
4002ns
4162ns
3974ns
```

結果は、最初のGuavaを使う場合が微妙に遅いですね。
1.5倍弱なのでそんなに差は無い気もしますが頭の片隅にいれておいてもいいかもしれません。

速度検証のソースコードは以下に配置しました。

https://github.com/okaponta/playground/blob/master/collections/src/test/java/AddSetsTest.java#L56

## 追記

中央値の方が速度の評価にはよいとFB受けたので中央値も計測してみました！

```
5043ns
3827ns
4033ns
3868ns
```
PICTとPictMasterでのサブモデル生成の違い

# はじめに

組合せテストを行うときに因子間網羅を満たすテストケースを作るために、PICTやPictMasterといったツールが使われます。

網羅条件として2因子間網羅や3因子間網羅がよく選択されます。ですが、場合によっては「組合せの一部の条件を3因子網羅、それ以外の条件を2因子網羅」といった網羅条件を変えた組み合わせを生成したくなる場合があります。PICTやPictMasterではそれを実現するために「サブモデル」という機能を利用します。

ですが、PICTとPictMasterではサブモデルで生成される組合せに違いが生じます。PictMasterは内部でPICTを使う場合がありますが、サブモデル生成は独自の処理を行っているようです。

PICTはこちら

https://github.com/Microsoft/pict/blob/main/doc/pict.md

PictMasterはこちら

https://ja.osdn.net/projects/pictmaster/

# 結論

以下にあるサブモデルを用いた例題をPICTおよびPictMasterで実行しました。扱った例題ではPICTは16ケース、PictMasterは9ケースを生成しています。

> 例題：パラメータA,B,C,D,Eでそれぞれ2つの値の候補を持ちます。A,B,Cは3因子網羅で、それ以外は2因子間網羅で組合せたケースを生成します。

PICTではA,B,Cの3因子網羅で生成したケース(8ケース)とD,Eで2因子間網羅を生成しているため、最終的なテストケースが多くなっています。

PictMasterではA,B,Cの3因子網羅とそれ以外の要素での2因子間網羅が上手く考慮されており、テストケース数が削減されています。

## PICTの出力結果

![pic6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/5049af43-4204-8b5f-83a3-b85aeac1f88c.png)

## PictMasterの出力結果

![pic5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/17c23bc5-8f6b-940d-8f83-629507c2a98a.png)

# 例題

パラメータA,B,C,D,Eでそれぞれ2つの値の候補を持ちます。A,B,Cは3因子網羅で、それ以外は2因子間網羅で組合せたケースを生成します。

## PICTの場合

### 1. 組合せ条件ファイルを作成する

ここでは「a.txt」ファイルで組合せ条件ファイルを作成します。`{A, B, C} @ 3`はサブモデルの指定です。

```a.txt
A:	1,2
B:	1,2
C:	1,2
D:	1,2
E:	1,2

{A, B, C} @ 3
```

### 2. PICTを実行する

PICTを実行します。今回は「dst.csv」というファイルで出力します。

```sh
PICT.exe a.txt > dst.csv
```

### 3. 組合せ結果を出力する

計16ケースを生成しています。（分かりやすいように結果ソート済み）

![pic6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/14fac824-2551-56fd-3d5c-be7b9b1b737c.png)

## PictMasterの場合

### 1. サブモデルを有効にする

環境設定からサブモデルを有効にできます。

![pic1_circle.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/b0ff2e6c-2d04-e361-8ca2-6efa1dc29456.png)

環境設定にある「サブモデルを使用」を有効にします。

![pic2_circle.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/14d34135-55fa-cdda-0af5-baee8fcce3c4.png)

「サブモデル」欄が追加されます。

![pic3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/3aaaea39-ca43-7307-638a-38ba80602dc2.png)

### 2. 組合せ条件を入力する

組合せ条件を入力します。

![pic4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/2deef27c-587d-9054-7555-d999c65e8531.png)

### 3. 組合せ結果を出力する

実行して結果を生成します。

![pic4_circle.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/9f174923-3464-708c-19a0-08236dd59c25.png)

計9ケースを生成しています。（分かりやすいように結果ソート済み）

![pic5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67356/299d4755-45ba-2f8a-a7bd-c3a3abb9245f.png)

# 参考情報

https://ameblo.jp/pictmaster/entry-10117125780.html
Flask2でURLルーティングを別ファイルにまとめたい

# はじめに
Falskは非常にシンプルなフレームワークな故に、ファイルやディレクトの配置に悩めます
機能のひとつBlueprintを利用すれば、URLルーティングやビジネスロジックを分けられるので、ここで整理します

- Flaskでルーティングを整理したい。ルーティング用のファイルにまとめたい。
- アプリケーションを分割したい。
- Laravelのweb.phpのようにルーティング用のファイルとアプリ（ビジネスロジック）を分割したい
- Flask2の新機能であるネストも試してみる

以前の続き
[EC2にPython/Flask2を構築](https://qiita.com/miyakiyo/items/cbaf0d1e1e4769073098)
[Flask2でGET/POSTの値を取得する](https://qiita.com/miyakiyo/items/f815258773dc8f20854f)

Falskの公式ドキュメント
https://flask.palletsprojects.com/en/2.0.x/


## 準備
起動用のファイルを作成。今回はrunコマンドではなく、app.run()で起動

```Python:app_bp.py
from flask import Flask, Blueprint
from route import web

app = Flask(__name__)

app.register_blueprint(web.bp)

if __name__ == "__main__":
  app.run()
```

register_blueprintで別ファイルのURLのルーティングを記述しているファイルを呼び出し
下のweb.pyファイルを作成してます
web.bpとあるのは、web.pyのbp変数をセットしています

web.pyにLaravelのweb.phpのようにURLのルーティングをまとめます
/yamada

```Python:route/web.py
from flask import Blueprint
from models import Yamada

bp = Blueprint('web', __name__, url_prefix="/yamada")

yamada = Yamada.Yamada()

@bp.get('/name')
def name():
  return yamada.name()

@bp.get('/age')
def age():
  return yamada.age()

@bp.get('/weight')
def weight():
  return yamada.weight()
```

yamadaクラスを用意して、そこにビジネスロジックを書くようにしてます
名前や年齢などを返すようにしてますね

```Python:models/Yamada.py
class Yamada:

  def name(self):
    return "山田です"

  def age(self):
    return "20歳"

  def weight(self):
    return "60Kg"

```

では実行してみます

```
python3 app_bp.py
```
Flask実行

curlで呼び出し

```
curl http://localhost:5000/yamada/name
```
>
山田です

表示されましたね

Blueprintのネストもやってみます
個人的にはルーティングの記述がわかりにくくなってしまいそうで使いたくないのですが
Githubなんかを読んでると需要があるようで待ち焦がれた機能のようです

ネストするルーティングファイルを用意します

```Python:route/web_sub.py
from flask import Blueprint
from models import Tarou

bp = Blueprint('web_sub', __name__, url_prefix="/tarou")

tarou = Tarou.Tarou()

@bp.get('/name')
def name():
  return tarou.name()

@bp.get('/age')
def age():
  return tarou.age()

@bp.get('/weight')
def weight():
  return tarou.weight()
```


web.pyにネスト用のweb_sub.pyを呼び出すようにします

```Python:route/web.py
from route import web_sub
bp.register_blueprint(web_sub.bp)
```
ビジネスロジック用のtarou.pyも用意

```Python:models/Tarou.py
class Tarou:

  def name(self):
    return "山田太郎です"

  def age(self):
    return "24歳"

  def weight(self):
    return "100Kg"

```

curlで呼び出し

```
curl http://localhost:5000/yamada/tarou/name
```
>
山田太郎です

yamadaにtarouがネストされて表示されましたね


# まとめ
- 一つのファイルが大きくなりがちなのをBlueprintを利用すれば、ファイル・ディレクトが整理できます
- Falskの公式ドキュメントは分かりにくい

今回のサンプルコードはGitHubにアップしております
[github/flask2_demo](https://github.com/offgrid-jp/flask2_demo)
【Android】Jetpack Composeでwakelock対応(スリープさせない)をする【Tips】

個人的なメモも兼ねて

## 概要

Androidアプリにおいて、何らかの都合で画面をスリープ状態にさせないようにする場合は専用の実装が必要です。
Android公式の推奨方法は`FLAG_KEEP_SCREEN_ON`をActivityから呼ぶ実装です。

https://developer.android.com/training/scheduling/wakelock



```kotlin
    // コードで呼ぶ例
    class MainActivity : Activity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        }
    }
```

ところで、Jetpack Compose対応する場合、Activityから`setContent`を呼んで実装していきますが、Jetpack ComposeのComposable側からはActivityにアクセスできないように見えます。どのように実装すればいいのでしょうか。

## 結論

Stack Overflowで紹介されていました。

https://stackoverflow.com/questions/69039723/is-there-a-jetpack-compose-equivalent-for-androidkeepscreenon-to-keep-screen-al

[LocalContext](https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/package-summary?hl=ja#LocalContext())を使うとcontextを取得できるため、ここからActivityを取得し、フラグを追加することができます。

```kotlin
@Composable
fun KeepScreenOn() {
    val context = LocalContext.current
    DisposableEffect(Unit) {
        val window = context.findActivity()?.window
        window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        println("FLAG_KEEP_SCREEN_ON")
        onDispose {
            window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
            println("FLAG_KEEP_SCREEN_OFF")
        }
    }
}

fun Context.findActivity(): Activity? {
    var context = this
    while (context is ContextWrapper) {
        if (context is Activity) return context
        context = context.baseContext
    }
    return null
}
```

## もうちょっと解説

既存のAndroidフレームワークとの連携については以下のページで解説されています。

https://developer.android.com/jetpack/compose/interop/interop-apis?hl=ja#call-view

`CompositionLocal`を使用している一連のクラス群を使うことでAndroidフレームワークの値にアクセスできます。[LocalContext](https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/package-summary?hl=ja#LocalContext())でContextが取得できる他、[LocalConfiguration](https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/package-summary?hl=ja#LocalConfiguration())でConfigration(端末のサイズなど)を得たり、[LocalView](https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/package-summary?hl=ja#LocalView())で現在のViewそのものを得ることもできます。覚えておくと今後役に立つでしょう。

## 参考
- [Stack Overflow - Is there a Jetpack Compose equivalent for android:keepScreenOn to keep screen alive?](https://stackoverflow.com/questions/69039723/is-there-a-jetpack-compose-equivalent-for-androidkeepscreenon-to-keep-screen-al)
- [Compose から Android フレームワークを呼び出す](https://developer.android.com/jetpack/compose/interop/interop-apis?hl=ja#call-view)
- [デバイスの起動状態を維持する](https://developer.android.com/training/scheduling/wakelock)
iOS15で透明になってしまったStatusBarとNavigationBarに色をつける


##はじめに
以前作ったアプリをXcode13.0でビルドするとiOS15.0でStatusBarとNavigatoinBarが透明に
なってしまったため、色をつけるコードを追加した忘備録。


##環境
Xcode Version 13.0 (13A233)

※StoryBoardは使わずコードのみでViewを作ったアプリです。


##状況
StatusBar,NavigationBarがiOS15で透明になってしまう。

![スクリーンショット 2021-10-03 14.20.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/636f48c4-09b8-8fc7-2472-6d45efcd697d.png)


##手順
###1.AppDelegateのdidFinishLaunchingWithOptionsにコードを追記


```AppDelegate.swift

var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        //★★バーの色を変更するコードを追記する
        if #available(iOS 15.0, *) {
            let appearace = UINavigationBarAppearance()
            appearace.backgroundColor = .lightGray
            UINavigationBar.appearance().scrollEdgeAppearance = appearace
            
        }
        //★★ここまで 
        
        //元々自分で追記していた、rootViewControllerを表示するコード
        let window = UIWindow(frame: UIScreen.main.bounds)
        self.window = window
        window.makeKeyAndVisible()
        window.rootViewController = UINavigationController(rootViewController: ViewController())
        
        return true
    }
```


###2.結果

BarがLightGray色になった。

![スクリーンショット 2021-10-03 14.35.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/0a2e2492-0e43-17ee-9257-2e522b4f8a48.png)


##最後に
間違いなどありましたらご指摘いただけると幸いです。
Gsonを使用してJSONをパース。うまくいかないのは難読化のせいでした。

## 経緯
APIからJSONを受け取って、Gsonを使用しDataクラスにパースしてもらっていました。
開発中は問題なく動いていましたが、いざ完了したらなぜかパースしたDataクラスを使用している機能が急に動かなくなりました。うまくAPIから引けなかった時と同じ挙動でした。困った。

## Gsonとは
Googleさんが提供している、JSONとオブジェクトを相互変換できるライブラリです。
細かい部分は省略しますが、toJson()、fromJson()なんかを使用してサクッと変換してくれるので大変重宝しています。

## 本題（原因）
タイトルにも書いたので結論から。
ProGuardが有効になったため、クラス名やフィールド名がなんの意味もないてきとうな文字列に変換（難読化）され、
パースしようにもJSONのキー名と一致しなくなり失敗、みたいです。

無知のため調査は難航し、
・API側が変わったのか確認してみたり、
・気づかないうちにフィールド名を変更してしまっていないか必死に差分確認したり、
・このご時世なのでネットワークの問題か？VPNか？
など見当違いも甚だしい確認をひたすらにしていました・・・。

## 実装

``` SampleData.kt
data class SampleData(
    val id: String,
    val name: String,
    val hoge: String
)
```
こんなクラスがあったとして、JSONはこんな感じ

``` sample.json
{"id":"111","name":"test","hoge":"hoge"}
```

``` Sample.kt
val hogefuga = Gson().fromJson(jsonStr, SampleData::class.java)
```
みたいにするとhogefugaはjsonStrからSampleDataにパースされたものが入ります。

## 解決方法
難読化された場合、
上記SampleDataで言うと、idがa、nameがb、hogeがc みたいに（実際はどうなるのかわかりませんが）変わってしまうので
JSONのキーと合うものがないじゃん、ということでうまくいかなかった、と。

### 解決方法その1
SerializedNameを付与してあげればGson側に認識させることができます。

``` SampleData.kt
data class SampleData(
    @SerializedName("id")
    val id: String,
    @SerializedName("name")
    val name: String,
    @SerializedName("hoge")
    val hoge: String
)
```

SerializedNameを付与しておけば変数名はなんでも大丈夫になってしまうので注意。

### 解決方法その2
難読化の対象外とする

``` proguard-rules-sample.pro
-keep class hoge.fuga.〇〇
```

みたいにすれば名称を見失うことはないですね。

``` proguard-rules-sample.pro
-keepnames class hoge.fuga.〇〇
```

みたいなのもあるそうです。
ProGuardはよくわからないのですが、いくつかオプションパターンがあるようです。

## 終わりに
冷静に考えてみればうまくいかない原因を絞り込むことはできたように思います。
難読化は全く頭にありませんでしたが、今後は真っ先に疑えるようそのあたりの知識もつけていきたいです。
ProGuardも勉強しなくては。
【AutoHotkey】フットペダルでZoomのミュート切り替え

# はじめに

作業中話しかけられて、Zoomウィンドウを探してミュート切り替えするのが面倒
フットペダルを使ってちょちょいと解決

# 必要なもの

- フットペダル
- AutoHotkey

# 完成形

フットペダルを踏んだら
    
- Zoomが画面前面に表示される
- ミュート切り替え

という処理になるようにします。
なので今回作るものは

- フットペダル：特定のキーを割り当て
- AutoHotkey：上記のキーが押されたらZoomを操作

という構成になります。

# フットペダル

## キーの割当
よく使うものは他とかち合うので、普段使わないものがよいです。
例えば、F12とかにすると、エクセルで名前をつけて保存したいのにミュート切り替えちゃう、みたいなことに
私は Ctrl + F7 にしました。

![hid.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/455b794e-4c4e-8bde-9ac6-7f70d73bb8b5.png)

フットペダルは安価だった[これ](https://route-r.co.jp/?p=1216)を購入しました。
キーの割当も[専用のソフトウェア](https://route-r.co.jp/?p=1216)をダウンロードして設定します。

## AutoHotkeyを使う

### まずはインストール

[ここ](https://www.autohotkey.com/)からインストールします。

### 次にプログラム

テキストエディタを開いて下記のコードを貼り付け。
拡張子.ahkで保存します。

``` zoomMute.ahk
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
#SingleInstance force
#HotkeyInterval 200

^F7::
  WinActivate, ahk_exe Zoom.exe
  Sleep, 100
  Send, !a
```

以下で軽く処理を説明します。
最初の数行は[ここ](https://electricdoc.net/archives/7692)からコピペしただけなので意味はわかってません。

#### ^F7::

^ が Ctrl を表しており、「Ctrl + F7 を押したら以下の処理を実行するよ」といった意味になっています。

#### Sleep, 100

0.1秒間待機します。
これがないと処理に失敗したりするそうです。

### Send, !a

! が Alt を表していて、「Alt + A を押す」という命令になります。
Alt + A はZoomのミュート切り替えのショートカットキーです。

## スタートアップフォルダに移動

上記のファイルを保存し、ファイルをダブルクリックして実行すると、フットペダルが使えるようになります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/331c3627-3c66-6ac4-3dde-e60dc8bbcb8f.png)

でも毎回そんなことするのは面倒なので、PC起動時に実行するように設定します。手順は以下。


1. zoomMute.ahkのショートカットを作成
1. Windows + R を押してから`Shell:start up`と入力
1. 開いた「スタートアップ」フォルダに先程のショートカットを移す

これで次回以降毎回PC起動時にプログラムが実行されます。

# 完成

これで今日から話しかけられてもたもたすることがなくなりますね。

# その他の参考リンク

https://qiita.com/xrxoxcxox/items/d175f074b5d9677375d8
Javascriptでinputのテキスト変更後に処理

過去に書いたウィンドウリサイズのパロディ
オートコンプリートとかでつかえるかもな、、と勝手に思っています


``` HTML:入力項目のHTML
<input type="text" id="test">
``` 

``` Javascript
// 変更が止まった後、指定時間(ミリ秒)後処理を行う
const term = 500;
// タイマーの受取変数
let timer = 0;
// 変更時に処理した内容を退避
let testValue = "";

window.addEventListener("load", function () {

    const testText = document.getElementById("test");
    // テキストに入力されているときの処理
    testText.addEventListener("input", function () {
        // 内容が変わっているときは、タイマーをリセットする
        clearTimeout(timer);

        // 指定時間後、一度だけ処理を実行
        timer = setTimeout(function () {
            // 内容が同じ場合は処理しない(エンターの決定対策)
            if (testValue !== testText.value) {
                // 処理時のテキスト内容を保持
                testValue = testText.value
                // 実際の処理を記載↓↓
                console.log(testText.value)
            }
        }, term);
    });
});
```

最近、Reactとかvueとかも経験値がたまってきたので、そっちでの記述も考えたい。
Go言語でhttpリクエスト結果が403の解決方法の一例

# はじめに

カクヨムのサイトをGo言語の`net/http`のライブラリーを使用していてデータ取得していたけど
ある時から、403と表示するようになった。curlコマンドでは取得できるのでなんでかわからなかったけど
可決方法が分かったのでやり方を記載する。

# 失敗時のやり方

以下のプログラムを組んだ時に403と返す。

```go:main.go
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	url = "https://kakuyomu.jp/"
	web1(url)
}

func web1(url string) {

	resp, _ := http.Get(url)
	defer resp.Body.Close()

	byteArray, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(byteArray))
}
```

実行すると以下の通りになる。

```:log
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
```

# 解決の方法
以下の通りに、ヘッダーにAcceptとUser-Agent情報を追加するとうまくいく


```go:main.go
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	url = "https://kakuyomu.jp/"
	web2(url)
}

func web2(url string) {

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return
	}
	req.Header.Add("Accept", `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`)
	req.Header.Add("User-Agent", `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11`)
	client := new(http.Client)

	resp, err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		return
	}

	byteArray, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(byteArray))
}
```

実行すると取得できるようになる。

# まとめ

とりあえず、`http.Get`関数を使用して失敗しても、ヘッダーに情報取得することでできることが分かったのでとりあえずこのまま進める
GASでスプレッドシートに書き込むのにハマった話

# 何をしようとしていたか
+ スプレッドシートの内容を取得する
+ JSONで内容の結果を取得
+ 結果をスプレッドシートに書き込むの

語彙力ないですがこんな感じです

# どうしてハマったのか

```javascript:GAS
function getJSON(name) {
  var response = UrlFetchApp.fetch('https://***.json?screen_names=' + name);
  var result = null;
  var text = response.getContentText('utf-8');
  if (text != '') {
    var data = JSON.parse(text);
    if (data.length == 1) {
      result = data[0];
    }
  }
  return result;
}

function addSheet() {
  var id = '***'; //スプレッドシートのID
  var spreadsheet = SpreadsheetApp.openById(id);
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getRange(2, 2, 12); //2行目、2列目から縦に12セルの範囲
  var values = range.getValues();
  const user_ids = [];
  values.forEach(function(item){
    user_ids.push(getJSON(item[0]).id);
  })
  Logger.log(user_ids)

  sheet.getRange(2, 3, user_ids.length, user_ids[0].length).setValues(user_ids);
}
```

バグりました

```
Exception: The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues.
addSheet	@ コード.gs:27
```

って言われました。

作られた配列は
`[hoge, fuga, piyo, ...]`
でした。
大手検索サイトで調べてみると、
`[[hoge], [fuga], [piyo], ...]`
こんな形で出力するといいらしいです。
スプレッドシートから取得しても、この形が出てきます。

# じゃあどうしたのか
簡単なことです

```javascript:GAS
function addSheet() {
  var id = '{ID}';
  var spreadsheet = SpreadsheetApp.openById(id);
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getRange(2, 2, 12);
  var values = range.getValues();
  const user_ids = [];
  values.forEach(function(item){
+++    user_id = getJSON(item[0]).id
---    user_ids.push(getJSON(item[0]).id);
+++    user_ids.push([user_id]);
  })
  Logger.log(user_ids)

  sheet.getRange(2, 3, user_ids.length, user_ids[0].length).setValues(user_ids);
}
```

これだけです。結果を`[]角括弧`で囲んであげるといいだけでした。
作られた配列は
`[[hoge], [fuga], [piyo], ...]`
サクセスでした！！

# まとめ
範囲を指定して書き込むときは`[[hoge], [fuga], [piyo], ...]`で書き込む！
Sequelize typescirptでnumberがstringになっちゃう問題

## Sequelize-Typescriptでnumberがstringになる
DBのcolumnがdecimalに設定されるとなります。DBでは数字なのに、桁数がJavaScriptの限界を超えるのでstringになってしまいます。


Precisionの参考
```
Float uses 32 bits to represent data.
Double uses 64 bits to represent data.
Decimal uses 128 bits to represent data.
```
MACでpyenvとvenvを使ってPythonの仮想環境を構築するメモ

以前MACでpyenvをインストールしたときのメモ。もし間違っていたらすみません。


# pyenv とは
pyenv は、Python バージョン管理ツールです。
Python の複数のバージョンを簡単に切り替えることができます。

# 今回は、Homebrewを使用してpyenvをインストールします

Homebrewは他のアプリケーションをインストールする際にインストールしていることもあるのでbrew -vコマンドを実行してインストール済かどうか確認できます。

```bash
$ brew -v
Homebrew 3.2.14
```

インストールしていなければ、Homebrewをインストールします。

```bash
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

インストールが完了したら、もう一度、brew -vのコマンドを実行し、インストールできたかを確認します。

#pyenvのインストール

```bash
$ brew install pyenv
```

以下のコマンドを実行してインストールされたかどうか確認します。

```
$ pyenv --version
pyenv 1.2.16
```

デフォルトのシェルがzshの場合、こちらのコマンドを実行します
どのSHELLかを使用しているかは、echo $SHELL のコマンドで確認できます。
bashと表示されたら.zshrcではなくファイル名は.bash_profileを指定します。

```
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc    
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
$ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.zshrc
```
以下のコマンドで、.zshrcに設定した内容を反映させます。

```
$ exec zsh
```

bashの場合は以下のコマンドになります

```
$ source ~/.bash_profile
```


PATHに./pyenv/shimsが追加されていることを確認してください。pyenvではこのshimsへのパスが切り替えの重要な役割を果たします。

```
$ echo $PATH /Users/xxxxx/.pyenv/shims:/Users/xxxxx/.pyenv/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin
```

#サポートしてる Python のバージョンの一覧を見る
```bash
$ pyenv install --list
Available versions:
  2.1.3
```

#指定のバージョンをインストールする
例として、3.7.3をインストールします。

```bash
$ pyenv install 3.7.3
```

#環境に設定できるバージョンの一覧を確認する

```bash
$ pyenv versions
* system (set by /Users/xxxxxx/.python-version)
  3.7.3
```

#環境の設定を行う

バージョンの切り替えをしてみます。localの場合は現在のディレクトリにしたpythonを実行します。
globalの場合は全体に反映されます。

```bash
$ cd <作成したプロジェクトフォルダ>
$ pyenv local 3.7.3
$ pyenv versions
```

```bash
$ pyenv global 3.7.3
```

# python のバージョンが環境に反映されなかったら

pyenv initコマンドによってpythonの実行パスが差し替えられます

```
$ eval "$(pyenv init -)"
$ python -V
Python 3.7.3
```

# 仮想環境の作成

```bash
$ python -m venv <仮想環境名>
```

# 作成した仮想環境をアクティベートする
作成した仮想環境にてpipを使いインストールができます。

```bash
$ source <仮想環境名>/bin/activate
```

# ディアクティベートする場合は以下のコマンドを実行する

```bash
$ deactivate
```
Mysql

Mysql

DOWNLOADS
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/4130c576-5c03-1e42-8e9e-0e7be6af39ec.png)

MySQL Community (GPL) Downloads »
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/f2c03996-0654-60c7-8c7f-548a45907b58.png)

MySQL Installer for Windows
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/0e1f9ff2-d0c9-52e7-77c1-77dbb036e7a8.png)

450.7M
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/07f67698-3d37-e721-2c0c-c4d98bce12a8.png)

next
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/459a3a17-caf3-31cf-ec99-f10ecf709caa.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/f0d168d9-a4ac-b5f0-5e86-230b52777355.png)

next
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/30d22733-7c04-a3e3-8b8f-91f64049e1fd.png)

yes
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/e2f18d52-32e7-2153-3e1e-cb50e060ab2d.png)

next
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/5bc962b0-77e4-a0eb-80ec-d47ada6d2183.png)

execute
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/704f5cc5-e6eb-2ea0-6d7f-7d21ff7bff93.png)

next
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/4f32c27b-8c56-3aee-451f-31684025f834.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/87a077e9-bb55-71e8-52e7-08073e58ea13.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/e4ac6e82-7895-dee6-9f76-01e4c6d98de3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/6f492d26-b5d1-ceb7-85fa-81c291369fe2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/8f4f3ed2-b468-5470-0352-c9a81d267383.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/a61a3750-2746-0e6a-800c-2841910e0008.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/54ef9626-f148-8f5a-49a0-23a4671ed1c8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/d1954e06-ac69-be3d-501b-4e76bb6b7240.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/6e5245af-b0bf-767b-f751-b117ad35a1be.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/c0ccf795-48e6-3ad0-dea6-b7abe4e60516.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/03cd6e34-1278-a3a7-07a1-b60a9a863b89.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/5fa2d4cb-8624-a253-0fcb-8e3f454d5316.png)

-------------------------------------------------------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/014a3066-8850-a272-676d-dcb8c3ba9489.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280122/38e8047c-7cd5-b474-9d02-48c5014dcf26.png)
AWS Systems ManagerのParameter StoreからLambdaでパラメータ取得

#パラメータの作成
パラメータの作成ボタンからパラメータを2つ作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/e0952c93-d95a-2fcf-0e27-29c49235b86a.png)
<hr>
今回サンプルとして作ったパラメータの値は、テキスト型の架空のURLです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/7195f374-0777-6d22-7080-ee26d10364ab.png)

#Lambdaの作成
①関数名とランタイムだけ変更し関数を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/ce775a2c-51e1-39ee-912c-45b7a3c3b57c.png)
<hr>
②設定タブ→アクセス権限→ロール名をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/44a159b5-ac45-c892-1c01-f5e860e80f21.png)
<hr>
③ポリシーをアタッチしますボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/7d962382-03b0-e9cc-1d74-1e390db57837.png)
<hr>
④ポリシーの作成ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/dd181622-3fab-c328-87e3-45f5e57a5c30.png)
<hr>
⑤JSONタブを押下し下記のコードに変更し、次のステップボタンからそのまま完了まで進みます。

```policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameters"
            ],
            "Resource": "*"
        }
    ]
}
```
<hr>
⑥先ほどの③のロール画面に戻り、再びポリシーをアタッチしますボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/08ac543a-e217-f446-c34e-00f9aa44961b.png)
<hr>
⑦先ほどの⑤で作成したポリシー名を検索し、チェックを付けポリシーのアタッチボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/418a804b-b775-3443-e87a-eda50eee5b1b.png)
<hr>
⑧関数の画面に戻り、コードを修正します。

```lambda_function.py
import json
import boto3
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)


def get_ssm_params(*keys, region='ap-northeast-1'):
    result = {}
    ssm = boto3.client('ssm', region)
    response = ssm.get_parameters(
        Names=keys,
        WithDecryption=True,
    )
    
    for p in response['Parameters']:
        result[p['Name']] = p['Value']
    
    return result


def lambda_handler(event, context):
    parameters = get_ssm_params('sample-url', 'sample-url2')
    logger.info(parameters['sample-url'])
    logger.info(parameters['sample-url2'])
```
<hr>
⑨deployボタンを押してtestボタンを押すと、logでパラメータの値が取れているのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/8e5f3146-1765-718a-80a9-8f5c1bf451a9.png)
[シリーズ] docker-compose を使って同一物理マシン上に Jenkins Master(docker) - Slave(docker) [SSH通信]を構築する

# はじめに

docker-compose を活用して、同一物理マシン上に
Jenkins Master(docker) と Slave(docker) を立ち上げたときの記録です.

Master - Slave 間の通信は SSH です.

個人的には、Pipeline を記述する際の検証に便利でした.

|コンテンツ|
|:--|
|[[01] docker-compose を使って同一物理マシン上に Jenkins Master(docker) - Slave(docker) [SSH通信]を構築する](https://qiita.com/robozushi10/items/0298a01cdffcf835fe38)|
|[[02] 前述[01]で構築した Jenkins Master(docker) - Slave(docker) [SSH通信] の Slave を複製するバッチ](https://qiita.com/robozushi10/items/172d3dde4de7c56d2106)|
【Unity】ボタンでオブジェクトの表示・非表示を切り替える方法

##環境
Unity 2019.4.22f
Windows10


##やること

[![Image from Gyazo](https://i.gyazo.com/2355b83bc98c11afa5a0a15676ead391.gif)](https://gyazo.com/2355b83bc98c11afa5a0a15676ead391)



##やり方

テキストとボタンを設置
Hierarchy ＞　＋　＞　UI　＞ Text
Hierarchy ＞　＋　＞　UI　＞ Button

[![Image from Gyazo](https://i.gyazo.com/b98cfdb0a1e4c029a950b64373d59521.png)](https://gyazo.com/b98cfdb0a1e4c029a950b64373d59521)


空のGameObjectを作る。
Hierarchy ＞　＋　＞　UI　＞ Create Empty

作った空の GameObject に以下のスクリプトをアタッチ

```ButtonController.cs
using UnityEngine;
using UnityEngine.UI;

public class ButtonController : MonoBehaviour
{
    public GameObject textGameObject;
    public Button button;

    private void Start()
    {
        bool isActive = true;
        
        button.onClick.AddListener(() =>
        {
            isActive = !isActive;
            textGameObject.SetActive(isActive);
        });
    }
}
```

空の Gameobject の Inspector のスクリプトのコンポーネントに以下のようにアタッチする

[![Image from Gyazo](https://i.gyazo.com/384f4bdb3587f822a097b64674a2bfab.png)](https://gyazo.com/384f4bdb3587f822a097b64674a2bfab)


以上

## 最初は非表示ではじめる場合

TEXT オブジェクトの Inspector のチェックマークをはずし、
[![Image from Gyazo](https://i.gyazo.com/6ab3f26944214eaa909c118f3d06273e.png)](https://gyazo.com/6ab3f26944214eaa909c118f3d06273e)

スクリプトで
isActive を falseにする。

こうしないと、最初ボタンを押しても反応しない。

```ButtonController.cs
using UnityEngine;
using UnityEngine.UI;

public class ButtonController : MonoBehaviour
{
    public GameObject textGameObject;
    public Button button;

    private void Start()
    {
        bool isActive = false;  //ここ
        
        button.onClick.AddListener(() =>
        {
            isActive = !isActive;
            textGameObject.SetActive(isActive);
        });
    }
}
```
【Ｕnity】ボタンを押したら InputField の値を取得する方法

##環境
Unity 2019.4.22f
Windows 10

## やること
以下の動画のように、インプットフィールドに何かを入力し、ボタンを押すと、インプットフィールドの値をコンソールに表示する。
　
[![Image from Gyazo](https://i.gyazo.com/102e07133e3d95e43056ed834025fced.gif)](https://gyazo.com/102e07133e3d95e43056ed834025fced)


## やり方
Unity 2D　プロジェクトを新規に作成。

Hierarchy > + > UI で下図のように InputField と Button を配置。
 
[![Image from Gyazo](https://i.gyazo.com/de25bfba698f28597df8c28416ea5f22.png)](https://gyazo.com/de25bfba698f28597df8c28416ea5f22)


以下のスクリプトを作成

```ButtonController.cs
using UnityEngine;
using UnityEngine.UI;

public class ButtonController : MonoBehaviour
{
    public GameObject inputGameObject;
    public Button button;

    public void OnClick()
    {
        Debug.Log(inputGameObject.GetComponent<Text>().text);
    }
}
```

そのスクリプトを ボタンのオブジェクトにアタッチ
[![Image from Gyazo](https://i.gyazo.com/e86499f22496e820017658676c9ccf57.png)](https://gyazo.com/e86499f22496e820017658676c9ccf57)


Button の Inspector を下画像のようにする。

[![Image from Gyazo](https://i.gyazo.com/9cfac93cfe3dcd4c05103577a80aa7dd.png)](https://gyazo.com/9cfac93cfe3dcd4c05103577a80aa7dd)


以上。
Mapbox for Unity で住所を整形する

[Mapbox for Unity](https://www.mapbox.com/unity/)はとても便利で控えめに言って最の高なんですが、

```
_resFromLatLon = new ReverseGeocodeResource(latLon);
MapboxAccess.Instance.Geocoder.Geocode(_resFromLatLon, HandleGeocoderResponse);
```
と緯度経度から住所を検索したときに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/5c324960-1480-bafd-fd5c-24be64adaf44.png)
のような形で微妙に要らないものがついてきます。おしい。
便利でかゆいところに手の届くMapbox for Unityがこれを整形する、または同じ言語だけのアドレスを返してくれる機能を持っていないはずはないと思うのですが、残念ながら見つけることができなかったので、返ってくる情報の規則性を元に整形するものを作成しました。

```
static public string GetPlaceNameFromFeatures(List<Feature> _features)
{
    string placeName = "";
    for (int i = 0; i < _features.Count; ++i)
    {
        int cnt = _features.Count - 1 - i;
        if (_features[cnt].Id.StartsWith("country"))
            continue;
        if (_features[cnt].Id.StartsWith("region"))
            continue;
        if (_features[cnt].Id.StartsWith("postcode"))
            continue;
        placeName += _features[cnt].Text;
        if (_features[cnt].Address != null)
            placeName += _features[cnt].Address;
    }
    return placeName;
}
```

これで以下のような住所が返ってくるようになりました。
以下は新宿近辺のランダムなWorldPositionの住所を検索したものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/15e07dac-63c8-31fa-04e7-66f172b030f3.png)