OmniAICreator/Qiita-1.07M huggingface dataset:
YouTubeDataAPIを用いた複数チャンネルのライブ配信ステータス取得において、リクエストの上限制限を回避する

### 概要

- YouTubeDataAPIでは一日の上限Queries(呼び出し回数 × Cost)が制限されているため、「任意の配信者の動画一覧を取得し、その配信者が現在配信中の動画のリアルタイム情報(視聴者数など)を毎分APIを通して監視しよう」と考えるとすぐにAPI上限に達してしまう
- YouTubeが公開しているRSSフィード用のURL経由で最新動画1件のvideo_idを調べ、そのidの動画情報のみをAPIを用いて取得することで、Queries上限に達しないよう節約している

### 使用環境
- Rails 6.0.4.1
- YouTube Data API v3
- MariaDb  Ver 15.1

### データベース

**配信者テーブル (streamers)**

| id | title | channel_code | description |
|:-:|:-:|:-:|:-:|
| 1 | YouTubeアカウント名|  チャンネルID | チャンネル概要  |
| 2 | 27歳高学歴ニートさの |  UCmFq0wZGLfjtXdUINyOZ7hQ | 毎日たのしく生きてたら大卒27歳職歴なしになってしまいました。|
| 3 | レンジの中に毒を持て | UCfBjINK2PzS432RihFow99w  | ポーカーで生きる人間の業 |

**動画テーブル (streamer_videos)**

| id | streamer_id | title | video_code | audience |
|:-:|:-:|:-:|:-:|:-:|
| 1 | 外部キー |  動画タイトル  | 動画ID | 視聴者数 |
| 2 | 2 |  最速で慶應ロースクールに落ちました | UbHSJapfMSAM| 258 |
| 3 | 3 | Piosolverと配信デート | DfG32VJMZV0 | 1120 |

### 対応方針

以下のRSSフィード用URLを用いて最新動画の動画IDを取得することで、「任意の配信者の動画一覧を取得する」というフローのAPI実行を削減している

```
https://www.youtube.com/feeds/videos.xml?channel_id=チャンネルID
```

実装のイメージは以下です

:::note warn
本質的な処理だけ抽出しているので、実際のソースコードとは異なります。
:::


```ruby
    youtube = Google::Apis::YoutubeV3::YouTubeService.new
    youtube.key = Rails.application.credentials.google[:api_key]

    Streamer.all.each do |streamer|
      # YouTubeが公開しているRSSフィード用のURLは以下
      feed_url = "https://www.youtube.com/feeds/videos.xml?channel_id=#{streamer.channel_code}"
      xml = URI.open(feed_url)
      parsed_xml = Nokogiri::HTML.parse(xml, nil, 'utf-8')
      video_ids = parsed_xml.xpath('//entry/videoid').map{|v| v.text}

      # データベースに保存している最新動画と、RSSフィードで取得した最新動画を突き合わせる
      saved_latest = streamer.streamer_videos.order(created_at: :desc).first
      if saved_latest
        saved_index = video_ids.index(saved_latest.video_code)        
        # 最新動画がすでに保存されているアーカイブ動画である場合は無視
        next if saved_index == 0 && saved_latest.uploaded?
      end

      # 最新1件の動画に対して、動画情報を取得するAPI実行
      response = youtube.list_videos('snippet, liveStreamingDetails, contentDetails', {:id => video_ids[0]})
      video = StreamerVideo.find_or_initialize_by(video_code: response.items[0])

      if video.new_record?
        video.streamer_id = streamer.id
        video.title = r.snippet.title
        video.description = r.snippet.description
      end

      case r.snippet.live_broadcast_content
      when "live" then # ライブ配信中の動画は、ここで毎分視聴者数を取得して更新している
        video.video_type = "live"
        video.audience = r.live_streaming_details.concurrent_viewers.to_i
      when "none" then # ライブ配信ではない動画は、ここでデータを登録して以降処理を行わない
        video.video_type = "uploaded"
      end

      video.save!
    end
```
Vue-Quill-Editorでデフォルトの全表示から使うものだけ表示

## 解決したいこと
Vue-Quill-Editorを使用すると下記のように全表示される、、、当たり前のなのだけど、動画とかあげられたくないし、全部使いたくないなと思い使用するツールだけ表示させたいと思いました。![vue-quill-editor-Homepage-Surmon-s-projects.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1970914/eaf78c56-ea00-20cf-4dd9-f4f733de6988.png)

## 解決する方法
すごく簡単でした
コメントアウトしたものはツールとして表示されなくなります。

```vue:main.vue
editorOption: {
  modules: {
    toolbar: [
      ["bold", "italic", "underline", "strike"],
      ["blockquote", "code-block"],
      [{ header: 1 }, { header: 2 }],
      [{ list: "ordered" }, { list: "bullet" }],
      // [{ script: "sub" }, { script: "super" }],
      //   [{ indent: "-1" }, { indent: "+1" }],
      // [{ direction: "rtl" }],
      [{ size: ["small", false, "large", "huge"] }],
      //   [{ header: [1, 2, 3, 4, 5, 6, false] }],
      //   [{ font: [] }],
      // [{ color: [] }, { background: [] }],
      //   [{ align: [] }],
      // ["clean"],
      ["link"],
    ],
  },
},
```

##こんな感じになりました。![ANKEN-KUN (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1970914/bce7b6e2-280f-d961-f6b6-351510037991.png)
JavaScriptの小技集


# テンプレート文字列

```javascript
const name = "hoge";
const age = "30";

const message =  "私は" + name + "です。" + age + "歳です。"

const message2 = `私は${hoge}です。${age}歳です。`
```

message2がテンプレート文字列を使ったもの。
見やすく、コーディングしやすくなっている。

# アロー関数
## 従来

```javascript
const func1 = function(str) {
  return str;
}
```

## アロー関数

```javascript
const func2 = (str) =>{
  return str;
}
```

# 分割代入

## オブジェクト
```javascript
const ob = {
  name: "hoge",
  age: "30",
};

const { name, age } = ob;
const message = `私は${name}です。${age}歳です。`
```

## 配列にも使える！
配列の場合は、名前が決まってないから順番でうけとる。

```javascript
const array_ = [ "hoge", 30 ];
const [ name, age ] = array_;
const message = `私は${name}です。${age}歳です。`
```

# デフォルト値
関数の引数を空欄にしてもデフォルト値が設定されているので、"Hello, who!"と出力される。
```javascript
const sayHello = ( name = "who" ) => console.log(`Hello, ${name}!!`);
sayHello();
```

# スプレッド構文
## 配列の展開
配列の中身を順番に開くみたいなイメージ。

```javascript
const arr = [1, 2];

const sumFunc = (num1, num2) => console.log(num1 + num2);
sumFunc(arr[0], arr[1]);
sumFunc(...arr);
```

## まとめる

![スクリーンショット 2022-02-24 18.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284107/94fc3992-1cf0-bfe4-5282-aff41ab3b62b.png)

## 配列のコピー、結合

![スクリーンショット 2022-02-24 18.55.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284107/50dd0ee4-7c92-3965-7cbb-72a504df4e73.png)

# map, filterの使い方
![スクリーンショット 2022-02-24 19.12.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284107/cb1a022a-238b-7e56-6cfe-961f2b7fcb0b.png)


# 論理演算子の意味

![スクリーンショット 2022-02-24 19.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284107/5a54aa74-6de7-8c41-923b-a6eb4d9ad65e.png)
php xml request with curl

```
<?php
       $xmldata = '<?xml version="1.0" encoding="UTF-8"?>
					<student>
					<info>
					<name>Rahul kumar</name>
					<age>10</age>
					<class>5th</class>
					<rollno>25</rollno>
					</info>
					</student>';


        $url = "https://www.website.com/ws";

        $ch = curl_init();
        if (!$ch) {
            die("Couldn't initialize a cURL handle");
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_POST, true);
       curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xmldata);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $result = curl_exec($ch); // execute
	echo $result;             //show response
	curl_close($ch);
?>
```

https://github.com/aizwellenstan/php_xml_request
[Laravel] HTTPS での接続を強制する

Laravel を使ったサイトをさっき検証環境、本番環境にリリースしたらHTTPとHTTPSが混在してるよ！！という事でうまく動きませんでした。

```
{!! Form::open(array('url' => '/login', 'role' => 'form', 'name' => 'loginForm', 'id' => 'loginForm', 'class' => 'login')) !!}
```

こういう記述があるとHTTPSページ内にあるフォームのPOST先がHTTPになってエラーになったりします。

こちらの解決方法を以下に記します。


# 結論
web.php に以下を記述します。

```php
if (App::environment('production') || App::environment('staging')) {
    URL::forceScheme('https');
}
```

`App::environment('production')`は本番環境の.envファイルに`APP_ENV=production`と記述されている前提で動きます。

`App::environment('staging')`は検証環境の.envファイルに`APP_ENV=staging`と記述されている前提で動きます。

これで全てのリクエストはHTTPSに統一されます。


以上
OCamlを始める時に役立つ資料


<br><br>

関数型プログラミング何もわからないって方は
[プログラミングの基礎](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E7%A4%8E-Computer-Science-Library-%E6%B5%85%E4%BA%95/dp/4781911609)をおすすめします。

身に付くかどうかわからないし、お金は..
って人は[「プログラミングの基礎」を使った授業紹介](http://pllab.is.ocha.ac.jp/~asai/book-mov/) で基本的な機能を覚えて
[numb86/learn-ocaml](https://github.com/numb86/learn-ocaml)の問題を見て、何をやっているかがわかるまで考える。
(実はこっちの方がおすすめかも.. )



<br><br>



## OCaml 日本語リンク集
<br>

[「プログラミングの基礎」を使った授業紹介](http://pllab.is.ocha.ac.jp/~asai/book-mov/)  
こんな事言ったらなんだけど.. 本は買わなくても何とかなるような..

[OCaml入門](https://ocaml.jp/?OCaml%E5%85%A5%E9%96%80%281%29)  
C/C++ などの手続き型言語を学んだことのある人を対象にした、簡単な入門記事です。

[Objective Caml 入門](https://www.fos.kuis.kyoto-u.ac.jp/~igarashi/class/isle4-07w/mltext/)  
五十嵐 淳さん

[numb86/learn-ocaml](https://github.com/numb86/learn-ocaml)
[プログラミングの基礎](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E7%A4%8E-Computer-Science-Library-%E6%B5%85%E4%BA%95/dp/4781911609)の問題集

[OCaml『プログラミングの基礎』勉強メモ 前編](https://qiita.com/hash/items/05bc5ccdaea1ce3f5646)  
[OCaml『プログラミングの基礎』勉強メモ 後編](https://qiita.com/hash/items/e78ef70dc2782e64c873)
まとまっています。見直しに

[関数型言語 Objective Caml 入門](https://www.math.nagoya-u.ac.jp/~garrigue/lecture/tsukuba06/tsukuba.pdf)  
PDF

[お気楽 OCaml プログラミング入門](http://www.nct9.ne.jp/m_hiroi/func/ocaml.html#abc)
お気楽じゃなくて、本気にならないとキツイような...

[OCamlチュートリアル](https://ocaml.org/learn/tutorials/index.ja.html)  
はじめの一歩が翻訳されてないのが残念

[マニュアル](https://ocaml.jp/archive/ocaml-manual-3.11-ja/)
和訳マニュアル


<br><br><br>

## おすすめ本
<br>

[プログラミングの基礎](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E7%A4%8E-Computer-Science-Library-%E6%B5%85%E4%BA%95/dp/4781911609)
こちらの方が説明が、やさしいくわかりやすいと思います。

[プログラミング-in-OCaml-](https://gihyo.jp/dp/ebook/2012/978-4-7741-5314-8)
今後の為に買っておいても良いと思います。初心者へのわかりやすさは　プログラミングの基礎　

<br><br><br>


## プログラミング　サンプル
<br>

[more-ocaml-exercises](https://github.com/johnwhitington/more-ocaml-exercises)  


[OCaml でゲームボーイエミュレータを書いた話](https://qiita.com/linoscope/items/244d931aaae07df2c27e)



<br><br><br><br>
ブラウザバック判別

```js
if(window.performance.navigation.type === 2) {　// ちなみにリロードの場合は1
	// ブラウザバック時に実行したいイベント
}
```
こっちでもいける
```js
if(window.performance.navigation.type === performance.navigation.TYPE_BACK_FORWARD){ // リロードの場合はTYPE_RELOAD 
	// ブラウザバック時に実行したいイベント
}
```
Amazon EMRのセキュリティグループに関してはまった事

## はじめに

EMRをプライベートサブネットで利用する場合最低3つのセキュリティグループが必要になります。

- マスターインスタンスの Amazon EMR 管理セキュリティグループ 
- コアインスタンスとタスクインスタンスのセキュリティグループ
- サービスアクセス用のセキュリティグループ

今回はこれらのSecurity Groupをカスタムとして手動で作成した際にはまった事を備忘で書いておきたいと思います。




## はまった事
EMRではマスター/スレーブ間で別々にセキュリティグループをアタッチし、各々通信しなければならないポート/プロトコルが決まっています。プレイベートサブネットを利用する場合はサービスアクセス用のセキュリティグループも要件にあったポート/プロトコルを解放する必要があります。

https://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-man-sec-groups.html

私の環境ではプライベートサブネットでクラスターを起動している事もありSecurity Group間の通信は
SG-to-SGでALL解放していたので問題なく使えていました。

問題は Amazon EMR リリース 5.30.0 以降を利用し始めた時に発生しました。
上のリンク先に記載があるのですが、サービスアクセス用のセキュリティグループではインバウンドのルールとして
マスター用のセキュリティグループからの9443/TCPを許可する必要があるのですが、元々ALL解放していた事もあり
変更はしていませんでした。

しかしながらEMRを利用しようとしたところ以下のエラーが表示されました。

```
ServiceAccessSecurityGroup is missing ingress rule from EmrManagedMasterSecurityGroup on port 9443
```

どうやらEMR側で**明示的に**9443/TCPが許可されているかをチェックしているようです。
9443/TCPを別途解放したところ利用できるようになりました。
マスター側セキュリティグループのアウトバウンドはALL開放だけで明示的にポートを開放する必要はありませんでした。

## 教訓
AWSマネージドサービスによっては通信が許可されているかではなく**設定が入っているか**をチェックしているものもあるようです。
もし同様の経験をされた方がいれば、参考になれば幸いです。
Rでエクセルからデータ読み込み、重回帰分析をする

# エクセルのデータをRに読み込む。
エクセルで範囲選択して、`Ctrl＋C` でクリップボードにコピーした状態で、

```R
data <- read.delim("clipboard",header=T)
```

を実行すると読み込める。
セルの中身が数式でも、数値として読み込んでくれる。便利。


# グループ分け
変数 `data$CL01` にグループ番号が入っているので、カテゴリ数量に変換した後、グループに分けたデータセットを作る。

```R
# クラスタNoをカテゴリ数量に変換
data$CL01 <- factor(data$CL01)

# ４グループに分ける
df1 <- subset(data, CL01==1)
df2 <- subset(data, CL01==2)
df3 <- subset(data, CL01==3)
df4 <- subset(data, CL01==4)
```

# 重回帰分析
※データセット `df1` に目的変数 `Y` と説明変数 `P01`～`P10`　が入っている。

## １回だけ分析する場合
説明変数が固定されているときは、これでOK。
```R
ans <- lm( Y ~ P01 + P02 + P03 + P04 + P05 + P06 + P07 + P08 + P09 + P10, data=df1)
```

## 変数選択する場合
説明変数のどれが有効か、影響度が大きいかわからないとき、`step()`関数を使えば、AICを見ながら適切に選んだ変数を増減して、コンパクトなモデルを作ってくれる。

```R
ans <- step( lm( Y ~ P01 + P02 + P03 + P04 + P05 + P06 + P07 + P08 + P09 + P10, data=df1))
```

## 変数増加法を使いたい場合
今回は、説明変数が多すぎて（＞サンプル数）解けなかったため、増加法を使って有望な説明変数から順に追加する分析をやってみた。
手順は、１．最小のモデルを定義　２．最大のモデルを定義　３．`step()`関数に初期モデル（＝最小のモデル）と最大のモデル、`step`数を指定して分析実行（ ここでは `steps＝5` を指定。５回変数追加＆効果検証のプロセスを回すということ）

```R
model1 <- lm( Y ~ 1, data = df1)
model2 <- lm( Y ~ P01 + P02 + P03 + P04 + P05 + P06 + P07 + P08 + P09 + P10, data=df1)
ans <- step( model1, direction="forward", scope=list(upper=model2, lower=model1), steps=5)
```


参考にしたページ

https://biolab.sakura.ne.jp/forward-backward-or-backward-forward-stepwise-by-r.html

## 結果の表示
最終的なモデル、係数、p値、R＾2値などが出力される。
```R
summary(ans)
```

## 予測値の書き出し（csv）
`predict(ans)` で計算できる予測値を、ファイルに書き出す。
~~`paste()` コマンドで、出力ファイル名を指定できる。~~
（2022.2.25追記）
　コメントいただきましたが、ファイル名は `""` で文字列を指定すればできますね。
　`paste()` を使うのは、文字列をつないで使いたい場合でした。

※ファイルの場所は、現在のディレクトリ（フォルダ）

```R
write.csv( predict(ans), "output.csv")

# 文字列をつないでファイル名にする場合
write.csv( predict(ans), paste("output",".csv"))
```

## VIFの確認
多重共線性の確認。変数選択をした場合、多重共線性の低い変数が選ばれているはずだが、念のため確認。
アウトプットしたモデルについて、VIFを確認する。

```R
library(car)
vif(ans)
```

相関行列のようなマトリクス形式で出力されるのかと思いきや、１変数にVIF値は１個。最大値が出力されている？
~~（2022.2.25追記）
　コメントいただきましたが、データフレームでVIFを計算する場合と考え方が違うのですね。~~
（2022.3.1追記）追記の内容が間違っているようなので打消し線入れました。



データフレームからVIFを計算する場合。このときはマトリクスが出力される。
```R
vif <- 1/(1-cor(df1)^2)
```

### VIFと相関係数の目安
| VIF | R^2 | R |
|:-:|:-:|:-:|
| 10  |  0.9 | 0.95  |
| 5  | 0.89  | 0.89  |
| 3  | 0.67  | 0.8  |


参考にしたページ

https://toukeier.hatenablog.com/entry/how-to-calculate-vif-by-r/
Ghostscript と GSview のインストール

## 研究室で必須のソフトウェアの導入
#### Ghostscript と GSview のインストール
ご存じの通り，弊研究室ではTexに読み込む画像ファイルとして
EPS ファイル（Encapsulated PostScriptの略，端的に言えば高品質の画像ファイル）
を採用しています．EPS ファイルの画像を見るために，
フリーソフトの Ghostscript と GSview のインストールを必要とするのですが，
日本語のサポートや丁寧なインストール指南書が存在せず，
個人のPCに導入することは困難でした．そこで，GSview と Ghostscript のインストールに
関して以下の文章で丁寧に解説することを試みました．お役に立てば幸いです．

:::note info
**手始めに，お使いのPCのbit数を確認してください**
bit数は画面のスタートボタンの隣にある検索バーに
"PC情報"と入力し，出てきたアイコンを選択してください．
一度で確認画面まで飛べますので，システムの情報という項目で確認を．
:::

:::note info
**Windows 64bit userを想定して解説します**
具体性のある解説をすべく，64bit userに限定していますが，Macも一緒です．
32bit userは文章中の64を32に置き換えて，インストールをお願いします．
:::

**１．Ghostscriptのインストール**

Ghostsciript のインストールファイル [gs952w64.exe][link-1] をダウンロードしてください．
ダウンロードしたファイルをダブルクリックして開きましょう．
すると，実行を許可するかのウインドウが出るので，許可を選択
続いて表示される英語の小型タブも Next → I agree を選択
新しくフォルダを作成する場所を尋ねられます．
ここで，インストール先を**C:\gs\gs9.52**としてください．
インストール先を設定後，自動でインストールが開始されますので，
終われば Exit でタブを閉じましょう．

[link-1]:https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/tag/gs952

**２．Ghostscript の環境変数を設定**

次に Ghostscript の動作上，重要な環境変数を設定します．
まず，画面スタートボタン脇の検索バーに環境変数の編集と打ち込みましょう．
出てきたアイコンをクリックしてください．設定画面のウインドウが出現しますので，
ユーザーの環境変数のセクションに表示されている新規(N)を押してください．
押すと新規作成の画面が出現し，変数名と変数値を要求されます．
ここからが肝です．**２つ設定しますので以下↓のように入力してください．**
PATH1 を設定後，再び新規を押して PATH2 を設定してください．

| 変数名  | 変数値 |
|:-:|:-:|
|PATH1|C:\gs\gs9.52\bin|
|PATH2|C:\gs\gs9.52\lib|

成功すれば作成した環境変数が，下の画像内の赤枠のように表示されるはずです．
画像内では\が￥になっていますが，同じ意味ですので気にしないでください．
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536951/d7dacfd6-4ec0-43b1-2978-692a04323634.png)
後はウインドウ下部の適用ボタンを押し，設定を反映させます．

**２．GSviewをPCのビット数と揃えてインストール**
続いて，GSviewのインストールファイル [gsv50w64.exe][link-2] をダウンロードしましょう．
同様にダブルクリックして実行すると，やはり許可を求められるので許可を選択．
英語の画面が表示されますので Setup をクリック．
言語選択の画面ではご自身が読める言語を．Japanease は選択肢にありません．
表示されるウインドウで Next を選択し続けます．
途中のチェックボックスやインストール先の選択ウインドウもいじらなくていいです．
Finish ボタンが最後に表示されますので，クリックします．
Install was successful とのメッセージが表示されれば成功です．
失敗した場合，Install failed と表示されます．
アプリ一覧から gsview5.0 を選択し，アンインストールしてから再挑戦しましょう．

お疲れさまでした．
執筆にあたり以下のサイトを参考させていただきました．感謝申し上げます．

[LaTexを書いていたeps画像がPDFファイルに出力されない問題を解決](https://betat.hatenablog.com/entry/2015/01/07/190911)

[link-2]:http://khotta.org/ghost/#disk
40 代おっさん GASのFileクラスについて学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## Fileクラス

Fileクラスとは
ファイルを操作する機能を提供するクラス

＊Fileクラスの主なメンバーの図は、参考資料の本を見ていただくか、ネットで調べください。

ちなみにこちらで書いてありました。
<https://excel-ubara.com/apps_script1/GAS036.html>

お試し

```javascript
function tosiki() {
  const id     = '****************';
  const file   = DriveApp.getFileById(id);

  console.log(file.getId());
  console.log(file.getName());
  console.log(file.getDescription());
  console.log(file.getMimeType());
  console.log(file.getSize());
  console.log(file.getSize());

  console.log(file.getUrl());
  console.log(file.getDownloadUrl());

  console.log(file.getDateCreated());
  console.log(file.getLastUpdated());

  console.log(file.isStarred());
  console.log(file.isTrashed());
}
```

### ファイルのコピー・移動・削除

ファイル移動
moveToメソッドを使用

構文

```javascript
Fileオブジェクト.moveTo(フォルダ)
```

ファイルをゴミ箱に移動
setTrashedメソッドを使用

構文

```javascript
Fileオブジェクト.setTrashed(真偽値)
```

お試し

```javascript
function tosiki() {
  const id     = '**********************';
  const file   = DriveApp.getFileById(id);

  const movedFile     = file.makeCopy('tosiki.txt');
  const destinationId = '1XzpL7AEzOCRunIc4NCI60MTFbWbWpaFM';
  const destination   = DriveApp.getFolderById(destinationId);
  movedFile.moveTo(destination);

  const trasheFile = file.makeCopy('tosiki.txt');
  trasheFile.setTrashed(true);
}
```

## 参考資料

<https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3-Google-Apps-Script%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80-%E7%AC%AC3%E7%89%88/dp/4798064742>
Apache RoyaleでJavaScriptのAPIを利用する

# はじめに

Apache RoyaleでのJavaScriptのAPIの使い方を簡単にまとめます。

# 普通に利用できるAPI

alert、console.log、等は普通に利用できる

```actionscript
alert("Hello World");
```

```actionscript
console.log("Hello World");
```

# windowを使って利用できるAPI

fetch、localStorage、等はwindowから取得することで利用できる


```actionscript
window["fetch"]("http://localhost:3000/xxx")
    .then(function(response:Object):Object {
        return response.json();
    }).then(function(jsonObject:Object):void {
        console.log(JSON.stringify(jsonObject));
    });
```

```actionscript
window["localStorage"].setItem("test-key", "Hello World");
```

# サンプル


```mxml:Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.apache.org/royale/spark"
               xmlns:mx="library://ns.apache.org/royale/mx"
               width="100%" height="100%">

    <fx:Style>
        * {
            font-family: "Meiryo";
        }
    </fx:Style>

    <fx:Script>
        <![CDATA[
            private function alertMessage():void {
                alert("Hello World");
            }

            private function logMessage():void {
                console.log("Hello World");
            }

            private function fetchMessage():void {
                window["fetch"]("http://localhost:3000/xxx")
                    .then(function(response:Object):Object {
                        return response.json();
                    }).then(function(jsonObject:Object):void {
                        console.log(JSON.stringify(jsonObject));
                    });
            }

            private function setLocalStorageMessage():void {
                window["localStorage"].setItem("test-key", "Hello World");
            }
        ]]>
    </fx:Script>

    <s:Label left="10" top="10" text="Click the button."/>
    <s:Button left="10" top="40" width="150" label="alert"
        click="alertMessage();" />
    <s:Button left="170" top="40" width="150" label="console.log"
        click="logMessage();" />
    <s:Button left="330" top="40" width="150" label="fetch"
        click="fetchMessage();" />
    <s:Button left="490" top="40" width="150" label="localStorage.setItem"
        click="setLocalStorageMessage();" />

</s:Application>
```
Go言語で配列・スライスをなんでも受け取れる関数を作る

## はじめに

`[]int` でも `[]string` でも、どのような型の配列でも、どのような型のスライスでも、引数として受け取れる関数を作りたいことがありました。
作ろうとしたら一筋縄ではいかなかったので、その方法を書き留めておきます。

## 環境

```zsh:terminal
% go version
go version go1.17.6 darwin/amd64
```

## 失敗例

はじめに、引数の型に `interface{}` を使うとなんでも受け取れるので `[]interface{}` を使えばどのような型の配列・スライスでも受け取れるだろうと思い、以下のコードを書きました。

```go:main.go
package main

import (
    "fmt"
)

func printElements(array []interface{}) { // []int や []string など、配列・スライスならなんでも受け取りたい
    for _, e := range array {
        fmt.Println(e)
    }
}

func main() {
    numbers := []int{2, 3, 5, 7, 11}
    printElements(numbers)

    texts := []string{"foo", "bar", "baz", "qux", "quux"}
    printElements(texts)
}
```

```console:実行結果
./main.go:15:15: cannot use numbers (type []int) as type []interface {} in argument to printElements
./main.go:18:15: cannot use texts (type []string) as type []interface {} in argument to printElements
```

しかし、これを実行しようとするとコンパイルに失敗します。
どうやら `[]interface{}` 型の引数は `interface{}` 型の配列・スライスしか受け取れないようです。

## 解決方法

やっていることの本質は同じですが、一応2パターンあるので分けて記載します。

### 引数の型に `interface{}` を使用する

どのような型の配列・スライスでも受け取れるように、引数の型をなんでも受け取れる `interface{}` にします。
そして、リフレクションを使用して引数の値を判別し、配列またはスライスでない場合はエラーを返すようにします。

```go:main.go
package main

import (
    "fmt"
    "reflect"
)

func printElements(array interface{}) error {
    arr := reflect.ValueOf(array)
    if arr.Kind() != reflect.Array && arr.Kind() != reflect.Slice {
        return fmt.Errorf(`"%#v" is not array`, array)
    }

    for i := 0; i < arr.Len(); i++ {
        fmt.Println(arr.Index(i))
    }

    return nil
}

func main() {
    numbers := []int{2, 3, 5, 7, 11}
    _ = printElements(numbers)

    texts := []string{"foo", "bar", "baz", "qux", "quux"}
    _ = printElements(texts)
}
```

```console:実行結果
2
3
5
7
11
foo
bar
baz
qux
quux
```

### 配列・スライスを `[]interface{}` 型に変換する

まず、どのような型の配列・スライスでも `[]interface{}` 型に変換する関数を用意します。
この関数はリフレクションを使用して引数の値を判別し、配列またはスライスでない場合にエラーを返します。
そうしたら、行いたい処理は `[]interface{}` 型を引数にとる関数として実装します。

```go:main.go
package main

import (
    "fmt"
    "reflect"
)

func convert(array interface{}) ([]interface{}, error) {
    arr := reflect.ValueOf(array)
    if arr.Kind() != reflect.Array && arr.Kind() != reflect.Slice {
        return nil, fmt.Errorf(`"%#v" is not array`, array)
    }

    res := make([]interface{}, arr.Len())
    for i := 0; i < arr.Len(); i++ {
        res[i] = arr.Index(i).Interface()
    }

    return res, nil
}

func printElements(array []interface{}) {
    for _, e := range array {
        fmt.Println(e)
    }
}

func main() {
    numbers := []int{2, 3, 5, 7, 11}
    ns, _ := convert(numbers)
    printElements(ns)

    texts := []string{"foo", "bar", "baz", "qux", "quux"}
    ts, _ := convert(texts)
    printElements(ts)
}
```

```console:実行結果
2
3
5
7
11
foo
bar
baz
qux
quux
```

## おわりに

これで便利にどんな配列・スライスでも扱えますね。
リフレクション様様です。

## 関連

1. [golangのinterface{}の不思議](https://nemunemu-zzz.hateblo.jp/entry/2018/03/22/000410)
1. [【Go言語】[]string, []int to []interface{} とかそういうの](https://otiai10.hatenablog.com/entry/2015/05/01/172955)
1. [Go言語 スライスのchunk関数をつくる](https://tyablog.net/2019/11/10/make-chunks-of-slice-in-golang/)
【個人開発】日々の晩酌を記録する日記帳「お酒録」をリリースしました



# はじめに・・・
これまでに飲んだお酒を覚えていますか？色は？味は？フレーバーは？

そうした日々のお酒を記録するためのWebサービス「お酒録」を作りました。
自分の飲んだお酒を記録することはもちろん、他の人が飲んでいるお酒を見たり、コメントできます。

ワインや日本酒だけに特化した類似のスマホアプリはありますが、
本サービスはそうした区別をせず、ビール、酎ハイ、日本酒、ワイン、焼酎、ウィスキーとあらゆるお酒を対象としています。
また、Twitterにお酒の写真を投稿する人が多いことからTwitterへの投稿機能も備えています。

https://s-roku.me/

お酒はビールや日本酒といった種類だけじゃなく、銘柄にも興味を持つとより楽しめるものと思います。
この香りが〜とか、この味が〜といった感じで。
そんな観点で、これまでお酒の銘柄を気にしたことがなかった人ほど使って欲しいです。
※お酒は20歳になってからです。飲み過ぎにご注意ください。

# 「お酒録」3つの機能
## 記録する
日々飲んでいるお酒を記録し、後から見返すことができます。
いわゆる、「お酒の日記帳」としての使い方です。
お酒の銘柄はもちろん、味わいや香りも残すことができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1717756/1fc06da8-6edd-2d77-713b-a7cac3c46bf4.jpeg" width=250>

上記の日々の記録に加えて、下のように統計データを表示することもできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1717756/6778c8c2-3b7d-6569-c3a6-83b7a75f560d.jpeg" width=250>

## 探す
他の人のレビューを見て、自分が次に購入するお酒を探すことができます。
ユーザーの皆さまの投稿を元に夫々の銘柄ごとにフレーバーやスッキリしている等の味覚チャートが表示されるようになっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1717756/fe23d59e-d879-0194-c370-487219825fff.jpeg" width=250>

## 繋がる
お酒録にTwitterアカウントを登録することで、お酒録からTwitterアカウントへ、また、お酒録に投稿した内容をTwitterにも投稿することで、お酒好き同士の方々が繋がる仕組みを作っています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1717756/bbc4dd47-83e7-a0ba-939c-b6468a174a7a.jpeg" width=250>

# 開発環境
今回は、Vue.jsを採用して、SPA（シングルページアプリケーション）として作成しました。
また、UI周りはVuetify、データベースや認証機能関連はとっつきやすいFirebaseを採用しました。

## 使用言語
* Vue.js(SPAとして開発)

## ライブラリ
* Vuetify
* Vue-Router
* Browser-Image-Compression（投稿画像圧縮のため）

##その他
* Twitter API
* Firebase

# 所感
## SPA（シングルページアプリケーション）も捨てたもんじゃない
今回はSPAとして作成しました。
ネットでSPAについて調べると、SEO対策で不利とか実用レベルではない！と言われています。
まぁ、確かにSSRで作成するに越したことはないと思います。

ですが、SPAも昔に比べると大分受け入れられる下地ができてきたように思います。
Google検索にも引っかかるしAdsenseの広告審査にも通る時代になりました。

https://qiita.com/boneskeleton/items/ea86d129fe9231f0b8d9

とはいってもSSRには敵わないな〜というのが私の感想です。
この「お酒録」はSPAに固執してしまいましたが、今後、一部はSSRに切り替えようと思っています。

## 普段コーディングばっかりやってる人はデザインを学んだ方が良いかも
普段はコードを書いていることの方が多く、デザインをゼロからやったのは今回が初めてです。
今更ですが、デザインは難しいですね。。。

今回の「お酒録」は、全体のデザインを3、4回はゼロから作り直すハメになりましたw
個人開発だからと甘えずにデザインは最初の段階で各機能も含めて、しっかりとデザインを最初に作った方が開発速度はかなり速くなるだろうと思います。
Python itertoolsつかって多次元リストを１次元リストにしてリスト内包表記でforループさせたらリストが消えた！？

itertoolsでchainして生成されるのはリストではなくて、**itertools.chainクラス**。こいつは**ジェネレータ**だから、forで最後までループさせると空になるまでnext()しちゃうって訳さ！

以下で動作確認をしてみるね！

```python
import copy
import itertools

ls = [[1,2,3],[4,5,6]]

genr = itertools.chain.from_iterable(ls)

print(type(genr))

# 1が取り出される
print(next(genr))
# 2が取り出される
print(next(genr))

# この時点の要素
print(list(copy.deepcopy(genr)))
# ここでコピーせず、そのままprintすると
# 全要素がnext()されてしまうので注意
# print(list(copy.deepcopy(genr)))
# genr = [] になってしまう

# 奇数を取り出す例
pick_out_odd =[n for n in genr if n % 2 != 0]

print(pick_out_odd)

print(list(genr))
```

```
<class 'itertools.chain'>
1
2
[3, 4, 5, 6]
[3, 5]
[]
```
40 代おっさん GASのFolderクラスについて学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## Folderクラス

Folderクラスとは
フォルダを操作する機能を提供するクラス

＊Folderクラスの主なメンバーの図は、参考資料の本を見ていただくか、ネットで調べください。

ちなみにこちらで書いてありました。
<https://excel-ubara.com/apps_script1/GAS036.html>

お試し

```javascript
function tosiki() {
  const id     = '××××××××××××××××××××××';
  const folder = DriveApp.getFolderById(id);

  console.log(folder.getId());
  console.log(folder.getUrl());
  console.log(folder.getName());
  console.log(folder.getDescription());

  console.log(folder.getDateCreated());
  console.log(folder.getLastUpdated());

  console.log(folder.isStarred());
  console.log(folder.isTrashed());
}
```

### ファルダやファイルの作成

FolderオブジェクトにたいしてcreateFolderメソッド、createFileメソッドを実行することで、追加、作成が可能

フォルダ

構文

```javascript
Folderオブジェクト.createFolder(ファルダ名)
```

お試し

```javascript
function tosiki() {
  const id     = '1BxF2vAvoSvfc9mEpaOIt6mPT37BMeHSV';
  const folder = DriveApp.getFolderById(id);

  for (let i = 1; i <= 3; i++) {
    const name = String(i).padStart(2, '0');
    folder.createFolder(name);
  }
}
```

ファイル

構文

```javascript
Folderオブジェクト.createFile(ファイル名, 内容, [, MIMEタイプ])
```

お試し

```javascript
function tosiki() {
  const id     = '***************';
  const folder = DriveApp.getFolderById(id);

  const name = 'tosiki.txt';
  const content = '利樹君です！';
  folder.createFile(name, content, MimeType.PLAIN_TEXT);
  
  const targetId = '******************';
  folder.createShortcut(targetId);
}
```

## 参考資料

<https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3-Google-Apps-Script%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80-%E7%AC%AC3%E7%89%88/dp/4798064742>
JavaScriptのコールバック関数を理解する

## コールバック関数とは

コールバック関数とは、関数またはクラスメソッドの引数として関数を渡すことで、実行する処理を外部から注入するための手法です。

JavaScriptにおいて、このコールバック関数は非常に重要な役割を持ちます。
いたるところでコールバック関数が散見され、コールバック関数を見ないJavaScriptプロジェクトはないのでは？
と言われるレベルです。

### コールバック関数の仕組み

コールバック関数は、前述のとおり関数の引数として関数を渡すということをしています。
~~C言語で言う所の「関数ポインタ」なのですが、なかなか理解されないことが多いです~~

コールバック関数の非常に簡単な例が以下のコードです。

```javascript
// コールバックを受け取る関数
function loopback(_callback) {

    console.log('処理開始');
    // 1～5までの数字をコールバック関数に渡す
    for(let i=1;i<=5;i++) {
        _callback(i);
    }

    console.log('処理終了');
}

// コールバック関数を指定して、「loopback」を呼び出し
loopback(function(i) {
    console.log(`callback number is ${i}`);
});
```

これを実行すると、以下のようにコンソールに出力されます。

```shell
処理開始
callback number is 1
callback number is 2
callback number is 3
callback number is 4
callback number is 5
処理終了
```

### コールバック関数が内部でどう使われているか

ここでのポイントが、**関数「loopback」の呼び出しに対して、関数を指定している**という点です。

関数「loopback」上では、普通の変数と同じように引数として関数を受け取っています。

```javascript
function loopback(_callback) {
```

そのうえで、この関数は、あたかも定義された関数かのように利用できます。

```javascript
for(let i=1;i<=5;i++) {
    _callback(i);
}
```

このように、JavaScriptは関数であっても変数として取り扱うことができるという珍しい特性を持っています。
~~（と言っているとC言語使いに怒られます）~~

そのため、以下のように呼び出す部分を書き換えると理解がしやすいかもしれません。

```javascript:変更前
loopback(function(i) {
    console.log(`callback number is ${i}`);
});
```
↓
```javascript:変更後
const callback = function(i) {
    console.log(`callback number is ${i}`);
};

loopback(callback);
```

### コールバック関数の引数

今回のサンプルでは、コールバック関数の引数として数値を渡しています。

このように、この**引数として渡される値はコールバックごとにあらかじめ決められています。**

そのため、「コールバック関数だから引数は○○だ！」といったような決まりごとはなく、
コールバックに引数がない場合もあります。

コールバック関数を要求するような機能を利用したい場合には、あらかじめ必要な（受け取れる引数の数と型）をしっかりと確認するとよいでしょう。

## さいごに

コールバック関数はJavaScriptを使う上で非常に重要です。~~（大事なので２回）~~

いわゆる「コールバック地獄」なんていう単語も存在するくらいなので、気になる方は調べてみるとよいでしょう。
Power Automateでライブラリ内の特定のファイルを指定する

表題の件、よくやることなのですが、必要になるたびに毎回調べている気がするのでちゃんと書いておきます。

やりたいこととしては以下のファイルの情報を取得することです。（何に使うかというのは後日書きます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/9c685603-f660-e64f-80f8-0705da60e2c7.png)
まずはファイル一覧を取得してみます。このなかからファイルを特定できる情報を取得できればいいはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/f18690ae-4f9a-106a-1fbf-1217e320a04b.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/2d82fa93-2afb-f5d8-2c28-a82de91c703a.png)

結果を見てみます。

```result.json
{
                "{Link}": "https://******.sharepoint.com/sites/Sample1/Shared%20Documents/Sample2.xlsx?d=wa0009bbe024b48b7b742da3ba4cd5921",
                "{Name}": "Sample2",
                "{FilenameWithExtension}": "Sample2.xlsx",
                "{Path}": "Shared Documents/",
                "{FullPath}": "Shared Documents/Sample2.xlsx",
                "{IsCheckedOut}": false,
                "{VersionNumber}": "3.0"
}
```
単一のファイルの一部を抜き出したものですが上記のようになっています。つまり、ファイル名（拡張子つき）は{FilenameWithExtension}なんですね。{ } ってなんだろう…

とりあえず、ODATA フィルタークエリーにそのまま書いてみますが動きません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/3e5d9e31-8728-fbe4-bb58-1cd43f9bc698.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/7faeeb97-d0e5-6823-6066-282a7fdacda6.png)

{  } を省いてもシングルクォートで囲っても動きません。

正解は何かというと FileLeafRef と指定します。これで動作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/28ec52ae-e42c-d317-d43d-e9845f05effd.png)

IDが取得できるので、これでファイルに関する様々なアクションを後続で利用できるようになります。
SharePoint 内部フィールド名なので、 CSOM とかを利用している方だとなじみ深いのかもしれませんが、結構忘れますね…。
【unittest】辞書型オブジェクトに期待するkeyが存在するかテスト

Pythonでの**unittest**において、辞書型のオブジェクトに期待する``key``が存在するかテストしたのでテスト方法をメモしておく。

# テスト方法
辞書型オブジェクトに期待する``key``が存在するかテストするために、**unittest**の``assertIn()``を使用した。
## assertIn(a,b)
``assertIn(a,b)``は、**aがbに含まれているかテスト**するメソッド。これを使ったサンプルが以下となる。

```python
import unittest

class TestSample(unittest.TestCase):
    def test_sample1(self):
        test_data = {
            "name": "ryota",
            "score": 63,
        }
        self.assertIn("score", test_data)

    def test_sample2(self):
        test_data = {"name": "ryota", "score": {"Math": 63, "English": 50}}
        self.assertIn("Math", test_data["score"])
        # これだとダメ
        # self.assertIn("Math", test_data) 

if __name__ == "__main__":
    unittest.main()
```
また、``assertIn(a,b)``の否定が``assertNotIn(a,b)``となる。
MacでDjangoのプロジェクトを作る参考サイト

# 開発環境
Mac（M1)
Python3.8
VSCode

# Pythonのインストール
Homebrew
↓
pyenv
↓
python

https://prog-8.com/docs/python-env


# Pythonがインストールされているか確認

```
python -V
```

きちんとバージョンが返ってきたらOK。

# pipは？
pipも最新化してバージョンを確認しておく。

```
pip -V
```

# VSCodeはこちらでインストール
https://qiita.com/watamura/items/51c70fbb848e5f956fd6

# Djangoのインストール
https://tomato-develop.com/mac-local-django-settings/

こちらの`Python仮想環境の作成`から進めます。

# 次回起動時のコマンド
djangoサーバを動かすために手順があります。

venvファイルがあるフォルダに移動し、venvを起動する。
```
source venv/bin/activate
```

manage.pyがあるフォルダに移動。
```
cd フォルダ名
```

manage.pyを起動する
```
python3 manage.py runserver
```
JavaScript Canvasのサイズについて

_HTMLコード_

```
<body>
  <canvas id="can"></canvas>
  <script src="example.js"></script>
</body>
```

上記コードのように、HTMLで「canvas要素」をID名「can」で記述し、
それをJavascript（ファイル名「example.js」）でいじっていきたいときの
サイズに関してのお話です。

まず「canvas」には「キャンバスサイズ」と「表示サイズ」があり、
「キャンバスサイズ」はHTMLで定義したcanvas要素をJavaScriptでいじっていく時の
基本となるサイズになります。
「表示サイズ」は、「キャンバスサイズ」で決定したサイズや形などを基準にどれだけの倍率でブラウザに表示するかというサイズになります。

_JSコード_

```
let can=document.getElementById("can");
let con=can.getContext("2d");

can.style.border="5px solid #000";

function square(){
  con.fillStyle="red";
  con.fillRect(140,65,20,20);
}
square();
```
上記コードのように、
まず「getElementById」でHTMLの「canvas要素」を取得、
「getContext」で２Dの描画を作成していくとし、
キャンバスサイズ（初期値）に枠線を描画、
塗りつぶし(fill)の「色」と「座標、サイズ」を指定した「square関数」を定義、
その「square関数」を呼び出し、
![スクリーンショット 2022-02-24 15.58.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521240/40b1b7d7-1463-6cdc-f592-ea7584616863.png)
上記画像をブラウザに表示させました。

まず最初に知っておかないといけないのは
キャンバスサイズは何も設定していなければ
初期値である「width:300px,height:150px」に自動で設定されます。
なので画像のような横長長方形になっているんですね。

キャンバスサイズは初期値の３００×１５０ですが、
表示サイズもまだ何も設定されていないため、
キャンバスサイズに準じている状態です。

その初期値の縦横の長さを踏まえた上で、「square関数」で指定した塗りつぶし四角を
丁度真ん中に持ってくるように指定しています。

それではこの長方形のキャンバスサイズ正方形にするために、
まずキャンバスサイズを変更していきます。

_HTMLコード_

```
<body>
  <canvas id="can" width="300px" height="300px"></canvas>
  <script src="example.js"></script>
</body>
```
HTMLのcanvas要素に上記コードのように「width」と「height」を追加して指定すると
![スクリーンショット 2022-02-24 16.18.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521240/45316709-0d73-f3d6-8fc6-02df4d440fe4.png)
初期値であった長方形が、
画像のような正方形のキャンバスサイズに変更されました。

次に「表示サイズ」を見ていきます。
表示サイズは今まで設定してきた「キャンバス」自体をブラウザにどのように表示させるかというもので、
普通はCSSを使って記述していくのですが、
今回はJSにCSSを記述していくやり方です。

_JSコード_

```
can.style.width="300px";
can.style.height="300px";
```

先程のJSの記述に上記コードを追加しました。
JSにサイズのCSSを記述するときは、
取得ID名（今回だと「can」）.style.「width or height」="サイズ";
という感じで記述します。

このコードだと、先程設定した「キャンバスサイズ」も３００×３００なので、
表示サイズもキャンバスサイズと一緒になり、先程の正方形になります。

_JSコード_

```
can.style.width="600px";
can.style.height="３00px";
```
次に表示サイズのwidthを６００pxにしてみます。
![スクリーンショット 2022-02-24 16.32.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521240/dfd4403c-d971-0acb-4a0f-49b5a9eab66e.png)
すると、黒の外枠は横長の長方形になりましたが、中の赤正方形も横に引き伸ばされました。
これは元の「キャンバスサイズ」は変わらず３００×３００の正方形なのに対し、
「表示サイズ」を横長にすることによって
キャンバス自体はそのままに、表示サイズで設定した横幅６００pxまで引き伸ばした結果になるためです。

HTMLで「canvas要素」を設定して、
「キャンバスサイズ」を設定せず（この時点で縦１５０px、横３００pxの初期値）、
CSSで表示サイズを３００×３００の正方形に設定したとしても、
![スクリーンショット 2022-02-24 16.43.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521240/825bd073-e83c-94cc-e924-cb75e2679c1b.png)
上記画像のようにブラウザに表示されるのは
横長のキャンバスが縦に引き伸ばされた正方形ができてしまうということですね。
[初心者向け][エンジニア的思考]  設計書とはどうして書くのか？

## 設計書って何なの？なんで書かないとダメなの？コードだけでいいでしょ？

スクールでプログラムを勉強している、学校で習った、趣味で何か作ってる・・・そういう方々が「仕事」で何かやろうと思ったときにこんなことを疑問に思うかもしれないです。

**「え？設計書なんているんですか？」「ソースコードだけでいいですよね？」「設計書なんていらないでしょ？」**

でも結論から言うとほとんどのケースであった方がいいです。


## 「設計する」ことと「設計書」をわけて考える

**設計**することは絶対大事です。
紙に書かず頭の中だけでも「これをどうやって解決しようか？」「本当にこの方法でいいのか？」と設計することは大事です。ここに異論がある人はいないと思います。

**設計書**とはその設計をドキュメントとして書くこと（書いたもの）です。

「**設計**」することの大事さはおいておいて今回は「**設計書**」に着目します。

## 設計書には必ず「目的」がある

作るからには何かしら目的があります。よくある目的を説明していきます。

### **目的１．自分の頭の整理のため**

意外とこれ多いです。
小さいプログラムなら頭の中で整理できるのですが、ちょっと大きいプログラムになると紙にメモしながらじゃないと大変です。そのメモが設計書です。

### **目的２．未来の自分のためのメモ（書かないとすぐ忘れるから）**

人は意外と忘れっぽいです。「あれ？なんでこんなことしてるんだっけ？？」というのを残すことも大事です。
もちろんこれはソースコード上にコメントで残しても良いです。

### **目的３．レビューや承認というコミュニケーションのため**

趣味で1人で作るようなプログラムと違って、仕事で作るプログラムは関係者が多く、かつ、なるべく間違ったものを作らない方がいいです。
最後まで書き上げてから「あ、それ違うよ」と言われると手戻りが大変です。
なのでなるべく最初の方に「こんな感じで作ろうと思うのですが変なところありますかね？」と確認したいです。ソースコードだけで全体像を把握するのはちょっと難しいのでそのために設計書は便利です。

承認というのも大事です。（自分の身を守るためにも）関係者にちゃんと理解してもらって うん と言ってもらうことは大事です。

### **目的４．プログラムが得意じゃない関係者にレビューしてもらうため**

目的３の補足ですが、レビュアーがあまりプログラムが得意じゃないケースはよくあります。
ちなみにQiita読者なら設計書は日本語が多いかなと思います。英語も多いかもしれないです。でもエスペラント語で書く人は少ないかなと思います。なんでエスペラント語が少ないかと言うと理解できる方が少ないからです。
同じ理屈で一般的にビジネスの関係者はソースコードを読むより日本語（英語）を読む方が得意なので「（日本語で書かれた）設計書」は重宝されます。

### **目的５．ソースコードでは表現できないことを書く場所に使う**

プログラムはプログラム単体で存在しません。
必ず使う人や外部のシステムや実行する環境などがあります。
そことのつなぎ込みの部分や前提や制限などソースコードを取り巻く環境について書くことはたくさんあります。
こういうことはソースコードには書きづらく設計書が重宝します。
もちろんソースコードにコメントとして書くこともできます。読みやすいかどうかは置いておいて……その場合はソースコードが設計書になってると言ってもいいです。

### **目的６．納品や管理のため**

仕事の内容を証明する・後世に残すためです。
だったら「ソースコードだけでもいいでしょ？」と思うかもしれないです。
「言われた通りソースコードを作るだけ」の作業ならそれでもいいです。でもエンジニアの仕事って「ソースコードを作るだけ」じゃないことがほとんです。あいまいだった要件を補完したところ、ソースコードがこういう形になった理屈理由、使い方、制限、ライセンスや法務的な注意事項・・・などなど言わないといけないことはたくさんあります。

### **目的７．なんとなく惰性で書いてるだけ**

もちろんそんなこともあります。
書かなくていい正統な理由があるなら書くのやめちゃいましょう！

### **補足：読者をちゃんと想定して書く**

読者を想定しましょう。
小学生？大人？エンジニア？企画？・・・日本人？英語圏の方？・・・熟練チームメンバー？新規参画者？
書くべき内容や粒度は変わってきます。

### **補足：書くコストも考えて書く**

「明日急に会社やめるかもしれないからいつでも引き継ぎ出来るように書く」・・・会社辞める確率はどれくらいでしょう？その確率が極めて低いなら「いつでも引き継ぎできるように全てドキュメント」はちょっとコストかかりりすぎですよね。
「明日隕石が衝突して人間が絶滅するかもしれないからプログラム組みません」・・・という人がいないのと一緒です。可能性だけで考えるのではなくちゃんとコストや確率を考えましょう。

## まとめ

書くためにはもちろん理由があります。
やるにしても、やめるにしても、ちゃんと理由は考えましょう！
AWSで機械学習を試してみたい方のための便利なツール

AWS INNOVATEで紹介されていたので、利用できそうなツールをいくつか紹介します。

# AmazonSageMakerCanvas
ビジネスアナリスト向けに作られたデータ分析ツール。
機械学習用の学習データをノーコードで準備できます。

# AmazonSageMakerJumpStart
コードを書かずにすでに学習済みのモデルを利用できます。

# AmazonSageMakerStudioLab
AmazonSageMakerのみを無料で利用したい方はこちらから登録をすることをお勧めします。

* [AmazonSageMakerStudioLab](https://studiolab.sagemaker.aws/)

※ただし、アカウント作成の申請後、承認をもらわないと利用できないためすぐに利用はできません。

# 学習データの精度向上ツール群
学習元となるデータの偏りをなくし、よりよいデータ群に変更する支援ツールを提供してくれています。

* Data Wrangler:データの可視化、グラフ化
* Feature Store:特徴量の管理
* Clarify:偏りの検知

# まとめ
機械学習とAIシステム構築については、継続的に学んでいきたいと思います。
面白いツール作れないかな。
3D空間で紙飛行機を回転（クオータニオン）


# 紙飛行機をモデルにしてクオータニオンで回転する様子をpython matplotlibで見てみます

https://github.com/OkitaSystemDesign/python3d

クオータニオンを使って紙飛行機を回転
PaperAirplaneQuaternion
![Quaternion400.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2489321/3861c90a-2090-8cc4-f70a-2bebb60ab214.gif)
## 環境
Windows10
python3.9
numpy
Matplotlib


## 使い方
#### 紙飛行機を回転させる関数
```python
PaperAirplaneQuaternion(angle, order)
```
angleに目標とする姿勢のオイラー角[x,y,z]をセットて渡します
orderは回転順でXYZ,XZY,YXZ,YZX,ZXY,ZYXの種類の中から選択します
#### 例
```python
angle = [80.0, 120.0, 60.0]       # 最終姿勢のオイラー角
order = EulerOrder.XYZ
PaperAirplaneQuaternion(angle, order)
```
オイラー角（angle）にX=80度、Y=120度、Z=60度回転するようにセットします  
回転順（order）にXYZ順を指定します 回転順はEulerOrder列挙型で指定します  
PaperAirplaneQuaternionを実行すると3次元のグラフが表示されて回転が始まります

## 説明
紙飛行機は各頂点の点を結んでポリゴンで表示しています
回転軸を中心にクオータニオンで回転する様子を確認できます

## クオータニオンとオイラー角の計算
計算はこちらを参考にしました
[回転行列、クォータニオン(四元数)、オイラー角の相互変換](https://qiita.com/aa_debdeb/items/3d02e28fb9ebfa357eaf)
Git switchコマンド

# 背景
Gitをコマンドで操作していて、
今までブランチを切り替えるときはcheckoutを使っていました。

# 概要
`git switch` コマンドは、
**ブランチの切り替え専用**のコマンドです。

バージョン2.23でリリースされたようです。

# なぜできたのか
`checkout` コマンドには問題がありました。
それは、ブランチの切り替え操作以外に、変更の取り消し操作も兼ねていたということです。

# switchとcheckoutの違い
## 作業ブランチ切り替え
```
git switch <branch name>
```

```
git checkout <branch name>
```

作成済みのブランチに切り替える場合はどちらも変わりません。

## 一つ前のブランチへの切り替え
```
git switch -
```

```
git checkout -
```
こちらも同様であるようです。

## 新たにブランチを作成して切り替え
```
git switch -c <branch name>
```

```
git checkout -b <branch name>
```
オプションが変わっています。

# まとめ
`git checkout` よりも機能を制限され直感的になった `git switch` の方が分かりやすく、
誤操作防止にもなるかと思いました。

# 参考
[gitコマンド checkoutとswitchの違い　～これからはswitchを使おう～](https://snowsystem.net/git/git-command/git-switch/amp/)
基本的なコンソールアプリケーションの構造 with ConsoleAppFramework

2022版を作った後で ConsoleAppFramework https://github.com/Cysharp/ConsoleAppFramework を見つけたので記録。

## パッケージ

```xml
    <PackageReference Include="ConsoleAppFramework" Version="4.0.6" />
    <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
```

## 設定ファイル

appsettings.json

```json
{
  "Id": "101",
  "Name": "name1"
}
```
nlog.config

```xml
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Error"
      internalLogFile="${basedir}\logs\internal-nlog.log">

	<extensions>
	</extensions>

	<variable name="logDirectory" value="${basedir}\logs" />
	<targets>
		<target xsi:type="File" name="file" fileName="${logDirectory}/log-${shortdate}.log"
				layout="${longdate} [${level:uppercase=true}] [${threadid}] ${callsite:includeNamespace=false}#${callsite-linenumber} ${message} ${exception:format=tostring}" />

		<target name="Console" xsi:type="console" layout="${longdate} [${level:uppercase=true}] [${threadid}] ${callsite}#${callsite-linenumber} ${message} ${exception:format=tostring}"/>
	</targets>

	<rules>
		<logger name="*" minlevel="Trace" writeTo="file,console" />
	</rules>
</nlog>
```

いずれも "常にコピーする" または "新しい場合はコピーする"を設定しておく

## 設定クラス

```csharp
class SampleSettings
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
}
```

string はnullable警告が出るので回避のため空文字列で初期化しておくとか、nullableにしておくとか、 nullable referenceを使わないとかしておく。

## コマンドクラス

コマンドの本体

```csharp
class Foo : ConsoleAppBase
{
    private readonly Microsoft.Extensions.Logging.ILogger _logger;
    private readonly SampleSettings _settings;
    public Foo(IOptions<SampleSettings> settings, ILogger<Foo> logger)
    {
        _settings = settings.Value;
        _logger = logger;

    }
    public void Hello(string name)
    {
        _logger.LogTrace($"{_settings.Id} {_settings.Name}");
        _logger.LogTrace($"{name}");

    }
}
```

ConsoleAppFramework が Microsoft.Extentions.DependencyInjection をサポートしているおかげで対象Commandへの注入が効く。
ここではIOption と ILogger<T> を注入しているけど、EFCore6とか使うならDbContext も注入できるだろうしほかの関連サービスも行けるはず。

## プログラム本体

今回は VS2022/c#10 なので `void Main(string[] args` 不要

```csharp
var builder = ConsoleApp.CreateBuilder(args);
builder.ConfigureServices((ctx, services) =>
{

    // Register appconfig.json to IOption<MyConfig>
    services.Configure<SampleSettings>(ctx.Configuration);

    // Using Cysharp/ZLogger for logging to file
    services.AddLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddNLog();
        logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
    });
});

var app = builder.Build();
app.AddCommands<Foo>();

app.Run();

```

ConfigureServices 内でサービス設定やらログ設定やらを実行しておく。

## その他

前回よりはコード記述量が大幅に減る。よい。
カテゴリとクラス拡張についてメモ


　UIImage+Rect.mとか、NSString+size.mとか、不思議だなと思っていた。


やっていることは、もともとのiOSフレームワークを活用して、やりたい機能だけ追加しているという感じだった。
なので、もともと存在するiOSフレームワークにだけ使える拡張機能かと思っていたが、違うらしい。

新規で作成したVCなどにも活用できる。


いや、そりゃそうでしょって感じなのですが。



クラス拡張は、UIImageやNSString、UIButton、UILabelなどよく使うUIKitやFoundationの機能拡張が多い。
カテゴリは。冗長化してきたソースを機能ごとに分割するのに使うケースが主流なのかな。



そうじゃないよ、というときは、指摘していただければ、確認しますので、
気楽にコメントください。
javascript での位置取得と submit の備忘録

# はじめに

仕事で位置情報を取得する Javascript コードを書いたのでその際の経験を忘れないように記載しておきます。

# 位置情報取得の構文

以下の構文が現在地を取得する基本的な構文です。

```javascript
function success(position) {
    // 成功の場合
    var latitude  = position.coords.latitude; // 緯度
    var longitude = position.coords.longitude; // 経度
};
function error() {
    // エラーの場合
    alert("現在位置を取得できません");
};

// 位置情報を取得し、どちらかのコールバック関数を実行
navigator.geolocation.getCurrentPosition(success, error);
```

## Geolocation.getCurrentPosition()
```navigator.geolocation.getCurrentPosition(success, error)``` は端末の現在位置を取得するメソッドです。位置情報の取得に成功した場合は **success** に与えたコールバック関数を実行し、位置情報の取得に失敗した場合やユーザーが位置情報の取得を拒否した場合は **error** に与えたコールバック関数を実行します。
その他、第３引数にオプションの設定が可能です。

## コールバック関数の入力引数
```getCurrentPosition(success, error)``` のうち、**success** 側には **GeolocationPosition** インターフェイスのインスタンスが与えられ、現在位置の情報や取得した時刻が取得できます。
**error** 側には **GeolocationPositionError** インターフェイスのインスタンスが与えられ、エラーコードやエラーメッセージを取得できます。

# Geolocation.getCurrentPosition() と submit() の併用

ここで、位置情報の取得と submit が並んだ際の挙動について記載しておきます。

## 問題設定

位置情報の取得と submit() の併用のサンプルとして、

1. 送信するボタンを押下した際に実行される
2. 現在位置を取得して、指定の input に値を設定
3. 設定後にフォームの内容を submit

という処理を行う ```pushSubmit()``` 関数を用意するとします。

## 実際に書いた構文と発生した問題

例えば、以下の様な構文を書いたとします。

```javascript
function pushSubmit() {
    function success(position) {
        // 成功の場合
        var latitude  = position.coords.latitude; // 緯度
        var longitude = position.coords.longitude; // 経度

        document.getElementById('latitude').value = latitude;
        document.getElementById('longitude').value = longitude;
    };
    function error() {
        // エラーの場合
        alert("現在位置を取得できません");
    };

    // 位置情報の取得を試みる
    navigator.geolocation.getCurrentPosition(success, error);

    // 実際にsubmit
    var form = document.getElementById('form');
    form.submit();
}
```

この構文は流れとしては **「位置情報の取得 → submit」** と書いているので位置情報が取得できているように思われます。
ですが、実際に実行して submit されたサーバサイドでリクエストパラメータを確認すると以下の様になります。

```
[
   'latitude' => null,
   'longitude' => null
]
```

ご覧の通り、取得したはずの位置情報が記載されていません。

これはコードの実行とコールバック関数の処理の順序が原因です。
```getCurrentPosition()``` が実行され、その結果を基に ```success``` のコールバック関数が実行される場合でも、```success```に処理が渡った段階でメインの処理も```submit()```に進むため、```success```の処理が終わる前に submit されてしまうという流れになります。

## 対策

対策は簡単で、コールバック関数の中に submit を移動してしまうというものです。

```javascript
function pushSubmit() {
    function success(position) {
        // 成功の場合
        var latitude  = position.coords.latitude; // 緯度
        var longitude = position.coords.longitude; // 経度

        document.getElementById('latitude').value = latitude;
        document.getElementById('longitude').value = longitude;

        // 実際にsubmit                              //
        var form = document.getElementById('form'); // <-- ここに移動
        form.submit();                              //
    };
    function error() {
        // エラーの場合
        alert("現在位置を取得できません");
    };

    // 位置情報の取得を試みる
    navigator.geolocation.getCurrentPosition(success, error);
}
```

上記の様に構文を変更することで、確実に指定の input に値を設定した上で submit されます。
もし、位置情報の取得が失敗した場合も submit したい場合は ```error()``` にも submit の構文を記載してください。
switch_to_blogでタクソノミーが出力されない

マルチサイトで、子サイトにメインサイトの情報を出力するのに、タクソノミーの配列が適応されなくてハマりました。
get_siteとか色々調べてみたけど、なんと単純に出力したい子サイトに、メインサイトと同じように投稿タイプとタクソノミーを追加したら出力されました。。。
同じようにお困りの方のお役に立てたらと思い記しておきます。

WordPress 5.9
SwiftUI で大量のファイルをドキュメントパッケージとして扱うアプリの開発は不向き

## はじめに

毎年 `SwiftUI` に期待しながら、ちょっと触ってみてまだ早熟かなと、ずっと距離を置いていたのですが、ある人言葉をきっかけにやっぱりそろそろ試してみようかなと思うようになりました。

個人的にはグラフィックやメディアを扱うアプリを扱う事が多いので、ちょっとメディアコンテンツのエディターみたいなものを冷やかして書いてみようかなと思いました。

想定するアプリをこんなものに想定してみます。

- iOS、または macOS のドキュメントベースのアプリとする
- データのサイズが大小さまざまの大量のテキストやイラストや動画や音声を扱うため、パッケージ（フォルダ）ベースのドキュメントとする

## やってみた

さて、Xcode から `Multiplatform > Application > Document App` からドキュメントベースのテンプレートを選びます。`Multiplatform` からだと、`SwiftUI`ベースのプロジェクトに勝手になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65634/0c5e03d2-caa5-3249-f828-46d3fc7ce95a.png" width="512" />

`CFBundleDocumentTypes`や`UTExportedTypeDeclarations`そして`UTImportedTypeDeclarations`を設定して、ドキュメントをパッケージとして扱います。

そして、`FileDocument`ベースで`MyPackageDocumentAppDocument`を実装します。まずはドキュメントを読み込むには次のメソッドを実装します。

```
init(configuration: ReadConfiguration) throws
```

```
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper
```

さて、`configuration.file` で`FileWrapper`にはアクセスできますが、`FileWrapper`経由でディレクトリに直接アクセスする事はできません。

さて、気を取り直すとして、`UIDocument`では次のメソッドをオーバーライドして、ディレクトリに直接アクセスする事ができました。

```.swift
override func write(to url: URL, ofType typeName: String) throws
```

```.swift
override func read(from url: URL, ofType typeName: String) throws
```

さて、`SwiftUI`では・・

「………」

`FileDocument`はそもそもプロトコルで`func read(from url: URL, ofType typeName: String)`に相当する実装はできません。

まぁ、`iCould Drive`のような環境が出てきて、ドキュメントのディレクトリに直接アクセスしてくれるなという気持ちは分かりますが、ドキュメント内で大量のファイルをパッケージとして扱いたい場合に、これらを全て`FileWrapper`で包んで読み書きするのは無理筋そうなので、今回はここで詰んだという事になりそうです。

## コード

今回の検証の為に書いたコードは以下のURLから取得できます。ドキュメントを保存すると無駄に巨大なバイナリファイルがパッケージ内に作られるので、動作確認後は書類は削除してください。

https://github.com/codelynx/MyPackageDocumentDemo

## 結論

特定のアプリの実装に`SwiftUI`を採用するにはまだ早すぎるようです。

## 環境

執筆時点での環境は以下の通りです。

```
Xcode: 13.2.1
Swift: 5.5.2
macOS: 12.2.1
iOS: 15.3.1
```