OmniAICreator/Qiita-1.07M huggingface dataset:
放置されたクレートをなんとかする

# はじめに

この記事は [Rust 3 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/rust3) の24日目です。
最後1つ埋まっていないのは気になるので埋めておきます。

Rustのクレートは比較的よくメンテナンスされている印象ですが、やはり放置されたクレートというのも時々見かけます。十分枯れていて問題なく動いているならいいのですが、放置された結果コンパイルが通らなくなっているような場合は困ってしまいますね。そういったクレートに対して個人的にやっている対処法を書いてみます。

## Pull Request(PR)を送る

最初にやるのはPRを送ることです。放置されているように見えて、PRを送るとすぐにマージしてくれる場合もあります。特定のプラットフォームでコンパイルエラーになるようなケース（特にWindowsはケアしてる人が少ないです）は、単に作者が気づいていないだけ、ということも多いです。

## メールを送る

PRを送っても反応がなく、他の人のPRもたくさんたまっている状態であることもあります。このような場合でも、直接メールを送ってみると案外すぐ反応してくれることがあります。自分自身を振り返っても、仕事が忙しいときに来たPRは「あとで見よう」と思って通知から消して、そのまま忘れてしまうことがありますね…。
個人的には、PRを作成してから1~2か月反応がなくて、ユーザ側で回避不能な問題がある場合はメールを送ってみることにしています。

## メンテナになる

↑でメールを送るときに、「もし時間がとれないならメンテナンスを引き継いでもいいですよ」というようなことを一緒に書いています。ちょうど昨日このパターンで、cargo-licenseというツールのメンテナになりました。

https://github.com/onur/cargo-license

## フォークする

これはできれば避けたいのですが、全く反応がなければフォークするしかありません。GitHub上では単にフォークすればいいのですが、crates.ioに登録されている名前はどうしようもないので適当に名前を変えるしかないです。
名前がちょっとだけ違うクレートが乱立すると「どれ使ったらいいの？」となってしまうので、なるべくこうならないようにしたいですね。
こうなっているパターンとしては [interfaces](https://github.com/andrew-d/interfaces-rs)と[interfaces2](https://github.com/aep/interfaces-rs) があって、これはどちらも放置状態です。
（正確にはinterfaces2の作者さんとは連絡が取れていますがメンテナンスする気はないとのことで、interfacesの作者さんとはまだ連絡が取れていません。interfacesが無理そうならinterfaces2を引き継ごうかな、と思っています）

追記(2020/12/30)
interfacesの作者の人と連絡がついて、こちらも引き継ぐことになりました。interfaces2は閉じてもらって、こちらに一本化したいと思います。

# まとめ

クレートが放置されているときに個人的にやっていることを書いてみました。やはりOSS活動というのは各個人の事情によるところが大きいのでなかなか難しい部分がありますね。最近[Inside Rust Blog](https://blog.rust-lang.org/inside-rust/)（とそこからリンクされたブログ）にこんな記事がありました。

[Changes to Rust compiler team](https://blog.rust-lang.org/inside-rust/2020/12/14/changes-to-compiler-team.html)
[Rotating the compiler team leads](https://smallcultfollowing.com/babysteps/blog/2020/12/11/rotating-the-compiler-team-leads/)

Rustのコンパイラチームリーダーを定期的にローテーションさせることにした、という話です。このように継続的に開発が続けられる仕組みづくりに取り組んでいるのはとてもいいと思います。
【初めてのAPI】PythonでQiita記事を取得してみる

## はじめに

初めてAPIを叩いたので個人的備忘録として残します。

今回はデータ取得までしか行っていませんが、いずれは色々とやってみたいです。


## アクセストークンの取得

QiitaのAPIを使うために、アクセストークンを取得します。

アクセストークンとは、API利用者かどうか判断するライセンスのようなもの。

発行方法ですが、まずはQiitaの自分のページにアクセスし、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933996/d42d950a-8f84-6046-eb54-602dbe7444c9.png)

上記画面の設定から、設定画面に行き、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933996/6326d035-5df2-7d5a-dd03-3862521cfac2.png)

アプリケーションをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933996/66d847dd-640c-ec44-7773-7258730b42dd.png)

私はもう発行していますが、個人用アクセストークンのところからアクセストークンを発行する。

ランダムな英数字の列が表示されるので、必ずメモしておいてください

## コマンドラインで動作確認

コマンドライン上でcurlコマンドを使ってまずは取得できるかを確認します。

```
curl -s -H "Authorization: Bearer <先ほどのアクセストークンの値>" https://qiita.com/api/v2/authenticated_user/items
```

* -s : 進捗状況を表示しない(サイレントモード)
* -H : リクエストヘッダーを指定する

```
C:\>curl -s -H "Authorization: Bearer <アクセストークンの値>" https://qiita.com/api/v2/authenticated_user/items
[{"rendered_body":"\n\u003ch2\u003e\n\u003cspan id=\"はじめに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eはじめに\u003c/h2\u003e\n\n\u003cp\u003e個人的備忘録として発信しています。\u003c/p\u003e\n\n\u003ch2\u003e\n\u003cspan id=\"起きたこ と\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e起きたこと\u003c/h2\u003e\n\n\u003cp\u003eリモートリポジトリにp・・・
```

長いので省略。。ですが、取れていそうです。

## Pythonで実装する

コマンドベースでは出来たので、これをpython経由で実行します。

調べているとcurlコマンドをpythonに変換してくれる神ツールを見つけたのでこれをベースにしています。
(あれ、私実装っぽいこと何もしていない。。)

[curlコマンドをpythonに変換するサイト](https://curl.trillworks.com/)

変換したものを少し直して、次のようになりました。

```
import requests
import json
import pprint

URL = "https://qiita.com/api/v2/items"
TOKEN = "<アクセストークンの値>"
HEADER = {
    'Authorization': 'Bearer {}'.format(TOKEN),
}

response = requests.get(URL, headers=HEADER)
pprint.pprint(response.json())
```
pprintを使って、少しきれいにしています

実行してみると

```
・・・
  'title': '[Serverless Framework] yarn workspaceを使ったmonorepo',
  'updated_at': '2020-12-28T19:26:14+09:00',
  'url': 'https://qiita.com/allJokin/items/9316e5384a3bf7a4536b',
  'user': {'description': None,
           'facebook_id': None,
           'followees_count': 0,
           'followers_count': 0,
           'github_login_name': 'allJokin',
           'id': 'allJokin',
           'items_count': 1,
           'linkedin_id': None,
           'location': None,
           'name': '',
           'organization': None,
           'permanent_id': 600358,
           'profile_image_url': 'https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/600358/8d5eba69a13ba6bef9ae50d23c9a1fa3e87b60ae/large.png?1607605958',
           'team_only': False,
           'twitter_screen_name': 'AllJokin',
           'website_url': None}}]
・・・
```

取れていそうです！！

## 補足

python 3.8.0
requests 2.25.1

## 感想
APIの仕様書が全然理解できず、記事情報全部持ってくることしかできませんでした。。
更に読み込んで、使いこなせるようになりたいです。
あと、今回はハードコーディングしていますが、config管理するなども考えていきたいです。

次はAmazonのAPIに挑戦するつもりです。
Dockerを用いたLaTeX環境で文章を作成する

本記事は[東京学芸大学 櫨山研究室 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/hazelab)の19日目の記事になります．

私が所属する研究室では月1でゼミ資料(文章)の提出を伴う研究の進捗報告があります．
私はこのゼミ資料をDockerを用いたLaTeX環境で作成しています．

本記事ではこのDockerを使ったLaTeX環境での文章作成について紹介したいと思います．

# そもそもTeXとは何か？

TeXは組版ソフトであり，macOS，Windows，LinuxなどOSの環境が異なっていても，全く同じ動作をします．入力が同じなら原理的には同じ出力が得られます．

**またTeXファイルはテキストファイルでありGitHubなどで版管理・再利用することが容易です．**

## ではLaTeXとは何か？

LaTeXはLeslie Lamportにより機能強化されたTeXです．

LaTeXは文章の論理構造と視覚的なレイアウトを分けて考えることを機能としてサポートしており，文書の再利用性を高めています．
章・節・図・表・数式の番号付けや目次・索引・引用文献の処理も自動的に行えます．


# TeXの動作原理

TeXファイルでのPDFファイル生成までの動作原理は図で示すと以下のようになります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225901/cbecbd0e-1e2a-0195-7f55-b4fee31c6f7b.png)

TeXでは，組版結果をdviファイルという中間ファイルに書き出し，このdviファイルをdviドライバと称されるソフトウェアに渡すことでPDFを作成します．

# Dockerを用いたLaTeXでの文章作成

LaTeXの環境構築ですがホストマシンにLaTeXを入れると余計なエディタなどが付いてきます．
そこでDockerを用いてLaTexのコンパイルとPDFの生成を行ってしまいます．

このDockerを用いたコンパイルとPDFの生成の流れは以下の図の通りです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225901/299b1cdf-b0d3-3c26-cdd2-1cd52488aef3.png)


TeXファイルの作成・編集はホストマシン上で行い，コンパイルとPDFの生成をDockerコンテナ内で行います．

## Dockerイメージの取得

Dockerイメージには[paperist/docker-alpine-texlive-ja](https://hub.docker.com/r/paperist/alpine-texlive-ja/)を利用します．
alpineベースのイメージでLaTeXのイメージとしては軽量(1Gb程度)です．
`docker pull`コマンドでimageを取得しておきます．

```bash
docker pull paperist/alpine-texlive-ja
```

## 文章ファイル(.tex)の用意とコンテナの作成

まず文章ファイルを`doc.tex`としてを用意します．

```bash
# ファイルの作成
touch doc.tex
```

中身はとりあえず適当です．

```tex:doc.tex
\documentclass[a4j, twocolumn]{jsarticle}

\begin{document}
  Hello, World!
\end{document}
```

先ほど取得したイメージを元にコンテナ名`latex-complile`，現在のディレクトリをDockerコンテナ内の`/workdir`と共有したコンテナを立ち上げます．

```bash
$ docker run --rm --name latex-compile -it -d -v ${PWD}:/workdir paperist/alpine-texlive-ja
```

## コンテナ内でコンパイルとPDFの生成

Dockerコンテナ内でコマンドを実行するには`docker exec`を利用します．
コンテナ内にはLaTeXの環境があり`uplatex`コマンドが利用できます．

```bash
$ docker container exec -it latex-compile bin/ash -c "uplatex doc.tex && dvipdfmx doc.dvi"
```

正常にコンパイルが通れば，PDFファイルをホストマシン上で確認できます．

## コンパイル手順をMakefileに記述する

先ほどのDockerコマンドは長すぎるので`Makefile`にタスクとして記述してしまった方が無難です．

またMakeのタスクでは`latex-compile`というDockerコンテナが無ければコンテナを立ち上げてから`docker exec`コマンドを実行するようにします．

```make:Makefile
.PHONY: compile
compile:
	docker ps -a | grep latex-compile || docker run --rm --name latex-compile -it -d -v ${PWD}:/workdir paperist/alpine-texlive-ja
	docker container exec -it latex-compile bin/ash -c "uplatex doc.tex && dvipdfmx doc.dvi
```

これにより以下のコマンドで編集した文章ファイル(doc.tex)のPDFを生成可能です．

```bash
make compile
```

なお本記事で解説している内容を含んだゼミ資料のテンプレートは以下のリポジトリで公開しています🙇‍♂️

<a href="https://github.com/HazeyamaLab/seminar-template" target="_blank" rel="noopener noreferrer"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/HazeyamaLab/seminar-template.png" width="460px"></a>

# 参考

- paperist/alpine-texlive-ja, https://hub.docker.com/r/paperist/alpine-texlive-ja/
- Paperist/docker-alpine-texlive-ja, https://github.com/Paperist/docker-alpine-texlive-ja
Spring BootでDBアクセスするコンソールアプリ

#前提
1. Maven
1. Postgres
1. テストコードなし

#手順
1. eclipse起動
1. 新規＞Springスターター・プロジェクト
1. 適当に入力して(思い通りにならないことがあるので)次へ
1. 以下選択して完了
 1. JDBC API
 1. PostgreSQL Driver
 1. お好みでLombok
1. 生成されたプロジェクトの以下についてeclipseのリファクタリング機能で好きに修正
 1. eclipseのプロジェクト名
 1. 生成ソースのフォルダ
 1. 生成ソースのパッケージ
 1. 生成ソースのメインクラス名
 1. pom.xmlのgroupId/artifactId/version/name/description
1. pom.xmlからspring-boot-starter-testのdependency削除
1. 生成ソース内のsrc/testフォルダ削除
1. 生成ソースのメインクラスに「implements CommandLineRunner」追加、エラーになるので実装されていないメソッドの追加、runメソッドが生成される、これが実行開始場所になる
1. src/main/resources/application.propertiesに「spring.datasource.url=${DATABASE_URL}」追加
1. eclipseのBootダッシュボードで作成プロジェクトの構成を開き、環境変数「DATABASE_URL」追加、値の形式は「jdbc:postgresql://＜ホスト＞/＜DB＞?user=＜ユーザ＞&password=＜パスワード＞」
 1. 必要に応じて「&sslmode=require」付与
1. DBアクセスを行うクラス(生成メインクラスでも良い)で以下を書く
 1. クラスに「@Component」付与
 1. お好みでクラスに「@Slf4j」を付与するとlog.debug()等が使えるようになる
 1. フィールドに「@Autowired protected JdbcTemplate jdbcTemplate;」作成
 1. トランザクション単位となるメソッド(生成メインクラスのrunでも良い)に「@Transactional」付与、jdbcTemplateでDB操作

以上
「amazon-linux-extras」→「No module named amazon_linux_extras」になる場合の対処法

pyenvがインストールされ、pythonのバージョンを変えていると、以下のようにamazon-linux-extrasは使えないそうです。
なので、使えるようにしてあげます。

現在のエラー

```
$ amazon-linux-extras
/home/ec2-user/.pyenv/versions/3.7.0/bin/python: No module named amazon_linux_extras
```

### 解決策

pyenvで、python3.7.0にしている人はコチラ。

```
ln -s /lib/python2.7/site-packages/amazon_linux_extras ~/.pyenv/versions/3.7.0/lib/python3.7/site-packages/
```
pyenvで、python3.7.5にしている人はコチラ。

```
ln -s /lib/python2.7/site-packages/amazon_linux_extras ~/.pyenv/versions/3.7.5/lib/python3.7/site-packages/
```

他のバージョンの人はこれを参考に書き換えてください。
これで「amazon-linux-extras」周辺のコードは使えます。✌️
Minikubeでdocker hubからimageをpull出来ない問題の解消法

## 環境

* Mac OS X 11.1
* Minikube v1.16.0

## 起きた問題

podを起動しようとした時にdocker hubからpullしようとしているイメージが毎回 `failed to pull image`となってイメージがpull出来なかった

## 解決方法

現状のminikubeのドライバーのvmとhyperkitにはネットワークアクセスの問題があるらしく、driverを`docker`にして起動することで解消できた

```sh
$ minikube start --driver=docker
```
nuxt/content + netlify で爆速ブログ構築

## はじめに
@nuxt/contentを使ってブログを作って公開してみたので備忘録的に一通りの手順を残しておきます。

## @nuxt/content
GitベースのヘッドレスCMSとして動作するモジュールで、```/content```ディレクトリ内のマークダウン、JSON、YAML、CSVファイルを取得できます。

## まずは環境構築
create-nuxt-app を使う

```
$ yarn create nuxt-app プロジェクト名

...
? Choose rendering mode Universal (SSR)
...

```

一通り終わったら、

```
$ yarn add @nuxt/content
```

nuxt.config.jsで以下の設定をします。

```nuxt.config.js
modules: ['@nuxt/content'],
  generate:{
    async ready () {
      const { $content } = require('@nuxt/content')
      const files = await $content().only(['slug']).fetch()
      console.log(files)
    }
  },
```

これで準備完了！！！

## コンテンツを作成する
プロジェクト内の```/content```ディレクトリを作成。今回はマークダウンファイルを作成します。

```
content/
  articles/
    my-first-blog-post.md
```

```my-first-blog-post.md

---
title: 記事のタイトル
description: 記事のディスクリプション
---

## heading

<info-box>
 /// 
</info-box>
```
記事内では```<info-box>```のように```/components/global/```内で作成したVueコンポーネントを使用することができます。コンポーネントの南昌はケバブケースでしないとエラーが出ます。またセルフクローズタグは使えませんのでご注意。

## コンテンツを表示する
template内で```<nuxt-content>```コンポーネントを使用して記事のbodyを表示します。

```_slug.vue
<template>
  <article>
    <h1>{{ article.title }}</h1>
      <nuxt-content :document="article" />
  </article>
</template>
<script>
export default {
  async asyncData({ $content, params }) {
    const article = await $content('articles', params.slug).fetch()
    return {
      article
    }
  }
}
</script>

```


## netlifyにdeploy
netlify側の設定手順は以下

1. netlifyにログイン、もしくは登録
2. 「New site from Git」をクリック
3. リポジトリとビルドコマンド(```yarn generate```)、公開するディレクトリ(```/dist```)を選びます

あとはプロジェクトディレクトリ内で```yarn generate```を叩くと公開されます！
[実際に公開したものはこちら(コンテンツはサンプルです)](https://dreamy-williams-c59aa6.netlify.app/)

## おわりに
今回はNuxt-content + netlifyでブログを手軽に作成、公開までをざーーーっと書きました。
自分も環境構築から公開まで約１時間くらいで終わりました。
今後は検索機能やタグを付与したりなどどんどん拡張していきたいなと思います。

## 参考記事等
* [nuxt/content公式](https://content.nuxtjs.org/ja)
* [Nuxt.jsでGatsbyJS的なことができるnuxt/contentを試してみる](https://qiita.com/tetsushi-ito/items/d3ec0043316b81d1f86e)
* [Nuxt/Content で Markdown なブログ・お知らせサイト作る](https://qiita.com/feb19/items/f030474fbdc4bcb4e0c7)
Unity歴一ヶ月目の初心者の学習方法

#はじめに
N高等学校1年のdaichiです。
プログラミングもまともにできない、何もかもが初心者の自分が
1ヶ月前にゲーム作りたい！FPSつくってみたい！
と、唐突に思い立って、ゲームを作り始めてからの一ヶ月間何やってきたかの、学習記録です。
Qiitaの記事を書くのは二度目なので、文章も稚拙だとは思いますが、読んでいただければ幸いです。
#やった内容
・N予備校のUnity講座で、Unityの基礎知識を習得
・C#がわからなさすぎたので、paizaラーニングでC#の勉強
・「何事も実践だ！」と思って、FPSを制作開始
#N予備校
まず[N予備校](https://www.nnn.ed.nico/)の中にあるUnityで基礎を固めることにしました。
ですが、まだ、初めて一ヶ月もたっていないわけで…
そんな初歩的な内容でさえ、一つの単元を終えるのに、かなりの時間がかかってしまっていました…
まぁ、その一番の大きな原因が、C#なんて一切勉強したことがなかったことが原因だったんですね…
#paizaラーニング
progateにはC#講座ないし、どうしようって思ってたときに、ふとpaiza覗いてみたら、
C#の講座が全部無料だったんですね。
これはやるしかねぇ！っておもって勉強始めました。
ある程度やって、レベルチェック問題やろう！と思い、やってみるが…
D問題ですら、全然解けなかったです…
軽く挫折しましたね…
#FPS制作
「もうそれなら、実践だ！」
ってのりで制作を始めて
[こちらのサイト](https://unity.moon-bear.com/zombie-slayer/fps-character/)などを参考にしながら、制作を進めていたのですが…
まぁ、出てくるコードすべてわからんで、大変でした。
というか、内容がわからなすぎて、
弾丸を発射するコードを書くことが未だにできていません。
内容を理解できていないまま、コピペして仕上げるのはなんか違うなって思ったので、まだできてません…
なので、今は![スクリーンショット 2020-12-28 3.14.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/861438/c3f49a07-aa60-afb6-6ee9-c563faa91336.png)
まぁ、フィールドは凄い雑だし、さらに銃をセットアップしたところで、進捗止まってます…
Google先生に聞いて調べながら進めてるんですが、rayとか、全然理解できてないですね…
#終わりに
はい、私は今月このようなことをやっていました。
かなり、色々なところで挫折した一ヶ月でした。
頑張りたい、やりたいって気持ちはあるんですけど、
ゲームに対してかなりモチベーションが下がって来てしまっているので
少し離れるかもなーって思ってます…
ここまで読んでいただきありがとうございました。
良ければ、アドバイス、いい勉強法など教えていただけると幸いです。
Unicorn の timeout (61s > 60s), killing で worker が死なない件

Sinatra + Unicorn + Nginx で、重たい処理があって、タイムアウトをしたのは良いのですが、何故か Unicorn が エラーを吐いただけでワーカーが死んでくれなくて、ついには稼働可能なワーカーがなくなってアクセスできない現象がおきました。

＃ワーカーが死なないので、こんな感じで食い潰される。。。

```
E, [2020-12-28T16:40:26.120353 #3627] ERROR -- : worker=1 PID:3634 timeout (61s > 60s), killing
E, [2020-12-28T16:40:27.122323 #3627] ERROR -- : worker=1 PID:3634 timeout (62s > 60s), killing
E, [2020-12-28T16:40:28.124271 #3627] ERROR -- : worker=1 PID:3634 timeout (63s > 60s), killing
E, [2020-12-28T16:40:29.126276 #3627] ERROR -- : worker=1 PID:3634 timeout (64s > 60s), killing
...
```

## unicorn-worker-killer
検索すると、だいたいが、タイムアウト時間の調整とか、そもそもタイムアウトするような処理にするな、とか、そういうものばかりでして、いや、どうしてもタイムアウトになってしまったらどうなのよ？、と思いながらも、調べていると、```unicorn-woker-killer```というものがあるらしく、ちょっとみてみましたが、どうやらこれは、指定回数ワーカーがアクセスされたら再起動、メモリ使用量が指定量を超えたら再起動、という感じで、タイムアウトしたら再起動、というものでは無いらしいことがわかりました。

むむむ。

## 困った時のソースコード
しばらく色々とやってみましたが、ダメでしたので、ソースコードを見ることにしました。

https://github.com/defunkt/unicorn

```killing``` で検索すると ```/unicorn/lib/unicorn/http_server.rb``` に何かあるようです。

真ん中あたりにある ```def murder_lazy_workers``` の中に

```ruby
logger.error "worker=#{worker.nr} PID:#{wpid} timeout " \
             "(#{diff}s > #{@timeout}s), killing"
kill_worker(:KILL, wpid) # take no prisoners for timeout violations
```
というコードが見つかりました。これはエラーログに出ている文言と一緒なので、ここで合っているっぽいです。
コメントに何が書いてあるかは良く分かりませんが、```kill_worker(:KILL, wpid)```でプロセスを殺してるのがわかります。

というわけで、```kill_worker```を見てみます。

## ん！？
下の方に ```def kill_worker(signal, wpid)```というメソッドがあるので、見ていきます。

```ruby
def kill_worker(signal, wpid)
  Process.kill(signal, wpid)
rescue Errno::ESRCH
  worker = @workers.delete(wpid) and worker.close rescue nil
end
```

。。。ん！？ ```@workers``` から wpid を削除するのって、```Process.kill```でエラーになった時だけなの？？？

## こんな感じにしてみた
というわけで、```config/unicorn.rb``` に以下を追加してみました。

```unicorn.rb
class Unicorn::HttpServer
  def kill_worker(signal, wpid)
    Process.kill(signal, wpid)
    worker = @workers.delete(wpid) and worker.close rescue nil
  end
end
```

一応このメソッドが呼ばれるときに渡される ```signal``` が ```:TERM```と```:KILL```しかないことも確認したので、大丈夫だと思いますが。。。

＃あーあれですかね、失敗したときにエラーを吐かないようにした方がいいかもですね？

## 動作確認
ということで、```unicorn.rb```の```timeout``` を短くして、わざとタイムアウトを発生させてみました。

```
E, [2020-12-28T16:43:53.212943 #4062] ERROR -- : worker=1 PID:4193 timeout (11s > 10s), killing
I, [2020-12-28T16:43:53.215218 #4230]  INFO -- : worker=1 spawned pid=4230
I, [2020-12-28T16:43:53.215512 #4230]  INFO -- : Refreshing Gem list
I, [2020-12-28T16:43:54.302023 #4230]  INFO -- : worker=1 ready
```

いい感じですね。
これで最悪タイムアウトが発生してもワーカーが食い尽くされることがなくなりました。

## まとめ
タイムアウトでワーカーが死なない問題は一応解決しましたが、やっぱりあれですね、皆さんが仰る通り ```タイムアウトしないような作りにしなさい``` ですかね。。。

以上です。
[SwiftUI] TabView 対応

#SwiftUI でアプリ作成する際のメモです。
## TabView （struct、iOS 13.0+） を利用することに。

```struct TabView<SelectionValue, Content> 
where SelectionValue : Hashable, Content : View
```
[参照：SwiftUI Structure Tabview reference](https://developer.apple.com/documentation/swiftui/tabview)
## tabItem(_:)でタブ付きのユーザーインターフェイスを作成する。
ビューをに配置し、各タブのコンテンツに修飾子を適用します。
以下は、3つのタブを持つタブビューを作成します。

![tabview-base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/e41d1175-b39a-e6fb-f171-6b92d6fed056.png)

```basic.swift
TabView {
    Text("The First Tab")
        .tabItem {
            Image(systemName: "1.square.fill")
            Text("First")
        }
    Text("Another Tab")
        .tabItem {
            Image(systemName: "2.square.fill")
            Text("Second")
        }
    Text("The Last Tab")
        .tabItem {
            Image(systemName: "3.square.fill")
            Text("Third")
        }
}
.font(.headline)
```
## PageTabViewStyleでページングスクロールビューを作成する

[[参照：SwiftUI tabviewstyle]
(https://developer.apple.com/documentation/swiftui/tabviewstyle)

![tabview-paging.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/ff6a2147-b606-3cd1-fe62-446bb2a3b2cd.png)

```CustomTabView.swift
    ...省略
    @State var selection = 0
    var body: some View {
        TabView(selection: $selection) {
                    ForEach(0..<contentList.count) { index in
                        HStack {
                            Spacer()
                            Text(contentList[index].systemImage)
                                .padding()
                            Image.init(systemName: contentList[index].systemImage)
                            Spacer()
                        }
                    }
                }
                .tabViewStyle(PageTabViewStyle())
    ...省略
    }
```

## TabView + ZStack + Button + State でページングをボタンで制御する

![tabview-paging-button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/4f66c18a-a324-9b5e-c12e-e1de05227a4e.png)

ボタンでTabViewを制御するため、<font color="DeepPink">tag を付けること</font>
```func tag<V>(_ tag: V) -> some View where V : Hashable```

```CustomTabView.swift
        TabView(selection: $selection) {
               ForEach(0..<contentList.count) { index in
                      //表示内容
                      .tag(index)
               }
         }
         .tabViewStyle(PageTabViewStyle())
```

[参照　GitHub - CustomTabView.swift](https://github.com/mario7/SwiftUI/blob/feature/advanced_tabview/TabBarSwiftUI/TabBarSwiftUI/CustomTabView.swift)
IBM i (旧AS400）の自己学習メモ　コマンド／ツール／運用　FNDSTRPDMでソースコード横断キーワード検索

# 自己学習メモインデックス

[IBM i (旧AS400）の自己学習メモ　インデックス](https://qiita.com/You_name_is_YU/items/3964849e7803c8eaf767)

# 概要

AS400では制限がある程度ありますが、ソースコードを横断してキーワードを検索することが可能です。
それを実現するのが`FNDSTRPDM`コマンドです。
テキストエディタのgrepとは異なり、検索にヒットしたファイルのパスやキーワードと隣接する行のデータなどがまとめて一括表示されることはありませんが、ソースコードを横断してキーワードを検索し、1つずつ次へ次へ次へ・・・と地道に探すことができます。

# FNDSTRPDMでキーワード検索

以下の例は、YAMAGUCHI1ライブラリにあるQRPGLESRCファイルのメンバーとして、RPGソースコードが格納されていることを前提に、得意先マスタの得意先名（TOKNM）の検索キーワードを指定して、TOKNMを利用しているRPGプログラムを探しています。
少し長いコマンドとなっているので、`call qcmd`でコマンド入力画面（Command Entry）を表示してから実行すると良いかもしれません。


```
FNDSTRPDM STRING('TOKNM') FILE(YAMAGUCHI1/QRPGLESRC) MBR(*ALL) OPTION(*DSP *NOPROMPT)                                                                     
```

上記コマンドを実行すると、最初にヒットしたソースコードの`TOKNM`キーワード部分にカーソルが合わさって表示されます。
画面の右上をみると、YAMAGUCHI1/QRPGLESRC  RPG01など、ヒットしたソースコードの名前なども確認できますので、どのソースのどこでヒットしているのかを確認できます。
複数ソースにまたがって検索していますが、次のヒットへ遷移する場合、Enterキーを押下することで、次にヒットした場所へ遷移してくれます。
![1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/0aa11db9-8616-eb0a-d8ea-487312162414.gif)

ここで紹介しているように、テキストエディタのgrepとはだいぶ使い勝手が違いますが、AS400ではこんなもんなんですねー。
地道にEnterを押下し、どのソースで使っているのか目視で確認し、必要に応じて手元でメモを取りながら、キーワードを利用しているプログラム（ソースコード）を把握する作業が必要となります。

# 一括して検索する方法

上記で紹介したFNDSTRPDMコマンドで、OPTIONを少し変更することで、1つずつEnterを押下しなくても、キーワードがヒットしたソースコードの一覧を、スプールに出力することも可能です。
（それでも、ものすごい使い勝手がいいとは思えませんが。）

```
FNDSTRPDM STRING('TOKNM') FILE(YAMAGUCHI1/QRPGLESRC) MBR(*ALL) OPTION(*NONE *NOPROMPT) PRTMBRLIST(*YES)                      
```

![スクリーンショット 2020-12-28 18.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/61095ad0-9706-618b-6948-a9dff6830f07.png)

上記コマンドを実行したあと、出力されたスプールを確認します。

1. wrkjob コマンドを実行
2. `4. Work with spooled files`のコマンドを選択
3. ファイル名が`QPUOPRTF`というスプールファイルができているのでOPT=5 で内容を表示

![スクリーンショット 2020-12-28 19.04.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/bafb32f0-f22c-16a8-5f61-cc3fad3b6eb6.png)
![スクリーンショット 2020-12-28 19.03.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/a117c2c4-9e9d-982e-7c43-c1033a702cbf.png)

このように、検索キーワードにヒットしたメンバーの一覧が表示されます。
Recordsには、ヒットした行番号が表示されていますので、どのソースメンバーの何行目でヒットしたのか？というのは把握できます。
ただ、その詳細はよくわからないので、結局ソースコードの中身まで確認しに行く必要があります。

以上が、FNDSTRPDMによるソースコード横断のキーワード検索です。
M1 macでハードウェアエンコードする

# 動機
M1チップのMBAを買ったので、ハードウェアエンコードとソフトウェアエンコードを比較します。
厳密にはトランスコードですが、ここでは"エンコード"を使います。
macOSではvideotoolboxを通して、vaapiなどのハードウェアエンコードが利用出来るようです。
M1チップでも同様で、脳死でvideotoolboxを使えばハードウェアエンコードできるようです。

# 環境
MacBook Air (M1, 2020) 8コアGPU
ffmpeg (https://ffmpeg.org/download.html#build-mac) はこちらのものを使いました。

```shell
ffmpeg version N-100466-g29cef1bcd6-tessus  https://evermeet.cx/ffmpeg/  Copyright (c) 2000-2020 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.17)
  configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libmysofa --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvmaf --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-version3 --pkg-config-flags=--static --disable-ffplay
  libavutil      56. 62.100 / 56. 62.100
  libavcodec     58.115.102 / 58.115.102
  libavformat    58. 65.100 / 58. 65.100
  libavdevice    58. 11.103 / 58. 11.103
  libavfilter     7. 94.100 /  7. 94.100
  libswscale      5.  8.100 /  5.  8.100
  libswresample   3.  8.100 /  3.  8.100
  libpostproc    55.  8.100 / 55.  8.100
Hyper fast Audio and Video encoder
```

# 対応フォーマット

```shell
user@h94 ~ % ffmpeg -encoders | grep VideoTool   

 V..... h264_videotoolbox    VideoToolbox H.264 Encoder (codec h264)
 V..... hevc_videotoolbox    VideoToolbox H.265 Encoder (codec hevc)
```
h264とhevcが利用可能なようです。

# エンコード時間の比較

適当な地デジの録画ファイルを変換してみます。

```shell:元の動画
Stream #0:1[0x111]: Video: mpeg2video (Main), yuv420p(tv, bt709, top first), 1440x1080 [SAR 4:3 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc, 13Mbps
Stream #0:2[0x112]: Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 189 kb/s
```
```shell:実行例
user@h94 ~ % ffmpeg -i {input} -c:v {エンコーダ} -b:v 6M {output}
```

| エンコーダ | 実時間比(Large is better) |
|:-----------:|:------------:|
| libx264          | 1.43 |
| libx265          | 0.63 |
| h264_videotoolbox| 8.27 |
| hevc_videotoolbox| 8.25 |

# まとめ

思ってたより早い。
画質はそんなに良くないけど、録画したファイルをテレビで見るには十分な画質という感じ。
h264とhevcが同じ速度なので、もっと最適な条件はありそう。
MEF (Managed Extensibility Framework)の.NET 5(.NET Core)対応状況

個人的に混乱したのでまとめました。

結論としては、MEF、MEF2共に.NET 5(.NET Core)で使用できる。

## MEF(`System.ComponentModel.Composition`)

- .NET Platform Extensions 2.1から提供される。(.NET 5でも使用できる)
- 「.NET Coreでは MEF2に移行する必要である」という旨の情報があったが、過去(.NET Core 2.1 より前)の情報である。
- NuGet パッケージ: https://www.nuget.org/packages/System.ComponentModel.Composition/
- docs: https://docs.microsoft.com/ja-jp/dotnet/api/system.componentmodel.composition

## MEF2(`System.Composition`)

- .NET Core 1.1 から提供される。
- NuGet パッケージ: https://www.nuget.org/packages/System.Composition/
- docs: https://docs.microsoft.com/ja-jp/dotnet/api/system.composition
- 以前は [Microsoft.Composition というNuGet パッケージ](https://www.nuget.org/packages/Microsoft.Composition/)で提供されていたが、こちらは古い。
- [「.NET Framework 4.5のMEF」をMEF2と呼んでいる場合があるが、昔の話なので気にしない。](https://stackoverflow.com/questions/33484403/is-mef-or-mef2-baked-into-the-net-framework)
Rails アプリを Azure App Service に Docker を使い、デプロイ & 継続的デプロイ

この記事は、[求ム！Cloud Nativeアプリケーション開発のTips！【PR】日本マイクロソフト Advent Calendar 2020](https://qiita.com/advent-calendar/2020/azure-cloudnative) の 20 日目です（後から追っかけで書いています）。

----
本記事では Rails アプリを [Azure App Service](https://azure.microsoft.com/ja-jp/services/app-service/?WT.mc_id=AZ-MVP-5001601) に  Docker を使い、デプロイ & 継続的デプロイする方法について、ご紹介したいと思います。

# 手順

手順は以下の通りです。

1. Azure CLI or Portal でログインする
2. Azure CLI or Portal でリソースグループを作成する
3. Azure CLI or Portal で Azure Container Registry(以下ACR) に使用するイメージを登録する
4. Rails アプリの Docker Image を作成する
5. Azure CLI で作成した Rails アプリの Docker Image を ACR に push する
6. Azure CLI or Portal で App Service Plan を作成する
7. Azure CLI or Portal で App Service Plan と ACR の Docker Image をパラメーターに指定して App Service を作成する
8. Azure CLI or Portal で App Service と ACR を関連づける
9. Azure CLI or Portal で App Service に CD を設定する
10. Azure CLI or Portal で ACR に Webhook を設定する
11. Azure CLI or Portal で環境変数の設定

以下に Azure CLI での実行コマンド例を記載します。

## 1. Azure CLI でログインする
```
$ az login
```

## 2. Azure CLI でリソースグループを作成する
```
$ az group create --name [リソースグループ名] --location [リソースグループの場所]
```

## 3. Azure CLI で Azure Container Registry(以下ACR) に使用するイメージを登録する
```
$ az acr create --resource-group [リソースグループ名] --name [ACR 名] --sku [好きなの選択] --admin-enabled true --location [リソースグループと同じ場所]
```

## 4. Rails アプリの Docker Image を作成する

（Azure CLI ではないので、スキップ）

## 5. Azure CLI で作成した Rails アプリの Docker Image を ACR に push する
```
$ az acr login --name [ACR 名]
$ docker push [ACR の名とタグ]
```

## 6. Azure CLI で App Service Plan を作成する
```
$ az appservice plan create --resource-group [リソースグループ名] --name [App Service Plan 名] --sku [B1とかS1とか指定] --location [リソースグループと同じ場所] --is-linux
```

## 7. Azure CLI で App Service Plan と ACR の Docker Image をパラメーターに指定して App Service を作成する
```
$ az webapp create --resource-group [リソースグループ名] --plan [App Service Plan名] --name [App Service 名] --deployment-container-image-name [ACR の名とタグ]
```

## 8. Azure CLI で App Service と ACR を関連づける
```
$ az webapp config container set --name [App Service 名] --resource-group [リソースグループ名] --docker-custom-image-name [ACR の名とタグ] --docker-registry-server-url [ACR の場所] --docker-registry-server-user [ACR 名] --docker-registry-server-password [ACR の Password]
```

## 9. Azure CLI or Portal で App Service に CD を設定する
```
$ az webapp deployment container config --resource-group [リソースグループ名] --name [App Service 名] --enable-cd true
```

## 10. Azure CLI or Portal で ACR に Webhook を設定する
```
$ az acr webhook create --name [App Service 名] --resource-group [リソースグループ名] --scope [ACR の名とタグから場所を引いたもの] --location [リソースグループと同じ場所] --uri [URI] --actions push delete
```

## 11. Azure CLI or Portal で環境変数の設定
```
$ az webapp config appsettings set --settings RAILS_ENV=[環境名] --name [App Service 名] --resource-group [リソースグループ名]
```
【MySQL】SQLでランキング 【ユーザ定義変数】

# 【MySQL】SQLでランキング
・自分なりに見やすいやり方（ぇ
・@ を使ったユーザ定義変数を利用
・MyBatis の外だしSQLで実際に利用可能
・8.0以降で使える RANK() 関数は使わないでいきます
・ [【Java】Caffeineでお手軽にローカルキャッシュ](https://qiita.com/a__i__r/items/44e9b0aa934de26ba5bd)　と組み合わせるとキャッシュされていい感じになります

## 環境
・Windows10 64bit
・SpringFramework 4
・MyBatis 3.2.5
・MySQL 5.6

## ショップのランキングを想定
・shop テーブル
ショップの情報が登録されている

・shop_review テーブル
ショップのレビュー情報が登録されている
ランキングで順位をつけるポイント数はこちらに登録

・同点の場合は同一順位、次点は同点の分を飛ばして順位をつける

## 元になる抽出用SQLを作る
・shop_review.point_total の平均を小数点１位まで出して降順で並べる
・同点の場合はレビュー件数が多いほうが先
・50件以上レビューがある
・10件まで

```sql
	SELECT
		sr.shop_id,
		shop.name AS 'shop.name',
		ROUND(AVG(sr.point_total), 1) AS 'avg_point_total',
		COUNT(sr.point_total) AS 'cnt_point_total'
	FROM
		shop_review sr
		INNER JOIN shop ON
			sr.shop_id = shop.id
	GROUP BY
		sr.shop_id
	HAVING COUNT(*) >= 50
	ORDER BY
		avg_point_total DESC,
		cnt_point_total DESC
	LIMIT 10 OFFSET 0
```

| shop_id | shop.name | avg_point_total | cnt_point_total | 
| ---: | --- | ---: | ---: | 
| 12 | ショップなんとか | 5.0 | 123 | 
| 1 | まいショップ | 4.8 | 148 | 
| 14 | いいお店 | 4.7 | 312 | 
| 35 | こちらもいい店です | 4.6 | 5144 | 
| 22 | 株式会社ショップ | 4.6 | 1222 | 
| 78 | サンプル店舗 | 4.6 | 101 | 
| 4 | 私はこちらが好きです店 | 4.5 | 464 | 
| 9 | いやこちらでしょう店 | 4.5 | 121 | 
| 43 | そろそろネタがない店 | 4.4 | 138 | 
| 7 | １０位の店 | 4.2 | 90 | 

## ランキングを付加
・@rank : ランキング
・@gap : 同一順位用のギャップ
・@rankval : 順位付けをする avg_point_total 保存用

```sql
SELECT
	@rank := CASE
		WHEN @rankval = avg_point_total THEN @rank
		ELSE @rank + @gap + 1
	END AS 'ranking',
	@gap := CASE
		WHEN @rankval = avg_point_total THEN @gap + 1
		ELSE 0
	END AS 'gap',
	@rankval := avg_point_total AS 'rankval',
	base.*
FROM
(
	SELECT
		sr.shop_id,
		shop.name AS 'shop.name',
		ROUND(AVG(sr.point_total), 1) AS 'avg_point_total',
		COUNT(sr.point_total) AS 'cnt_point_total'
	FROM
		shop_review sr
		INNER JOIN shop ON
			sr.shop_id = shop.id
	GROUP BY
		sr.shop_id
	HAVING COUNT(*) >= 50
	ORDER BY
		avg_point_total DESC,
		cnt_point_total DESC
	LIMIT 10 OFFSET 0
) AS base,
(SELECT @RANK:=0, @rankval:=NULL, @gap:=0) AS X
```


| ranking | gap | rankval | shop_id | shop.name | avg_point_total | cnt_point_total | 
| --- | ---: | ---: | ---: | --- | ---: | ---: | 
| 1 | 0 | 5.0 | 12 | ショップなんとか | 5.0 | 123 | 
| 2 | 0 | 4.8 | 1 | まいショップ | 4.8 | 148 | 
| 3 | 0 | 4.7 | 14 | いいお店 | 4.7 | 312 | 
| 4 | 0 | 4.6 | 35 | こちらもいい店です | 4.6 | 5144 | 
| 4 | 1 | 4.6 | 22 | 株式会社ショップ | 4.6 | 1222 | 
| 4 | 2 | 4.6 | 78 | サンプル店舗 | 4.6 | 101 |  
| 7 | 0 | 4.5 | 4 | 私はこちらが好きです店 | 4.5 | 464 | 
| 7 | 1 | 4.5 | 9 | いやこちらでしょう店 | 4.5 | 121 | 
| 9 | 0 | 4.4 | 43 | そろそろネタがない店 | 4.4 | 138 | 
| 10 | 0 | 4.2 | 7 | １０位の店 | 4.2 | 90 | 

以上、お疲れさまでした！
PlayCanvas EditorのコードをGitで管理をするために使えるライブラリ「playcanvas-sync」


PlayCanvas Editorで開発をしていると、ソースコードの管理をPlayCanvas Editorのバージョン管理機能を使用しないで、Gitで管理をしたい場合があります。その際に使える便利なライブラリがplaycanvas/playcanvas-syncです。

ライブラリ(GitHub)
https://github.com/playcanvas/playcanvas-sync

このライブラリは、`PlayCanvas Editor`の`API Token`を使い、ローカルマシーンのアセットをPlayCanvas Editorへ`REST API`経由で同期できるライブラリです。

## 使い方
### PlayCanvas Editorのアセットをローカルマシンに同期する

#### インストール
`pc-sync`は`node.js`の環境で動くライブラリですが、`npm`では公開されていないのでGitHubのリポジトリからインストールする必要があります。

##### 1. リポジトリをクローンします。

```zsh
git clone git@github.com:playcanvas/playcanvas-sync.git
```

##### 2. npm install

```zsh

cd playcanvas-sync
npm install
```

##### 3. パスを通す
`npm インストール`をしたフォルダにパスを通します。
.zshの場合はこのような形でパスを通します。

##### 4. パスの確認をします
```
pwd  
```

##### 5.zshrcを編集してパスを通します
Mac BigSurでの設定です。
各 OSで必要な方法でパスを通してください。

```.zshrc
export PATH="$PATH:パス"
```

これで`pcsync` | `pcsync.js` | `pcwatch` | `pcwatch.js`コマンドが使えるようになりました。


次に作業フォルダを作成します。

### プロジェクト管理用のフォルダを作成

PlayCavas Editorと同期するフォルダを作成します。

```zsh
mkdir project
cd project
```


#### 1. `pcconfig.json`を作成

同期をするプロジェクトの、`ブランチID`, `プロジェクトID`, `アップロード先ディレクトリ`, `API_KEY`
を含む設定ファイルを作成します。
`ブランチID`, `プロジェクトID`はPlayCanvas Editorのプロジェクトから取得します。

#### ブランチID
Versionコントロールから確認できます
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/ba2ec4b9-97fc-22ac-9613-82aaf38aa9aa.png)

#### プロジェクトID

`https://playcanvas.com/project/*プロジェクトID*`から取得できます。
![ma.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/7b36fc7d-602b-b75a-1120-aa390532d23a.png)


#### PLAYCANVAS_TARGET_DIR
同期する、ローカルのフォルダを設定します。
ここでは`./playcanvas`を作成します。

```
mkdir playcanvas
```

#### API_KEY
API Keyはこちらから、`GENERATE TOKEN`から生成したものを設定します

https://playcanvas.com/account

```pcconfig.json
{
  "PLAYCANVAS_BRANCH_ID": "ブランチID",
  "PLAYCANVAS_PROJECT_ID": 00000000000000,
  "PLAYCANVAS_TARGET_DIR": "./playcanvas",
  "PLAYCANVAS_API_KEY": "API_KEY",
  "PLAYCANVAS_BAD_FILE_REG": "^\\.|~$",
  "PLAYCANVAS_BAD_FOLDER_REG": "\\."
}
```

ここまで設定した現状のディレクトリはこのような形です。

```zsh
- project
  - pcconfig.json // 設定ファイル
  - playcanvas //アップロード先
```


#### コマンド

https://github.com/playcanvas/playcanvas-sync

#### 1. ローカルのファイルをPlayCanvasへアップロード

```
pcsync or pcsync.js pushAll
```

##### 2. テクスチャを含むPlayCanvasへアップロード

```
pcsync or pcsync.js pushAll -r "\\.(png|jpeg)"
```

#### 3. PlayCanvas Editor内のファイルをローカルへダウンロード
```
pcsync or pcsync.js pullAll
```

#### 4. テクスチャを含むPlayCanvasへをローカルへダウンロード
```
pcsync or pcsync.js pullAll -r "\\.(png|jpeg)"
```

このような形で、プロジェクトの同期をすることが出来ます。
Serverspecみたいにサーバの構成が正しいか確認する場合はGossがよさそう

# 概要

Serverspecのようにサーバの構成が正しいかどうかを確認したいときに、Go言語でかかれたGossというツールがよい。このツールは動作もはやく、Go言語なのでランタイムもいらない。ServerspecはRubyが必要。

Gossは,goss.yamlファイルにYAML形式でプロセスが起動しているか、ポートをListenしているか、ファイルは存在するか、ファイル内容は正しいか、HTTPリクエストはできるか。といった内容をチェックできる。

# インストール

```
# Install latest version to /usr/local/bin
curl -fsSL https://goss.rocks/install | sh
```

# Quick Start

systemdなどのプロセス管理システム管理しているサービスであれば、goss autoadd で自動的にgoss.yamlに現在の状態を正しいものとして書き込んでくれる。

```
sudo goss autoadd sshd
```

この状態で `goss validate` を実行すると、下記のように結果を出力する。

```
........

Total Duration: 0.023s
Count: 8, Failed: 0, Skipped: 0
```

# /healthzを提供する

gossは標準でhealth checkも実行できるようになっている。

```
goss serve --format json
```

このコマンドを実行すると、gossはサーバとして動作する。そしてこのサーバに対してcurlでリクエストすると、ヘルスチェックの実行結果が出力される。

```
curl http://localhost:8080/healthz | jq .
```

# DockerのHEALTHCHECKに使う

下記のDockerfileのようにDockerfileのHEALTHCHECKをgossでチェックさせることもできる

```Dockerfile
FROM alpine:3.4

RUN apk add --no-cache --virtual=goss-dependencies curl ca-certificates && \
    curl -fsSL https://goss.rocks/install | sh && \
    apk del goss-dependencies
ADD goss.yaml /goss/goss.yaml

HEALTHCHECK --interval=1s --timeout=6s CMD goss -g /goss/goss.yaml validate
```

# 参考

* [aelsabbahy/goss: Quick and Easy server testing/validation](https://github.com/aelsabbahy/goss)
* [Docker 1.12/Kubernetes simplified health checks and container ordering with Goss | by aelsabbahy | Medium](https://medium.com/@aelsabbahy/docker-1-12-kubernetes-simplified-health-checks-and-container-ordering-with-goss-fa8debbe676c)
* [aelsabbahy/dgoss-examples: Some examples utilizing dgoss](https://github.com/aelsabbahy/dgoss-examples)
Python+TkinterをGithubActions上でunittestする場合にno display nameが発生したときの対応方法メモ

#Python+TkinterをGithubActions上でunittestする場合、ディスプレイ設定が必要

Pythonで開発したコードリポジトリをgit pushしたら、GithubActions上で自動でunittestが走るようにしています。

Tkinterなど画面描画を必要とするmoduleのテストをGitActions上で実施する場合、仮想環境でのディスプレイ設定をする必要があります。この設定をしていないと、no display name　とエラーが吐き出されます。

以下、エラーを回避するための対応方法メモとなります。
unittestを走らせる前に下記内容でディスプレイ設定します。

```.github\workflows\test.yml
disp=:99
screen=0
geom=640x480x24
exec Xvfb $disp -screen $screen $geom 2>/tmp/Xvfb.log &
export DISPLAY=:99
```

GithubActions用のymlファイルはこんな感じになります。
ymlファイルは.github\workflows内に入れておく決まりになっています。

```.github\workflows\test.yml
name: Python package

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.7]

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    # インストール
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    # pythonバージョンの表示
    - name: Display Python version
      run: python -c "import sys; print(sys.version)"
    # unittestの実行
    - name: Test
      run: |
        disp=:99
        screen=0
        geom=640x480x24
        exec Xvfb $disp -screen $screen $geom 2>/tmp/Xvfb.log &
        export DISPLAY=:99
        python -m unittest discover tests
```

#参考資料
StackOverflowのこちらの記事を参考にしました。
[_tkinter.TclError: no display name and no $DISPLAY environment variable](https://stackoverflow.com/questions/37604289/tkinter-tclerror-no-display-name-and-no-display-environment-variable)


#その他GithubActionsでのTips

GithubActionsでのunittestをskipしたい場合

```test.py
@unittest.skipIf("GITHUB_ACTIONS" in os.environ and os.environ["GITHUB_ACTIONS"] == "true", "Skipping this test on Github Actions")
class TestHoge(unittest.TestCase):
    def setUp(self):
        print("setUp")

    def test_hoge(self):
        print("test_hoge")
```
ウィルコクソンの順位和検定でノンパラ検定の雰囲気をつかむ

## 本記事の概要
ウィルコクソンの順位和検定を概観することでノンパラメトリック検定の雰囲気を掴んでみます。

## ノンパラメトリック検定とは
t-検定では正規分布を仮定しましたが、そのような確率分布の仮定を置かない検定をノンパラメトリック検定といいます。分布の仮定が不要なので、使用場面としては事前に詳細が分かっていないデータのように汎用性の高い検定手法であるといえます。

確率分布である程度正確に記述できる場合はパラメトリック検定が優れていますが、そうでない場合はノンパラメトリック検定が外れ値に影響されにくくロバストで高い検出力を達成すると言われています。しかし、ノンパラ検定の検出力の減少は意外と少なく、経験的に$n=6$程度でt検定(パラメトリック)とウィルコクソンの順位和検定(ノンパラ)は殆ど同等の結果となるそうです [^1]

[^1]: [本記事の9-10頁を参照](https://www.jstage.jst.go.jp/article/kagakutoseibutsu/51/6/51_408/_pdf)


## ウィルコクソンの順位和検定
ノンパラ検定の例として、ウィルコクソンの順位和検定を説明します。「対応のない２標本の平均に差があるか否か？」へのノンパラ検定として知られており、同じ問題に対するパラメトリック検定はt検定になります。

2つの標本、$\\{X_1,\ldots,X_m\\}$と$\\{Y_1,\ldots,Y_n\\}$を考えます。機械学習の文脈で言うならば2つの手法のテストデータに対する精度や誤差でしょう。それぞれを第一標本、第二標本とよぶことにします。第一標本、第二標本ともに互いに独立に確率密度関数$f(x)$と$g(y)$に従うものとします。$f,g$の形に関してはなにも仮定していないことに注意してください。

ここで次の仮説：

```math
\begin{align}
	{\text 帰無仮説} :\quad &f = g\\
	{\text 対立仮説} :\quad &f \neq g
\end{align}
```

を検定することを考えます。

いきなりですが、2つの標本を一緒にして値の小さいものから並べます。例えば

```math
\begin{align}
	X_5, X_2, Y_1, X_7, Y_9, \ldots, X_m, Y_n
\end{align}
```

のような感じです。この列に$1$から$M(=m+n)$まで順位（rank）をつけ、$X_1,\ldots,X_m$の順位を$R_1,\ldots,R_m$とします。

帰無仮説が正しい場合は二組の標本を小さいものから並べても両標本は均等に入り混じり、帰無仮説が正しくない場合は偏って並びそうだと直感的に思います。以下、それを数式に落とし込んでいきます。

帰無仮説を仮定した場合、二標本は同一の分布に従うので$R_1,\ldots,R_m$が$\\{1\ldots,M\\}$中の任意の$m$個の数$r_1\ldots,r_m$をとる確率はすべて等しく

```math
\begin{align}
	P(R_1=r_1,\ldots,R_m=r_m) = \frac{1}{M ( M - 1 ) \cdots ( M - m + 1 ) }
\end{align}
```

となります。分布の形に依存せず順位の実現値への確率が計算できます。ここで検定統計量として順位和

```math
\begin{align}
	W = \sum R_i
\end{align}
```

を定義すると、$P(W=w)$となる確率は同様に分布の形に無関係に計算できます。分布が大きくずれている場合、$R_1,\ldots,R_m$は小さな値か大きな値へ偏ると想定されるので

```math
\begin{align}
	P(W\le c_1) + P(W\ge c_2) = \alpha
\end{align}
```

を満たす定数$c_1, c_2$を定め、棄却域$\\{W\le c_1, c_2 \le W\\}$とすることで有意水準$\alpha$の検定方式が得られます。

$m,n$があまり大きくない場合はウィルコクソンの順位和検定の数表から$c_1,c_2$を決定します。一方、$m,n$が大きい場合は検定統計量$W$が正規分布

```math
\begin{align}
	N\left(\frac{m(M+1)}{2}, \frac{mn(M+1)}{12}\right)
\end{align}
```

に漸近することが知られており、この性質から棄却域を決定します。

## 例題
2つの標本があります。第一標本の標本数は15で、それらを昇順に並べると

42.6 43.9 44.1 44.2 45.0 45.8 47.4 48.0 48.7 49.5 49.6 50.0 51.4 52.7 52.8

です。第二標本の標本数は10で、それらを昇順に並べると

44.7 46.8 46.9 47.1 48.2 50.0 52.1 53.5 54.2 56.3

です。ウィルコクソンの順位和検定により2つの分布が等しいという仮説を有意水準5%で検定しなさい。

**(答え)**
$m=10,n=15$とし、第二標本の順位和を検定統計量とする。実現値は$W=154$である。数表[^2]から棄却域は$\\{W\le 94, 166\le W\\}$であるから帰無仮説は棄却できない。

[^2]: [数表](https://data-science.gr.jp/theory/tst_wilcoxon_rank_sum_test.html)
【nuxt/vue】 Presentational and Container Components

# 目次
・[Presentational and Container Componentパターン](#Presentational and Container Componentパターン)
・[Presentational and Container Componentパターンのメリット](#Presentational and Container Componentパターンのメリット)
・[Presentational and Container Componentパターンのデメリット](#Presentational and Container Componentパターンのデメリット)
・[まとめ](#まとめ)

## Presentational and Container Componentパターン
@dan_abramovさんが提唱したコンポーネントの分割方法。

分類すると、 Presentational Component と Container Componentの二つに分類できます。

### Presentational Component
見た目を担当するコンポーネント。
DOMやスタイルに対する関心を持ち、コンテンツはpropsによってのみ与えられる。
どのように見えるかに関心があります。

* 独自のマークアップとスタイルを持つ
* 多くの場合this.props.childrenとして他に内包される
* またアクションやストアに依存しない
* なのでデータのロードや変更などのロジックの部分は切り離される
* propsとしてデータとコールバックを受け取れる
* 稀に独自のstateを持つ、それはデータではなくUIの状態として持つ
* stateやライフサイクルフック、パフォーマンスの効率化を必要としない限りはfunctional componentとして記述される

### Container Component
動作担当するコンポーネント。
データや振る舞いを自身以外へ供給する役割を担う他、状態の参照や管理を行います。
どのように機能するかに関心があります。

* 通常、ラッピングのdivを除いて独自のDOMマークアップはもたない。スタイルもなし。
* Presentational Componentまたその他のコンポーネントにデータと振る舞いを提供する
* アクション呼び出しなどをコールバックとしてPresentational Componentに渡す
* スタイルなどを持たないという点から、データソースとして機能する傾向があるため、基本的に状態保持と処理を行う
* 通常、React Reduxのconnect()、RelayのcreateContainer()、Flux Utilsの* Container.create() などの上位コンポーネントを使用して生成される

## Presentational and Container Componentパターンのメリット
* 関心の分離
    * 見た目部分とロジック部分を切り離すことで責務を分けることができる
* デザイナーとの調整はPresentation Componentのみを使用することで、ロジックから切り離すことができる
    * 逆にAPIなどの調整などの場合はContainer Componentのみで対応が可能
＊ デザイナーとエンジニアで協業しやすくなる

## Presentational and Container Componentパターンのデメリット
* 冗長になる
* 作成ファイルが増える


## まとめ
nuxt/vueでPresentational and Container Componentパターンを試しましたが、利点で書いたようにメリットは大きいなと感じます。
デメリットにある部分はもし開発がデザイナーとエンジニアで切り分けて作業を進めることができる場合はそこまで大きなデメリットには感じないですが、一人で全てをやるなどの場合は作成するファイルが増える分デメリットに感じる部分はあるかなと思いますが、長い目で見たときに運用面などを考えると切り分けておくことの方が大きなメリットと感じます。





参考サイト
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
2回目のHerokuデプロイで訳わからない人必見！


現在Railsチュートリアルを進めており

今回は１回目のデプロイは順調にできたけれども２回目の演習で結局何やったらいいかわからない病にかかってしまい

ググって解決したので同じ状況に陥ってる方がいましたら初心者がわかりやすく説明いたします！<br>よろしくお願いします！

先ず演習の内容なんですが簡単に説明すると

「今表示されている文字を変えろ的な？ついでにルーティングも変えてな的な」

なんだこの舐めた問題は簡単じゃねーか
と思い実際にルーティングと表示内容を変えてと....

あれこのまま

```
$ git push heroku
```
でいいんだっけな

<h2>スミマセン舐めてたのは僕でした</h2>
はい、必ず失敗します。とゆうかできませんでしたww
では説明に入ります。
先ずはgitに変更をcommitしてpushすることを思い出しましょう。

１.　先ずはアプリの中身を変更します

２. ブランチの状態を確認する

```
$ git status　
```

３.commit

``` 
$ git commit -a -m "変更内容のコメント" 
```
でコミットする

４.　そして最後に push

```
$ git push 
でできなかったら　
$ git push origin master
(masterのところがmainの方ならmainと入力しましょう) 
```

<h2>最後にデプロイ</h2>
ここまでやったら最後の仕上げとしてHerokuにデプロイしましょう。

```
$ git push heroku
```
もしこのコマンドでこんなエラーが出てしまったら（僕は出ました）
Username for 'https://git.heroku.com/stark-oasis-数字.git': username
Password for 'https://username@git.heroku.com/stark-oasis-数字.git': 
remote: !       WARNING:
remote: !       Do not authenticate with username and password using git.
remote: !       Run `heroku login` to update your credentials, then retry the git command.
remote: !       See documentation for details: https://devcenter.heroku.com/articles/git#http-git-authentication
fatal: Authentication failed for 'https://git.heroku.com/stark-oasis-15325.git/'

多分なんですけど

「herokuにログインせずにこのコマンドを打ち込むんじゃねーばかたれが！！」

みたいな感じで怒っていらっしゃるのですねと、解釈しましたので、

```
$ heroku login
```
でログインしてあげましょう。

そしてこの時にもこんなのが出てしまうかも、、（僕は出ましたw）

heroku: Press any key to open up the browser to login or q to exit:

これは多分になってしまいますが

「ブラウザでログインするからなんかキー押してブラウザ開いてログインしてやー」

的なこと言ってないとは思いますがとりあえずコマンドからではログインできないっぽいので
こんなオプションをつけてあげます

```
$ heroku login --interactive
```
と入力してあげると成功すると思います！

そうしたら

Email [メールアドレス]:
（ここで自分のherokuで登録してあるアドレスが出ていればそのままenterを押しましょう
僕は出てました。もし記載なければ登録してあるアドレスを入力しましょう！）
Password: herokuのパスワード

これでHerokuでのログインは完了しているので
ここでやっと

```
$ git push heroku
```
と入力してあげれば数十秒で、デプロイが完了しますので URLを開いてみて確認してみましょう！

長々とありがとうございました！！
Vuex データや処理の流れ　個人学習用

##　初めに
現在Vue.jsを学習しており備忘録として、Vuexの使用方法を残していきます。

## state
stateは格納したいデータを記述する

```
const state = {
  user: null
}

```
## mutation
stateを更新するメソッドを定義する。
stateの第一引数はstate,　第二引数はデータ。

```
const mutations = {
   setUser(state, user) {
      state.user = user;
   }
}
```

## action
- actionにて非同期処理にてバックエンド側のconectionを行いデータのやりとりをおこう。受け取ったデータはcontextを使用しmututationをよびstateの更新を行う。
- front側からの通信はthis.$store.dispatch('modul/action name', data)でvuexのactionにアクセスできる。

store.actions
  - 第一引数はcontext 第二引数はfromt側から送られてきたデータ
  - async awaitでPromiseオブジェクトを受け取り、backend側のデータを受け取る。
  - mutationsを呼び出す際はcontext.commitで呼び出す。第１引数にmutationMethod、第２引数にpromiseオブジェクトのデータ

```
store.js

const actions = {
  aysnc login(context, data) {
     const response = await axios.post('api', data);
     context.commit('setUser', response.data)
  }
}

```
front側
- front側でactionsとアクセスする際は$store.despatch()を持ちいいる。
- 第１引数はactionMethod, 第２引数はdata

```
export default {
  data() {
    return: {
      userDate: {
        name: '',
        password: ''
      }
    }
  },
  method: {
    async login() {
      //store.jsにてnamespaced:trueにしておけばnamespaceが付与できfaileの分割ができる（余談）
      await this.$store.dispatch('auth/login', this.userData);
      this.$router.push('/');
    }
  }
}
```

## getters
gettersはstateを参照する為のもの

```
store.js

const getters = {
  userName: state => state.user? state.user.name : "";
}
```

**参照方法はstore.getters**で行う。モジュール設定をしている場合配列で’モジュール名/メソッド名’でアクセスできる

```

export default {
   computed: {
     isLogin () {
       this.$store.getters['auth/username'];
     }
   }
}
```

## login状態を維持する
vueの使用上、リロードをすると、再度Vueインスタンスが生成され、storeでのstateは破棄されます。
その為、vueインスタンが生成され前にloginUsaerを取得してその後インスタンスを生成する手順をふむことで解決できます。

**まずはAPI**
LoginUserを取得

```
routes/api.php(laravel)

//get currentUser
Route::('/current_user', fun() => Auth::User())->name(''crrent_user');

```

**続いてstoreの記述**
actionsにて非同期処理を記述する。

```
const actions = {
   async currentUser(context) {
     const response = await axios.get('api/current_user');

     //apiでuserdataが取得できていたら、そのまま変数に格納、なければ、nullを格
     const user = reponse.data || null;

　　　//contextでmuutationメソッドを呼び出し、stateの更新。
     context.commit('setUser', user);
   }
}
```
**最後にapp.jsにてactionの呼び出し**
非同期処理にてアクションを呼び出す。

```
const createApp = async () => {
  await store.dispatch('auth/currentUser')

const app = new Vue({
    el: '#app',
    render: h => h(App),
    router,
    store,
});

createApp()
```

**login状態は維持できるが、直接URLを打てば、LoginComponentにアクセスできます。**
なのでこれを抑止する為に**ナビゲーションガードを使用します。**
またあapp.jsで呼び出したdispatchの非同期処理は処理が完了する前にメインスレッドが進み、vueインスタンスが生成されてしまします。このタイムラグがあることで数秒間ん印象状態が維持できない状態になり、この状態でナビゲーションガードをせってしても処理をすり抜けてしまいます。なのでナビゲーションガード自体に**setTimeout**を設定してこの問題を回避します。

**navgation gruadの設定**

```
import store from './store'

{
    name: "login",
    path: "/login",
    component: Login,
    beforeEnter: (to, from, next) => {
      setTimeout( () => {
        if (store.getters['auth/check']) {
          next('/')
        } else {
          next()
        }
      }, 3000)
    }
  },
```

##終わりに

備忘録としては終了しますが、学習を深めれば再度更新を行っていきます。
Macで授業のためのRuby環境構築

\![macOS-11.1](<https://img.shields.io/badge/macOS-11.1-brightgreen>) \![ruby-2.7.2p137](<https://img.shields.io/badge/ruby-2.7.2p137-brightgreen>) 


# Preface (はじめに)

マルチスケールシミュレーション特論という授業を受けるにあたって, 研究室から支給されたmacbook Air(2019)で環境を構築する.

書いてる途中にM1 Macが話題になったり, Rubyが3.0.0にバージョンアップしたりしましたが, 本記事では残念ながらそれらには対応していません.


# Homebrew

macのパッケージマネージャーをインストールします.

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

正常にインストールできたか確認

```
> brew docotor
-> Your system is ready to brew.
```


# Git & GitHub

まず`Git`をインストールします.

```
> brew install git
```

`Git`のバージョンは

```
> git --version
-> git version 2.29.2
```


# fish

デフォルトのシェルは`zsh`ですが, 代わりに`fish`を使いたいと思います. 

```
> brew install fish
```

`fish`のバージョンは

```
> fish -v
->fish, version 3.1.2
```


## Fisher

`fish`のプラグイン管理ツールとしてFisherがあります.他にoh-my-fishがありますが, 管理のしやすさ(GUIで設定を変更できる)でFisherを選びました. 

```
> curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fish
```

Fisherのバージョンは

```
> fisher -v
-> fisher, version 4.1.0
```


## zshからfishへ

デフォルトシェルを`fish`に変更する. 

```
> sudo nano /etc/shells
```

以下のように変更

```
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
#下のようにPATHを追加
/usr/local/bin/fish⏎ 
```

またコマンドで

```
> chsh -s /usr/local/bin/fish
```


## Fisherでプラグインをインストール

`C-r`で簡単にコマンド入力を表示及び検索できるプラグインを入れる. 

まず, fzf補完をインストール

```
> brew install fzf
```

そのあとに, Fisherでプラグインを入れる. 

```
> fisher add jethrokuan/fzf
```

これで完了. 


# Ruby

Macにはすでに`Ruby`は入っている. 

```
> which ruby
-> /usr/bin/ruby
```

しかし, `Ruby`のバージョン管理ツール`rbenv`を用いて, 最新(執筆当時 v2.7.2)のものを使いたいため, `rbenv`を入れる.

```
> brew install rbenv
```

`rbenv`のバージョンは

```
> rbenv -v
-> rbenv 1.1.2
```

ただ, 設定をしていないため, 環境変数は変わっていない

```
> echo $PATH
-> /usr/local/bin /usr/bin /bin /usr/sbin /sbin
```

なので, fishの設定ファイルを作成し,

```
> cd ~/.config/fish
> nano config.fish
```

下記を追加する. 

```
set -x PATH $HOME/.rbenv/shims $PATH
```

その後再起動をし, パスが通ったか確認

```
> which ruby
-> /Users/[User name]/.rbenv/shims/ruby

> which gem
-> /Users/[User name]/.rbenv/shims/gem
```

```
> echo $PATH
-> /Users/hisanagaken/.rbenv/shims /usr/local/bin /usr/bin /bin /usr/sbin /sbin
```


## 指定したバージョンのRubyのインストール

現在の`Ruby`のバージョン確認

```
> rbenv version
-> * system (set by /User/[User name]/.rbenv/version)
```

入れたい`Ruby`のバージョン入力する. 

```
> rbenv install 2.7.2
```

とりあえず, これで一応は完了. 


# 参考資料

[iOSアプリエンジニアのmac環境構築メモ](https://qiita.com/nakagawa1017/items/b0ac953f3448a46899fb)