OmniAICreator/Qiita-1.07M huggingface dataset:
Rails権限・ロールまわり調査

## 概要
Railsでのロール管理・アクセス権限管理のやり口について調べたときのメモ

### アクセス権限チェック(認可)
・cancancan
・pundit
・banken

### 認可について
設定ファイルがシンプルそうでrubyで書けるpunditかbankenがやりやすそう。
普及具合で言えばpundit。ただbankenのスライドを見ると、「作成者がcancancanとpunditの不満点をクリアしたもの」、ということもありbankenが良さそうに見える。

### role設定(権限管理)
・rolify
	
それぞれのgemの概要は後述。

それぞれのgemの


※以下スライドはcancancan、pundit、bankenの違いがわかりやすい。
https://speakerdeck.com/kyuden/rails-authorization

※以下はcancancanとpuditの比較参考
https://www.icare.jpn.com/dev_cat/pundit%E3%81%A8cancancan%E3%81%AE%E6%AF%94%E8%BC%83/

### role(権限)の設定については
１.roleは１ユーザーに一つだけなら、usersテーブルにenumで持たせるで事足りそう。(rolifyでもOK)
2. 複数設定可能にしたいならrolifyを使うのが簡単そう。
3. roleのテーブルに役職和名など付加情報も持たせるなら、独自でroleのマスタと関連付けテーブルを作成するか。

認証は、sorceryの方がカスタマイズしやすいという記述をみるので、汎用テンプレートとしてはsorceryの方が無難かなと。

なので
	認証：sorcery
	認可：bunken (or pundit)
権限付与：rolifyか独自か


というイメージが汎用的そう。

以下のgunosyブログの構成と似た感じ、というか引きずられている

https://tech.gunosy.io/entry/gunosy-admin-rails


## 　各geｍの概要

### cancancan(DL数:22,394,057)
https://github.com/CanCanCommunity/cancancan

出来ること
・一つのAbilityクラスファイルに、権限毎にモデル + アクションで許可条件を定義できる。

基本的な使い方
・Abilityクラスを作成して、独自DSLで記述していく。
・「can/cannot アクション名、モデル、条件」というのが基本的な書き方の様子。

```
  def initialize(user)
    can :read, Post, public: true

    if user.present?  
      can :read, Post, user_id: user.id
      
      if user.admin?  
        can :read, Post
      end
    end
  end
```

		
		


デメリット
・独自記法の学習コストあり
・基本一つのAbilityファイルに権限*各モデルへのcan/canontを書いていくので肥大化しやすい。条件分岐も多くなると見通しが悪くなりそう。

参考URL
https://qiita.com/senou/items/e28ff548e93ad0eeed3f
https://qiita.com/naoki85/items/266c8d7ab469cc6ab1fe
https://qiita.com/umanoda/items/679419ce30d1996628ed
https://happy-teeth.hatenablog.com/entry/2018/12/09/002905
	

### pundit(DL数:20,682,033)
https://github.com/varvet/pundit
出来ること
・Model毎にPolicyクラスを作成しAction名に対する認可条件を定義できる
・rubyで書ける。
・※一つのモデルに対して、一つのポリシーしか紐付けることは出来ない。apiと通常の画面で同じモデルを参照する場合、一つのpolicyファイルに記載することになる。

基本的な使い方
・モデル毎にPolicyファイルを作成する。
・Policyファイルの中で条件判定用の関数を書く。
・利用する時はコントローラー等から、authorizeを実行して判定結果を受取って制御する。

		
デメリット
・Model + アクション名に対して一つしか定義をかけない。画面用コントローラーとAPIコントローラで制御を別にするなら、アクション名が重複するとだめらしい。


参考URL
https://qiita.com/senou/items/e28ff548e93ad0eeed3f


### banken(DL数:285,710)
https://github.com/kyuden/banken

出来ること
punditにおける「モデルとpolicyが1対1の必要がある」という制約をはずして、コントローラー毎にActionに対する認可条件を記載できるようにしている。


基本的な使い方
・コントローラー毎にloyaltyファイルを生成する。
・アクション名毎に認可条件を記載して、コントローラ側でauthorizeを実行して判断する。

デメリット
・pundit, cancancanに比べて利用数が少ない。
・punditとくらべると、scope機能なし

参考URL
スライドシェア
https://speakerdeck.com/kyuden/rails-authorization
https://github.com/kyuden/banken
[日本語ドキュメント](https://github.com/kyuden/banken/wiki/Tutorial-(japanese))


### Rolify(DL数:6,307,168) (権限設定gem)
https://github.com/RolifyCommunity/rolify

出来ること
Usersなど認証に使っているモデルにRoleを関連付けることができる。role用のモデルとメソッドが生成される。前段の認可の仕組みでは無くて、権限付与のためのgem。
Roleは１ユーザーに複数の設定も可能。


基本的な使い方
・ユーザー作成時等に、add_role()で特定のロールをセットしてあげる。
・ユーザーが特定の権限を持っているかどうかは、user.has_role?()で取得できるのでroleをそこで確認。その結果のアクセス制御はcancancanやpunditで設定する。

参考URL
https://qiita.com/tatsurou313/items/0f632887d049e9503e3b
https://github.com/RolifyCommunity/rolify


### 他
認証にclearchnceとauthlogicというものもあるが、割愛
laravel調査


## まずmacのlaravel環境構築
https://qiita.com/S-Masakatsu/items/b231a8a02737aff6a808


■サーバーに配置して動かしたい(apache)
https://qiita.com/sskmy1024y/items/c2e434941400bd4ee82c


### lalabeの基本コマンド

```
#サーバー起動
php artisan serve

#routes確認
php artisan route:list

#model作成
php artisan make:model User
		
#controller作成
php artisan make:controller HelloController

# mailer作成
php artisan make:mail SampleNotification

#migrate
php artisan make:migration create_users_table
php artisan migrate
```

## Ractの導入
https://qiita.com/10mi8o/items/b435ef7fb838a40058c5



## type script
https://qiita.com/bo_yakitarako/items/ae4b0debe3000fc3b3b7


## 調整・エラー対応

### メールをsmtpで送信するように変更
```
 config/mail.php
    'mailers' => [
        'smtp' => [
            'transport' => 'smtp',
            'host' => 'localhost',
            'port' => '25',
            // 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            // 'username' => env('MAIL_USERNAME'),
            // 'password' => env('MAIL_PASSWORD'),
            // 'timeout' => null,
            // 'auth_mode' => null,
        ],

```



## RoutingでCotollerクラスが見つからないエラー
laravel8でroutingの書き方がちょっと変わったらしい。
web.phpを修正する

```
Route::get('posts', 'PostController@index');
Route::post('posts', 'PostsController@store');
```
↓

```
use App\Http\Controllers\PostsController;
Route::get('posts', [PostsController::class, 'index']);
Route::post('posts_json', [PostsController::class, 'json']);
```



### apacheで単純配置すると。public/index.php/ルートみたいに、なる index.phpまで明示しないと行けない
以下で行けるらしいが、うまくいかなかった..要調査。

[Laravel 5.8 でpublic/index.phpを表示させないために.htaccessとserver.phpを追加と変更](https://tako1192.hatenablog.com/entry/2019/08/15/Laravel_5.8_%E3%81%A7public/index.php%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AB.htaccess%E3%81%A8server.php%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%A8%E5%A4%89)


### Support for the experimental syntax 'classProperties' isn't currently enabled

以下で対応。.babelcはプロジェクトのrootに新規作成でOK。
 https://gugutasuujimasa.blogspot.com/2018/12/babelsupport-for-experimental-syntax.html
PythonでDiscordのAPIを操作する方法（bot登録編）

Discordでbotを使ってユーザーにDMやチャンネルへ投稿する必要があったので方法を記載します。
今回はdisocrd.pyを使わず書いていこうとおもいます。
## Discordの管理者権限が自分にあるか確認する。

ない場合は、管理者の権限を付与してもらう
or
最後に表示されるURLを管理者に教えて追加してもらう必要あり。

## botの登録

### Discordの開発者ページに移動する 
https://discord.com/developers/applications

### NewApplicationをクリックする
![Group 9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/d3c712a6-9c0e-1680-d3f6-34994565a8ad.png)

### CREATE AN APPLICATION画面で任意の名前を入力し、CREATEを押す。
![1601620912.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/53e55ce6-a71f-e935-15f7-eba675a13cc2.png)

### GeneralInformation画面に移動するので左のメニューからbotを選択
![Group 10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/f1105682-19ca-018b-5e2f-75f947e27dbd.png)

### 「Add Bot」を選択する。
特に何も考えずYes,do it!を選択
※この際bot名が他の人と被っているとエラーになることもあるようです。私はtestとしたときにエラーになりましたのでtest3298にしました。
![1601621030.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/1dd392b7-c714-9edb-a439-9b8700839881.png)


### OAuth2のメニューへ移動しScopeをbot選択
![Group 11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/70e3ff0f-863e-da98-24d1-99ec45f49cea.png)

### bot permissionsのチェックボックスはメッセージを送るのでSend Messageにチェック
![1601621522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/30a6d759-05f8-f314-0447-040b90ddd027.png)


### SCOPE部分にURLが生成されているのでコピー
![Group 11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/c10f16c3-e391-6b9f-0400-0b9371fcdfab.png)

### コピーしたURLをブラウザなどに貼り付けてアクセスすると認証画面が出てくる
![Group 12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270620/d9d114cb-d096-e9a2-6f08-ce2a6515008f.png)
サーバーを選択して「はい」を選ぶとサーバーにbotが追加される


API操作編へ続く
HTMLのstrikeタグは使っちゃだめ！

#プログラミング勉強日記
2020年10月2日
`<strike>`タグ初めて見て、調べていくと`<strike>`は使ってはいけないと学んだのでまとめる。

#strikeタグとは
　<b>打消し線を引くタグだが、HTML5の仕様では廃止されている</b>。その代わりにdelタグとsタグを使用することが推奨されている。delタグは削除されたテキスト文という意味のマークアップをすることができる。sタグはdelタグとは違い正確ではない・関連性がないテキスト文という意味である。sタグでは削除されたテキストとして定義はできない。

```html:例(HTML)
<p>Hello World</p>
<p>
Hello World
</p>
<p><del>Hello World</del></p>
<p><span class="cancel">Hello World</span><p>
```

```css:例(CSS)
.cancel {
  text-decoration: line-thorough;
}
```


実行結果は以下のようになる
![1002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/fe110ca7-a343-c255-0620-6841c6a61c29.png)

#参考文献
[打ち消し線を引く](http://www.htmq.com/html/strike.shtml)
[HTMLでstrikeタグを使う注意点を現役デザイナーが解説【初心者向け】](https://techacademy.jp/magazine/29316)
Amplifyでログアウトボタンを配置する。

# やりたこと
Amplifyでログアウトして、ログイン画面に遷移する。

# 環境(今回の作業に関連ないものも記載)
* react:16.13.1
* aws-amplify:3.3.2

# 手順
## 前提
ログインは以下マニュアルで実装している。
https://docs.amplify.aws/start/getting-started/auth/q/integration/react

## うまくいかなかったもの
以下の方法でやってみたが、`onStateChange`が定義されていないとエラーになり利用できない。
（ログアウトまではできるのだが、ログイン画面に遷移しない。）
https://qiita.com/oliverSI_/items/ffb73c9ae76ab2382bef
https://github.com/aws-amplify/amplify-js/issues/1529

## うまくいったもの
こちらを利用した。
https://docs.amplify.aws/ui/auth/sign-out/q/framework/react

```XxxNavbar.js
import { AmplifySignOut } from '@aws-amplify/ui-react';
```

```XxxNavbar.js
<AmplifySignOut button-text="Custom Text"></AmplifySignOut>
```
デザインは変えなきゃいけないけど、とりあえず動作する。
【ReactNative】ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication)が表示されアプリが起動できない

## 事象

ReactNative初心者です。
ReactNativeでアプリを作成し、最初のビルドでいきなりハマりました。
事象としては、アプリ起動時に以下のようなエラーがログ上に表示され、シミュレータは真っ白な画面になりました。

```console:エラー内容
ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication)
```

## 対応

エラー内容で調べると、エラー自体は正確に何が間違っているかは表しておらず、もっと掘り下げて調べる必要があるそうです。
ただ、その前にキャッシュをクリアすると上手くいく可能性があることを共有している方がいました。

>Fixed the issue on my end by double checking that i modified all the files correctly during my RN upgrade, then running `watchman watch-del-all`, and `react-native start --reset-cache`. Then on android, build -> clean. then it worked! sigh

[Invariant Violation: Module AppRegistry is not a registered callabel module (calling runApplication)](https://github.com/facebook/react-native/issues/26687)

自分の場合は、以下の記事を参考にさせて頂き、正常に起動することができました。

```bash:自分が打ったコマンド
lsof -n -P -i :8081 -t | xargs kill
rm -rf ios/build
rm -rf android/app/build
rm -rf node_modules
npm install
```

[React Native キャッシュの削除方法](https://qiita.com/sekitaka_1214/items/4f13400eabf7a4250700)

ReactNative開発者にとっては定番の問題なのですかね？
とにかく、開発を進められそうで良かったです。参考にさせて頂いた方、ありがとうございました。
Ruby微経験者がGo言語の基本的な文法を学んでみた


# 概要

Rubyを学習して半年たちたまには別言語を学びたいなと思いGoを少し触ってみました。

# RubyとGoの違い(FizzBuzz)


RubyでFizzBuzz問題をとく場合for,whileなど色々書き方がありますが今回はtimesメソッドで書きました。

```fizzbuzz.rb
1..100.times do |i|
    if i%15==0
        puts "FizzBuzz"
    elsif i%3==0
        puts "Fizz"
    elsif i%5==0 
        puts "Buzz"
    else
        puts i
    end
end
```

Goで書いた場合は下記のようになりました。

```fizzbuzz.go
package main

import (
	"fmt"
)

func main() {
	for i := 0; i < 100; i++ {
		if i%5 == 0 && i%3 == 0 {
			fmt.Println("Fizz Buzz")
		} else if i%3 == 0 {
			fmt.Println("Fizz")
		} else if i%5 == 0 {
			fmt.Println("Buzz")
		} else {
			fmt.Println(i)
		}
	}
}
```

簡単なプログラムを組んだだけでも Rubyと比較して違う点がいくつかありましたので、自分なりにまとめてみました。

- packageについて
- importについて
- 繰り返し処理について
- := について


## package

Goではプログラミングに関する要素は何かしらのパッケージというものに属しており 必ずパッケージの宣言をしなければいけません。
試しに空のファイルを作成し`go run test.go`を実行したところ`expected 'package', found 'EOF'`といったエラーが出力されました。

そのため下記のコードのようにパッケージ、またmain関数がなければ、実行時にエラーとなってしまいます。

```test.go
package main

func main() {

}
```

## import
Goではmainパッケージの中に書かれていない関数を使う場合、その関数を持つパッケージ名を記載しなければなりません。
これはRubyのライブラリの中の`標準ライブラリ`のようなイメージですね。

Rubyの場合

```standard_library.rb
require 'Time'
p Time.strptime('2020-03-21T01:58:30+09:00', '%Y-%m-%dT%H:%M:%S%z') 
# -> 2020-03-21 01:58:30 +0900
```

Goの場合

```hello.go
package main
import("fmt")


func main() {
	fmt.Println("Hello World")
	// -> Hello World
}

```


## 繰り返し処理
Rubyでは繰り返し処理を行う際,for,while,timesなど色々な書き方があります。
Goでは繰り返し処理にはfor文のみです。

しかし下記のようにforeachのように書くことも可能です。

```foreach.go
package main

import (
	"fmt"
)

func main() {
	fruits := map[string]string{
		"apple": "りんご",
		"banana": "バナナ",
		"pineapple": "パイナップル",
	}
	for key, value := range fruits {
		fmt.Println("key:", key, " value:", value)
	}
}

// key: apple  value: りんご
// key: banana  value: バナナ
// key: pineapple  value: パイナップル
```

## :=について
goで明示的に変数を定義する場合下記のように記載します。

```variable.go
package main

import ("fmt")

func main() {
	var x,y,z int
	x = 1
	y = 2
	z = 3

	fmt.Println(x)
	fmt.Println(y)
	fmt.Println(z)
}

// 1
// 2
// 3
```

しかし、暗黙的に変数を定義することも可能でその場合は下記のようになります。

```variable.go
package main

import ("fmt")

func main() {
	x := 1
	y := 2
	z := 3

	fmt.Println(x)
	fmt.Println(y)
	fmt.Println(z)
}

// 1
// 2
// 3
```

型の指定を省略することができるためこちらで書いた方が開発効率をあげることができます。

## 参考資料
[Goの基本的な文法を学ぼう](https://thinkit.co.jp/article/11049)
[golangを基礎から学ぶ　制御構造編](https://qiita.com/high5/items/3fe34d2feeff2c11f5ca)
PHPで時間計算

勤務時間など算出したいときに「PHP 時間　計算」と調べていたのですが、検索上位に出てくるのがどうしても「日時の計算」で出てきてしまうため、自身の備忘として。


# Code
例えば10:00から18:00まで仕事をしたときの勤務時間を算出。


```php:time_diff.php
<?php

$Date = date("Y-m-d");
$InTime = $Date." 10:00:00";
$OutTime = $Date." 18:00:00;

$WorkTime = (strtotime($OutTime) - strtotime($InTime))/3600; 

?>
```

これで$WorkTimeをechoしてあげれば「8」と表示されるはずです。
小数点以下第一位まで出したい場合は

```
echo number_format($WorkTime, 1);
```

としてあげれば良いです。

# 計算詳細
計算内容を見ていきます。

strtotimeは英文形式の日付をUnixタイムスタンプに変換します。
(ひとまずdateでその日の年月日を取得しているので、日付は投稿日の2020/10/02とします）

```
strtotime($InTime) = 1601600400
strtotime($OutTime) = 1601629200
```

これを引き算。

```
strtotime($OutTime) - strtotime($InTime) = 1601629200 - 1601600400 = 28800
```

Unixタイムスタンプなので、単位は「秒」です。
なので、これを時間に直すために3600で除算します。

```
28800 / 3600 = 8
```


※参考URL
[PHP]strtotime
https://www.php.net/manual/ja/function.strtotime.php
PHP開発環境を理解しながら構築！ ①

#はじめに
###動機
　未経験でエンジニアとなり、PHPの環境構築で言われるがままに導入したソフトウェアなどをあれって何だったんだ…。とそのままにしてしまっていた。
なので本記事は自分なりにそれぞれまとめながらPHPの開発環境構築を忘れないために書いた備忘録です。
###やること
　・Visual Studio Codeのインストール
　・XAMPPをインストール
###環境
　Windows10 64bitを使用

#XAMPPでのPHP環境構築
##①Visual Studio Codeのインストール
###Visual Studio Codeとは？
　Visual Studio CodeとはMicrosoft社が出している、プログラミングを行う際に使う「エディタ」と呼ばれるソフトウェアの一つ。プログラミングを行う際に便利な機能が多く用意されています。略して「VSCode」とも呼ばれます。
　無償で誰でも使うことができて、多くのOSに対応している・拡張機能が多数用意されていて使いやすいようにカスタマイズができるのが特徴です。
###注意事項
　似ている名前で「Visual Studio」があり、同じものではなく用途が違うので注意してください。

　参考：https://techacademy.jp/magazine/39548
###インストール手順
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666516/11a83133-1726-8fa9-28c7-3e2313980ed0.png)
画像出典：Visual studio Code公式サイト

　公式サイト:https://code.visualstudio.com/download

　ここからダウンロードできます。自分のOSやbit数など自分の環境に合わせてDLしてください。
　その後はインストーラーに沿ってインストールを進めてください。

##②XAMPPのインストール
###XAMPPとは
 xamppとは、WEBアプリケーションの実行環境を構築するソフトウェアで構築に必要なソフトウェアがひとまとまりになっていてボタンクリックで環境構築が可能。無駄な時間がかからず高速な環境構築が実現できます。

XAMPPは

　・X  クロスプラットフォーム(OSにとらわれない)
　・A　Apache(Webサーバーソフトウェア)
　・M　MariaDB(MySQLから枝分かれしたデータベースシステム)※別のDBも使用可能です
　・P　PHP(スクリプト言語)
　・P　Perl(プログラミング言語)

の頭文字を取ったものです、要はこれさえあればWebアプリケーションが作れちゃうということです。便利。
メリットデメリットそれぞれありますが、それはまた別の機会に。

参考：https://www.geekly.co.jp/column/cat-technology/1908_005/
###インストール手順
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666516/243794d6-e537-ec75-e130-8bb4eca86835.png)
画像出典：XAMPP公式サイト

　公式サイト：https://www.apachefriends.org/jp/index.html
こちらも自分の環境に合わせてセットアップファイルをダウンロードして、インストーラーに沿ってインストールを進めていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666516/b867edba-e192-8273-44b2-caf769e5d458.png)
DLが終わりインストーラーが開きました、基本的には［Next>］で。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666516/6f61bbe5-378a-9bf3-f46c-7adaecc9a806.png)
今回はすべてインストールしたいので、すべてのソフトウェアを選んで［Next>］。
(灰色になっている部分はすでにインストール済み)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666516/7265a401-05fb-f893-ddde-45054496ee9c.png)
インストール先はデフォルトで「C:¥xampp」となっているのでそのまま［Next>］。

その先も［Next>］で進んでいくとインストールが始まります。
インストールが終わったら早速XAMPPを開いてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666516/dc9f332b-f825-a703-b504-0834a6f75f1e.png)
無事開けたらインストール完了です！お疲れ様でした！
ModuleにApacheとMySQLがあります。
それぞれ[start]を押せばWebサーバーとデータベースシステムが起動出来ちゃいます！
※MySQLとなっていますが実際に起動するのはMariaDBです。

実際の操作などはまた次の記事で。

#まとめ
XAMPPは全部ひとまとめになっていてとても便利ですが、少し慣れてきたらそれぞれのソフトウェアについてしっかりと理解しないとずっと初期構築ができないままになってしまいますね…。
すごい初歩的な内容ですがここまで読んでいただいてありがとうございました。

次記事：[PHP開発環境を理解しながら構築！②](https://qiita.com/kyo_suke/items/e6646662e70c5833bb9b)
ACMで証明書を発行し、好きなドメインでcloudfrontを利用する

cloudfront.net以外のドメインでwebページを配信したのでやり方をまとめておきます
cloudfrontでページの配信はできたけどドメインを変えたいという人の参考になればと思います

## 目的
自分が取得したドメインを用いてコンテンツを配信する

### やること
- ACM(Amazon Certificate Manager)で証明書を発行する
- cloudfrontのCNAMEを設定する
- Route53でDNS設定をする

### 前提
- ドメインを取得済
- cloudfrontでコンテンツを配信済み

### ACMとは
AWS 管理のリソース(cloudfront, ELB)に対して SSL/TLS 認証のプロビジョニングを行うことができるサービスです
AWS限定ですが、証明書の発行が無料かつ簡単にできるということですね
使わない手はないです

## やり方

### ACM

リージョンをバージニアにしてからACMにアクセスします
(cloudfrontではバージニアしかACMを利用できません)
証明書のプロビジョニング欄の「今すぐ始める」をクリック
![スクリーンショット 2020-10-01 13.25.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/d8870c28-2c2d-260c-60b3-7038332454f3.png)

パブリック証明書のリクエストが選択されていることを確認して「証明書のリクエスト」をクリック
![スクリーンショット 2020-10-01 13.26.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/556e7aba-c9dc-d63c-e3fd-56aee486d143.png)

ドメインを記入して(example.comなど)次へをクリック
![スクリーンショット 2020-10-01 16.18.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/ce5f7b0c-b7fe-d78d-a533-b98d3d754b46.png)

ドメインの検証方法を選択します
Eメールの検証を選択してしまうと825日ごとにメールを受信し、対応しなければならないので
DNSの検証を選択します

![スクリーンショット 2020-10-01 16.21.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/3f8d97d3-3d09-8136-0fbc-2628f2a70ac7.png)

### cloudfront
cloudfrontでCNAMEと証明書の設定をします
CNAMEとはドメイン名のあだ名みたいなものです
今回は***.cloudfront.netのあだ名としてつけます
GeneralタブでEditをクリックします
![スクリーンショット 2020-10-02 10.01.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/6f3226d3-c3a0-7c0d-47ac-50bcad4f010c.png)

CNAMEs欄にドメインを入力します
ACMで正常に証明書のプロビジョニングができていればSSL Certificateの欄の
Custom SSL Certificateが選択できる様になっているのでそちらを選択します
プルダウンメニューから発行した証明書を選択して「Yes Edit」をクリックして完了です
![スクリーンショット 2020-10-02 10.00.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/a0db662d-bf5c-3629-af7d-c07073deedbf.png)

### Route53
DNSルーティング設定をしないとまだアクセスできないので
cloudfrontで設定したCNAMEをRoute53に設定します

「ホストゾーンの作成」をクリック
![スクリーンショット 2020-10-02 10.36.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/f8e467c9-fb66-0e04-ea2c-86ff17c2a879.png)

ドメイン名を入力してパブリックホストゾーンが選択されていることを確認して「ホストゾーンの作成」をクリック
![スクリーンショット 2020-10-02 11.07.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/680f442b-17d2-79a6-8d8a-16a2ae5e77f8.png)

作成したホストゾーンをクリックしてレコードを作成します
ルーティングポリシーはシンプルルーティングを選択
![スクリーンショット 2020-10-02 11.09.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/8e65ff80-85e7-b0db-e39b-ec27c7433b41.png)

「シンプルなレコードを定義」をクリックするとこんな画面が立ち上がるので
トラフィックのルーティング先をCloudFrontディストリビューションへのエイリアスにして
ディストリビューションを選択をクリックしてルーティングしたいcloudfrontを選択
(レコード名とcnameが一致しないとプルダウンに選択肢が出てこないです)

レコードタイプはAを選択します
最後に「シンプルなレコードを定義」をクリック
![スクリーンショット 2020-10-02 11.10.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693244/c6e499df-92f1-2f3d-70b9-f7de2ad777f2.png)


自分で設定したドメインにアクセスするとページが表示できます
おめでとうございます！

### 最後に
ドメインの設定や証明書の発行など今までやったことがなかったので勉強になりました
手順通りやるのは簡単でしたが、何が行われているのかを考えながらやると思いの外自分の理解が浅かったので時間がかかってしまいました
UnityWebRequestのSendWebRequestが、iOS上でUnknown Errorとなり動作しない

# 状況
Unityのeditor上では問題なく動作していたUnityWebRequestが、ビルドしてiOS上で実行すると、SendWebRequestで"Unknown Error"となる。

# 原因
urlにhttpを使っていた。

# 解決方法
### 1. httpを許可する
iOS上でhttp(insecureな通信)を行うためには、Info.plistに以下を追加して許可をしないといけないらしいです。
以下を追加することで解決します。

```
<key>NSAppTransportSecurity</key>
<dict>
       <key>NSAllowsArbitraryLoads</key>
       <true/>
       <key>NSExceptionDomains</key>
       <dict>
           <key>just-an-example.com</key>
           <string></string>
       </dict>
</dict>
```

### 2. httpsを使う
httpにこだわりがなければ、httpsにすることでも解決できます。

# 参考
https://stackoverrun.com/ja/q/11035750
apollo federationをgqlgenで使う際にunable to bind to interfaceエラーが発生する

マイクロサービス化のためにApollo Federationを使おうと思ってgqlgenで試していたところ、`go run github.com/99designs/gqlgen`で`unable to bind to interface`エラーが発生。

自分はgoの構造体をschemaにマッピングしていたのだが、そこでエラーが発生していました。
gqlgenのコードを見るとgoのstructにはやさないとinterfaceを満たせないようなので、以下のようにIsEntity()メソッドを追加したところ、エラーが出なくなった。

```
type User struct {
    ID: int
    Name: string
}

func (m User) IsEntity() {}
```
タイピング早くなる練習方法

## はじめに
タイピング練習は①指に位置を慣れさせる②スピードアップ。の順で練習をすると
正しいフォームでミスタッチの少ない効率の良いタイピングができるようになるメリットがあります。

## 本題
最初はスピード追わない！！
まずはゆっくりでも大丈夫なので、指に文字の位置を慣れさせる。

__ルール__
* 下を見ずに、__前を向いて入力する__練習をする
* 最初のうちは__手全体で動かす__
* 入力後に必ず__ホームポジションに戻す__
* スピードアップは__指の位置を覚えてから__

スピードアップには１ヶ月〜３ヶ月かかると言われています。
なので1日５分だけでも良いので、まずはタッチタイピングで見ずに打つ練習して
徐々にスピードをアップさせていきましょう！

因みに私は
[P検定タイピング練習（英語編）](https://manabi-gakushu.benesse.ne.jp/gakushu/typing/eigonyuryoku.html)と [寿司打](http://typingx0.net/sushida/play.html)で練習をしています。
P検定では５分で１０００文字を目標に、寿司だでは一万円コースで2000円のお釣りを出すのを目標にしています！

参考にした記事:[ブラインドタッチのコツ](https://pcacademy.jp/typing-3)
ProgressBarで待機中を表示

## はじめに
何らかのWEB APIをリクエストして処理待ち。
そういことよくありますよね。
そういった待機中なのを示すのに、ProgressBarを使ってみました。

## [ProgressBar](https://developer.android.com/reference/android/widget/ProgressBar)
ProgressBarはいくつかのstyleがあり、またコードを書かなくてもレイアウトで設定するだけで動きます。

- Widget.ProgressBar.Horizontal
- Widget.ProgressBar.Small
- Widget.ProgressBar.Large
- Widget.ProgressBar.Inverse
- Widget.ProgressBar.Small.Inverse
- Widget.ProgressBar.Large.Inverse

これらのstyleがデフォルトで用意されています。
今回は Widget.ProgressBar.Large を使いました。

## デモ
簡単なサンプルを作成しました。

![progress_sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103548/4db6f5e5-ac0e-4aa4-9299-9c6b58b0a1a0.gif)


## コード
```MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val progressBar = findViewById<ProgressBar>(R.id.progress_bar)
        val button = findViewById<Button>(R.id.button)

        button.setOnClickListener({
            if (progressBar.visibility == ProgressBar.VISIBLE) {
                progressBar.visibility = ProgressBar.INVISIBLE
                button.text = getString(R.string.start)
            } else {
                progressBar.visibility = ProgressBar.VISIBLE
                button.text = getString(R.string.stop)
            }
        })
    }
}
```

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        style="@android:style/Widget.ProgressBar.Large"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="@string/stop"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progress_bar" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

## 振り返り
用意されたstyleを使って、円か棒で進捗を表示するようです。
もっとカスタマイズしたいという要望がなければ、これで十分な気がします。
追加でやるなら、不透明な背景を挿入するとか、サークルの色を変更するとかですかね。
styleを独自で用意すれば、もっとリッチにできるのでしょうか？

他の人がどうやっているのか知りたいので、俺はこうやっているとか、もう少し見た目がリッチなライブラリがあるとか、コメントください！
クラウドワークスでGoogleスプレッドシートを共有して編集する

クラウドワークス、クラウドソーシング、ランサーズなどで、スプレッドシートを使って、ユーザーを管理したい時がある。
その時のスプレッドシートの設定方法。

#リンクを知っている人全員が編集可能にする
１．右上の共有をクリック
２．リンクを取得、編集をクリック
３．リンクを知っている人全員が編集者になるようにする
（閲覧者のままだと編集できない）
４．リンクをコピーして、貼り付ける

#特定の範囲を編集できないように固定する
１．固定しておきたいセルを選択する
２．右クリック→範囲を保護
３．＋シート・範囲を追加　をクリックし、権限を設定
４．編集できるのを自分のみにしたら保護完了
続！pyAutoGUIでリモートワークサボり隊！

※この記事は新入社員の問いにあることないことないことないこと話した備忘録です。
# 本日の困りごと
ぱんだーさん、[これ](https://qiita.com/pnd75/items/cfe4cb39fb501258be59)でTeamsが退席中になるんですけどどうにかしてください

＿人人人人人＿
＞　垢バレ　＜
￣Y^Y^Y^Y￣

# 経緯
前回の記事は元クライアントとの雑談(LINE)の中で生まれたソース。。
それをまさか使おうとする強者がこんなに近くに現れるとは思わなかったよ…！

「退席中になるんですよ」
「仕事しろよ…」
「だって、リモートワークやることないじゃないですか！」

というわけで、MicrosoftTeams(会社での標準チャットツール)の退席表示を回避させろという話。
もうその端末でネットサーフィンしてたらいいと思う。

# 今回の解決方法
今回解決するのは「Teamsをいかに連絡可能な状態で保つか」という点。
出先なので、思いつく方法何点か候補を書いていこうと思う(検証は帰ってからね)。

## 1. スマホでTeamsを開けばいいじゃない
①アプリ版Teamsをダウンロードし、自身のアカウントを設定
②スマホの自動ロックを「なし」に設定
③アプリ版Teamsを開いて側に置く(充電はしとく)

MicrosftTeamsはこの手順で簡単に「連絡可能」の維持ができる。
注意点は**アプリがアクティブでなければ「連絡可能」とならない**こと。
バックグラウンド起動してスマホでゲームを…というわけにはいかないのだ。
普段使ってないスマホがある…とか、スマホ触らずに寝てたい…って人はコレでいいんじゃないかと思う。
(会社の評価がどうなっても)知らんけど。

## 2. Python(pyAutoGUI)を使って操作してる風にみせる
MicrosoftTeamsでは退席中表示は放置5分だったと思う。
しっかり仕事中でもそのぐらい放置することは多々ある。
その際、復帰させようとして

- マウス/タッチパネルでのカーソルの移動
- キーボード(矢印キー、タブキー)でのカーソル移動

と動かしてみると「退席中」のまま変わらない…ということが起きていた。
この時の退席中表示を確実に解除する方法は**キー入力操作**だ。
ということは、同じことをPythonにさせればいいんじゃないだろうか。

```sample2.py
import pyautogui as pg
import time
try:
    while True:
        time.sleep(180)

        # chromeを開く
        pg.hotkey('win','r')
        pg.typewrite('chrome.exe')
        pg.press('enter')
        time.sleep(5)

        # 文字列testを検索
        pg.typewrite('test')
        pg.press('enter')
        time.sleep(5)

        # ウィンドウを閉じる
        pg.hotkey('alt','f4')

except KeyboardInterrupt:
    print('仕事しよ')
```

解説はソース内のコメントのとおり。
前回のマウス操作を「Chromeを開いて「test」という文字列で検索して閉じる」に変更しただけだ。
[Alt]+[F4]で別のものまで閉じないように、それぞれの処理に待ち時間を設定している(時間は適当なので起動しながら調整してほしい)。

## 3. っていうか「連絡可能」にすればいいんでしょ？
2のコードを書きながら思っていたのだが…
単にMicrosoftTeamsを開いて状態を「連絡可能」にすればいいんじゃなかろうか？

つまりこういうことだ。

```sample3.py
import pyautogui as pg
import time
try:
    while True:
        time.sleep(180)

        # Teamsを開く
        pg.hotkey('win','r')
        pg.typewrite('XXX\Teams.exe') # 起動ファイルはフルパスが必要
        pg.press('enter')
        time.sleep(10)

        # 状態を連絡可能に変更する
        pgui.press('/')
        pgui.typewrite('available')
        pg.press('enter')

except KeyboardInterrupt:
    print('仕事しよ')
```

こちらも解説はソース内のコメントのとおり。
処理待ちの```time.sleep```が10秒と長めに取られているのは「起動に時間かかるなー」と感じたため。
MicrosftTeamsのデスクトップアプリはインストールするとデフォルトでスタートアップに登録されているため、単にアクティブにするだけならそこまで時間はかからないと思う(二重起動もしなかったはず…はず…)

# さいごに
そもそもの発端となった元クライアントに「動かしました？」と聞くと、「バレるのヤだから使ってないよ！」とのこと。そんなものをおまいらはマジに動かしたというのか。。
仕事がなくてヒマというのなら、仕事を作ればいいんだよ…

というか私、こんなサボり推奨記事なんて書いていたらその内シバかれると思うんだぜ？
プロキシサーバー経由WLSでvuetify環境構築まで

## やりたいこと
windows10でWLSをダウンロードし、gitでのvue.jsプロジェクトを実行する
会社環境の為、プロキシーサーバー設定が必須なので、手間が掛かりました。

## プロキシサーバー設定
<pre>
C:\Users\userName>netsh winhttp show proxy
現在の WinHTTP プロキシ設定:
    直接アクセス (プロキシ サーバーなし)。
↑プロキシ設定してない状態
C:\Windows\system32>netsh winhttp import proxy source=ie

現在の WinHTTP プロキシ設定:

    プロキシ サーバー:  wwwxxxxxxxxxx.com:80
    バイパス一覧     :  <local>
</pre>
## git インストール
<pre>
$ git --version➡ないなら↓でインストール
$ sudo apt install git
</pre>
## git clone
<pre>
$ git clone https://userName:<トークン>@gitlab.devops.xxxx.xxx.xxx.git
Cloning into 'nextmail_2020'...
fatal: unable to access 'https://gitlab.devops.xxxx.xxx.xxx.git/': gnutls_handshake() failed: The TLS connection was non-properly terminated.
↑失敗したら以下の手順でプロキシーサーバーを設定してください
</pre>
## git プロキシー設定
<pre>
$ sudo vi ~/.bashrc 
export HTTP_PROXY=http://xxxx.xxx.com:80
export HTTPS_PROXY=http://xxxx.xxx.com:80
git config --global http.proxy ${HTTP_PROXY}
git config --global https.proxy ${HTTPS_PROXY}
↓一応確認する
$ printenv HTTP_PROXY HTTPS_PROXY
http://wwwxxxx.xxx.xxx.com:80
https://wwwxxxx.xxx.xxx.com:80
</pre>
参考記事：https://qiita.com/Gushi_maru/items/5ba23d997e32abc98620
# ブランチ切り替え
<pre>
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/xxx
$ git checkout xxx
Branch 'xxx' set up to track remote branch 'xxx' from 'origin'.
Switched to a new branch 'mock'
$ git branch
  master
* xxx
</pre>
# apt設定
<pre>
$ sudo apt update
$ sudo apt upgrade
$ sudo vi /etc/apt/apt.conf
Acquire::http::No-Cache true;
Acquire::http::Pipeline-Depth 0;
Acquire::http::Proxy "http://wwwxxxx.xxx.xxx.com:80";
Acquire::https::Proxy "http://wwwxxxx.xxx.xxx.com:80";
Acquire::ftp::proxy "http://wwwxxxx.xxx.xxx.com:80";
</pre>
# nodejsインストール
<pre>
$ curl -sL https://deb.nodesource.com/setup_current.x | sudo -E bash -
↑gpg: can't connect to the agent: IPC connect call failed
エラーが出ましたら、一回無視してください。
$ sudo apt install -y nodejs npm　→　npmもついでにインストール
</pre>
# Yarnインストール
<pre>
$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
$ sudo apt-get update && sudo apt-get install yarn
$ yarn -v
$ npm -v
</pre>
# VueCLIインストール手順（ubunts環境）
<pre>
(yarnかnpmでインストール今回はyarnを使用)
$ yarn global add @vue/cli
$ vue --version
</pre>
# 起動
<pre>
$ cd xxxxxx →　gitのプロジェクトに移動
$ yarn serve (プロジェクトがすでにあるので、そのまま起動)
↑xxがないから起動できないエラーが出ます。
$ yarn install xx ➡　足りないPKGをインストール
$ yarn serve ➡再度起動
yarn serve　
Vue packages version mismatch:の為エラー
バージョン低いPKGを上げるのをおすすめします。
$ yarn serve ➡再度起動　
http://127.0.0.1:8080/　につながった
</pre>
# トラブルシューティング
## curl時エラー
<pre>
以下のコマンドを何回も実行する
sudo apt remove gpg
sudo apt install gnupg1
</pre>

## プロキシ設定後
<pre>
wslの再起動を試す（Windowsのcmdコマンド環境で操作）
# net stop LxssManager
# LxssManager サービスを停止中です.
# LxssManager サービスは正常に停止されました。
# net start LxssManager
# LxssManager サービスを開始します.
# LxssManager サービスは正常に開始されました。
</pre>
## yarn/npm 通信refusedエラー
<pre>
原因：プロキシサーバーが必要
$ sudo yarn(npm) config set proxy http://wwwxxx.xxx.xxx.com:80 -g
$ sudo yarn(npm) config set https-proxy http://wwwxxx.xxx.xxx.com:80 -g
$ yarn(npm) config list ➡　確認
</pre>
IBMCloud Watson SpeechToText 小ネタ

##小ネタ

* IBMCloudのWatson SpeechToTextへのアクセスには、FullProxyでCDNを経由させる事はできない。
* **フロントサービス側はAkamai(CDN)にてMZR冗長**されている
    * **負荷分散やトラフィックオフロードを意識する必要はない**。
* 東京フロントサービス:「**api.jp-tok.speech-to-text.watson.cloud.ibm.com**」
* CDN上のDNSサービスのみ利用し、直接クライアントからoriginであるWatson SpeechToTextへのアクセスは問題ない(あまり意味ないが)


##証明書問題
IBMCloudではCDNサービスとしてCIS(Cloudflare)を利用できるが、EdgeサーバからOriginに対してのトラフィックをSSL暗号化できない。
originであるWatson SpeechToTextでは、証明書の管理、インストールが許可されていないため、Edgeを経由してFull Proxyできない。

##参考
**Edge->origin間の証明書発行方法**
CISで証明書の発行を実施し、オリジンサーバ側に証明書をデプロイする必要がある
**セキュリティ-** -> **起点** -> **注文**を選択する。
![Cloud_Internet_Services_-_IBM_Cloud-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/0a3da1be-825e-a4b4-44bf-099193596cc7.png)

####新規発行
**新規に生成** -> **秘密鍵のタイプを選択** -> **証明書発行ホスト名を記入** -> **証明書の期限を選択** -> **注文**を選択
![Cloud_Internet_Services_-_IBM_Cloud-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/abc1b79c-7936-fd86-df4d-92d3d950e688.png)
select(プルダウン) の文字を左右中央揃えにする

下記を参考に実施した
[select(プルダウン) の文字を左右中央揃えにしたいときのCSSメモ](https://qiita.com/skwbr/items/658a690e90392106497d)

【ポイント】
(1)selectタグそのものは中央揃え出来ないので表示はpタグで実施（今回はdivタグで実施しました)
(2)selectタグとpタグを重ね合わせてselectは普段は非表示、フォーカスされた時に表示し選択できるようにする
(3)上記実現するためにselectタグ、pタグの親要素を追加

【具体的にCSSを】
重ね書きするために
・親要素にposition: relative;を設定する
・selectタグにposition: relative;を設定する
・pタグにposition: absolute;を設定する

【pタグの表示とselectタグを選択できるように】
・pタグにz-index: 1; selectタグにz-index: 2;を設定する
・selectタグにopacity: 0;
・selectタグのフォーカス時に{z-index: -1; opacity: 1;}を設定する
OGP画像を動的に変更させる

ページをシェアする時にOGP画像を変更させたいという要望があったので、やってみました！

## 実装方法

動的に変更させたいページの url にパラメーター付きでアクセスした場合にOGP画像を変更させます。
といっても、`head`  要素内の `og:url` と `og:image` の `content` の値を変更させるだけです…

1. パラメーター付きの url にアクセス
2. url のパラメーターの値を取得
3. `head`  要素内の `og:url` と `og:image` の `content` の値に url のパラメーターを挿入

### パラメーターなしの url にアクセスした場合

```html
<!-- https://example/にアクセス -->
<meta property="og:url" content="https://example/">
<meta property="og:image" content="https://example/og-image.png">
```

### パラメーター付きの url にアクセスした場合

```html
<!-- https://example/?image=hogeにアクセス -->
<meta property="og:url" content="https://example/?image=hoge">
<meta property="og:image" content="https://example/og-image_hoge.png">
```

## 実装

最初は JavaScript で実装したのですが、Facebookシェアデバッガーで確認したところ変更せず…
次に PHP で実装してみたところ、変更されたOGP画像が表示されました！

https://developers.facebook.com/tools/debug/


```html:HTML
<!DOCTYPE html>
<html lang="ja">
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">
  <meta charset="utf-8">
  <title>タイトル</title>
  <meta name="viewport" content="width=device-width, viewport-fit=cover">
  <meta name="description" content="ディスクリプション">
  <meta name="twitter:card" content="summary_large_image">
  <meta property="og:title" content="タイトル">
  <meta property="og:description" content="ディスクリプション">
  <?php if (isset($_GET['image'])) : ?>
    <?php $imageParam = $_GET['image']; ?>
    <meta property="og:url" content="https://example/?param=<?php echo $imageParam; ?>">
    <meta property="og:image" content="https://example/og-image_<?php echo $imageParam; ?>.png">
  <?php else : ?>
    <meta property="og:url" content="https://example/">
    <meta property="og:image" content="https://example/og-image.png">
  <?php endif; ?>
</head>
```

## 補足

`.html` のまま PHP が動作するようにするためには `.htaccess` に設定が必要です。

:::note info
`.htaccess` は、Apache Webサーバーで使用される設定ファイルの一種です。
ディレクトリ内に配置され、そのディレクトリおよびそのサブディレクトリに対する設定をカスタマイズするために使用されます。
:::

### AddType を使う方法

```apache:.htaccess
<FilesMatch "\.html$">
  AddType application/x-httpd-php .html
</FilesMatch>
```

### AddHandler を使う方法

```apache:.htaccess
<FilesMatch "\.html$">
  # PHPのバージョンはご利用のバージョンに変更してください
  AddHandler php7-script .php
  # PHP 8 の場合は php8-script ではなく php-script となる
  AddHandler php-script .php
</FilesMatch>
```
Sunaba講座 #5　点を動かす ＆ 画面更新 について

## はじめに
sunabaの導入については「[Sunaba講座 #0 導入編](https://qiita.com/gmasa/items/62ae871d1f017d4cc682)」をご覧ください。各講座へのリンクも貼ってあります

## **課題04** 点を横方向に走らせる
**画面左上から右方向に点を走らせてください。**走らせる距離は10ドット程度でOKです。
はじめに**アニメーションの仕組み**について考えてみましょう。
パラパラ漫画を思い浮かべてください。ノートの隅に絵を描いてペラペラめくって遊んだ経験はあると思います。Sunabaのアニメーションもこれに近いのです。紙のパラパラ漫画とSunabaで異なる点をあげてみます。

- パラパラ漫画と異なる点
    - Sunabaは絵を作りながらパラパラめくっている
        - その場で絵を作ってすぐ表示、これを高速で繰り返しているイメージです。
        - 1枚表示している間に次の絵を急いで描く。描き終えたら表示を切り替える、そんな感じです。
    - Sunabaは絵を切り替える頻度が1/60秒毎
        - Sunabaは1/60秒毎に1枚表示しようと頑張ります
        - 1枚描く間に考える（計算）時間が長いと、更新速度が遅れます
        - 逆に、早く描けてしまった場合は、1/60秒更新になるよう待機時間を設けて調整します

以降、画面表示の切り替え動作を『 画面更新 』と呼びます  

---
### 画面更新の詳細
Sunabaは画面メモリにアクセスする命令を実行すると、 **自動的**に60000～69999番の値すべてをPC画面に反映します。例として、2×2ドットの四角を画面の中心に描くプログラムで説明します。

<pre><code>
memory[64949]->990099
memory[64950]->990099
memory[65049]->990099
memory[65050]->990099
</code></pre>

前提条件として、**Sunabaのプログラム実行直後は全メモリの値が0（ゼロ）** になることを認識しておいてください（画面メモリ的には黒ですね）
一行ずつSunaba君の動きを追っていきます。

- 1行目の memory[64949] -> 990099** をSunaba君が読み取って実行
    - 64949番だけピンク、他の9999個の画素は全て黒 の1枚絵作成。
    - できた絵をPC画面表示部に送信（計10000メモリの情報）
- 2行目の memory[64950] -> 990099 をSunaba君が読み取って実行
    - 64949,64950番がピンク、他の9998個の画素は全て黒 の1枚絵作成。
    - できた絵をPC画面表示部に送信（計10000メモリの情報）
- 3行目の memory[65049] -> 990099 をSunaba君が読み取って実行
    - 64949,64950,65049番がピンク、他の9997個の画素は全て黒 の1枚絵作成。
    - できた絵をPC画面表示部に送信（計10000メモリの情報）
- 4行目の memory[65050] -> 990099 をSunaba君が読み取って実行
    - 64949,64950,65049,65050番がピンク、他の9996個の画素は全て黒 の1枚絵作成。
    - できた絵をPC画面表示部に送信（計10000メモリの情報）
- プログラム終了（最後の絵が表示された状態で終了）


1ドット打つたびに画面が更新される様子は、今まで実際に画面を見てきたイメージ通りでしょう。
なんにしても、この方法では大きな絵を表示するのに長い時間を要することは想像できると思います（1画面10000ドットなので、1/60 * 10000 = 166.6秒．．．遅！）
このままではゲーム作りなんて無理です。もちろん1枚絵を一気に表示する機能は用意されていますが、それは次の課題で解説します。

Sunabaはなぜこの仕組みをデフォルト設定にしているのでしょうか。それは**プログラムが実行される様子を、画面の動きをみて実感できるようにするため**でしょう。横線を縦に並べることで四角を描いたプログラムを思い出してください。横線が上から徐々に描かれる様子がアニメっぽく表示されたはずです。**Sunabaは初心者のため開発言語なので、デフォルトがこの設定なのです**。たぶん。
画面更新の中でも、今回のデフォルトの動作を**自動更新**と呼びます。これに対なす機能として、プログラマが画面更新タイミングを決める**手動更新**が用意されています。こちらは先ほど述べた**1枚絵を一気に表示**する方法です。後々の課題で解説します。  

---
### 課題04の解説
あらためて課題04の解説をしたいと思います。画面更新の話が長くて、課題内容が頭から抜けたと思うので再掲します。

- **課題04：画面左上から右に点を走らせる。距離は10ドット程度でOK**
    - 自動更新の仕組みを意識して、点が動くように見えるプログラムを考えてみましょう
    - whileを使わず、コピペコードでOKです
    - 点が点滅しますが、画面自動更新の仕組み上、どうにもならないので気にしないことです
    - <details><summary>疑似コード</summary>
    <pre><code>
    60000を白
    60000を黒
    60001を白
    60001を黒
    ・・・・
    ・・・
    ・・
    </code></pre>
    </details>

- お手本コードは掲載しません。点が右側に走っていればOKです。完成した後は色をピカピカさせて遊んでみましょう。

---
Redmine ViewCustomizeで準備して良かったもの

# 概要
Redmineにview customize plugin Pluginを導入してから準備して良かったコードをまとめる.
導入方法等は公式のGithub:[redmine-view-customize](https://github.com/onozaty/redmine-view-customize)に載っているので割愛.

## チケット(JavaScript)

### チケット編集時のエンターキー誤送信防止

パスのパターン```/issues```.

```JavaScript
$(function(){
  $(document).on('keypress', '#issue-form input[type="text"', function(event) {
    if(event.keyCode == 13) {
      return false;
    }
  });
});
```

### 期日1週間前のチケットにthis_week_taskのクラスを追加

パスのパターン```.*```.

```JavaScript
$(function(){
  var today = new Date();
  var y = today.getFullYear();
  var m = today.getMonth() + 1;
  var d = today.getDate();
  var today_str = y + "/" + m "/" + d;
  var limit_day = 7;
  $('table.list.issues td.due_date').each(function(){
    due_date_millsec = Date.parse($(this).text());
    diff = due_date_millsec - Date.parse(today_str);
    if (diff / (1000 * 60 * 60 * 24) < limit_day && diff / (1000 * 60 * 60 * 24) >= 0) {
      $(this).parent().addClass('this_week_task');
    }
  });
});
```

## チケット表示(CSS)

パスのパターン```.*```.

### 担当チケットを太文字にする
```css
/* 自分が担当のチケットは太文字 */
tr.issue.assigned-to-me {
  font-weight : bold,
}
```

### 期日が過ぎたチケットの色をピンクにする
```css
/* 期日が過ぎたチケットの色をピンクにする */
tr.overdue * {
  background-color : mistyrose;
}
/* 期日が過ぎたチケットを選択した場合は濃いピンクにする */
tr.overdue.context-menu-selection * {
  background-color : hotpink;
}
```

### 期日1週間前のチケットの色を緑にする

期日が1週間前のチケットに対して,```this_week_task```のクラスを追加する必要がある.

```css
/* 期日1週間前のチケットの色を緑にする */
tr.this_week_task * {
  background-color : #DDFFDD;
}
/* 期日1週間前のチケットを選択した場合は濃い緑にする */
tr.this_week_task.context-menu-selection * {
  background-color : #668866;
}
```

## プロジェクト表示(CSS)

パスのパターン```.*```.

### プロジェクト毎のヘッダの色を変更
```css
/* class*=""に各プロジェクトを識別できるクラス名を記入 */
/* top-menu */
body[class*=""] #top-menu {
  background-color : #4B0082;  
}
/* header */
body[class*=""] #header {
  background-color : linear-gradient(#4B0082, #800080);
  /* Imageを入れる場合 */
  /* background-image : url("http://hoge/hoge.png"); */
}
/* マウスオーバ対応 */
body[class*=""] #main-menu a:hover:not(.selected) {
  background-color : rgba(128, 128, 128, 0.5);
}
```
EC-CUBE4のEntityを書く時の作法

カスタマイズでもプラグインでも、Entityを書く時はclassの存在チェックをしよう、というのは@tao-sさんのブログにて指摘済み。

https://eccube.hatenablog.com/entry/add-trait-for-plugin-entity

``` php
// 前略
if (!class_exists(NewEntity::class)) {
    class NewEntity extends AbstractEntity
    {
        // 後略
```

これだと階層が無駄に増えるし、早期returnで良くない？と思って以下のコードを書いたんです。

``` php
// 前略
if (!class_exists(NewEntity::class)) {
    return;
}

class NewEntity extends AbstractEntity
{
    // 後略
```

そしたらですね、Entityのプロキシを生成した時に…

``` php
// 前略

    return;


class NewEntity extends AbstractEntity
{
    // 後略
```

ifが消えていきなりreturnするファイルになってしまいました。

横着せずに元のコードに従って書きましょうねというお話。
非直角双曲線

# はじめに
直角双曲線(の一種)の式が

```math
y=\frac{a}{x}
```

であることは誰もが覚えていると思うが，非直角の場合はどうだったか，忘れてしまうので備忘録として記録する．

双曲線の定義から攻めていくと，焦点をどこにすればいいのかとか，変換行列をどうすれば求める双曲線になるのかとかがわかりにくい．ので，本記事では，私にとってわかりやすいようにパラメータを定めた．

# 式
漸近線をそれぞれ $y=ax$, $y=bx$ とする双曲線は，

```math
y=\frac{a+b}{2}x+\frac{b-a}{2}\sqrt{x^2+c}
```

と書ける．$x\rightarrow\pm\infty$ の極限で $y=ax,\,bx$ となることがわかる．$c=0$ なら2直線となり，$c$ の絶対値が大きくなるほど漸近線から離れる．

さらに，$b<a$ なら漸近線の下側，$a<b$ なら漸近線の上側となり，$0<c$ なら連続したカーブ，$c<0$ なら多値となる双曲線の上側か下側になる．具体的には下図の通り．

![png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483881/ac4257c5-882a-9ff9-bb3b-6ca5c39d8aff.png)

さらに，漸近線の交点を原点から $(p,q)$ にずらすには，

```math
y=\frac{a+b}{2}(x-p)+\frac{b-a}{2}\sqrt{(x-p)^2+c}+q
```

とすればよく，一方の漸近線が $y$ 軸に平行の場合は．

```math
y=\frac{a}{x-p}+b(x-p)+q
```

とすればよい．これらが「双曲線」であることの証明は省略する．

# 利用
2直線に漸近するカーブのフィッティングに使うとうまくいくことがあったり，2直線に漸近するなめらかなカーブの一種として使われることがある．例えば

```math
y=\sqrt{x^2+1}
```

( $(a,b,c)=(-1,1,1)$ のケース ) は，絶対値関数 $y=|x|$ に漸近するなめらかな関数の一つである．
エージェント状態はグレーのまま

# 起因
zabbixのWEBUIからエージェント状態はグレーとなり、調査を行いました。
# ログ調査
<pre>
/var/log/zabbix/zabbix_agentd.log　
↓
 20341:20200929:120645.991 no active checks on server [127.0.0.1:10051]: host [xxxxxxx] not found
</pre>
# 設定ファイル調査
<pre>
# grep -v -e '^\s*#' -e '^\s*$' zabbix_agentd.conf | grep Host
Hostname=xxxxxxx
ログのホスト名と一致してます。
</pre>
# 通信調査
<pre>
# cat /etc/hosts | head -1
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 xxxxxxx
# ping xxxxxxx
pingは通ってます。問題ないね
</pre>
まさか原因不明？.............Proxyサーバーのagentが死んでる。
<pre>
zabbixProxyサーバーにログイン
systemctl zabbix-agent restart
</pre>
これで直りました。
WSL2  Error: Can't open display

WSL2 ＋ Ubuntu18.04 ＋ VcxrvでLinuxのGUIアプリ(xeyes、xclock等)を実行しようとして出たエラー。

検索にヒットする方法をすべて試したが解決しなかった。

**最終的にはセキュリティソフト「マカフィーリブセーフ」のファイアウォールを無効にしたところ、うまくいった。**

「マカフィーリブセーフ」を入れた覚えはなく、何かのフリーソフトをダウンロード時に抱き合わせで入ってしまった可能性が高い・・

ほとんどの記事でVcxrvをダウンロードする際に、ファイアウォールの設定をどうのこうのという説明書きがあったが自分はその画面すら出ていなかったのでファイアウォール周りが怪しいと思っていたがまさかセキュリティソフトが入っていたとは思いもしなかった。。盲点でした。

そもそもWsl2での既知のバグについては下記記事で対処したうえでセキュリティソフトをオフにすることでLinuxのGUIアプリ(xeyes、xclock等)を実行することができました。

参考：
[WSL2のGUI設定でつまずいたところ \- Qiita](https://qiita.com/baibai25/items/5841b0592727893d960f)
【ssh】ssh-keygen でパスフレーズの確認

## Pass Phrase

### 僕のRasPiのpass phraseを確認したい

タイトル通り、手元にあるraspberry pi 4 にある ~/.ssh/id_rsa、~/.ssh/id_rsa.pub を使うためのパスフレーズを忘れていて、手元で「これで合ってたかな？」と確認したい、という状態でした。

```
$ ssh-keygen -yf ~/.ssh/id_rsa
Enter passphrase:
```

で確認できます。一致していると、公開鍵が出力されます。

また、パスフレーズは

```
$ ssh-keygen -f ~/.ssh/id_rsa -p
```
で変更できます。

下記のサイトを参考にしました。（そのまま）
- [sshの秘密鍵のパスフレーズを設定していたかどうか思い出せないとき](https://doruby.jp/users/nakamatsu/entries/ssh%E3%81%AE%E7%A7%98%E5%AF%86%E9%8D%B5%E3%81%AE%E3%83%91%E3%82%B9%E3%83%95%E3%83%AC%E3%83%BC%E3%82%BA%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%84%E3%81%9F%E3%81%8B%E5%BF%98%E3%82%8C%E3%81%9F%E3%81%A8%E3%81%8D)
- [sshの秘密鍵パスフレーズの確認と変更](https://qiita.com/shukan0728/items/e654953c89aab6f847a4)

ちなみにパスワードはraspberrypi4でした。^^;

### 秘密鍵とパスフレーズから公開鍵を再生

よく考えると、秘密鍵の確認とやっていることは全く同じだった。。。

```
ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub
```

### Github に登録するために鍵を作った

```
ssh-keygen -t ed25519 -C username@hostname.jp -f filename_ssh_key
```

でメールアドレスを含んだ登録用の鍵が、ファイル名 filename_ssh_key で作られました。


## known hosts

## RasPiを再インストールしてＳＳＨサーバの鍵が変わったのでknown_hosts を更新したい

警告でコマンドが出力されるのでその通りなのですが。--

```
ssh-keygen -f "/home/yourname/.ssh/known_hosts" -R "my-raspi"
```

(2020/10/02)

追記

適当にメモを書き足しています。
- 公開鍵から秘密鍵を追加。2021/01/02
- Github登録用の鍵作成を追加 2022/04/11
from sklearn.datasets import fetch_mldata -> fetch_openml

# 背景
t-SNEでクラスタリングしようと思い、いろいろサンプルコードを漁っていた際に発生した事象
こちらを参考にコーディングしていた

- https://towardsdatascience.com/visualising-high-dimensional-datasets-using-pca-and-t-sne-in-python-8ef87e7915b

# 発生箇所

その1

```python
import matplotlib.pyplot as plt
from mpl.toolkits.mplot3d import Axes3D
import seaborn as sns
from __future__ import print_function
from sklearn.datasets import fetch_openml # <-　ここ
from sklearn.decompositon import PCA
from sklearn.manifold import TSNE

%matplotlib inline
```

その2

```python
mnist = fetch_mldata("MNIST original") # <- ここ
X = mnist.data / 255.0
y = mnist.target
print(X.shape, y.shape)
```

# 修正コード

その1

```python
import matplotlib.pyplot as plt
from mpl.toolkits.mplot3d import Axes3D
import seaborn as sns
from __future__ import print_function
from sklearn.datasets import fetch_openml # <-　ここ
from sklearn.decompositon import PCA
from sklearn.manifold import TSNE

%matplotlib inline
```

その2

```python
mnist = fetch_openml('mnist_784', version=1,) # <- ここ
X = mnist.data / 255.0
y = mnist.target

print(X.shape, y.shape)
```

# 発生原因
fetch_mldataの参照先である https://openml.org が落ちているのが原因らしい



# 参照
- https://github.com/ageron/handson-ml/issues/529
- https://github.com/scikit-learn/scikit-learn/issues/8588#issuecomment-292634781
- https://github.com/YutaroOgawa/Deep-Reinforcement-Learning-Book/issues/4
これは日本語
AtomでHTMLファイルの文字コードを変更する方法

#目標
HTMLファイルをShift-JISの文字コードでブラウザに表示させる。

#問題
HTMLファイルで、下記のように文字コードをShift-JISに指定するが、ブラウザで文字化けしてしまった。

    <meta charset="shift_jis">

# 解決法
HTMLファイル内で書かれているコードの文字コードがUTF-8になっていることが原因。
Atom画面の右下にUTF-8となっている部分をクリックしてShift-JISに変更する。
するとファイル内のコードの文字コードがShift-JISになるので、`<meta charset="shift_jis">`をファイル内に書いておけば、無事にブラウザで表示された。

![スクリーンショット 2020-10-02 13.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760850/df3f74ef-d484-1bdc-68ad-6a90c6d9ac4a.png)
Linuxのシステム領域とboot領域を含むパーティション変更の手順

# 用意するもの

### GParted Liveなど

OSのシステム領域を含むパーティション変更はOS起動中はできないので、別のOSを起動して外から変更しなければならない。そこで、LiveCD、LiveUSBとかの外部ストレージから直接OSを起動する仕組みを使う。
パーティション変更ソフトが含まれるLiveCDはたくさんある（OSのインストール用イメージに含まれることもある）が、GPartedだけがインストールされたものも用意されている。
https://gparted.org/liveusb.php
URL先の手順に従えば、OSを起動できるUSBが作れる。

# 手順

作ったOS起動USBを挿した状態でPCの電源を入れると、HDDやSSDをマウントせずにOSが起動される。
GPartedなどを使って、パーティション変更を行う。

GPartedでは、ブート領域を含むパーティションを変更すると、OSが起動できなくなるという警告が表示される。

これは、ブートローダーにはOS起動イメージが登録されているのに、イメージの場所が変わってしまうからである。

これはパーティション変更を行ってから修正することになる。

パーティション変更を確定して実行した後、GPartedを閉じてTerminalを開く。

ブートローダー(GRUB)を以下のページに従って修復する。
https://gparted.org/display-doc.php?name=help-manual&lang=C#gparted-fix-grub-boot-problem

GRUB2でEFIブートの場合、手順5のコマンドはマウント先を以下のように変更する。

```bash
# mount /dev/sdaX /tmp/mydir/boot/efi
```

GRUBの修復が終わったらシャットダウン後にOS起動用LiveUSBを外して、PCの電源を入れる。
「LENGTH ~ -1」がわからない。SUBSTRINGの文を分解してみる_ 『スッキリわかるSQL入門』5章

#はじめに
『スッキリわかるSQL入門第二版』5章の練習問題でつまずいたのでまとめます。
p165の問題5-2です。
解答を見ても、SUBSTRINGの文の意味を読み取ることができませんでした。

#問題の解答
あるアンケートの回答者のテーブルがあり、「メールアドレス、国名、性別、年齢」の列がある。それぞれにデータ型が定義されていて、国名は全てNULLとなっている。末尾2文字が国コードとなっているメールアドレスをもとにして、国名列を更新せよ、という問題でした。問題を転記するのが可なのかよくわからないので、問題の詳細はここでは書かないでおきます。

まず、解答はこれでした。

```
UPDATE 回答者
SET 国名 = CASE SUBSTRING(TRIM(メールアドレス),
                          LENGTH(TRIM(メールアドレス))-1, 2)
             WHEN 'jp' THEN '日本'
             WHEN 'uk' THEN 'イギリス'
             WHEN 'cn' THEN '中国'
             WHEN 'fr' THEN 'フランス'
             WHEN 'vn' THEN 'ベトナム' END
```

わからないのはこの部分。

```
CASE SUBSTRING(TRIM(メールアドレス),
               LENGTH(TRIM(メールアドレス))-1, 2)
```

ひとつひとつの関数の意味を復習してみます。

#CASE演算子
p144
構文①

```
CASE 評価する列や式 WHEN 値1 THEN 値1のときに返す値
　　　　　　　　　　(WHEN 値2 THEN 値2のときに返す値)...
　　　　　　　　　　(ELSE デフォルト値)
 END
```
構文②

```
CASE WHEN 条件1 THEN 条件1のときに返す値
　　　　　　　　　　(WHEN 条件2 THEN 条件2のときに返す値)...
　　　　　　　　　　(ELSE デフォルト値)
 END
```


#SUBSTRING関数
p154
「SUBSTRING関数」（読み：サブストリング）or「SUBSTR関数」
 どちらを利用できるかは、DBMS製品によって違う。
「何文字目から何文字分」という指定をして文字列の一部分を抽出できる。

#TRIM関数
p152
「TRIM」（読み：トリム）＝左右から空白を除去する
　（「LTRIM」（エルトリム）＝左側から空白を除去する。「RTRIM」（アールトリム）=右側から空白を除去する。）

#LENGTH関数
p152
「LENGTH」（レングス）＝文字列の長さを調べる。
  （SQL Serverでは「LEN」（レン））p166）

#解答のコードにそれぞれの意味をあてはめてみる

```SQL
CASE SUBSTRING(TRIM(メールアドレス),
               LENGTH(TRIM(メールアドレス))-1, 2)
```
・CASE 
WHEN/THEN/ENDとセットなので、ここでは保留。

・SUBSTRING
文字列のうち次に指定する部分を抽出する。

・(TRIM(メールアドレス),
左右から空白を除去する。メールアドレスの列は 30桁の[CHAR型](https://qiita.com/ume-san/items/0882009a8b278d8b1b92)(=固定長の文字列)　だと定義されているので、その空白を除去するということ。

**・LENGTH(TRIM(メールアドレス))-1, 2)**
ここです。**ここがわからないのです。**p152の解説とその中の例題を見ても、「LENGTH」が「文字列の長さを取得する」「文字列の長さで絞込検索をする」ということしかわかりません。
「-1,2」が何を指すのかがわかりません。
もう少し詳しく見てみます。

問題文からすると、ここのコードは「メールアドレスの最後の2文字」を指しているはずです。
この部分だけ見ているとよくわからないので、もう一度SUBSTRINGまで戻ってみます。

p154でこう解説されていました。
>SUBSTRING(文字列を表す列,抽出を開始する位置,抽出する文字の数)
>⇒抽出された部分文字列

ということは、
「LENGTH(TRIM(メールアドレス))-1」　＝抽出を開始する位置
「2」　＝抽出する文字の数
ということでしょうか。ここで「2」の意味がわかりました。

あとは「LENGTH(TRIM(メールアドレス))-1」です。「-1」は何を指すのでしょうか？
「抽出を開始する位置」を指しているはずなのですが…
メールアドレスの末尾1文字目を「0」、2文字目を「-1」としているのでしょうか？
p155の例題を見ると「文字列の頭文字を1文字目」として扱っているのだと読み取れますが、
末尾の文字についてはどこにも触れられていませんでした。
見落としているのでしょうか？

「LENGTH -1 関数」等でググってみました。
→目ぼしい記事は見つからず。

本の中から「-」が入った構文を探してみます。
→p156にこんな構文が出てきました。

>リスト5-13　百円単位の出金額を取得する

>SELECT 出金額,　ROUND(出金額, -2) AS 百円単位の出金額
> FROM　家計簿

>※解説：「これで、出金額の下2桁目、つまり10の位で四捨五入されることになるのよ。」 

**これだーーーーー！！！**
やっとわかりました。
「-1」は「末尾1文字目」という意味だったのですね。
スッキリしました・・・。

文字数を「前から」数えていくのだと思い込んでいました。
「末尾1文字目から　2文字を　抽出する」
なんですね。「後ろから」数えるとのこと。やっとわかりました。

#まとめ
最後に整理します。

```SQL
CASE ④SUBSTRING(①TRIM(メールアドレス),
               ②LENGTH(TRIM(メールアドレス))-1, ③2)
```
これは、
①メールアドレスの左右の空白を取り除いて、
②メールアドレスの末尾1文字目から
③2文字目までを
④抽出します
⑤その場合（→次のWHEN~に続く）
という意味だったのですね。

#さいごに
いき詰まっていましたが、Qiitaに書き出しながらひとつひとつを読み解くことで
無事にコードの意味を理解する事が出来ました。
終わってしまえば「なーんだ、そんなこと」なのですが、
記事を書いている最中は本当にわからない状態でした。
まだまだ序盤なのに時間をかけてしまい焦りますが、
ひとつひとつ進めていきたいと思います。

#参考
・書籍『スッキリわかるSQL入門第2版ドリル222問付き！』（インプレス）

#進捗記録
2020/9/15：データベースの学習スタート
2020/9/15～2020/9/21：『マンガでわかるデータベース』オーム社 / 1～4章（Qiita記事2本）
2020/9/22～：『スッキリわかるSQL入門第2版ドリル222問付き！』インプレス