OmniAICreator/Qiita-1.07M huggingface dataset:
Ruby On RailsでCSSが効かなくなった場合に考えられる原因について

#この記事を書いたきっかけ
ruby on railsを利用してアプリを作成している際、突然application.cssに書いていたcssが効かなくなってしまいました。
色々と調べていると、デフォルトでapplication.cssに書いてある以下のコードを消してしまったことが原因でした。

```:app/assets/stylesheets/application.css
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */
```

コメントになっていたので不要なコードと決めつけてしまい、消してしまいました^^;
ちゃんと内容を読んでから消すべきでした。

ちなみに、削除してしまったコードの以下の２行が非常に重要な意味を持っているコードなんです。

```
 *= require_tree .
 *= require_self
```
この２行は、Railsでデフォルトで導入されている「アセットパイプライン」というライブラリのディレクティブ (directive: 命令、指示) にあたります。

参考：[アセットパイプラインについて](https://railsguides.jp/asset_pipeline.html)
#*= require_treeって何??
「*= require_tree」はapp/assets/stylesheets内にあるcssファイルを全て読み込むという意味です。
ただし、読み込まれるファイルの順番は辞書順になります。

読み込まれるファイルの順番を変更することもできます。これについては以下のページが参考になります。

参考：[RailsでCSSの読み込む順番を制御する方法](https://qiita.com/takish/items/c5f264577d2db75fd10c)
#*= require_selfって何??
「*= require_self」はapplication.css自体を取り込むという意味になります。
これを削除してしまうと、application.cssの内容が作成しているアプリに反映されません。

#最後に
デフォルトで記載されているコードについては、必ず意味を理解してから必要に応じて削除もしくは残しておく必要があります。
何事も必ず意味があるということに、今回気付かされました。
GO 小数第N切り捨て


小数切り捨てをmath.Floorで対応した内容を書いていたのですが
コメントをいただいて、math.Floorでは誤差が起きることを知りました。
それから調べたところ以下のパッケージで対応しているようです。
・math/big.Rat
・github.com/shopspring/decimal

今回はshopspring/decimalの方で試してみました。

## 小数第3切り捨て
```go
hoge := decimal.NewFromFloat32(87.689)

hogemi := hoge.Truncate(2)
fmt.Println(hogemi)
```

## 小数第２切り捨て
```go
hoge := decimal.NewFromFloat32(87.689)

hogemi := hoge.Truncate(1)
fmt.Println(hogemi)
```

https://play.golang.org/p/jf4TJVbm7MV




## 以下にある、math.Floorの対応では誤差が出ます。
@Nabetani さんからいただいたコメント参照願います。

## 【誤差】小数第3切り捨て

```go
hoge := 87.689
fmt.Println(math.Floor(hoge*100)/100)
```

## 【誤差】小数第2切り捨て
```go
hoge := 87.689
fmt.Println(math.Floor(hoge*10)/10)
```

https://play.golang.org/p/HrGrlzDpUMa

参照
https://yourbasic.org/golang/round-float-2-decimal-places/
wmicの移行先としてのPowershellまとめ

# 移行するにはググラビリティは低い気がする

WMICが非推奨になってしまいました。

[旧「Edge」、「IE11」、wmicコマンド……「Windows 10 バージョン 21H1」で削除・非推奨となる機能たち - 窓の杜](https://forest.watch.impress.co.jp/docs/news/1325972.html)

そういう訳で色々まとめてみました。

## 参考になりそうな記事

まずは読むべき記事

https://docs.microsoft.com/ja-jp/powershell/scripting/learn/ps101/07-working-with-wmi?view=powershell-7.1

[貝殻本](https://book.mynavi.jp/ec/products/detail/id=90597)の著者による解説

https://tech.guitarrapc.com/entry/2013/02/08/210233

Wmi/CIMのクエリ解説

https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_wql?view=powershell-5.1

少しディープなテクニック集（英語）

https://devblogs.microsoft.com/powershell/cim-cmdlets-some-tips-tricks/

リモートでWMI使ってた人向け？

https://docs.microsoft.com/ja-jp/powershell/module/microsoft.wsman.management/about/about_wsman_provider?view=powershell-7.1

### エイリアス

CommandType| Name|Version|Source
|:-----------|:------------|:------------:|:------------:|
Alias|gcai -> Get-CimAssociatedInstance|7.0.0.0    |CimCmdlets|
Alias|gcim -> Get-CimInstance|7.0.0.0    |CimCmdlets|
Alias|gcls -> Get-CimClass|7.0.0.0    |CimCmdlets|
Alias|gcms -> Get-CimSession|7.0.0.0    |CimCmdlets|
Alias|icim -> Invoke-CimMethod|7.0.0.0    |CimCmdlets|
Alias|ncim -> New-CimInstance|7.0.0.0    |CimCmdlets|
Alias|ncms -> New-CimSession|7.0.0.0    |CimCmdlets|
Alias|ncso -> New-CimSessionOption|7.0.0.0    |CimCmdlets|
Alias|rcie -> Register-CimIndicationEvent|7.0.0.0    |CimCmdlets|
Alias|rcim -> Remove-CimInstance|7.0.0.0    |CimCmdlets|
Alias|rcms -> Remove-CimSession|7.0.0.0    |CimCmdlets|
Alias|scim -> Set-CimInstance|7.0.0.0    |CimCmdlets|

### 小ネタ

Powershellでwmiクラスを定義する方法
cimクラスはよくわからなかった……

```powershell
$newClass = [wmiclass]::new("root\cimv2", [String]::Empty, $null); 
$newClass.Name= "Test_Class"

$newClass.Qualifiers.Add("Static", $true)
$newClass.Properties.Add("ServerGroup", [System.Management.CimType]::String, $false)
$newClass.Properties["ServerGroup"].Qualifiers.Add("Key", $true)

$newClass.Properties.Add("ServerPhase", [System.Management.CimType]::String, $false)
$newClass.Properties["ServerPhase"].Qualifiers.Add("Key", $true)

$newClass.Methods.Add

# クラスを登録
$newClass.Put()

# クラスを削除
$newClass.Delete()
```
SQL 備忘録　続

SQL文の文末にセミコロン;を付ける必要がない
LIKEとは、文字列検索を行う際に使用できる句のこと
AND演算子とは、複数の条件がすべて正しい場合に、正とすることができる演算子のこと
OR演算子とは、複数の条件のうち、1つ以上を満たしたデータを取得する演算子のこと
NOT演算子とは、条件が正しくない場合に正となり、言わば否定形の演算子のこと
BETWEEN演算子とは、上限と下限を設定し、その範囲に含まれる場合は正となる演算子のこと
IN演算子とは、1つのカラムに対しリストを指定して、カラムの値がそのリストに含まれるとき、その式は正になるという演算子のこと
JOINとは、簡潔に言うと、指定したそれぞれのテーブルの、カラムの値が一致するデータを結合することができる句のこと
 結合する元となるカラムを、ONの後に=（イコール）を用いて指定します
grepでよく使うコマンドのメモ書き

grepでよく使うコマンドのメモ書きです。

##### カレントディレクトリ配下の全てのファイルからhogehogeを検索する

```
$ grep -ir hogehoge .
```

-rオプションはサブディレクトリ内のファイルも再帰的に検索する
-iオプションは大文字小文字を区別して検索する

##### 検索ヒットした対象の行だけじゃなくて上下の行も同時に表示する

例えば、対象行と上下4行を表示する

```
$ grep -ir4 hogehoge .
```


##### 特定のディレクトリを検索対象から除外したい場合、--exclude-dirオプションを使う

```
$ grep -r hogehoge . --exclude-dir=./test
```

複数のディレクトリを除外したい場合は(./testと./test2を除外)、

```
$ grep -r hogehoge . --exclude-dir={./test,./test2}
```

##### metaタグの行でdescriptionについて書いている部分を検索する

```
$ grep -ir meta.*desc .
```

　「.*」の部分は、.は何かの文字（空白も含む）、*は直前の文字の0回以上の繰り返し

##### grep,sedでカレントディレクトリ以下の全てのファイルを対象に、文字列を置換する

カレントディレクトリ以下の全てのファイルを対象に、文字列「ほげほげ：」を「もげもげもげ：」に置換するコマンドです。

```
grep -rl 'ほげほげ：' . | xargs sed -i 's/ほげほげ：/もげもげもげ：/g'
->sed: 1: "./dir1/dir2 ...": invalid command code .
```

ただ、自分のmacOSのコマンドライン環境だと、上の通りinvalid command codeエラーが発生しました。GNUのsedなら上のコマンドでできるみたいです。
macOSのsedの場合、sedの引数に''を追加する。

```
grep -rl 'ほげほげ：' . | xargs sed -i '' 's/ほげほげ：/もげもげもげ：/g'
```

参考サイト
[macOS High Sierraでsedで上書き更新しようとして-iオプションを付けて実行したらsed: 1: "ファイルパス": invalid command code mとなったときの対応方法](https://qiita.com/ponsuke0531/items/be8b4a3c5e19676f9691)

##### \eをgrep検索する

```
$ bind -p | grep '\\e'
```

##### -H（Hオプション）をgrep検索する

```
$ grep -r '\-H' .
```
Herokuへのデプロイでつまづいた


# 本記事について
Herokuへのデプロイ時に二つのエラーで時間が取られたので備忘にとして書きました。


# １つ目
```
remote:  !     The Ruby version you are trying to install does not exist on this stack.
remote:  !
remote:  !     You are trying to install ruby-2.6.5 on heroku-20.
remote:  !
remote:  !     Ruby ruby-2.6.5 is present on the following stacks:
remote:  !
remote:  !     - cedar-14
remote:  !     - heroku-16
remote:  !     - heroku-18
remote:  !
remote:  !     Heroku recommends you use the latest supported Ruby version listed here:
remote:  !     https://devcenter.heroku.com/articles/ruby-support#supported-runtimes
remote:  !
remote:  !     For more information on syntax for declaring a Ruby version see:
remote:  !     https://devcenter.heroku.com/articles/ruby-versions
```
## エラー文詳細
当初、使用していたStackが**20**。（アカウント作成してから初めてデプロイしたので**デフォルトが20**だったと考えられる）
エラー文には「**rubyの2.6.5がサポートされているherokuのstackが18までであり20は対応していない**」と書かれている。

## 解決までの手順
### Herokuのインストール
```
$ brew tap heroku/brew && brew install heroku
```
### Herokuのログイン
```
$ heroku login
```
### stackを18にダウングレード
```
$ heroku stack:set heroku-18 -a blogapp
```

最後に`bundle install`で完了。


# ２つ目
```
remote:        Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
remote:        Bundler Output: Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
```
## エラー文詳細
### 直訳
>「バンドルはプラットフォーム["x86_64-darwin-20"]のみをサポートしていますが、あなたのローカルプラットフォームはx86_64-linuxです。`bundle lock --add-platform x86_64-linux`でロックファイルに現在のプラットフォームを追加して、もう一度試してみてください。」

### 解決方法
エラー文通り新たなプラットフォーム`「x86_64-linux」`を`gemfile.lock`に追加することで解決。

## 解決までの手順
### プラットフォームを追加
```
$ bundle lock　--add-platform x86_64-linux
$ git add .
$ git commit -m 'Add platform'
```

最後に`bundle install`で完了。
（コミット忘れずに）




以上
英語キーボードで、xrdp接続

WindowsでもLinuxでも英語キーボードを使っているのですが
Windowsから、xrdpホストのLinuxにリモートデスクトップ接続すると
ログイン画面も含め、キー入力が日本語キーボードとして
認識されてしまったので、回避策を模索しました

１．言語「英語（米国）」を追加
Windows10だと、[設定]->[時刻と言語]->[言語]->[言語の追加]

２．タスクバーの右下で、言語を切り替えられるようになるので
「英語（米国）USキーボード」を選択してから、リモートデスクトップ接続

３．ログイン後に、タスクバー右下で「日本語 Microsoft IME」に戻しても大丈夫


確認したOSは
Windows 10 Pro 21H1（クライアント）
openSUSE Tumbleweed 20210524（ホスト）
です
Goの演習「Exercise: Loops and Functions」をやってみた

## 課題との出会い
GOのチュートリアルを進めていたら突如として課題が出てきました。
それがこちら
![スクリーンショット 2021-05-27 23.15.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/0699c634-d173-a293-2f79-1ea8cb81cf7e.png)

URL：https://go-tour-jp.appspot.com/flowcontrol/8

どうやら引数にある数値の平方根に近づけてみよ！とのこと
ニュートン法に関してはよくわからないのでスルーします。

## 実際にやってみた
```
package main

import (
	"fmt"
	"math"
)

// 引数の平方根に近づける
func Sqrt(x float64) float64 {
	z := 1.0

	// 10回繰り返すことが要件となっている
	for i:=1; i<=10; i++ {

		// 記載通りの計算式
		z -= (z*z - x) / (2*z)

		count := i  
		countString := "回目の結果"
		result := z
		fmt.Println(count , countString , result)

		// 実際の平方根と同じになれば抜ける
		if math.Sqrt(x) == z {
			fmt.Println("clear!")
			break;
		}

	}

	return z
}

func main() {
	var num float64 = 2 // 別の数値を試したい時はここを変更する
	result := Sqrt(num)	
	fmt.Println(result)
	fmt.Println(math.Sqrt(num))
}
```

まず上から

```
package main

import (
	"fmt"
	"math"
)
```

fmtパッケージを使うことで整形されたI/Oを使うことができます。
mathパッケージには数式に関する関数が詰まってます。

お次はこちら

```
// 引数の平方根に近づける
func Sqrt(x float64) float64 {
	z := 1.0

	// 10回繰り返すことが要件となっている
	for i:=1; i<=10; i++ {

		// 記載通りの計算式
		z -= (z*z - x) / (2*z)

		count := i  
		countString := "回目の結果"
		result := z

		fmt.Println(count , countString , result)
		// 実際の平方根と同じになれば抜ける
		if math.Sqrt(x) == z {
			fmt.Println("clear!")
			break;
		}
	}

	return z
}
```

`z := 1.0`にすることで浮動小数点数にする
`z -= (z*z - x) / (2*z)`は問題文にある計算式

```
	count := i  
	countString := "回目の結果"
	result := z
　　　　　fmt.Println(count , countString , result)
        // 実際の平方根と同じになれば抜ける
        if math.Sqrt(x) == z {
            fmt.Println("clear!")
            break;
        }
```
まずは結果を返してます。
先程のmathパッケージを使用して`Sqrt`という引数の平方根を返してくれる関数を使います。
xの平方根とzが一致すればループから抜けることになります。抜けたことがわかりやすく `clear!`も入れときます。
最後に条件分岐というのもおかしな書き方かと思ってます・・・ｗ

```
func main() {
    var num float64 = 2 // 別の数値を試したい時はここを変更する
    result := Sqrt(num) 
    fmt.Println(result)
    fmt.Println(math.Sqrt(num))

}
```
こちらに関しては特に追加で実装する必要はないのですが、良い感じにしてみました。
必要に応じて`num`を変更して実行するのも面白いよね！っていう意図で実装しました。

## 出力結果
下記のようになりました。

```
1 回目の結果 1.5
2 回目の結果 1.4166666666666667
3 回目の結果 1.4142156862745099
4 回目の結果 1.4142135623746899
5 回目の結果 1.4142135623730951
clear!
1.4142135623730951
1.4142135623730951
```
ググった感じ、結果に大きな違いはないかと思うのでクリアとしてます！ｗ

良い書き方等があれば教えていただけると幸いです・・・！

### 参考文献
https://xn--go-hh0g6u.com/pkg/fmt/
https://xn--go-hh0g6u.com/pkg/math/
https://xn--go-hh0g6u.com/pkg/math/#Sqrt
vue3にtailwind cssを導入する【作業メモ】

Vue3にtailwind cssを導入する機会が増えてきたので、作業メモ。

## `vue create`でプロジェクトを作成

とりあえずプロジェクトの作成。

基本的にVueのプロジェクトの作成は`vue-cil`を使うのが1番手っ取り早いからこれを利用。

```
$ vue create sample-app-add-tailwind
```

`vue-cil`をインストールしていない場合はインストールする。

```
$ npm i -g @vue/cli
```

`$ vue create sample-app`を実行すると最初の設定をいくつか聞かれるが、今回は`Default`の3系を選択。

```
? Please pick a preset: 
  Default ([Vue 2] babel, eslint) 
❯ Default (Vue 3 Preview) ([Vue 3] babel, eslint) 
  Manually select features
```

これで実行された通りにサーバーを起動するとVueのプロジェクトが立ち上がっていることがわかる。

```
$ cd sample-app-add-tailwind
$ npm run serve
```

![スクリーンショット 2021-05-27 21.40.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681937/a3546359-1f77-0b33-bc52-bf4cc7e87ec3.png)


## tailwind cssを導入

ここから実際にtailwind cssを導入していく。

導入方法については、[公式ドキュメント](https://tailwindcss.com/docs/guides/vue-3-vite)に忠実に実行していくだけ。

### 1. パッケージのインストール

```
$ npm install -D tailwindcss postcss autoprefixer
```

`tailwindcss`と依存関係にある`postcss`と`autoprefixer`も同時にインストール。

※ バージョンによっては`postcss8`が対応していない場合があるので、その場合はpostcss7をインストール（[参考](https://zenn.dev/ponkichi/articles/e1afcff5fd0f95)）

```
Syntax Error: Error: PostCSS plugin tailwindcss requires PostCSS 8.
Migration guide for end-users:
https://github.com/postcss/postcss/wiki/PostCSS-8-for-end-users
```

### 2. configファイルを作成

1.を実行した状態で、

```
$ npx tailwindcss init -p
```

実行すると、最低限の設定を行った`tailwind.config.js`と`postcss.config.js`が作成される。

```tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
```

```postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}
```

### 3. すべてのファイルでtailwindcssを適用

すべてのファイルでtailwindcssが使用できるように`tailwind.config.js`を修正

```tailwind.config.js
module.exports = {
- purge: [],
+ purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
```

### 4. tailwindをプロジェクトのCSSに追加

`./src/index.css`を追加して、ここにtaildwindのスタイルを追加する。

```src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

このファイル内容を`./src/main.js`に代入する。

```src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

createApp(App).mount('#app')
```

これでtailwindの設定が完了。

## 実際に確認

```src/App.vue
<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js App"/>
+ <div class="text-5xl text-bold">tailwind css</div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

・・・
```

このようにCSSが適応される（imgタグも）。

![スクリーンショット 2021-05-27 23.26.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681937/8cfd956a-fcfb-e8be-dcc8-216e4b07fa2a.png)

## 参考

https://tailwindcss.com/docs/guides/vue-3-vite

https://zenn.dev/ponkichi/articles/e1afcff5fd0f95
【PHP】要件および画像を参考に注文フォームおよび注文確認画面を作成せよ

```
・注文フォームの要件
```

ファイル名（フォーム): htdocs/14/order_form.php ファイル名（確認画面): htdocs/14/order_confirm.php

１・注文者名、注文者住所、注文者電話番号の入力欄をtype="text"で配置
２・注文する商品のラジオボタンを配置
３・「紙の領収書を希望する」チェックボックスを配置
４・「注文内容を送信」と書かれたsubmitボタンを配置

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954863/4b7d8343-73c1-4fc6-ec26-2da5289575ab.png)


order_form.php

```php

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>order_form</title>
  <style>
label {
	display:block;
}
  </style>
      <script src="jquery-3.6.0.min.js"></script>
    <script>
        var nowVal;
        function fnc(obj){
          if(nowVal == obj.value){
            obj.checked = false;
            nowVal = "";
          }else{
            nowVal = obj.value;
          }
        }
    </script>
</head>
<body>
  <h1>注文フォーム</h1>
  <form action="order_confirm.php"  method="get">
      <label>注文者名: <input type="text" name="radio1"></label>
      <label>注文者住所: <input type="text" name="radio2"></label>
      <label>注文者電話番号: <input type="text" name="radio3"></label>


  <h2>購入を希望する商品</h2>

      <label>単品: <input type="radio" name="radio4" value="単品"></label>
      <label>3個入り: <input type="radio" name="radio4" value="3個入り"></label>
      <label>10個入り: <input type="radio" name="radio4" value="10個入り"></label>

  
  <h2><label>紙の領収書を希望する:
       <input type="radio" name="radio"  onclick="fnc(this);"></label></h2>
      <input type="submit"  value="注文内容を送信">
  </form>
</body>
</html>
```

order_confirm.php

```php

<?php
  $errors = [];



  if($_GET['radio1'] !== "") {
    $radio1 = $_GET['radio1'];
  }else{
    echo $_GET['radio1'];
    $radio1 = "";
    $errors[]  = '注文者名を入力してください';
  }



  if($_GET['radio2'] !== "") {
    $radio2 = $_GET['radio2'];
  }else{
    $radio2 = "";
    $errors[]  = '注文者住所を入力してください';
  }



  if($_GET['radio3'] !== "") {
    $radio3 = $_GET['radio3'];
  }else{
    $radio3 = "";
    $errors[]  = '注文者電話番号を入力してください';
  }



  if(isset($_GET['radio4']) === true){
    $radio4 = $_GET['radio4'];

  }else{
    $radio4 = "";
    $errors[]  = '商品名を選択しください';
  }
  
  if(isset($_GET['radio']) === true){
    $radio = "領収書：要";
  }else{
    $radio = "領収書不要";
  }


?>

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>order_confirm</title>
  <style>
a {
	text-decoration: none;
  color: black;
}
button {
  display:block;
  margin-bottom: 10px;
}
.error {
color: red;
}


.error1 {
font-weight: bold;
}

  </style>
</head>
<body>
  <!-- エラーがあれば表示 -->

  <h1>注文確認画面</h1>
<?php 

    foreach($errors as $error){ ?>
    <p class="error" >  <?php echo $error;  ?>   <p> 
    <?php     } 
  ?>
  <dl>
      <dt>注文者名</dt>
      <dd><?=$radio1?></dd>

      <dt>注文者住所</dt>
      <dd><?=$radio2?></dd>

      <dt>注文者電話番号</dt>
      <dd><?=$radio3?></dd>

      <dt>商品名</dt>
      <dd><?=$radio4?></dd>

      <dt>領収書</dt>
      <dd class="error1"  ><?= $radio?></dd>
    </dl>
    <button type="button"><a href="order_form.php">注文を確定</a></button>
    <!-- <button type="button"><a href="order_form.php">戻る</a></button> -->
    <button onclick="location.href='./order_form.php'">戻る</button>
</html>
```
[cx_Oracle入門](第20回) cx_Oracle8.2 リリース 


# 連載目次
[連載：cx_Oracle入門　目次](https://qiita.com/nakaie/items/df170c3fa6895cf1b44d)


# cx_Oracle 8.2リリース 
cx_Oracle 8.2がリリースされました。
本記事ではリリースノートを元に、cx_Oracle 8.2の新機能、変更点などを解説します。
今回は大きな変更が入りますのでご注意ください。
この記事は[英語のRelease Note](https://cx-oracle.readthedocs.io/en/latest/release_notes.html#releasenotes)を元にまとめたものとなります。
なお、既存のcx_Oracleのアップグレードは、```python -m pip install cx_Oracle --upgrade```で実施します。

### 1. PEP8準拠
関数名がPEP8準拠になるよう変更されました。過去PEP8に適合していなかった関数名が変更されます。変更される関数の一覧と、変更後の関数名の表が[こちら](https://cx-oracle.readthedocs.io/en/latest/api_manual/deprecations.html#deprecations-8-2)にて参照可能です。
8.2では8.1までの関数名も使用可能ですが、旧関数名は将来バージョンのcx_Oracleにて廃止される予定ですので、8.2以降をお使いの場合は新関数名を使用するようにしてください。

### 2. ODPI-C 4.2.0対応
cx_Oracle 8.2は、ODPI-Cのバージョン4.2.0をベースに作成されています。

### 3. コネクション・プールに関する機能追加
以下の機能が追加されています。

- cx_Oracle.SessionPool()にmax_sessions_per_shardパラメータを追加。シャードごとのコネクションプールの最大接続数を指定します。また、設定値はSessionPool.max_sessions_per_shard属性で確認が可能です。これらの機能を使用するためにはOracle Client18.3以上が必要です。
- cx_Oracle.SessionPool()にstmtcachesizeパラメータを追加。ステートメントキャッシュに保存できる分の数を指定します。なお、このパラメータは、cx_Oracle.connect()にも追加されています。
- cx_Oracle.SessionPool()にping_interval パラメータを追加。プールされた接続を取得する際のpingの間隔を指定します。また、設定値はSessionPool.ping_interval属性で確認が可能です。なお、8.1以前のcx_Oracleではping間隔は60秒固定でした。
- cx_Oracle.SessionPool()にsoda_metadata_cacheパラメータを追加。SODAメタデータキャッシュの機能が利用できるようになります。また、SessionPool.soda_metadata_cache属性を追加し、セッションプール作成後に調整できるようにしました。この機能により、SodaDatabase.createCollection() (metadata パラメータに値を指定しない場合)および SodaDatabase.openCollection() メソッドのパフォーマンスが大幅に向上します。SODAメタデータキャッシュを使用するためにはOracle Clientバージョン21.3以降(またはOracle Client 19 19.11以降)が必要です。

### 4. SODAにヒント機能追加
SODAの操作に関するヒントの機能を提供するhint()メソッドが追加されました。また、SodaCollection.insertOneAndGet(), SodaCollection.insertManyAndGet(), SodaCollection.saveAndGet()の各メソッドにhintパラメータが追加されました。これらの機能を使用するためにはOracle Clientバージョン21.3以降(またはOracle Client 19 19.11以降)が必要です。

### 5. 文字コード関連の仕様変更
- cx_Oracle 8.0でUTF-8以外のエンコーディングが非推奨となったのを受け、cx_Oracle.connect()やcx_Oracle.SessionPool()のencondingパラメータやnencodingパラメータが非推奨となりました。
- cx_Oracle 8.0でUTF-8以外のエンコーディングが非推奨となったのを受け、Connection.maxBytesPerCharacter属性が非推奨となりました。代わりに4バイトを定数として使用してください。
- [issue 385](https://github.com/oracle/python-cx_Oracle/issues/385)への対応として、Cursor.var()にパラメータbypass_decodeを追加しています。Oracle DatabaseとPythonの間の文字列変換の際にデコードステップをバイパスする機能です。


### 6. デッド・コネクション検出強化
エラーによって接続が使用できなくなった場合、エラー「DPI-1080: connection was closed by ORA-%d」が返されるようになりました。メッセージ内の「%d」は、接続を閉じる原因となったORAエラーです。この後に接続を使用すると、「DPI-1010: 接続されていません」というエラーになります。この動作は、使用できない接続になる Connection.call_timeoutのエラーにも適用されます。

### 7. メモリリークエラー修正
SodaOperation.filter()をディクショナリで呼び出した際のメモリリークを修正しました。

### 8. 分散トランザクションのクリア
[issue 530](https://github.com/oracle/python-cx_Oracle/issues/530)への対応として、接続に関連付けられた分散トランザクションのハンドルは、Commit/Rollback時にクリアされるようになりました。

### 9. 一時LOBの型チェック
変数やオブジェクトの属性を設定する際に、一時LOBの型が期待される型と一致していることを確認するチェックを追加しました。

### 10. テストスイートの改良
具体的な改良点はリリースノートに記載されていません。


# 参考リンク
[cx_Oracle 8.2に言及しているOracle社のブログ(英語)](https://blogs.oracle.com/opal/cx_oracle-82-allows-connection-pool-reconfiguration-at-runtime)
[cx_Oracle リリースノート(英語)](https://cx-oracle.readthedocs.io/en/latest/release_notes.html)
<input type="file">のデザインを変更する方法


`<input type="file">`は直接デザインの変更ができないので、簡単にですがlabelタグとjQueryを用いてカスタマイズしていきます。

# デフォルト
![ab8fe718ef85639667d08e206dcba307.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474463/0e774640-0ef8-606a-c43a-a28d48c4e733.png)


# `<input type="file">`をカスタマイズ

```html:sample.html

<label for="form-image">ファイルを選択</label>
<input type="file" id="form-image">
<span class="select-image">選択されていません</span>

```

inputタグの上にlabelタグを記述します。labelタグでinputタグを囲ってしまっても構いません。

labelタグのforとinputタグのidに同じ値を指定してタグの紐づけをします。
こうすることでlabelタグ内の要素をクリックしたときにファイルの選択ができるようになります。

※ちなみにidは2つ以上指定できないので注意してください。


```css:sample.css

label {
  padding: 5px 20px;
  color: #ffffff;
  background-color: #295d72;
  cursor: pointer;
  border-radius:10px;
  transition: .3s;
}
label:hover {
  opacity: 0.8;
}
input[type="file"] {
  display: none;
}

```

inputタグを`display: none;`で非表示にしましょう。

先ほどforとidを紐づけているのでcssを当てたlabelタグをクリックしてもファイルを選択できます。

この時点ではファイルを選択してもspanタグ内にファイル名が表示されず、「選択されていません」のテキストのままなのでjQueryでテキストをファイル名に変換します。

※jQueryは適宜の環境でインストールしてください。

```javascript:input_file.js

//fileを変更したら
$('input').on('change', function () {
    //propを使って、file[0]にアクセスする
    var file = $(this).prop('files')[0];
    //text()で要素内のテキストを変更する
    $('.select-image').text(file.name);
});

```

inputタグにfileがセットされたときにselect-imageというクラスがあるタグのテキストをfile.nameに変更します。

`$('span').text(file.name);`でもいいんですが、他のinputタグの中にあるspanタグに意図しない変化がありうるのでクラスを指定しました。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="css,result" data-user="akimine27th" data-slug-hash="mdWxaxq" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="mdWxaxq">
  <span>See the Pen <a href="https://codepen.io/akimine27th/pen/mdWxaxq">
  mdWxaxq</a> by あきみね (<a href="https://codepen.io/akimine27th">@akimine27th</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
文末に丸括弧をつけるネットスラングをJavaScriptで使ってみる()

Twitter等のSNSで`〜〜じゃん()`という、**文末に丸括弧をつける**ネットスラングを度々？見かけるのでJavaScriptで再現してみました。

## 文末に丸括弧？
[ニコニコ大百科:括弧](https://dic.nicovideo.jp/t/a/括弧)より
> （） - 「（笑）を略した表現。ネットスラングのひとつ。」


## コード
JavaScriptでは**変数名に日本語が使える**のを利用しています。

```javascript
const それってあなたの関数ですよね = () => {};

それってあなたの関数ですよね();
```
【AWS】EBSスナップショットについて

#プログラミング勉強日記
2021年5月27日
　EBSはスナップショットを使ってバックアップを取得する。スナップショットを復元することで別のEBSとして新たに同じ内容のEBS構成を複製ができる。このスナップショットついてまとめる。

#スナップショットの特徴
　基本的にはRDSのスナップショットと同じ性能を持つ・

- スナップショットでバックアップを取得
- EBSを復元するときは別のAZでも可
- S3に保存される
- 2世代目以降は増えた分のデータを保存する増分バックアップになる(1世代を削除しても復元できる)
- 作成時にブロックレベルで圧縮して保管するので、圧縮後の容量に対して課金される
- 作成時でもEBSは利用可能

#スナップショットの管理
　スナップショットの作成時にはデータの整合性を保つために静止点を設けることが推奨されている。(しかし、いつでも実行可能でEBS操作に影響を与えない。)
　保存期間や世代数は無制限で、世代管理が必要な場合はAWS CLIやAPIで自動化する。DLMという機能を使ってスナップショットの取得をスケジューリングできる。

#スナップショットの共有
　スナップショットはリージョン間をまたいで利用できる。リージョンをまたぐときはリージョン間で直接使えない。(リージョンで一意のものなので、)他のリージョンで使うときはスナップショットをコピーして、コピーされたスナップショットを使って別のリージョンで立ち上げる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/8a0d6689-410b-f706-986e-cf8e6a27ac61.png)

　別アカウントでスナップショットを移行するときは、権限を変更する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/7f630520-1496-3bfc-374a-4859bbfde12d.png)

#スナップショットとAMI
　Amazon Machine ImageもEC2インスタンスのバックアップとして使うことができる。OS設定などをイメージとしてせってしておき、新規インスタンス設定に転用できる。
　スナップショットは、ストレージ・EBSのその時点での断面のバックアップとして保持するもの。ストレージの復元や複製に利用する。

　AMIの中にはスナップショットも含まれている。EC2インスタンスに接続されているEBSのスナップショットも含めてAMIの中に保存されているので、スナップショットはEBSのストレージだけのバックアップだが、AMIはスナップショットに加えてOSの設定も含まれている。なので、AMIさえ取っておけばアタッチされていたEBSも含めて復元される。
　[こちらの記事](https://qiita.com/mzmz__02/items/94155a92dd358359c86b)でAMIについて詳しく扱っている。
React  Storybook をインストールしてみた

# 目的
> storybookを使いこなす（インストール編）

# 前提準備
> node.js、webpack等はインストール済み

# Storybookとは
> フロントエンドの開発を補助するためのパッケージソフト。

> ReactやVueなどで設計するComponent郡をカタログ化させて、一覧で閲覧が可。 

> デザイナーとデザインの認識のすり合わせ、コンポーネントの単体テスト、詳細設計書作成などの目的で活用できます

# 実践
```bash
$ npx -p @storybook/cli sb init
```

```bash
$ npm run storybook 

．．．

｢wdm｣: Compiled successfully.
╭──────────────────────────────────────────────────╮
│                                                  │
│   Storybook 6.2.9 started                        │
│   42 s for manager and 34 s for preview          │
│                                                  │
│    Local:            http://localhost:6006/      │
│    
│                                                  │
╰──────────────────────────────────────────────────╯

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57249/32d87e9e-1788-89f4-4b5f-2e166e361d3b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57249/7fe13e22-e3b1-9b80-fc53-0f8714b5479c.png)

> VSCode内でもファイルが作成してあることを確認

```typescript:Button.tsx
import React from 'react';
import './button.css';

export interface ButtonProps {
  /**
   * Is this the principal call to action on the page?
   */
  primary?: boolean;
  /**
   * What background color to use
   */
  backgroundColor?: string;
  /**
   * How large should the button be?
   */
  size?: 'small' | 'medium' | 'large';
  /**
   * Button contents
   */
  label: string;
  /**
   * Optional click handler
   */
  onClick?: () => void;
}

/**
 * Primary UI component for user interaction
 */
export const Button: React.FC<ButtonProps> = ({
  primary = false,
  size = 'medium',
  backgroundColor,
  label,
  ...props
}) => {
  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
  return (
    <button
      type="button"
      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
      style={{ backgroundColor }}
      {...props}
    >
      {label}
    </button>
  );
};

```

```typescript:Button.stories.tsx
import React from 'react';
import { Story, Meta } from '@storybook/react';

import { Button, ButtonProps } from './Button';

export default {
  title: 'Example/Button',
  component: Button,
  argTypes: {
    backgroundColor: { control: 'color' },
  },
} as Meta;

const Template: Story<ButtonProps> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
Primary.args = {
  primary: true,
  label: 'Button',
};

export const Secondary = Template.bind({});
Secondary.args = {
  label: 'Button',
};

export const Large = Template.bind({});
Large.args = {
  size: 'large',
  label: 'Button',
};

export const Small = Template.bind({});
Small.args = {
  size: 'small',
  label: 'Button',
};

```

> はじめから用意されているファイルの確認までできた！

# 参考
[https://storybook.js.org/docs/react/get-started/install](https://storybook.js.org/docs/react/get-started/install)
pandasを用いたフラットファイルのインポート処理

## pandasを用いたインポート処理

pd.read_csv()を使用して単純なインポート処理を行います。

```python
import pandas as pd
df = pd.read_csv('test.csv')
```

ヘッダー行の指定や部分的に読込みたい場合、パラメータで指定します。

```python
df = pd.read_csv('test.csv', header=None, nrows=5)
```

* header : ヘッダー行の指定。1行目がヘッダーの場合は0、ヘッダーがない場合はNoneを指定します。（デフォルト値はinfer）
* nrows : 読み込む行数の指定

さらにタブ区切り、コメント行やNA/NaNを表す自前の文字列がある場合、以下のように指定します。

```python
df = pd.read_csv('test.tsv', sep='\t', comment='#', na_values='Nothing')
```

* sep : 区切り文字の指定
* comment : 行の先頭が一致する場合コメントとして無視
* na_values : 指定文字列が存在する場合NA/NaNとして読み込み

## 参考情報

[pandas.read_csv 公式リファレンス](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)
A/Bテストにあらわれるシンプソンのパラドックスについて

前回の記事で「シンプソンのパラドックス」の箇所がわかりにくいと指摘を受け、たしかにもっともだと思い、補足記事を書きました。

前回の記事

https://qiita.com/naosugi1987/items/42417b9adcd935f928eb


# シンプソンのパラドックス (Simpson’s Paradox)とは
ヒトは加重平均を直感的に扱えないという話

$ a/b < A/B $
$ c/d < C/D $

のとき

$ (a+c)/(b+d) > (A+C)/(B+D)  $

が数学的にありえる

例えば、

```
a = 20000
b = 990000

A = 230
B = 10000

print(a/b)
print(A/B)

>> 0.020202020202020204
>> 0.023
```

```
c = 5000
d = 500000


C = 6000
D = 500000

print(c/d)
print(C/D)

>> 0.01
>> 0.012
```

```
print((a+c)/(b+d))
print((A+C)/(B+D))

>> 0.016778523489932886
>> 0.012215686274509804
```
普通におこりうる

では、なぜこれがパラドックスとよばれるのでしょうか？具体的な例を代入するとわかりやすいです

## 具体例

あるとき画期的なUI変更を思いつきました。これによりクリックは激増するはずです。これをA/Bテストで確かめてみようと思います。
初週は1%のユーザにだけ新手法を適用し、エラーがおきないことを確かめてから翌週には50%のユーザに新手法を適用することにしました。

A/Bテストを初めて1週間たちました。

今までの手法では、99万人のユーザのうち、2万人がクリックしました。

新手法では、1万人のユーザのうち、230人がクリックしました。

```
a = 20000
b = 990000

A = 230
B = 10000

print(a/b)
print(A/B)

>> 0.01
>> 0.012
```
なんと、クリック率が13%も向上したではありませんか。
新手法でエラーも起きなかったので新手法の比率を50%に増やして、もう1週だけA/Bテストすることにしました。

```
c = 5000
d = 500000


C = 6000
D = 500000

print(c/d)
print(C/D)

>> 0.01
>> 0.012
```

今度はクリック率が20%も向上しました！
明らかな改善が見られたので、A/Bテストをやめて新手法を100%のユーザに適用しました。

ところが、雲の上の忙しい人は「サマった結果だけ知りたい」と初週と翌週の合計だけを見ました

```
print((a+c)/(b+d))
print((A+C)/(B+D))

print(((A+C)/(B+D))/((a+c)/(b+d)))
```
新手法では約27%もクリック率が下がってました！

** おしまい **


# どの結果をみるのが正しいのか

[Paurl(2009)](https://www.kyoritsu-pub.co.jp/bookdetail/9784320018778) のSure Thing Principle (確実性原則)によれば、「それぞれの部分集団において事象Eの確率を増加させるような行動Cは、その行動が部分集団の分布を変えないという条件の下で、集団全体においてもEの確率を増加させる」といった定理があります。

この場合、A/Bテストの介入は割当割合の原因ではないので「その行動が部分集団の分布を変えないという条件の下」の条件を満たします。

なので、真に介入がクリック率を向上させるのならば、前期の結果と後期の結果の両方とも向上するはずです。つまり合計を見るのではなく、それぞれでクリック率が向上していることを確認すればOKです。上の例で言えば、割合増やす前と割合増やした後の両方で改善が確認できれば問題なしです。

# どうやって仮説検定をすべきか
ここからは数学的な必然性の世界とは少し離れて、「じゃあ現実どうするの？」について簡単にふれます。 ~~（統計学もエンジニアリングもだいたいいつもそんな感じ）~~

パッと思いつくのは

1. 加重平均をとった全体の結果に検定
1. 割当割合変更前と変更後で独立な実験と解釈し、メタアナリシス
1. 割当割合変更後の結果だけ検定

の３つです。

「加重平均をとった全体の結果に検定」はかなりマニアックな検定手法が求められそうです。
「割当割合変更前と変更後で独立な実験と解釈し、メタアナリシス」は正しいのですが、メタアナリシスに馴染みがない場合は、たった２例のためでメタアナリシスを導入する元気が求められます（計算自体はフィッシャーのメタアナリシスなど簡易なものもありますが、考え方の導入〜特にA/Bテストの結果といったビジネス上の意思決定の場合には〜がしんどいことが多いです。あくまで一般論です。）
となると、既存の運用を大きく変えないですし、わずかな個数のサンプルからではさほど相互的な意思決定に影響を与えないという観点から、「割当割合変更後の結果だけ検定」に落ち着くことが多くなる気がします（あくまで個人の感想です）。

例の[カバ本](https://www.kadokawa.co.jp/product/302101000901)では、第１５章で実験割当割合の拡大の戦略について書かれていますが、拡大前の結果の検定方法までは明確に書いてなかったです。

# まとめ

1. シンプソンのパラドックスを例でわかりやすく説明した
1. シンプソンのパラドックス発生時はA/Bテストの場合は部分ごとにみるべし
1. じゃあどうやって検定するのよ、は唯一絶対の正解があるわけではない。やりやすいやり方で
Xserver標準のメールフォームはUI・UXにこだわるなら使わないほうがいい

## はじめに
レンタルサーバは[Xserver](https://www.xserver.ne.jp)を利用している方は多いと思います。標準機能として提供されているメールフォームがあるのですが、そのカスタマイズ案件で遭遇したトラブルの備忘録です。

>HTMLテンプレートやスタイルシートを直接編集し、自由自在にデザインを変更することが出来ます。
こだわったデザインにしたい方などにおすすめです。
[公式マニュアルより](https://www.xserver.ne.jp/manual/man_install_cgi_mailform.php)

この一文を見る限り、ＣＳＳでの見た目のデザインはもとより、入力項目のレイアウトや表示の順番なども、テンプレートを自作し、適用することで自由にカスタマイズできるように思えます。しかしながら、少なくとも自由自在ではありませんし、**こだわった（特にＵＩ・ＵＸ）デザインにしたい方**には**おすすめできません**。

## カスタマイズする上での問題点
以下のように、大きく３点の問題点が挙げられます。

### 1. テーブル構造での構築が前提
いわゆるテンプレートエンジンなので、サーバー側でテンプレート中のマーカーである`{$form_data}`部分を整形データで差し替える仕様となっています。問題点は、その整形データが`<tr><th>項目名</th><td>入力フィールド</td></tr>`といったガチガチのテーブルの子要素となっていることです。つまり、テーブル構造による構築を前提にしているわけです。せめて`<div>`や`<ul>`要素で出力されるのであれば、もう少し自由度があったのにと思います。

※もともとテーブル構造である、もしくはテーブル構造に準ずるデザインなら、ＣＳＳ次第でかなり柔軟にカスタマイズできると思います。

ちなみに、デフォルトの状態で出力したものから当該入力フィールドの`name属性値`を確認し、カスタムデザインを適用したところ、`{$form_data}`がない、ということでエラーになったようです[^1]。多少気持ち悪い感じは残りますが、`<!-- {$form_data} -->`として、コメントアウト部分に出力するようにしました。

[^1]: クライアント様による申告です。

### 2. テンプレート中のJavascriptは基本的に無効にされる
セキュリティ面からでしょう、`<script>`タグ中の`'`や`"`がエンコードされます。そのため、`Invalid Syntax エラー`が発生します。パスが通っていれば外部読み込みで問題ないと思いますが、実案件では都合上試していません。

※ちなみに、簡単で短いコードならば対策も可能ですが、攻撃の引き金になる可能性もあるため非公開とします。

### 3. 送信ボタンのvalue値を変更できない
どうやら内部で`<input type="submit">`の値を元に、固定値で処理の分岐判定をしているものと思われます[^2]。そのため、初期値を変更してしまうとフォームデータが送信されず、リロードしてしまうようです[^1]。送信ボタンの表示文字列を変更できない仕様というのは、地味にいやらしい落とし穴かと思います。

[^2]: `value="確認"`を`value="送信"`にした状態でボタンクリックすると、確認画面を経由せずフォームデータが送信されました。

## 最後に
フリーのメールフォームプログラムを探せば色々ありますので、目的にあったものを設置したほうが早かったかもしれません。[^3]

ＵＩ・ＵＸにこだわったフォームを使いたいのであれば、Xserver標準機能として提供されているメールフォームは使わないほうがいいと言えます。

[^3]: 予算とクライアント様スキル、開発工期の関係上、実案件では標準のものを使用しました。

### [参考]
+ [（Xserver公式）メールフォーム設置手順](https://www.xserver.ne.jp/manual/man_install_cgi_mailform.php)
アラサー未経験フリーターがITインフラ業界に放り込まれてawsの資格をプロフェッショナルまで取った話　②アソシエイト3種

アラサーIT未経験の私がawsアソシエイト系取得した時の勉強法まとめです。私と同じくIT経験の浅い方の参考になればと思います。
取得した資格は以下

1. ソリューションアーキテクト
2. SysOpsアドミニストレーター
3. デベロッパー

クラウドプラクティショナー編はこちら

https://qiita.com/instant_baby/items/cf39b67c044417d611b4

# ソリューションアーキテクト アソシエイト

勤続約半年で受験しました。
この時の技術レベルはまだまだ初心者状態で、知識レベル的にはクラウドプラクティショナーから毛が生えた程度でした。
触っているawsサービスも以下のもの程度でした。

https://aws.amazon.com/jp/aws-transfer-family/?whats-new-cards.sort-by=item.additionalFields.postDateTime&whats-new-cards.sort-order=desc

https://aws.amazon.com/jp/vpn/

受験しようとしたきっかけは、費用が会社持ちということと、合格すれば資格手当が出るからという金銭的な面からでした（あと会社からの圧）。
とまぁそんな感じで会社に受験しますと言ってしまったので何とかしなくてはと勉強法を探ることから始めました。
いろんな方の勉強法を探していきました。主にBlackBeltや公式ドキュメントを読み込むなどが主だった印象なのですが、私が軸にしたものはこちらです。

https://aws.koiwaclub.com/

有料でしたが、物は試しにと課金して進めました。

やり口としては

1. ココの問題集を解く
2. 問題に出てきたawsサービスの公式ドキュメントを総ざらい
3. 改めて問題集を解く
4. 間違えた問題に出てきたサービスの公式ドキュメント以下略

といった感じで、ひたすら問題集に出てきたサービスについて調べていくことを繰り返しました。
私が使用したのは先のサイトと公式ドキュメントのみです。

他にも書籍が販売されていたりしましたが、いろいろ手を出してた挙句情報がとっ散らかってしまうかもと考えこの二つに絞りました。
手の空いた時間（勤務中含め）を全て勉強に突っ込みました。出退勤の電車、帰宅から寝るまでの時間全てをつぎ込むイメージですね。

上記サイトの問題集は大体5周位した感じです。

勉強期間は大体1ヶ月位で試験に臨みました。
前日に友人と泥酔してしまい、当日は試験時間前まで会場のトイレで過ごしました。
モニターにピントが合わず苦戦しました。

結果は合格。
受験者スコアは852点でした。
![スクリーンショット 2021-05-27 21.46.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1526421/6e3d0255-5407-1a34-4c98-d38a9cd1aad9.png)

awsサービスに関しての試験問題は勉強の買いもあって結構スムーズでしたが、コスト関連で苦戦した印象でした。
嬉しくも一発合格できたのがとても嬉しかったことを覚えています。帰りにホープ軒食べました。

# SysOpsアドミニストレーター アソシエイト

ソリューションアーキテクト アソシエイト受験から1ヶ月位のスパンを開けて受験しました。
正直この資格はソリューションアーキテクトに合格できていれば流れで行けると思います。なので特筆して何かやっということはありません......
試験範囲がそこそこ重複していたので、正直1ヶ月も開けなくてよかったなという感想です。

試験方法は同じやり方で進めていきました。
前日に友人と泥酔してしまい、当日は試験時間前まで会場のトイレで過ごしました。
モニターにピントが合わず苦戦しました。

結果は合格
受験者スコアは782点でした。
![スクリーンショット 2021-05-27 21.57.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1526421/55805681-bbb1-dbc1-19b7-ab6fd5a33040.png)

自動化のスコアが低いですね。こればっかりは実務経験の無さが表れているんだろうなと感じます。
帰りに念願のラーメン神田に行きました。

# デベロッパー アソシエイト

一番苦戦したのはこの資格です。
これの受験あたりからコロナでリモートワークになってしまったので在宅受験です。
プログラムなんてやったこともなかったのでとにかくnode.jsを触ってました。
余談ですが、職業プログラマーの知人はこれが一番ちょろかったと聞きました。

jsonの類いならIAMポリシー等で触る機会があったのでとりあえずこれかな程度でした。
その他の勉強法は上記2つと同じです。
前日に友人と泥酔してしまい、当日は試験時間前まで会場のトイレで過ごしました。
モニターにピントが合わず苦戦しました。

結果は合格
受験者スコアは896点でした。
![スクリーンショット 2021-05-27 21.58.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1526421/cffdad11-b305-3ade-3f02-c4c07e0fc35b.png)

試験自体も一番苦戦し、半ば諦め状態で試験を終えたのですがスコアがこれまでで一番高く驚きました。

IT業界に入ってちょうど1年になりうそうな頃にアソシエイト系3種を取ることができました。

プロフェッショナル取得についてはまたいずれ。
最後まで閲覧いただきありがとうございました。

---

プロフェッショナル編はこちら

https://qiita.com/instant_baby/items/4b8d3104d7b941126e4a
Golang + Docker + RDB ユニットテスト実行時のローカルのホスト名の問題


# Golang + Docker + RDB ユニットテスト実行時のローカルのホスト名の問題

最近 Golang が楽しくなってきた、今回は、Golang + Docker + RDB で Golangのユニットテストで RDB 等にレコードを挿入したいときに、実行時のローカルのホスト名を読みかえなければならない問題に関して、自動化を図る方法があったので、そのメモ。

# 何がしたいのか
Golang の test コードから config.ReadConfig() を呼び出すことで設定の読みかえが可能になります。
Docker 等を活用している際にローカルと仮想環境内で接続先を切り替えたいときに使用します。

# 各種ステップ

書き換えたいファイル

```yaml:config.yml
db:
  host: host.docker.internal #ここをlocalhostに書き換えたい
  name: title
  password: password
  user: user
```

今までは手動でいちいち切り替えていたが、あまりにも効率が悪すぎるので、test を走らせる際に、自動で書き換えを行いたい。

まず、`config.go`

```golang:config.go
package config

import (
	"io/ioutil"
	"os"

	err "path/to/pkg/error"

	yaml "gopkg.in/yaml.v2"
)

type Config struct {
	DB configDB `yaml:"db"`
}

type configDB struct {
	Host     string `yaml:"host"`
	Name     string `yaml:"name"`
	Password string `yaml:"password"`
	User     string `yaml:"user"`
}

func ReadConfig() (*Config, error) {
	file := os.Getenv("CONFIG")
	if file == "" {
		return nil, err.ErrorEmptyEnvironmentVariableConfig
	}

	buf, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}

	var config Config
	err = yaml.Unmarshal([]byte(buf), &config)
	if err != nil {
		return nil, err
	}

	return &config, nil
}

```

GolangにはYAMLの標準ライブラリがないので、
なので外部ライブラリ等を使って、
Golangの構造体やマップなどに変換(Unmarshal) と、Golangのデータ型からYAMLに変換(Marshal)できる。

```
ライブラリ yaml.v2

ソース: go-yaml/yaml GitHub
```

構造体にconfigの項目を定義し、読みかえを可能にします。

```golang
type configDB struct {
	Host     string `yaml:"host"`
	Name     string `yaml:"name"`
	Password string `yaml:"password"`
	User     string `yaml:"user"`
}
```

次に例えば`setup_test.go`を書く

```golang
package db_test

import (
        "path/to/pkg/config"
	db "path/to/pkg/db"
	"os"
	"testing"
)

func TestMigration(t *testing.T) {
	os.Setenv("CONFIG", "../../config.yml")
	config, _ := config.ReadConfig()
	config.DB.Host = "localhost" #ここで読みかえます

	db.ConnectDatabase(config)
}
```

errorパッケージ

```golang:error.go
package error

import (
	"golang.org/x/xerrors"
)

var (
	ErrorEmptyEnvironmentVariableConfig = xerrors.New("Environment variable CONFIG is empty.")
)
```

このようにtestコードからconfig.ReadConfig()を呼び出すことで読みかえが可能になります。

Docker 等を活用している際にローカルと仮想環境内で接続先を切り替えたいときが度々発生すると思いますが、本当に便利ですね。

ありがとうございました、
もっとスマートな方法を知っているよという方がおられましたらぜひコメントください!
iPhoneショートカット VPN接続画面に一発で飛ぶ方法

## 概要

仕事でiPhoneのVPNを繋ぐことが多くなったので、ショートカットを作成したくなりました。

iPhoneショートカットで作れるかなと思って調べてみたら、VPN接続画面に一発で飛ぶ方法は見つけたのでメモです。

## 設定

1. テキストにprefs:root=General&path=VPNをあてる

2. 1を一度URLに渡す

3. 2をSafariのURLを開くに渡す

![275EE5E1-EEAB-4D9A-B884-63C88C2CC45D.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627146/be93d739-e5b6-8244-0294-afadb6e6faaf.jpeg)


## 参考

https://discussionsjapan.apple.com/thread/252022672
Cloud Run Admin APIでサービスを取得する時の注意点

特定のCloud Runサービスの情報を取得しようとした時に思いっきり嵌ったので備忘録を残しておきます。

まず始めにCloud Runを操作するAPIは以下に用意されています。

https://github.com/googleapis/google-api-go-client

上記ライブラリを読むと以下メソッドでCloud Runのサービス情報を取得できることが分かります。

```go
// Get: Get information about a service.
//
// - name: The name of the service to retrieve. For Cloud Run (fully
//   managed), replace {namespace_id} with the project ID or number.
func (r *NamespacesServicesService) Get(name string) *NamespacesServicesGetCall {
	c := &NamespacesServicesGetCall{s: r.s, urlParams_: make(gensupport.URLParams)}
	c.name = name
	return c
}
```

`name`をどういった形式で入れれば良いのかが判然としないので、Google Cloud公式のドキュメントを確認します。

以下にAPIに関する情報が記載されており、この内容を読むと`namespaces/{namespace_id}/services/{service_id}`の形式で渡してやれば良いと分かります。`namespace_id`と`service_id`の変数部分はそれぞれGoogle CloudのプロジェクトIDとCloud Runのサービス名を渡してやります。

https://cloud.google.com/run/docs/reference/rest/v1/namespaces.services/get

ここまで調べた内容をもとに以下のようなコードを書きました。

```go
import (
	"context"
	"fmt"

	"google.golang.org/api/run/v1"
)

func FetchURLByServiceName(ctx context.Context, projectID, name string) (string, error) {
	c, err := run.NewService(ctx)
	if err != nil {
		return "", err
	}

	service, err := c.Namespaces.Services.Get(fmt.Sprintf("namespaces/%s/services/%s", projectID, name)).Do()
	if err != nil {
		return "", err
	}

	return service.Status.Url, nil
}
```

しかし以下のようにエラーになってしまいます...。

```
googleapi: Error 404: Requested entity was not found.
```

どこもおかしいような箇所は無いように思うのですが、存在しないエンティティにリクエストを投げていると言われているので、取り敢えずデバッガーで実際に投げているURLを確認します。

![スクリーンショット 2021-05-27 21.46.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206595/9d5eab69-8be4-5ad4-f8b3-c8168974b77c.png)

一通り見ても期待通りの値が入っているので途方に暮れてしまいました。
ここで数時間悶々としていたのですが、以下のドキュメントに手がかりが書いてありました。

> https://run.googleapis.com (Global API endpoint, supports list methods only)

https://cloud.google.com/run/docs/reference/rest#rest_endpoints

デフォルトで付与されるエンドポイント`https://run.googleapis.com`はListメソッドでしか利用できず、その他のメソッドを使用する場合はリージョン毎のエンドポイントにリクエストを投げる必要がありました。

この点を踏まえ以下のように実装したところ、ようやく期待動作するようになりました。

```go
import (
	"context"
	"fmt"

	"google.golang.org/api/run/v1"
)

func FetchURLByServiceName(ctx context.Context, name, projectID, region string) (string, error) {
	c, err := run.NewService(ctx)
	if err != nil {
		return "", err
	}
	c.BasePath = fmt.Sprintf("https://%s-run.googleapis.com/", region)

	service, err := c.Namespaces.Services.Get(fmt.Sprintf("namespaces/%s/services/%s", projectID, name)).Do()
	if err != nil {
		return "", err
	}

	return service.Status.Url, nil
}
```

ドキュメントはちゃんと読め、ということですね...。
[m1]asdfでバージョン管理を行なったnodejsを使うまで[mac]

# asdfとは

いろんな言語のバージョン管理がまとめてできるやつ（雑）
類似ツール: anyenv

# 環境

- MacBook Air (M1, 2020)

# asdf

https://github.com/asdf-vm/asdf

https://asdf-vm.com/#/core-manage-asdf?id=install

```
% brew install asdf
```

zshを使ってるので以下を実行

```
% echo -e "\n. $(brew --prefix asdf)/asdf.sh" >> ${ZDOTDIR:-~}/.zshrc
```

# node

## 準備

https://github.com/asdf-vm/asdf-nodejs

```
% brew install gpg gawk
```

```
% asdf plugin-add nodejs 
```

## インストール可能なバージョンの確認

```
% asdf list all nodejs
```

## 最新安定板の確認/インストール

https://asdf-vm.com/#/core-manage-versions?id=show-latest-stable-version

https://asdf-vm.com/#/core-manage-versions?id=install-latest-stable-version

```
% asdf latest nodejs
16.2.0
% asdf install nodejs latest
```

## バージョン指定の場合はこっち

バージョンは適当な例

```
% asdf install nodejs 12.22.1
```

## インストールしてあるバージョンの一覧確認

https://asdf-vm.com/#/core-manage-versions?id=list-installed-versions

```
% asdf list
nodejs
  16.2.0
```
```
% asdf list nodejs
  16.2.0
```

## とりあえずのプライマリバージョン設定

https://asdf-vm.com/#/core-manage-versions?id=set-current-version

```
% asdf global nodejs 16.2.0
```

## 有効なバージョンの確認

```
% asdf current
nodejs          16.2.0          /Users/ユーザー名/.tool-versions
% asdf current nodejs
nodejs          16.2.0          /Users/ユーザー名/.tool-versions
% cat ~/.tool-versions
nodejs 16.2.0
% node -v
v16.2.0
```

globalやらlocalやら叩くと各所に `.tool-versions` ってファイルができてそこに記録されるらしい
gitとかで管理すれば環境構築の時とかバージョンはそこ見てねとかで済みそう


## 適当にファイル作って実行してみる

```
% touch test.js
```

```js:test.js
console.log("hello world");
```

```
% node test.js
hello world
```
# iOSアプリの#Typeを試しに使ってQiitaに投稿してみる

# iOSアプリの#Typeを試しに使ってQiitaに投稿してみる
まずはエディタ画面
![fahVk28MY7Ug9kTUpDRyGujZW5M2/0noYTXxmbmOYwwZr.jpg](https://firebasestorage.googleapis.com/v0/b/type-c1c71.appspot.com/o/fahVk28MY7Ug9kTUpDRyGujZW5M2%2F0noYTXxmbmOYwwZr.jpg?alt=media&token=c661ee96-f507-4a8f-b6d4-69737795aade)

共有ボタンからQiitaに投稿出来る。
![fahVk28MY7Ug9kTUpDRyGujZW5M2/vLrs9DhyR7wW5r4s.jpg](https://firebasestorage.googleapis.com/v0/b/type-c1c71.appspot.com/o/fahVk28MY7Ug9kTUpDRyGujZW5M2%2FvLrs9DhyR7wW5r4s.jpg?alt=media&token=34160605-5696-4b3d-8674-6388727251b5)

Qiitaを選ぶとこの画面になり、ここから投稿出来る。
![fahVk28MY7Ug9kTUpDRyGujZW5M2/IBYscLyVclwoxJL8.jpg](https://firebasestorage.googleapis.com/v0/b/type-c1c71.appspot.com/o/fahVk28MY7Ug9kTUpDRyGujZW5M2%2FIBYscLyVclwoxJL8.jpg?alt=media&token=f8ba7d97-0a3d-4b6d-9c93-de491bf8da53)
#Typeを試しに使ってみる

# #Typeを試しに使ってみる
まずはエディタ画面
![fahVk28MY7Ug9kTUpDRyGujZW5M2/0noYTXxmbmOYwwZr.jpg](https://firebasestorage.googleapis.com/v0/b/type-c1c71.appspot.com/o/fahVk28MY7Ug9kTUpDRyGujZW5M2%2F0noYTXxmbmOYwwZr.jpg?alt=media&token=c661ee96-f507-4a8f-b6d4-69737795aade)
【MuleSoft】MCD資格の勉強メモ（フローのエラー制御）

・MCD（MuleSoft Certified Developer）の勉強をした際に、フローのエラー制御でつまずいたので、メモです。
・試験では、フローが書いてあり、何が出力されるのか問う問題が多数ありました。（2021/5/25時点）



##定義
・エラーが発生したら、（同じフロー内の、）後続処理は実行しない。
・成功した場合、Payloadが出力される。（ステータスコードは200）
・失敗した場合、Errorオブジェクトが出力される。
・Errorメッセージは、上書くことが出来る。
・Errorは以下3種類ある。
　　①アプリ
　　②フロー
　　③プロセス
・フローにエラーが無い場合など、アプリのエラーが実行される。
（つまり余り実行されるケースはない。）
・On Error Continueは、エラーであっても、OK（成功）を返す。
・On Error Propagateは、エラーをエラーオブジェクトで返す。


##<問題>フローの結果、出力される値、後続処理の実行有無に関して。
#パターン①

以下、③でエラー発生した場合の場合の出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/753dfaf3-affc-ec1b-3d81-235d7d5e2c36.png)

・③でエラーが発生した際に、後続処理は実行されない。
・Subフロー内のエラースコープは、On Error Propagateなので、呼び出し元のフローに、NGを返す。
・②はNGを受け取り、⑤の後続処理を実行しない。
・Mainフロー内のエラースコープは、On Error Propagateなので、NGと、エラーメッセージを返す。
→結論
　結果：NG
　返却する値：③のエラーメッセージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/21d0f7cd-4b6c-ac0d-bcdc-2231792032a6.png)


#パターン②
今度は、MainフローがOn Error Continueのケース。
以下、③でエラー発生した場合の場合の出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/52872642-ccb9-883b-ec04-fa16d7a0d2a8.png)

・③でエラーが発生した際に、後続処理は実行されない。
・Subフロー内のエラースコープは、On Error Propagateなので、呼び出し元のフローに、NGを返す。
・②はNGを受け取り、⑤の後続処理を実行しない。
・Mainフロー内のエラースコープは、On Error Continueなので、OKと、Payloadを返す。
→結論
　結果：OK
　返却する値：Payload


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/6974330a-2a52-27a2-e349-67fd28239b9f.png)

#パターン③
今度は、SubフローもOn Error Continueのケース。
以下、③でエラー発生した場合の場合の出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/11e546fb-9b71-93f8-1836-4fdcf089a9a7.png)

・③でエラーが発生した際に、後続処理は実行されない。
・Subフロー内のエラースコープは、On Error Continueなので、呼び出し元のフローに、OKを返す。
・②はOKを受け取ったため、⑤の後続処理を実行する。
・Mainフロー内のエラースコープは、On Error Continueなので、OKと、Payloadを返す。
→結論
　結果：OK
　返却する値：Payload


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/baad1b24-b993-10f4-b94f-dd2fe9e34df1.png)

#パターン④

以下、③でエラー発生した場合の場合の出力結果

※考慮事項。エラーの返却時のBodyが、Payloadでうわがかれている。
< http:error-response >
  < http: body>< ![CDATA[#payload]>  < /http: body>
< /http:error-response >

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/753dfaf3-affc-ec1b-3d81-235d7d5e2c36.png)

・③でエラーが発生した際に、後続処理は実行されない。
・Subフロー内のエラースコープは、On Error Propagateなので、呼び出し元のフローに、NGを返す。
・②はNGを受け取り、⑤の後続処理を実行しない。
・Mainフロー内のエラースコープは、On Error Propagateなので、NGを返す。
　通常エラーオブジェクトを返すが、うわがかれているので、Payloadが返る。
→結論
　結果：NG
　返却する値：Payload

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/21d0f7cd-4b6c-ac0d-bcdc-2231792032a6.png)


##参考
https://qiita.com/ykibe/items/7788e75ead31eeeb8833
https://docs.mulesoft.com/jp/mule-runtime/4.3/error-handling
https://qiita.com/nori83/items/7a16de3b181384b10976
PowerShellで一括で改行コードをCR+LFからLFに変換する

#あるディレクトリ以下にある全部のファイルの改行コードをCR+LFからLFに変更する

ディレクトリ配下のファイルが全部上書きで変更されます。

```crlf2lf.ps1
 ls -n -r -file | foreach { ((Get-Content $_) -join "`n") + "`n" | Set-Content -NoNewline $_}
```


##参考にしたサイト

https://qiita.com/kurukurupapa@github/items/37fc3fe4ec27612ab7df

https://stackoverflow.com/questions/19127741/replace-crlf-using-powershell

https://m-yama.github.io/posts/2019/08/19/powershell_crlf/
コマンドプロンプトのShift-JISの扱いの記事について

https://dianxnao.com/windows%EF%BC%9A%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88%E4%B8%8A%E3%81%A7gcc%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%97%E3%81%9F%E5%AE%9F%E8%A1%8C/

結論は問題ないけど、途中の解説がちょっと違うような気がするので、元記事を補足する意味で書き残しておく。


>これはShift-JISコードの「表」の文字コードはUTF-8では扱えないことを意味します。gccコンパイラは内部では文字列をUTF-8として認識してコンパイルするので、こうした問題がでてきます。

Shift-jisの「表」でコンパイルエラーが出るのと、gccが内部でUTF-8を使っているのは関係がない。理論上おそらくgccの内部がShift-jisだったとしてもこの現象は起こる。たぶんUTF-8が存在する前から起きていた。

なお「表」を「表¥」とするとコンパイルエラーにならない。Shift-JIS問題は他のコンパイラ、他の言語でもおきるので、コンパイラではなく文字コード単独の問題。

>「表」の文字は先頭部分が「\」と同じ文字コードを表していてエスケープシーケンス文字（制御文字）として扱われることになってしまいます。

これは「表」の文字コードが「95」「5c」で、「5c」が「¥」だ、と言いたいのだと理解した。だとすると「先頭」ではなく「後ろ」ではないかなと…。
それから「エスケープシーケンス文字」は、厳密な意味では「制御文字」ではない。バックスラッシュがプログラミング上意味を持っているだけで、文字としては普通の記号。


>コマンドプロンプトをUTF-8モードにしても入力までUTF-8になっている訳ではないようです。

仕組みとして、chcpは表示を変えるだけなので、コンパイルしたプログラムに後から変更が加えるわけではないよ、と。エディタでShift-JISで書かれたファイルをUTF-8や他の文字コードとして開いてしまうと文字化けするけれど、それと同じようなもの(？)だ。
また、プログラムが出力するバイナリ値自体も変わっていない。ソースコードがUTFで「トマト」と書かれていればUTFの「トマト」、shift-jisならshift-jisの「トマト」の文字コードを出している。
同様に入力を変える効果もない。入力を渡すのは自作プログラムのほうではなく、コマンドプロンプトなので、受け付けられた文字＝shift-JISは変更されない。
プログラムの方も、入力された文字がshift-jisかUTF-8か、はたまた他の文字列か自動判定はしない。Shift-JISの「赤」と、UTF-8で保存された「赤」は別の数値なので、比較で一致しない、となる。
これはwindowsに限らず、またgccに限らず、「入力文字コードとソースコードの文字コードが違えば全部起きる」問題なので、組み合わせは無数にある。
今回は入出力が固定されているからgccのオプションで良いけれど、読むこむファイルが何の文字コードか分からない(メールなど)、ということもあるので、プログラム内でデコード、エンコードする方法も紹介したいなと思った…けど良いリンク先がみつからなかった。


Cだとデフォルトで汎用的な文字コードライブラリが付属しないから面倒だよね、というのを思い出した日でした。