OmniAICreator/Qiita-1.07M huggingface dataset:
DebianにSSHでログイン後、指定ディレクトリの配下のみしか操作をさせない

**debootstrap** を使用すると、指定ディレクトリ配下にDebian環境をインストールすることができます。
SSHログイン後のルートディレクトリを「debootstrap」で環境を設定したディレクトリとすることにより、指定のユーザのみ別のルートディレクトリ（別環境として）を見せることが可能になります。

## ■指定ユーザのルートディレクトリの環境設定

```bash
# debootstrapで環境をインストールするディレクトリ
WORK_HOME=/tmp/home/
# 今回は指定グループに所属するユーザのみ隔離します
WORK_GROUP=test_group

# 必要なパッケージ
apt install -y debootstrap
# 隔離対象となるグループを作成
groupadd ${WORK_GROUP}
# 環境をインストールするディレクトリを作成
mkdir ${WORK_HOME}
# 環境を設定（includeなどは調整してください）
debootstrap --arch amd64 --variant buildd --include=apt,wget,openssh-client sid ${WORK_HOME} http://ftp.jp.debian.org/debian

cp -f /etc/apt/sources.list ${WORK_HOME}etc/apt/sources.list
# chrootの設定を行います
# 「Match group」はグループに対する指定になります
# 「Match user」に変更するとユーザに対する指定になります
# ※アスタリスクを使用することが可能です
{ \
    echo ''; \
    echo "Match group ${WORK_GROUP}"; \
    echo ' X11Forwarding yes'; \
    echo ' AllowTcpForwarding yes'; \
    echo " ChrootDirectory ${WORK_HOME}"; \
  } >> /etc/ssh/sshd_config

# SSHの設定再読込
service sshd reload
```

## ■指定ディレクトリのみ見せたいユーザを追加

```bash
# ※rootユーザで追加することを想定しています

# 「test_user」を追加します
WORK_USER=test_user
# 「test_group」のグループに所属させるとルートディレクトリが変わります
WORK_GROUP=test_group
# 別環境を整えたディレクトリ
WORK_HOME=/tmp/home/

# ユーザ追加は詳しくは関連情報を参照してください
adduser ${WORK_USER}

usermod -aG ${WORK_GROUP} ${WORK_USER}

# ユーザやグループ情報を変更した場合、「debootstrap」で環境を整えたディレクトリにも反映をする必要があります
# 下記ファイルをコピーしなかった場合、SSHログインは出来ますがファイルのSCP転送などが出来ません
cp -f /etc/passwd ${WORK_HOME}etc/passwd
cp -f /etc/group ${WORK_HOME}etc/group
```

## ■使用例

例えば、rootユーザでApacheをインストールしApacheの設定を行っているとします。
作業者のユーザAさんには「HTML」を操作してほしいですが、全体の環境は触れなくしたいなどで使用できます。
※FTP設定などでも可能ですが、例えばの話です。
※指定ディレクトリの環境を壊すことはできますが、作り直しは簡単です

## ■関連情報
https://qiita.com/error484/items/05fc4113c1aa11db14cc
【今日の学びメモ】git と空ディレクトリ

git で追跡しているプロジェクト内にディレクトリを作っても、中身がないとトラッキングされない。

作業中、急にエラーが出るようになり`git reset`をしたけれど、直らず詰まったのでメモ。
誤って不要な空ディレクトリを作ってしまったことがエラーの原因だったが、`git status`上に表示されず気付くのに時間がかかってしまった。
【Kotlin】KtorでPOSTリクエストをjsonで受け取る

## 概要
最近少しKtorを触り始めてみました。コアの部分は軽量で起動まではすぐ出来るのですが、そこからいざPOSTリクエストをjsonで受け取ろうと思ったら、少しハマりましたのでメモ書きします。

## POSTリクエストをjsonで受け取るために必要なこと
* [こちら](https://jp.ktor.work/servers/calls/requests.html#typed-objects)のドキュメントにある通り、`ContentNegotiation`という機能を使って、jsonのパースを設定する必要があります。
* 実際のパース処理ですが、[Ktorはどう使う？](https://blog.takehata-engineer.com/entry/how-about-using-ktor)にて説明されている通り、`call.receive<リクエストの型>`のメソッドを実行することで、指定したオブジェクトへ、よしなにパースしてくれます。
* 蛇足ですが、バリデーションについては`valiktor`というライブラリが便利そうです。[valiktorを使ってVO値のバリデーションを行う](https://qiita.com/Takuyaaaa/items/32cca66d57a5a5934b26)の記事で詳細は解説されています。

## 実装サンプル
リクエストとしてtokenを受け取って、それをそのまま返すという処理をサンプルとしてのせておきます。
jsonのパースに使用するライブラリは、jacksonにしています。

```kotlin:Application.kt
fun Application.module() {
    install(ContentNegotiation) {
        jackson {}
    }
    install(Routing) {
        userController()
    }
}

fun main(args: Array<String>) {
    embeddedServer(
        Netty, 8080,
        module = Application::module
    ).start()
}
```

試しに空白チェックだけ設定しています。

```kotlin:UserAuthRequest
data class UserAuthRequest(val token: String) {
    init {
        validation()
    }

    private fun validation() {
        validate(this) {
            validate(UserAuthRequest::token)
                .isNotBlank()
        }
    }
}
```

パースに失敗したり、バリデートエラーになるとExceptionが発生します。
今回はサンプルなので、ざっくりとしたハンドリングにしています・・。

```kotlin:UserAuthRequest
fun Route.userController() {
    route("/user") {
        post("/auth") {
            try {
                val parameter = call.receive<UserAuthRequest>()
                call.respond(HttpStatusCode.OK, parameter)
            } catch (ex: Exception) {
                call.respond(HttpStatusCode.BadRequest)
            }
        }
    }
}
```
WSL2 Ubuntu 20.04 にDocker, docker-composeを入れる

# Docker

## 事前準備。
```
sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
```

## Docker公式のGPG公開鍵をインストール。
```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

## Dockerを入れる。
`**********`の所は自分のUbuntuユーザー名に書き換えてください。

```
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# sudo systemctl enable docker
# ↑自動起動がうまくならない場合が…
# なので↓に変更
sudo echo "sudo service docker start" >> ~/.bashrc

sudo service docker start
sudo usermod -a -G docker **********
```

## ターミナルを再起動する。

## Dockerを動作確認してみる。
```
docker run hello-world
```

# docker-compose

## https://github.com/docker/compose/releases で最新バージョンの番号を調べる。

## docker-composeを入れる。
`*.**.*`のところは、↑で調べたバージョン番号に書き換えてください。

```
sudo curl -L https://github.com/docker/compose/releases/download/*.**.*/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
```

## docker-composeコマンドを動作確認してみる。

```
docker-compose --version
```
【Heroku】"code=H14 desc="No web processes running"を解決する

#はじめに

久しぶりにHerokuを触っていたら，何故か簡単な"Hello world"さえも，エラーで動かなくて
かなり時間を取られました．
そのため，備忘録として記録しておきます．

#開発環境
開発環境は以下のようになっています．
・Heroku(無料版)
・Flask

#エラー

以下のエラーに悩まされました．

```
...code=H14 desc="No web processes running"...
```

https://qiita.com/rebi/items/efd1c36f0a9e46222d80

こちらの記事のような解決もできるかもしれません．
しかし，自分はもっと初歩的な部分でつまづいていました...
そもそも，このエラーはwebサービス(Flask)が立ち上がってないよ！と言っています...

##正常に動く場合

ちゃんと，Flaskが動くと，以下のようなログが確認できます．
これは，herokuのアプリ管理ページの右上More>View logsで確認できます．

![img2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262828/bc1f0060-ccc7-44cf-ff4a-e54e95814284.jpeg)


また，しっかりとFlaskが動くとdynoが表示されます．
逆に動いてないとここに，dynoが表示されません．

![img.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262828/318f8124-91a7-8387-d68b-15eb06670e91.jpeg)

#解決方法

Procfileが原因でした．

※"Procfile"ですが，どのpythonを実行するかを書くファイルです．

```:Procfile（修正前）
web:python main.py
```

これを以下のように編集します...

```:Procfile（修正後）
web: python main.py
```

気づきましたか？
```python```の前の半角スペースが重要！！！！ということでした...


#まとめ
しょーもないエラーでしたと...

つまり，このエラーが出た時は，何かしらのエラーで
Flaskなどのwebアプリが動いていないと解釈するのが無難でしょう．
ArduinoUNOとCO2センサーモジュールMH-Z19CでCO2測定


x 配線には、自信がないので各自、仕様書を確認の事

目的
今、コロナで流行りのCO2測定器
非営利、教育、研究目的

説明
771_8bitさんのプログラムを非営利目的でArduinoUNOに移植
あくまで参照

変更点
ハードシリアルからソフトウェアシリアル
A6 -> 6
A7 -> 7


![co2_bbb_uno_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/6d59e9c2-5242-0944-d02b-64eb94903633.jpeg)


![l_3pun_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/50555744-5003-bb7f-1125-838a0e0876b9.jpeg)




参考

秋月で買えるCO2センサーを使う(MH-Z19C)

https://qiita.com/771_8bit/items/193396a48ad0ee142a4a



```c++


//caa45040が追加　始まり
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2); // RX, TX
//caa45040が追加　終わり

uint16_t uartco2; 
unsigned long pwmco2;
bool reset = false;

byte ReadCO2[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
byte SelfCalOn[9]  = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
byte SelfCalOff[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
byte retval[9];

void setup() {
  pinMode(7 /*変更*/, INPUT);
  pinMode(6 /*変更*/, OUTPUT);
  Serial.begin(9600);
  Serial.print("400ppm");
  Serial.print(",");
  Serial.print("UART");
  Serial.print(",");
  Serial.println("PWM");
  delay(2000);
  mySerial.begin(9600);
  mySerial.write(SelfCalOn,sizeof SelfCalOn);
}


void loop() {
  //PWMでデータ取得
  pwmco2=pulseIn(7 /*変更*/,HIGH,2000000);

  //UARTでデータ取得
  mySerial.write(ReadCO2,sizeof ReadCO2);
  mySerial.readBytes((char *)retval, sizeof retval);
  uartco2 = retval[2]*256 + retval[3];

  //PCに送信
  Serial.print(2*(202000-2000)/1000);
  Serial.print(",");
  Serial.print(uartco2);
  Serial.print(",");   
  Serial.println(5*(pwmco2-1200)/1000);

  delay(100);

  //起動20分後手動キャリブレーション
  if(millis()>1200000 && !reset){
    digitalWrite(6 /*変更*/,LOW);
    delay(8000);
    digitalWrite(6 /*変更*/,HIGH);
    reset=true;
  }

}


```
【今日の学びメモ】pngとjpgの使い分け

# pngの使いどころ

- 色数の少ない画像を表示させるとき
- 透過画像を作るとき

# jpgの使いどころ

- 色数の多い画像を表示させるとき
- 写真を表示させるとき

<br>

png は何度保存しても画質が落ちない（可逆圧縮）が、jpgは段々と画質が悪くなっていく。
画像によって、どちらを使った方がデータサイズが小さくなるかは異なる。

今まで何も考えず使い分けていたのでメモ。
1ページに表示できる投稿件数を制限する[kaminari]

#はじめに
投稿一覧を作成している時投稿が何十件も増えたらスクロールが果てしなくなることに気がつきました。

そこでペーネーション機能を知り、実装ができたので忘れないために記事にしました。

![スクリーンショット 2021-07-14 22.26.04（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/4f5dfc02-86cc-e41e-7f51-2f0689f059dc.png)

よく見かけるこちらを実装していきます。

#ペーネーション機能を使う理由

投稿一覧がトップページに表示されるサイトの場合、全ての投稿がトップページに表示されると読み込むまでに時間がかかりますし、かなり読みにくくなってしまいます。
また底が果てしなくなり、フッターまでたどり着くのに時間がかかります。

そんなときにページネーションの機能を実装しておけば表示される項目が一定数を越えると自動的に次のページへ内容を移行してくれるのでものすごい便利になります。

[pikawaka引用](https://pikawaka.com/rails/kaminari#kaminari%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9)

#やること


- kaminari インストール

- コントローラーに定義

- ビューに表示できるように記述

これだけで使えるようになります。

あとはフレームワークなどで整えたり、日本語に直したりすることができます。

###kaminariインストール

gemをインストールします。

**Gemfile**に下記を記述して下さい。

```gemfile
gem 'kaminari'
```

後はターミナルで`bundle install`します。

これでインストールは完璧です！

###コントローラーに定義

```reviews_controller.rb
class ReviewsController < ApplicationController
 def index
    @reviews = Review.page(params[:page]).per(5) # 5件溜まったら次のページへ
 end
end
```

###ビューに表示できるように記述

```index.html.erb
<%= paginate @reviews %>
```

一番下にこれを書くだけ。。。

これで一応使えるようになります。

ここからは見た目をカッコよくする方法です。

```
rails g kaminari:views default
```
app>viewsフォルダにkaminariが追加されます。
そのフォルダの中にページネーションの部分のhtmlが記述されているので、ここでで変更を行うことができます。

私の場合はフレームワークでbootstrapを使ったので以下のようにしました。

```
rails g kaminari:views bootstrap4
```

最後に日本語に変えることもできます。

config>locals>ja.ymlに以下を記述します。

```ja.yml
ja:
  views:
    pagination:
      first: "&laquo; 最初"
      last: "最後 &raquo;"
      previous: "&lsaquo; 前"
      next: "次 &rsaquo;"
      truncate: "..."
```
EC-CUBE環境をDockerで構築する

# EC-CUBE環境をDockerで構築する

#### 経緯

EC-CUBEを使ったサイトの保守をお願い。って言われたので、とりあえずどんなものか、
ローカル環境作ってみて触ってみることにした。
最終的にやりたいことはEC-CUBEのmysqlに入ってるデータを抜いてJSONで返すAPIを作ること。


#### 手順

[Docker Composeを使用してインストールする](https://doc4.ec-cube.net/quickstart/docker_compose_install)

基本は上のページの内容に沿ってぽちぽちしていけばOK。

```
# git clone
git clone https://github.com/EC-CUBE/ec-cube.git ec-cube

# 作業フォルダに移動
cd ec-cube

# コンテナ起動
docker-compose -f docker-compose.yml -f docker-compose.mysql.yml up -d

# マイグレーション
docker-compose -f docker-compose.yml -f docker-compose.mysql.yml exec ec-cube composer run-script compile
```


localhost:8080にアクセス

![スクリーンショット 2021-07-14 22.37.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1763730/5cc86420-8062-a3ae-e53d-3fc82f41e819.png)

デフォルトで入ってるサンプルサイトかわいいw
EdgeブラウザでIEモードを利用できるようにする(レジストリ変更版)

#TL;DL
Microsoft Edge のIEモードを使おうと思ったけれど、組織で管理されているPCのため、
「設定＞既定のブラウザー」には「Internet Explorer モードでサイトの再読み込みを許可」が存在しなかった。

一部の環境ではグループポリシーを設定することで「その他のツール」に「サイトをInternet Explorer モードで開く」が表示されるようになったが、組織で管理されているPCではうまくいかない。

レジストリに設定値を追加する方法で「その他のツール」に「サイトをInternet Explorer モードで開く」が表示されるようになったので、備忘として記載する。

###環境
・Windows 10 OS Version 1909 (Build 18363.1621)
・Microsoft Edge 91.0.864.67 (公式ビルド) (64 ビット)

### 追加するレジストリ
| 名称 | 種類 | データ | 意味 |
|:--|:-:|:-:|:--|
| InternetExplorerIntegrationTestingAllowed  | REG_SZ | 1 |Internet Explorer モードのテストを許可｜
| InternetExplorerIntegrationLevel  | REG_SZ  | 1 |Internet Explorer 統合を構成する|

※REG_SZ ・・・文字列データ
※InternetExplorerIntegrationTestingAllowed  は近日廃止予定。

### 配布できるようにバッチも作成
```bat
rem 管理者として実行しているかチェック
net session > nul 2>&1

if %ERRORLEVEL% == 0 (
    echo 管理者権限：OK
    echo レジストリを登録します。中止する場合は「×」で終了して下さい。
    pause
) else (
    echo 管理者として実行してください。
    pause
    exit    
)

rem EdgeのIEモードを使用できるようレジストリ値を追加する。
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge" /v "InternetExplorerIntegrationLevel" /t "REG_SZ" /d "1" /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge" /v "InternetExplorerIntegrationTestingAllowed" /t "REG_SZ" /d "1" /f
pause
```

##備考
・レジストリ変更は怖いからやりたくないけど、全然解決方法が見つからなかったので最終手段として実行。
・Microsoft のサイト見ても分かりづらいのは相変わらず。
リモートリポジトリ上で変更していないファイルに差分が出てしまう場合の対処


#結論
エディタの設定によって改行コード・ファイル末尾の改行などが勝手に置換されてしまっていることが原因

#パターン①
改行コードの違いが差分として検知されてしまっているパターン
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/874156/f2fac4e9-d8d1-20fd-ef38-c3c1d8ca8c46.png)

###前提知識
MacOS/Linuxの改行コード：LF
Windowsの改行コード：CR+LF

###事例
プロジェクトメンバの使用している端末が異なることによって発生。
今回は他メンバがMacで自分がWindows。

bitbucket上のコードは改行コードがすべてLFだったが、
git cloneしてきたコードの改行コードを保存時にCR+LFに変換されていたため差分が出た。

###エディタ（VSCode）の設定
core.autocrlfの項目を編集することで、任意のタイミングで改行コードの変換を行うことができる。
今回の事例ではbitbucketにpushするときにLFになっていればいいのでtrue/inputのどちらかにすればいいと考えた。

| core.autocrlfの設定 | チェックアウト時 | コミット時 |
|:-----------:|:------------:|:------------:|
| true       | LF -> CRLF  | CRLF -> LF         |
| input     | 変換しない      | CRLF -> LF       |
| false       |変換しない        | 変換しない         |

###core.autocrlの設定方法

```php
// 今の設定値の確認
git config core.autocrlf //false

// inputに設定する場合
git config --global core.autocrlf input
```

#パターン②
ファイル末尾の空行有無が差分として検知されてしまっているパターン（何も差分がないように見える）
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/874156/666e98b3-2800-9324-c105-039148428ee0.png)

###前提知識
ファイルの末尾は改行で終わらせるべきである。

参考：

https://teratail.com/questions/71778


###エディタ（VSCode）の設定
settings.jsonに下記を追記することで、自動的に改行を挿入してくれる。

```php
 "files.trimTrailingWhitespace": true, // ファイル保存時に末尾の空白をトリミングする
 "files.trimFinalNewlines": true, // ファイル保存時に最終行以降をトリミングする 
 "files.insertFinalNewline": true, // ファイル保存時に末尾に改行を挿入する
```
AmiVoice体験版から学ぶ音声認識サービス利用のポイント

# AmiVoiceとは
音声認識APIなどを展開する商用サービス。
以下のページから気軽にお試しすることが出来ます。

https://acp.amivoice.com/main/acp-demo/

# やってみよう
## お題
以下の文章を読み認識結果を確認してみます。

>債券投資において、利率が額面金額に対する利子の割合であるのに対し、利回りは投資元本に対する収益の割合を指します。
債券の利回りとは、通常最終利回りを意味し、投資家が満期償還まで債券を保有した場合の年利子と1年当たりの償還差損益の合計額の投資元本に対する割合をいいます。

[出典：SMBC日興証券 初めてでもわかりやすい用語集](https://www.smbcnikko.co.jp/terms/japan/ri/J0416.html)

## １．会話_金融を選択した場合

>債券投資において、利率が額面金額に対する利子の割合であるのに対し、利回りは投資元本に対する収益の割合を指します。
債券の利回りとは、通常最終利回りを意味し、投資家が満期償還まで債券を保有した場合の**年率**1年当たりの**償還策損益**の 合計額の投資元本に対する割合を言います。

ほとんどパーフェクト。

## ２．会話_汎用を選択した場合

>**最近投資**において、利率が額面金額に対する**機種**の割合にであるのに対し**周り**は投資元本に対する収益の割合を指します。
債券の利回りとは、通常最終利回りを意味し、投資家が満期償還まで債券を保有した場合の**年率**と1年あたりの償還差損益の合計額の投資元本に対する割合を言います。

こちらも高い認識率を記録。
「利子」→「機種」や「利回り」→「周り」など、汎用モード故に変換候補の選択肢が広くなり、結果認識誤りに繋がっている様子が判ります。

## ３．会話_金融を選択したものの、なぜか倖田來未のButterfly調で読みたくなった場合

>債券投資において利率が額面金額 **2達するり C の割合で R の時体制で今は割は投資元本に対する襲撃の張りや企業指して言います。**
債券の利回り**等を通るちろん最終利回り大意味し、倒し看板起床**

歌うせいでお試し制限時間内に全文読み切れなかった。。
前のパターン達と比べて大幅に認識率が下がっていることが判ります。
「に」が「2」、「利子」が「りC」となっている様に、イントネーションやアクセントを単語理解に利かせている様子が判りますね。

##### Butterflyを知らない人は再生してみよう
<iframe width="560" height="315" src="https://www.youtube.com/embed/JDtHaS5htnY?start=21" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# まとめ
高い認識率を期待して音声認識サービスを利用する場合は以下の点に留意しましょう。
これらを整理出来るなら、十分に利用可能なレベルの性能が期待できそうです。

* ある程度落ち着いて丁寧に話すことが出来る（×ディスカッション、〇インタビュー）
* 金融や医療など何某かの領域に絞って利用する（辞書を作り込むことが出来る）

# 補足（今回の実行環境）
* 雑音の無い個室
* マイクは[Amazonベーシックのゲーミングヘッドセット](https://www.amazon.co.jp/AmazonBasics-Premium-Headset-Consoles-Desktop/dp/B07L8TTY9Z/ref=dp_prsubs_1?pd_rd_i=B07L8TTY9Z&psc=1)を利用
* パターン１、２は神奈川県育ちが標準語ではっきり喋っている
Flaskで画像が表示されない(備忘録)

#はじめに
普段はwebアプリを制作するのに，herokuでFlaskを動かして遊んでいます．

初歩的なことですが，単なる画像をhtmlで表示するのに
少しつまずいたので，備忘録として残しておきます．

いろんな要因で画像が表示されない場合があると思いますが，
その場合は，以下のようなマークが出ると思います．

![non_pic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262828/20916b32-b25e-4fbf-6ade-aff69b8104e2.jpeg)

原因としては，ファイル名を間違えていたり...，ファイル自体が存在していなかったり...


#TL;DR

"static_folder"で静的なファイルの置き場所を明示してあげると動く場合があります．

```python
app = Flask(__name__, static_folder='./templates/images') 
```


#詳細
細かい状況をまとめます．

###ファイル構造
Flaskのコードの配置は，以下のようになっています．

```
workspqce/
├── main.py
└── template/
    ├── home.html
    └── images/
    　   　　└── test.png

```

###HTMLのテンプレート

HTMLのテンプレートでは，画像の挿入を以下のように指定しています．

```html:home.html
...
 <img src={{ image_path }} alt="xxx" title="xxx">  
...
```

###Flaskでテンプレートを呼ぶ
上記のHTMLを以下のように，Pythonで呼んで動かしてあげます．

```python:main.py
# -*- coding: utf-8 -*-                                                            
from flask import Flask, render_template, request 
import os
import ast

app = Flask(__name__)

@app.route('/home', methods=['POST'])                                              
def home():
    img_path = 'images/test.png'
    return render_template('home.html', title='HOME', image_path=img_path)

if __name__ == '__main__':                                                         
    port = int(os.getenv("PORT", 80))                                            
    app.run(debug=True, host='0.0.0.0', port=port)   
```

いっけん，このコードで動きそうですが，動かなかったです．

なぜなら，静的なデータは，flaskのインスタンス化をする時点で，
明記してあげないといけないみたいです．

#解決方法
以下のようにして，静的なファイルのディレクトリを記述して，インスタンス化すると
無事画像が表示されました．


```python
app = Flask(__name__, static_folder='./templates/images') 
```
【Java】【Kotlin/JVM】整数へのキャストでの丸め

https://qiita.com/neonemo/items/0e27cccd845630e02edc

↑この記事を見て、そういえばよく忘れるなぁと思ったのでまとめておく。

---

Java と Kotlin/JVM で浮動小数点数を整数にキャストすると
端数は `0` に近づける方向に切り捨てられる。

```Java:Java
System.out.println((int) -0.75); // > 0
System.out.println((int) -0.25); // > 0
System.out.println((int) +0.25); // > 0
System.out.println((int) +0.75); // > 0
```

```Kotlin:Kotlin/JVM
println((-0.75).toInt()) // > 0
println((-0.25).toInt()) // > 0
println((+0.25).toInt()) // > 0
println((+0.75).toInt()) // > 0
```

---

The Java® Language Specification より

https://docs.oracle.com/javase/specs/jls/se15/html/jls-5.html#jls-5.1.3

> the floating-point value is rounded to an integer value V using the round toward zero rounding policy

／以上
xibでViewを作った

# xibでViewを作った
<img width="150" alt="816CF66F-0EEF-43D4-B13C-B078EC3866CA_1_201_a.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1466343/327d648b-f580-30a6-da0d-0dde49cb509b.jpeg"> 

# 機能説明

* Buttonを押したら、Modalでxibファイルで作成したViewを表示させる

# コード

* Podfileには、`pod 'FSCalendar'`を入力

```言語:Podfile
 pod 'FSCalendar'
```

## FSCalendar

* `FSCalendar()`をインスタンス化➡️カレンダーのサイズなどの見た目を決める➡️`addSubview(FSCalendarのインスタンス)`　

```Swift:FSCalendarModel
import Foundation
import FSCalendar

class FSCalendarModel:UIViewController{
    
    let fsCalendar = FSCalendar()
    
    func createCalemdar(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, targetView:UIView){
        
        self.fsCalendar.frame = CGRect(x: x, y: y, width: width, height: height)
        
        targetView.addSubview(self.fsCalendar)
        
    }
}
```

## View
<img width="250" alt="B76C93F9-9335-4952-8562-DA0A9764C444_1_201_a.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1466343/48f0aa0d-2f81-74a7-4f59-592f9042d9cb.jpeg"> 

```Swift:ModalView
import Foundation
import UIKit

class ModalView:UIViewController{
        
    @IBOutlet weak var partsView: UIView!
    @IBOutlet weak var calendarView: UIView!
     
    let fsCalendarModel = FSCalendarModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
                
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
         
        self.partsView.layer.cornerRadius = 22.0
        self.calendarView.layer.cornerRadius = 22.0
             
        self.fsCalendarModel.createCalemdar(x: 0, y: 0, width: self.calendarView.frame.size.width, height: self.calendarView.frame.size.height, targetView: self.calendarView)     
        
    }
}
```

## Controller

```Swift:ViewController
import UIKit

class ViewController: UIViewController, UIViewControllerTransitioningDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func show(_ sender: Any) {
        
        let modalView = ModalView()
        modalView.modalPresentationStyle = .automatic
        modalView.transitioningDelegate = self
        present(modalView, animated: true, completion: nil)
        
    }
    
}
```

# 終わり
素敵なUI作りたい
ただ、コードを載せただけになってる気がする
print関数の超かっこいい使い方

printって結構なんとなく使っていますが、関数なのです(知ってますよね:sweat_smile:)。
実は文字を表示する際に使える機能がいくつかあるので紹介したいと思います。
また、変数を気持ちよくかっこよくprint関数に入れて表示する方法を書いていきます！(<font color="Red">こっちが本命です！</font>)

## print関数の引数
まず簡単にprintの引数で使えるものを紹介していきたいと思います。
sepとendです。
sepは文字列を区切るときの区切り文字を決めます。
endは表示文字列の末尾に挿入する文字列を決めます。
言葉だけだとよくわからないので、コードを書いてみましょう。
まずデフォルトの状態で表示してみます。

~~~python:
# デフォルト値で表示
a = 'Why you are so mean'
b = 'Because I like to be'
print(a, b, sep='', end='\n')
~~~
~~~:output
Why you are so meanBecause I like to be
~~~

いつも通りの構成で表示されましたね。 半角スペースを手動で入れないと、繋がってしまいますね。
デフォルトのsepとendの値は上記になっています。
キーワード引数なのでsep, endと指定しないと、表示する文字列として扱われます。
次にsepとendの値を少し変えて文字列間がつながらないようにして、改行をしないように変更してみましょう。

~~~python:
# sep=' - '
# end='\t'
a = 'I am mad at you'
b = 'why?'
c = 'You broke my phone yesterday night'
d = 'No you did when you got drunk'
sep = ' - '
print(a, b, sep=sep, end='\t')
print(c, d, sep=sep)
~~~
~~~:output
I am mad at you - why?	You broke my phone yesterday night - No you did when you got drunk
~~~
説明するために少し無理矢理感がありますが、、、
意図通りに表示することができました。
覚えておくと意外と使える場面があるかもしれませんね！

## 変数のいろいろな表示方法
変数を組み合わして文字を表示するときは上記の方法だと少し面倒な時が多いです。
ここではもうちょっとスマートに表示する方法を紹介していきます。

まずは.formatを使う方法

~~~python:
name = 'Tako'
age = 25
hobby = 'baseball'
f = 9.5
print('{0} {1} {2}'.format(name, age, hobby))
~~~
~~~:output
Tako 25 baseball
~~~

右揃え、中央揃え(padding)、小数点の表示

~~~python:
# 幅10の右揃え
print('右揃え')
print('{0:>10s} {1:>10d} {2:>10s}'.format(name, age, hobby))
# 幅10の中央揃え
# 隙間は+で埋める(padding)
print('\n中央揃え')
print('{0:+^10s} {1:+^10d} {2:+^10s}'.format(name, age, hobby))
# 中央揃えして小数点第五位まで表示
print('\n中央揃えで小数点第五位まで表示')
print('{0:^10.5f}'.format(f))
~~~
~~~:output
右揃え
      Tako         25   baseball

中央揃え
+++Tako+++ ++++25++++ +baseball+

中央揃えで小数点第五位まで表示
 9.50000  
~~~

fを使っての表示(正式名称がわかりません・・・)

~~~python:
print(f'Name:{name:^10s} Age:{age:^10d} hobby:{hobby:^15s}')
~~~
~~~:output
Name:   Tako    Age:    25     hobby:   baseball    
~~~

## おまけ
pprintモジュールがあり自動的に綺麗に表示してくれます。
listやdictなどを自動的に改行を入れてみやすくしてくれます
例えば

~~~python:
from pprint import pprint
lst = [a, b, c, d]
print(lst)
pprint(lst)
~~~
~~~:output
['I am mad at you', 'why?', 'You broke my phone yesterday night', 'No you did when you got drunk']
['I am mad at you',
 'why?',
 'You broke my phone yesterday night',
 'No you did when you got drunk']
~~~
こんな感じです。興味のある方は調べてみてください

# まとめ
簡単にですが、printの役立つ知識を紹介していきました。
正直print関数をガッツリ使うことはあんまりないかと思いますが、
.formatやfはstr型の変数を作る時にも使えるので、その時に使えそうです！

指摘ありましたらコメントお願いいたします。
Couldn't find Blog with 'id'=show 

#エラーについて
paramの値が空か間違っているという意味です。
今回の場合は、投稿→showに遷移する際にこのエラーを検出しました。
#エラーの原因
pathにid指定されていなかったことが今回の原因でした。

```ruby:controller.rb
def create
    @book = Book.new(book_params)
    if @book.save
      flash[:notice] = "Book was successfully created."
      redirect_to "/books/show"
    else
      @books = Book.all
      render :index
    end
end
```
if文の中のredirect_toにidが指定されていないことが原因あると分かりました。
#解決方法

https://railsdoc.com/page/redirect_to

redirect_toに関するドキュメントを参考にしながら以下のように書き替えました。　

```ruby:controller.rb
 def create
    @book = Book.new(book_params)
    @book.user_id = current_user.id
    if @book.save
      redirect_to book_path(@book), notice: "You have created book successfully."
    else
      @books = Book.all
      render 'index'
    end
 end
```

そうすることによって、投稿の詳細ページにidが渡され、エラーが解決しました。
#まとめ
redirect_toの書き方が間違っていた。
このエラーが出て確認すべきポイントは、idという引数がしっかり送られているかについて考えると解決策が見えてくると思います。
何かご意見等あれば、ご指摘よろしくお願い致します。
Pythonで音付き動画を作る方法

# Pythonで音付き動画を作成
Pythonで音付きの動画を作成する方法です。なかなか調べても出てこなかったので、ここでまとめておきます。

## 候補1: opencv

pythonで動画や画像を扱うとき最も一般に使われるものは、おそらくopencv(cv2)だと思います。しかし、どうやらopencv単体では音声付の動画を作成することはできなさそうです。

## 候補2: pyav

音付きの動画から、以下のコードで音声つき動画を作成することが出来ました。
以下は[公式サンプル](https://pyav.org/docs/develop/cookbook/basics.html)を少し改変して音声付き動画を作るように変更したものです。

```python
import av
import av.datasets
import numpy as np


input_ = av.open("./videos/01_smile.mp4")
output = av.open('./videos/sample02.mp4', 'w')

# Make an output stream using the input as a template. This copies the stream
# setup from one to the other.
in_stream = input_.streams.get(audio=0, video=0) 
out_stream_video = output.add_stream("h264", rate=30, width=1920, height=1080)
out_stream_audio = output.add_stream("aac", rate=44100, layout="stereo")
audio_first_flag = True
for i, packet in enumerate(input_.demux(in_stream)):

   # We need to skip the "flushing" packets that `demux` generates.
   if packet.dts is None:
       continue

   # We need to assign the packet to the new stream.
   if packet.stream.type == 'video': 
       for frame in packet.decode():
           # get PIL image
           image = frame.to_image()
           # to numpy
           image = np.array(image)
           # porocessing_img
           image[:, :, 1]  = 255
           # to frame
           new_frame = av.VideoFrame.from_ndarray(image, format='rgb24')
           # encode frame to packet
           for new_packet in out_stream_video.encode(new_frame):
               # mux packet
               output.mux(new_packet)

   elif packet.stream.type == 'audio':
       for audio_frame in packet.decode():
           # to numpy
           arr = audio_frame.to_ndarray()
           # decrease volume
           arr = arr * 0.1
           # to audio frame
           new_audio_frame = av.AudioFrame.from_ndarray(arr, format="fltp")
           new_audio_frame.rate = 44100
           # encode frame to packet
           for new_packet in out_stream_audio.encode(new_audio_frame):
               output.mux(new_packet)


input_.close()
output.close()
```

簡単に流れを説明します。上記のサンプルは、入力の動画を加工し別の動画ファイルを出力するというものです。

どのような加工をしたかというと以下の２つです。

1. 元の動画のRGBのうちGの値を全ての時間で最大値(255)にする
2. 音量を1/10にする（波形の振幅を1/10にする）


コードに出てくる概念イメージを説明するとつぎのようなイメージです。

- input_やoutputはデータを詰めておく倉庫
- streamは倉庫の荷物を運ぶ流通経路みたいなもの
- packetが荷物
- frameやaudio_frameは荷物の箱の中に入っている中身
- 倉庫に荷物が箱で詰まってるとき動画として再生できる



これを踏まえた上でプログラムの流れを簡単に説明すると

1. 元の動画から、videoとaudioのstreamを一つのstreamとして取り出す
2. 出力する動画を指定して、videoのstreamとaudioのstreamを作成する
3. 入力のstreamからpakcetという動画の中身の一部をfor文で順番に取り出す4. packetには種類がありvideo時とaudio時とがあるり、処理を分ける。
5. videoだった場合は、packetからframeという画像のデータを取り出す。
6. 画像データをnumpyに変換する。
7. RGBのGの値を255にする。
8. numpyからframeを作成する。
9. outputのvideoのstreamを使いoutput用のpacketを作成する。
10. outputに作成したpacketを詰め込む。
11. 入力から取得したpacketが音だった場合、同様に音の処理をする。
12. 入力動画と出力動画のファイル操作を終了する

というような感じになります。



### 他の候補

moviepyというPythonで動画編集をしちゃおうというものがあるそうです。こちらについては今後どこかで触ってみたいと思います。
AppLovin Max SDK for Unity をAndroidでビルドエラーの解決(2022/7/22追記)

AppLovinのサンプルをビルドできないという問題が出たので、それの対処法をメモしておく。
以下のバージョンで試した。

- Unity 2021.1.6f1 
- Applovin Max SDK 4.3.1

## とりあえず手順通り進めてみる

UnityでApplovin Max SDK を導入する際にビルドエラーが出る問題を解決する。


とりあえず自分の環境のまっさらな状態でちゃんとサンプルプロジェクトが動くことを確認する。

以下のプロジェクトをダウンロードして適当な場所に展開

https://github.com/AppLovin/AppLovin-MAX-Unity-Plugin

しょっぱなから以下のエラーが出るので、

    Deterministic compilation failed. You can disable Deterministic builds in Player Settings
    Library\PackageCache\com.unity.multiplayer-hlapi@1.0.4\Editor\Tools\Weaver\AssemblyInfo.cs(22,28): error CS8357: The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation

Packages/manifest.json の以下の文を削除して保存

    "com.unity.multiplayer-hlapi": "1.0.4",

以下の作業を行い、とりあえずビルドしてみる

1. AppLovin -> Integration Managerを立ち上げて、__AppLovin SDK Key__ を入力
1. HomeScreen.cs の「MaxSdkKey」の「"ENTER_MAX_SDK_KEY_HERE"」も __AppLovin SDK Key__ に書き換える
1. Builds SettingsでAndroidにSwitch Platform
1. Buildする

## 問題発生

すると、以下のエラーが出る。

    Gradle build failed. See the Console for details.

![2021-07-14_18h02_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/d3e5a22a-8f03-6d19-c839-d925f0a5446f.png)

もしくはビルドできても、起動してすぐに強制終了してしまう。

というわけで、ここからが本題。

これ以降は要注意だが、あくまでも対処療法なので、これをすれば必ず治るわけでもないし、乱暴なやり方なのでプロジェクトを壊す恐れがある。以下は__必ず自分のプロジェクトではやらずに、サンプルプロジェクトで行うこと__。もしくは、__自分のプロジェクトでやる場合はGitなどでちゃんと元に戻せる状態で始めること__を注意されたし。

## 対処法


### 1. 最新版のApplovin Max SDK for Unityをインストールする

以下のサイトで配布している、最新版を改めてインストールする

https://dash.applovin.com/documentation/mediation/unity/getting-started/integration

（ちなみに、この時点で再度ビルドしてもやはり同様にビルドエラーが出る）

### 2. Force Resolveをする

メニューから Assets > External Dependency Manager > Android Resolver > Force Resolve をして強制的に解決する。

![2021-07-14_19h21_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/46f35e61-6029-6825-6c82-cd8b34892f0e.png)

すると、Plugins/Android/ に大量のファイルができる。

これでうまくいくだろうと思うが、ビルドしてもやはりエラーが出る。

### 3. Plugins/Android/ の中身を消す

最初からある「AndroidManifest.xml」「res/」以外の 2でできたものをいったん削除する。ただし、あくまでも2でできたものに限るので、余計なものを消さないように気を付ける。

### 4. もう一回Force Resolveをする

2でやった「Force Resolve」をもう一度する。するとやはりPlugins/Android/ に大量のファイルができる。

再度ビルドしてみると、今度はうまくいくはず。

## 結局どういうこと？

結果から考えると、

- Plugins/Android以下にAndroid用の関連ファイルがないとビルドできない
- そのためには Force Resolve をする必要がある
- しかし、そこにバージョンが古い関連ファイルが残ってしまうとNG
- つまり一回まっさらな状態にしてから Force Resolve すると最新版の関連ファイルだけになる

ということだと考えられる。

## それでもビルドできないときの対処法 (2021/7/16 追記)

- まずUnityをいったん落として、再度立ち上げてからビルドしてみるとうまくいくケースがある
    - おそらくTempフォルダに変な情報が残っているためだと考えられる
        - Unityを落とすとTempフォルダが削除されるので、それでうまくいくのではないか？
- それでもうまくいかないときは、上でやったPlugins/Androidのプラグインを一掃して、Force Resolve する
    - これでたいていうまくいく
        - それでもうまくいかないときは、引き金となったネットワークのSDKを一回削除して、もう一回ビルドから始める
- AppLovin Integration Manager で「Install」するだけでよい
    - それぞれのサイトからSDKをDLする必要はない
        - 余計なものも入るので


## それでもなおビルドできないときの対処法 (2022/7/22追記)

AdMobを入れたときどうにもこうにもエラーが出て進めなかった。

1. いったんUnityを落とす
1. Libraryフォルダを消す
1. Unityを起動する（プラットフォームはリセットされているのでちゃんとiOS/Androidに再設定すること）
1. ビルドする 

実際にこれでうまくいった。たまにこの症状が出たときはもう一回消すしかなさそう。
【環境構築Expo(Bare workflow)】TypeScript導入＆初期動作確認まで

### 完成品はこちら

https://github.com/nakapon9517/expo-bare-typescript


## 目次

[プロジェクト作成](#プロジェクト作成)
[Typescript設定ファイル作成](#typescript設定ファイル作成)
[App修正](#app修正)
[アプリ起動](#アプリ起動)

## プロジェクト作成

```sh
$ expo init example
```

minimalを選択

```sh
? Choose a template: › - Use arrow-keys. Return to submit.
    ----- Managed workflow -----
    blank               a minimal app as clean as an empty canvas
    blank (TypeScript)  same as blank but with TypeScript configuration
    tabs (TypeScript)   several example screens and tabs using react-navigation and TypeScript
    ----- Bare workflow -----
❯   minimal             bare and minimal, just the essentials to get you started
```

このようなフォルダ構成になる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630810/55592443-1dd9-3d6d-916d-b7f99308a874.png)

## Typescript設定ファイル作成

```sh
$ touch tsconfig.json
```

## App修正

```sh
$ mv App.js App.tsx
```

## アプリ起動

Expo Goを利用する場合 or Simulator(iOS/Android)を利用する場合

```sh
$ expo start
$ expo ios or expo android
```

動作確認時に以下メッセージ（react関連の@typesインストール)が出た場合は「y」を選択

```sh
? It looks like you're trying to use TypeScript but don't have the required dependencies installed. Would you like to install typescript, @types/react,
@types/react-native? › (Y/n)

```


# 参考

https://docs.expo.io/bare/exploring-bare-workflow/

https://docs.expo.io/guides/typescript/
対戦ゲームを作る。 その4

#概要

対戦ゲームを作る。
そこに、石が置けるか評価する関数の実装。

#考え方

前後左右、９方向に、違う石があって、同じ石があるのか、探索する。


#サンプルコード

```
	function check(put, d) {
		var x = put % 8; 
		var y = Math.floor(put / 8);
		var res = 0;
		if (x == 0 && (d == -9 || d == -1 || d ==  7)) res = 1;
		if (x == 7 && (d == -7 || d ==  1 || d ==  9)) res = 1;
		if (y == 0 && (d == -9 || d == -8 || d == -7)) res = 1;
		if (y == 7 && (d ==  7 || d ==  8 || d ==  9)) res = 1;
		return res;
	}
	function oku(put, iro, ban) {
		var res = 0;
		var turn = 0;
		if (iro == 0) turn = 2;
		var dir = new Array(-9, -8, -7, -1, 1, 7, 8, 9);
		var tugi;
		var i;
		var count;
		if (ban[put] == 1)
		{
			for (i = 0; i < 8; i++)
			{
				count = 0;
				tugi = put;
				do
				{
					if (check(tugi, dir[i]) == 1) break;
					count++;
					tugi += dir[i];
				} 
				while (ban[tugi] == turn);
				if ((count > 1) && (ban[tugi] == iro))
				{
					res = -1;
					tugi = put;
					do
					{
						ban[tugi] = iro;
						tugi += dir[i];
					}
					while (ban[tugi] == turn);
				}
			}
		}
		return res;
	}

```

以上。
CSV書き出し方法

＜方法１：pandasを使う（逐次処理版）＞
メリット：dataframeに格納してから、一気に書き出すので、dataframeで平均や合計などのデータ操作がしやい。

```python:（FOR文に対応しやすい書き方）
   csv_file_path = "C:\temp\csv.csv"
   code = []
   timestamp = []
   benefit_today = []
   fieldnames = ['code', 'timestamp', 'benefit_today']

   # データを追加
   code.append(stock_code)
   timestamp.append(time)
   benefit_today.append(benefit)

   df = pd.DataFrame(data={'code': code,
                           'timestamp': timestamp,
                           'benefit_today': benefit_today}, columns=fieldnames)

   # df.to_csv(csv_file_path, index=False, encoding='utf8')  # 上書きモード
   df.to_csv(csv_file_path, index=False, mode='a', encoding='utf8')  # 追記モード
```

＜方法２：csvパッケージを使う＞

```python
import csv

with open(csv_file_path, 'w', newline="") as csv_file:
    # header を設定
    fieldnames = ['code', 'timestamp', 'benefit_today', 'benefit_subtotal', 'open1', 'low1', 
                  'high1','close1', 'volume1', 'open2', 'low2', 'high2', 'close2', 'volume2']
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()

    # データの書き込み
    writer.writerow({'code': stock_code,
                         'timestamp': str(time),
                         'benefit_today': benefit_today,
                         'benefit_subtotal': benefit_subtotal,
                         'open1': row1['open'],
                         'low1': row1['low'],
                         'high1': row1['high'],
                         'close1': row1['close'],
                         'volume1': row1['volume'],
                         'open2': row2['open'],
                         'low2': row2['low'],
                         'high2': row2['high'],
                         'close2': row2['close'],
                         'volume2': row2['volume']})
```
        
引数newline=""　は改行コードをNullに指定することで、空行の出力を防ぐ。
追記にしたい場合、引数にmode="a"を追加。