OmniAICreator/Qiita-1.07M huggingface dataset:
build.gradle : IDE から Gradle が読み込まれていることを判定する (Android Studio, IntelliJ IDEA)

build.gradle が IDE から読み込まれていることは `idea.active` プロパティで判定できます。

IDE がプロジェクトを読み込んだり Gradle Tasks リストを読み出すときには `idea.active` = "true" がセットされています。


```build.gradle.kts
val ideaActive = (System.getProperty("idea.active") == "true")

if (ideaActive) {
    // IDE から読み込まれているときだけ実行したい処理
}
```

公式のドキュメントは見当たりませんでしたが、Gradle Plugin 作成時のテクニックなどで使われているようです。

* https://github.com/endanke/kotlin-mpp-framework-skeleton/blob/86f2b6ea2c545a562a8224536a4cb6bf03a9e05d/ProjectName/build.gradle.kts#L3 などで見かけました
Power BIに取り込んだテーブルを結合する

この記事でインポートしたPostgresのテーブルをPower BI上で結合してみます。
[Power BI DesktopからHeroku PostgresにODBC接続してデータをインポートする](https://qiita.com/sidious/items/202cb81a9f7b363f1d48 "Power BI DesktopからHeroku PostgresにODBC接続してデータをインポートする")
# Power Queryの起動
トップメニューから__「データの変換」__を選択してPower Queryを起動。
![power_bi_20201123_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236988/ea177efa-9cb1-95e4-8186-0815c1565372.png)


# クエリのマージ
駆動表(ベースとなるテーブル)となるテーブルを選択してトップメニューから__「クエリのマージ」__を選択。
![power_bi_20201123_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236988/6dad7d88-60a2-b274-b538-61914ab77ec4.png)

結合するテーブルを選択し、結合時のキーとなるカラムをクリックして、OKボタンを押す。
例では「XXXX_Hdr」を駆動表として「YYYY_Dtl」テーブルと「TUID」カラムで結合する。
![power_bi_20201123_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236988/fef3181b-49ec-e40b-b571-eba26efb46df.png)


結合の種類は以下から選択できる。

ちなみに
__左テーブル(最初)：上部のXXXX_Hdr__
__右テーブル(2番目)：下部のYYYY_Hdr__
となります。

- __左外部__：left outer join
- __右外部__：righ outer join
- __完全外部__：full outer join
- __内部__：inner join
- __左反__：左テーブルにのみある行を残す
- __右反__：右テーブルにのみある行を残す

OKボタンをマージ結果が表示されます。
結合したYYYY_Dtlのカラムが表示されています。
![power_bi_20201123_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236988/61e41ee0-7ee4-6054-e0e5-fa7da838ab4f.png)

メニューの__「閉じて適用」__でレポート作成画面にデータソースとして反映されます。
HULFT バイナリファイル送信時の圧縮単位における推奨値

#はじめに

HULFTの送信定義において、バイナリファイルを圧縮する場合、**圧縮単位**という設定値を設定しないといけないが[^1]、設定内容によっては送信エラーが発生する場合がある。

[^1]: 正確には、縦圧縮、縦横圧縮の場合のみ。DEFLATE圧縮の場合は設定不要


私が確認したのはHULFTのバージョン8でしたが、7でも同様かと思われます。

#HULFTの圧縮

HULFTの圧縮方式には、

+ 縦圧縮
+ 縦横圧縮
+ DEFLATE圧縮

の3種類があるが、DEFLATE圧縮については、HULFTのバージョン8以上でないと使用できない。

バージョン７との伝送で圧縮するためには、縦圧縮か横圧縮の設定が必要。

縦圧縮、横圧縮については、レコード単位に圧縮する処理なので、バイナリ伝送の場合はどのバイト長を１レコードとして扱うかを指定しないといけない。

その指定するパラメータが圧縮単位。

#圧縮単位

圧縮単位は、0~32760 の範囲で設定可能。
マニュアルによると、
https://www.hulft.com/help/ja-jp/HULFT-V8/UX-OPE/Content/HULFT_OPE_UNIX/HULFTSysMngmntInfo/SndMngmntInfo.htm

> 値が大きいほど、高速に処理を行います（ただし、メモリを消費します）。

とのこと。

なので、圧縮効率を最大化するため、最大値(32760)を設定設定するのが良いのではと判断してしまう。

32Kバイトは大きな値ではないし、メモリ消費についても、最近の機器スペックからすると桁が違うので
問題になることはほぼないと考えられるので。


#送信可能な最大レコード長

一方、HULFTには送信可能な最大レコード長があり、そのサイズは 32768 となっている（改行含む）。

圧縮においては、圧縮されたデータに制御情報が付加されて転送されるが、圧縮の効果がほぼなかった場合は、制御情報が付加されることで、元データよりもサイズが大きくなる場合がある。

そのため、圧縮単位を設定可能な最大値のような大きな値に設定していると、圧縮データによっては最大レコード長超過となり以下のエラーが発生する。

>231  The data length of one record exceeds the maximum value.
>内容）
>1レコードのデータ長が最大値を超えました。
>
>対処）
>圧縮により、1レコードの最大値32768バイトを超えたと考えられます。圧縮を行わないで配信を再実行してください。

https://www.hulft.com/help/ja-jp/HULFT-V8/UX-ERR/Content/HULFT_ERR_UNIX/ErrC_LogInfo/DC_SenPro.htm?tocpath=1.%20%E5%B1%A5%E6%AD%B4%E6%83%85%E5%A0%B1%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89%7C1.3%20%E8%A9%B3%E7%B4%B0%E3%82%B3%E3%83%BC%E3%83%89%7C_____1


#推奨値

圧縮単位については、メーカの推奨値（圧縮データの圧縮効率がどれだけ悪くとも、送信データが最大レコード長を超過することがない値の最大値）があり、以下の値となっている。

>**32255**

そのため、バイナリ伝送で圧縮単位を設定する場合は、32255 を設定するのが推奨されている。

できれば、マニュアルにその旨記載もしくは、圧縮単位の設定可能上限を 32255 にていただけると、大変ありがたいです。

#終わりに

HULFTに精通している方なら自明のことなのかもしれないですが、製品のマニュアルにはどこにも記載がないので記事にしました。

バイナリ伝送の圧縮については、ファイルそのものを事前に別途圧縮した上でHULFTでは圧縮しないでおくか、バージョン８同士であるなら　DEFLATE圧縮にするのがいいのかもしれないです。


#参考
https://hulftorangelab.zendesk.com/hc/ja/articles/215647578
メモ：超簡単にURLパラメータ事前入力

## コード

```JavaScript
window.onload = function(){
  const searchParams = new URLSearchParams(decodeURI(location.search));
  var input = document.getElementById('input');
  input.value = searchParams.get('q');
  window.history.replaceState(0, 0,'./');
};
```

## 内容

ページ読み込み時に実行

```JavaScript
window.onload = function(){
  //処理
};
```

デコードしたURLからパラメータを取得

```JavaScript
const searchParams = new URLSearchParams(decodeURI(location.search));
```

`q`というパラメータの値を`input`にセット

```JavaScript
var input = document.getElementById('input');
input.value = searchParams.get('q');
```

ブラウザのURL欄からパラメータを削除

```JavaScript
window.history.replaceState(0, 0,'./');
```
Auto LayoutのStack Viewの便利さ

#はじめに
Auto Layoutを勉強していてStack Viewの便利さを知ったので記事を書こうと思います。
また、Auto Layoutはエンジニア必須スキルで、ちゃんと理解できれば他のエンジニアと差をつけられる要素になるみたいです。
しっかり使いこなせるようになりたいですね。

#Stack Viewとは何か
公式ドキュメントにはこのように書かれています。
>Stack Viewは、複雑な制約を導入することなく、自動レイアウトの機能を活用する簡単な方法を提供します。

要するに、本来なら複雑な制約を書いて実装するけど、Stack Viewを使えば簡単に実装できるようになります！って感じです。

#使ってみた
今回はボタンを並べて、後からボタンを追加する作業にStack Viewを使っていきます。
###Stack ViewをViewに追加
HorizontalとVerticalがあります。
Horizontalは水平なので横並び、Verticalは垂直なので縦並びで設定したい時に使います。
今回はHorizontalを使います。
![スクリーンショット 2020-11-23 14.39.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/e96c2941-3ffb-3e49-e2b1-81f3686ce0f4.png)
###Stack Viewにボタンを上から載せて追加
3つのボタンを並べます。
![スクリーンショット 2020-11-23 14.59.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/cf626e13-7087-7737-c2f6-ff5c47e914f3.png)
###配置を設定
topとcenterの制約を設定します。
右下にあるAdd New Constraintsでtopの制約を追加します。
![スクリーンショット 2020-11-23 15.01.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/a031e036-dc04-a554-9cd4-a6a2febf91c1.png)
次に、Stack Viewをコントロール押しながらドラックしてViewで離します。
すると画像のような選択肢が出てくるので、Center Horizontallyを選択肢します。
![スクリーンショット 2020-11-23 15.03.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/ce48be75-5af0-31de-7d51-747470483d79.png)
これで配置が完了しました。
それぞれのボタンのスペースを８に設定してみました。
![スクリーンショット 2020-11-23 15.09.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/e5b04c46-ecf2-5ccd-b08b-66259f2363d6.png)

#ボタンを追加する
さて、ここでボタン追加の変更が入ったとします。Stack Viewでなければボタンを追加して、配置なども１からやり直しでしたが。
Stack Viewを使っているので、Stack Viewのなかにボタンをドロップするだけで配置することができます。
もちろん、さっき設定したスペースの８も自動で設定されますので、設定し直す必要がありません。
![スクリーンショット 2020-11-23 15.13.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/b91092a2-541c-1935-1c5d-77bae5b793f0.png)
![スクリーンショット 2020-11-23 15.16.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/77735016-6cad-e82e-9711-f2bd0141548c.png)
#最後に
レイアウトを管理することができるのがStack Viewの役割です。
これはかなり便利な機能だなと思いました。
まだこのくらいしか使い方知りませんが、また便利な使い方があれば更新していきます。
#参考サイト
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutWithoutConstraints.html#//apple_ref/doc/uid/TP40010853-CH8-SW1
MuleアプリケーションをDLBを接続する際のはまりどころ

# はじめに
　今回は、Muleアプリケーション開発者が専用ロードバランサーからMuleアプリケーションに接続する際に、ちょっとしたはまりどころの紹介です。
　みんな原因を説明すると「そんな問題あるのかよー」と言ってしまうはまりどころですが、知っていると問題なく回避できます。

# はまりどころ
　CloudHubにはMuleアプリケーションをCloudHubロードバランサーに接続するために8081ポートに変更してデプロイする機能があります。デプロイ時に${http.port}は8081に書き換えられます。

[公式ヘルプ：CloudHubネットワークガイド](https://docs.mulesoft.com/runtime-manager/cloudhub-networking-guide)

　しかし、専用ロードバランサー（DLB）では、Muleプリケーションのポートが違います。公式ヘルプでは下記のように紹介されています。
　”CloudHub 専用ロードバランサでは、ポート 8091 でリスンする Mule アプリケーションへの HTTP 要求とポート 8092 でリスンする Mule アプリケーションへの HTTPS 要求を転送する。”（公式ヘルプ引用）

[公式ヘルプ：専用ロードバランサアーキテクチャ](https://docs.mulesoft.com/jp/runtime-manager/lb-architecture)

　ここがはまりどころです！！。
　HTTPリスナーコンポーネントを、デフォルト又は、変数${http.port}を指定してCloudHubにデプロイすると、ポート8081に上書きされてデプロイされます。
　Muleアプリケーションん開発者は、上書きすることを知らないで専用ロードバランサーから接続しようとすると、「502 Bad Gateway」エラーが発生し、8091でハードコーディングする方法やプロパティファイルに設定する方法、Runtime Managerに設定する方法など色々試しても、上書きされるため、かなりの労力を消費します。

　解決方法は、Backend With Proxyで利用されている${proxy.port}変数に変更することで、Cloudhubにデプロイした際にCloudHubの上書きの除外されます。

```
    <http:listener-config name="http-listener-config">
        <http:listener-connection host="0.0.0.0" port="${proxy.port}" protocol="HTTP"/>
    </http:listener-config>
````

# まとめ
 専用ロードバランサーからMuleアプリケーションに接続する際に一番わかりずらいのは、DLBからMuleアプリケーション間の通信だと考えています。
　マッピングルールが正しい場合、次に確認すべきはポイントはポートです。
　「設定しているのに何で接続できないの！！」と思ってしまうところなので、変数名が正しいか確認してみてください、では！
pwnagotchi のお友達発見機能


> 履歴
> 20/11/23 新規作成

pwnagotchi とは ( https://qiita.com/k0uj1k/items/f91a3b7e3a4b9209774f ) を参照してください。

# お友達発見発見機能
IoTの師匠のご協力のもと、この機能の確認にたどり着けました。ありがとう
## 表示
お友達の pwnagotchi が近くにあると、お友達発見機能でお友達情報を表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587146/6bf0a566-7e25-0d5b-05cf-814d2e107acd.png)

並べるとお互いに、相手の情報を表示しています。

+ 表示内容
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587146/633c92b3-b6f9-bc99-2b59-abffad741ffd.png)

+ お友達の Pwnagotchi の表情 (水色)
+ どのくらい近くにいるか (黄)
+ お友達の Pwnagotchi の名前 (赤)
+ 今いくつ pwn したか (緑)
+ 今までいくつ pwn したか (紫)
を表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587146/cf8c0e62-0dc1-aaa2-f5e7-ee62c7478784.png)

遠くに行ってしまうとさみしい表情をします。

https://pwnagotchi.ai/usage/ によると、一番信号が強いpwnagotchi を表示するようです。


## 足跡

### ファイル
/home/peer に "fingerprint".json　ファイルを残します。

この"fingerprint"の部分は、PWNMail の宛先になるので、知らない間にすれ違った Pwnagotchi にも、後からメッセージを送ることができます。

取得した時刻は含めて、かなり詳細な情報を残します。

また、この情報は backup.sh の対象になっています。ずっと残っていてくれます。

## 仕組
Wi-Fi Beacon Frame を使ってお互いの情報を送ります。
\# みんな大好き deadbeef （笑）。

師匠の解析によると Wi-Fi Beacon Frame を送ることで、お友達発見機能のやり取りをしています。
wireshark で Beacon Frame で検索すると、たくさんの情報を送っています。

![wireshark2730.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587146/485ae1fd-db7e-91c3-4359-77ababc45b84.jpeg)

----
# ハックザプラネット！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587146/1ea7dc03-e2a4-6788-4e65-ec4143f61ede.png" width=75%>
GAS内のHTML間で遷移したり、パラメーターを渡したりする方法

# はじめに

GAS で複数の HTML が含まれる Web アプリを作ることがあります。
そういう時に、特定の HTML を開きたいとか、HTML どうしでページ遷移したいとか、パラメーター渡したいとか思うけどやり方をいつも忘れてるので、まとめておきます。

## 対象の方

* 基本的な JavaScript が読める方
* GAS で Web アプリを作ったことがある方

## 前提

以下のような構造の GAS プロジェクトを想定します。
ここで GAS プロジェクト と言っているのは、Google ドライブ上で「新規」→「その他」→「Google Apps Script」から作成されるファイルを指します。

* GAS プロジェクト
  * Code.gs
  * index.html
  * page1.html
  * page2.html

# 特定の HTML を開けるようにする

一般的な Web サイトのように URL から開く HTML を指定したいです。
ただし GAS の Web アプリには標準でそういった機能は提供されていません（と思います）。

## ないんだったら自分で作ればいいのよ！

以下のコードを書いておけば、URL から開く HTML を指定できるようになります。

```js:Code.gs
function doGet(e) {
  let page = e.parameter.page;
  if (!page) {
    page = 'index';
  }
  return HtmlService.createTemplateFromFile(page).evaluate();
}
```

GET でアクセスされると `Code.gs` の `doGet` 関数が呼ばれるので、ここでリクエストパラメーター `page` と同じ名前の HTML を返すようにしています。
例えば https://script.google.com/xxxxx/exec?page=page1 を開けば、GAS プロジェクト内の `page1.html` が返されるようになります。

# HTML から別の HTML へ遷移する

GAS 内部の HTML どうしで行き来できるようにします。

まず準備として、`Code.gs` に下記の関数を追加します。
アプリの URL を返す関数です。

```js:Code.gs
function getAppUrl() {
  return ScriptApp.getService().getUrl();
}
```

## a 要素を使う場合

HTML の a 要素を下記のように書きます。

```html:index.html
<a href="<?= getAppUrl() ?>?page=page1">PAGE1へ</a>
<a href="<?= getAppUrl() ?>?page=page2">PAGE2へ</a>
```
```html:page1.html
<a href="<?= getAppUrl() ?>?page=index">INDEXへ</a>
```

`getAppUrl()` でアプリの URL が取得できるので、その後ろにリクエストパラメーターでページを指定すれば良いです。

## JS から遷移する場合

```html:index.html
<script>
window.top.location.href = '<?= getAppUrl() ?>?page=page1';
</script>
```

`window.top.location.href` に URL を代入すれば遷移できます。

# 各 HTML で固有のリクエストパラメーターを使う

アクセスされる URL は↓と想定します。
https://script.google.com/xxxxx/exec?page=page1&param1=hoge&param2=fuga

## クライアントサイド

```html:page1.html
<script>
google.script.url.getLocation(function(location) {
  const param1 = location.parameter.param1;
  console.log(param1);  // => 'hoge'
  const param2 = location.parameter.param2;
  console.log(param2);  // => 'fuga'
});
</script>
```

`google.script.url.getLocation` のコールバック関数内でリクエストパラメーターを取得できます。

## サーバーサイド

前に書いた `doGet` 関数を修正します。

```js:Code.gs
function doGet(e) {
  let page = e.parameter.page;
  if (!page) {
    page = 'index';
  }
  // -- 変更ここから --
  const template = HtmlService.createTemplateFromFile(page);
  if (page === 'page1') {
    template.param1 = e.parameter.param1;
    template.param2 = e.parameter.param2;
  }
  return template.evaluate();
  // -- 変更ここまで --
}
```

doGet で受け取ったパラメーターをテンプレートに設定しておけば、HTML 側でスクリプトレットを使って `param1` と `param2` を取得できます。

```html:page1.html
<div>
  <span><?= param1 ?></span>
  <span><?= param2 ?></span>
</div>
```

画面ごとに使うパラメーター名は違うと思われます。
この方法だと画面ごとに分岐してパラメーターを設定する処理を書くことになります。

画面ごとにいちいちやってられない！という場合は、受け取ったリクエストパラメーターをまとめて登録することもできます。

```js:Code.gs
function doGet(e) {
  let page = e.parameter.page;
  if (!page) {
    page = 'index';
  }
  // -- 変更ここから --
  const template = HtmlService.createTemplateFromFile(page);
  for (const key in e.parameter) {
    template[key] = e.parameter[key];
  }
  return template.evaluate();
  // -- 変更ここまで --
}
```

これだとラクだし、コードもスッキリですが、意図していないリクエストパラメーターまで登録される可能性があるので、その点は注意してください。
GO環境でcould not import Cエラー


## エラー発生

Goのgraphqlライブラリの`gqlgen`でスキーマを更新しようとしたら謎のエラー


```sh
/go/src # go run github.com/99designs/gqlgen
validation failed: packages.Load: /usr/local/go/src/net/cgo_linux.go:12:8: could not import C (no metadata for C)
exit status 1
```

## 解決

どうやらgccがdockerイメージ上に入ってない模様。
たぶんきっとこれ? https://github.com/golangci/golangci-lint/issues/602

`apk update`してapkをアップデートした後、`alpine-sdk`というビルドパッケージ?を入れたらうまく行きました。
apkについては、[この記事](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)が分かりやすかったです。

```
/go/src # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz

fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
v3.12.1-44-g754f23ac8f [http://dl-cdn.alpinelinux.org/alpine/v3.12/main]
v3.12.1-41-g42f619918d [http://dl-cdn.alpinelinux.org/alpine/v3.12/community]
OK: 12746 distinct packages available
```

```
/go/src # apk add alpine-sdk
(1/37) Upgrading musl (1.1.24-r9 -> 1.1.24-r10)
  0%                                                                                                                                                                                                                   
(2/37) Installing fakeroot (1.24-r0)
(3/37) Installing openssl (1.1.1g-r0)
(4/37) Installing libattr (2.4.48-r0)
(5/37) Installing attr (2.4.48-r0)
(6/37) Installing libacl (2.2.53-r0)
(7/37) Installing tar (1.32-r1)
(8/37) Installing pkgconf (1.7.2-r0)
(9/37) Installing patch (2.7.6-r6)
(10/37) Installing libgcc (9.3.0-r2)
(11/37) Installing libstdc++ (9.3.0-r2)
(12/37) Installing lzip (1.21-r0)
(13/37) Installing nghttp2-libs (1.41.0-r0)
(14/37) Installing libcurl (7.69.1-r1)
(15/37) Installing curl (7.69.1-r1)
(16/37) Installing abuild (3.6.0-r1)
Executing abuild-3.6.0-r1.pre-install
(17/37) Installing binutils (2.34-r1)
(18/37) Installing libmagic (5.38-r0)
(19/37) Installing file (5.38-r0)
(20/37) Installing gmp (6.2.0-r0)
(21/37) Installing isl (0.18-r0)
(22/37) Installing libgomp (9.3.0-r2)
(23/37) Installing libatomic (9.3.0-r2)
(24/37) Installing libgphobos (9.3.0-r2)
(25/37) Installing mpfr4 (4.0.2-r4)
(26/37) Installing mpc1 (1.1.0-r1)
(27/37) Installing gcc (9.3.0-r2)
(28/37) Installing musl-dev (1.1.24-r10)
(29/37) Installing libc-dev (0.7.2-r3)
(30/37) Installing g++ (9.3.0-r2)
(31/37) Installing make (4.3-r0)
(32/37) Installing fortify-headers (1.1-r0)
(33/37) Installing build-base (0.5-r2)
(34/37) Installing expat (2.2.9-r1)
(35/37) Installing pcre2 (10.35-r0)
(36/37) Installing git (2.26.2-r0)
(37/37) Installing alpine-sdk (1.0-r0)
Executing busybox-1.31.1-r19.trigger
OK: 224 MiB in 51 packages
```

### ひとりごと

使っているdockerイメージ`golang:1.15.5-alpine3.12`がいけなかったのか。。
詳しい方教えてください>_<
k3sをdocker-composeで起動する

## ソース取得

```
git clone git@github.com:rancher/k3s.git
```

## 起動する

```
cd k3s
K3S_TOKEN=${RANDOM}${RANDOM}${RANDOM} docker-compose up -d
```

## kubectlに設定を参照するようにする

```
export KUBECONFIG=./kubeconfig.yaml
```

## nodesを取得してみる

```
kubectl get nodes
```

### 出力

```
NAME           STATUS   ROLES    AGE   VERSION
65e2440e6916   Ready    <none>   11m   v1.19.4+k3s1
774f7268c91f   Ready    master   11m   v1.19.4+k3s1
```

## dashboardをインストールする

```
GITHUB_URL=https://github.com/kubernetes/dashboard/releases
VERSION_KUBE_DASHBOARD=$(curl -w '%{url_effective}' -I -L -s -S ${GITHUB_URL}/latest -o /dev/null | sed -e 's|.*/||')
kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/${VERSION_KUBE_DASHBOARD}/aio/deploy/recommended.yaml
```

```
 echo 'apiVersion: v1                                                                                                                                                                    
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard' | kubectl apply -f -
```

```
echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard' | kubectl apply -f -
```

### tokenを取得する

```
kubectl -n kubernetes-dashboard describe secret admin-user-token | grep "^token"
```

### proxyを起動してdashboardにアクセスする

```
kubectl proxy
```

```
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/193a22ab-fbb1-af86-a3b9-c1e1f19c1655.png)


## refs

* [rancher/k3s: Lightweight Kubernetes](https://github.com/rancher/k3s)
* [Rancher Docs: Kubernetes Dashboard](https://rancher.com/docs/k3s/latest/en/installation/kube-dashboard/)
Latexで「舘 暲」を引用する方法

#課題　「舘 暲」が引用できない
Latexで舘暲や山﨑ＯＯなどの著者の参考文献を引用しようとすると，エラーが出る

```
Latex failed to resolve 2 reference(s)
```

#原因　「暲」「﨑」などはデフォルトのＬａｔｅｘで取り扱えない文字（環境依存文字）
「暲」「﨑」などはデフォルトのＬａｔｅｘで取り扱えない文字（環境依存文字）であることが原因


#解決方法　\UTF{66B2}や\UTF{FA11}に置き換える
文字をUTFコードに置き換えることで解決する。

1.otfパッケージを使用する（次の１行をソースファイル中に追加）

```
\usepackage{otf}
```
2.環境依存文字を次のように置き換える「暲」→\UTF{66B2}、「﨑」→\UTF{FA11}

他の環境依存文字の場合も、UTFコードをネットで検索することで同様に解決できる。


```


@article{Yamazaki,
  title={整合的な視触覚刺激がテレイグジスタンスにおける自己位置定位に与える影響},
  author={山\UTF{FA11} 喬輔 and 井上 康之 and MHD Yamen Saraiji and 加藤 史洋 and 舘 \UTF{66B2}},
  journal={日本バーチャルリアリティ学会論文誌},
  volume={23},
  number={3},
  pages={119-127},
  year={2018},
  doi={10.18974/tvrsj.23.3_119}
}

```

##参考
https://minowalab.org/solution_latexmk_package_inputenc_unicode_character/

http://ishikawa-vision.org/~naoko/keisu-style/otftest.pdf

http://osksn2.hep.sci.osaka-u.ac.jp/~taku/osx/gaiji.html
レイヤーパターンについて　備忘録

備忘録のため、レイヤパターンについてまとめる。

### レイヤパターンとは？？
レイヤパターンとはアーキテクチャパターンの1つ。レイヤーパターンはシステムを階層化し、上位レイヤが下位レイヤの提供する機能を利用することで、各レイヤの作りを単純化していく考え方。ここでポイントなのが、各レイヤはそのレイヤが依存する直接下位レイヤ以外を知る必要がない。例えば下図では、レイヤ２はその下位レイヤであるレイヤ3に依存する。レイヤ2が意識するのはレイヤ2自身とレイヤ3のみであり、上位レイヤであるレイヤ１やレイヤ３より下位のレイヤを意識する必要がない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602844/39298f3a-c98b-df07-d46e-0e5cd67dabe8.png)

このように設計することで各レイヤの責務を明確にすることができ、各レイヤがその責務を全うできるように開発するだけで、システム全体がうまく動かすことができる。

### webアプリケーションでの一般的なレイヤ
webアプリケーションのレイヤの分離の仕方は下図の分け方が一般的な分け方になっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602844/8e63596b-ba07-71ca-1e13-f110f2a31d4d.png)

#### プレゼンテーション層
プレゼンテーション像とは、システム利用者とのインターフェースを担当するレイヤ。Webブラウザを通してユーザからの入力を受け付けて下位レイヤであるビジネスロジック層へ渡し、その処理結果を再びWebブラウザへ表示させたり、画面遷移を制御したりといったことを担当するのがその役目。

#### ビジネスロジック層
ビジネスロジック層は、アプリケーションが実現すべき固有の処理を実行するためのレイヤ。ビジネスロジックは、ユーザが入力した情報をプレゼンテーション層から受け取り、必要に応じてデータアクセスそうを通じてデータベースを利用し、処理を実行する。処理結果は再びプレゼンテーション層へ返す。

#### データアクセス層
データアクセス層は、ビジネスロジックとデータベースの仲立ちを行うためのレイヤ。データベースへアクセスするためには、多くのコードを記述しなければならない。このような処理をビジネスロジック層から切り離し、データベースへの細かなアクセス手順を意識せずとも利用できるようにすることが、データアクセス層の役割となる。

#### MVCモデルとの関係
MVCモデルもアーキテクチャーパターンの１つだが、レイヤパターンと相反するものでなく、下図のような関係である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602844/1c97f1ef-d6bc-0b6d-c60c-2db636ee6f01.png)

コントローラとビューがそのままプレゼンテーション層となり、モデルはビジネスロジック層とデータアクセス層に分かれる。Webアプリケーションで頻繁に発生するデータベースへのアクセス処理をデータアクセス層に分離することで、ビジネスロジック層とデータアクセス層、それぞれの開発がよりシンプルに行えるようになる。

参考
プロになるためのWeb技術入門
JUCEメモ ~ノートONトリガーについて~

# ノートONトリガーメモ
主にSynthesiserクラスの中でも重要なnoteOn関数についてメモする事が目的になっています。

**参考文献：「JUCE JAPAN 2018: JUCEで作ろう！ VST/AUプラグイン ～シンセサイザー制作記録～」**
(とても参考になるのでJUCEでの制作を行いたい人は購入すると良いと思います)

## ノートONトリガーとは
* MIDIキーボード等から受け取るノートONメッセージをトリガーとしてオーディオレンダリングを行う際のトリガー部分

* SynthesiserクラスがnoteOn関数を持っており、この関数はノートONメッセージを受信した事を検知すると発生する

## noteON関数について
### 行われる処理の流れ
1. Sythesiserクラスに登録されたサウンドクラスに対して、ノートONメッセージで受け取ったノート番号とチャンネル番号がトリガー可能であるかをbool型で判別する。**この判別関数はSynthesiserSoundクラスの中にあり、基本的にはSynthesiserSoundクラスを継承した独自のクラスにappliesToNoteメンバ関数をoverrideして、独自にトリガーを許可する範囲を設定する**

2. もし、すでに同じノート番号andチャンネル番号をレンダリングしていたVoiceがあれば、ノートOFFトリガーを送る(ノートOFFトリガーを送る関数はstopVoice関数)

3. 指定したノート番号andチャンネル番号がトリガー可能であれば、状態がフリーでレンダリングが可能なVoiceオブジェクトを検索する(findFreeVoice関数)

4.  特定したVoiceオブジェクトに対してノートONトリガーを送る(startVoice関数)

## StartVoice関数について
### 役割
findFreeVoice関数から取得したボイスクラスに対してノートONトリガーを送る関数

### 行われる処理
* ボイスがレンダリング実行中だった場合、レンダリングを強制終了して新しいノートをレンダリング出来るようにする(ボイススチール処理)
* ボイスのメンバ変数に次回のバッファからレンダリングするノート番号、チャンネル番号等の各種データをセットする
* ボイスに対してのレンダリング処理を開始する準備処理を呼び出す(startNote関数)
PoseNetをローカルで動かしてみた

#概要
PoseNetを使用してWebアプリを作りたい。
ローカルで動作するまでの手順を、[こちら](https://github.com/tensorflow/tfjs-models/tree/master/posenet)を参考に内容をまとめた。

##PoseNetとは
様々なサイトで紹介されているが、Googleが公開した骨格推定が可能なオープンソース（Apacheライセンス2.0）。
ブラウザで動くため、JavaScript,HTMLが書ければ開発が容易にできる。[デモ](https://storage.googleapis.com/tfjs-models/demos/posenet/camera.html)
Python版もあるらしい（[こちら](https://github.com/rwightman/posenet-python)）
![camera.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471496/21aeec6f-ccea-f059-e026-9d8f65d83801.gif)
参考URL：https://github.com/tensorflow/tfjs-models/tree/master/posenet


#環境
OS：macOS Catalina ver10.15.6 (メモリ8GB)
デフォルトでデモは12fps出ました！！

#ローカル環境構築

ここからは備忘録として環境構築方法を残しておく。
今回の環境ではgitのみインストールしてあるためgitのインストール方法は割愛する。

基本的には[Github](https://github.com/tensorflow/tfjs-models/tree/master/posenet)の内容と同じです。

####○gitからcloneする
作業ディレクトリに移動して以下のコマンドでGitHubからcloneする。

```sh:
$ git clone https://github.com/tensorflow/tfjs-models.git
```
####○yarnをインストール
まず始めに、javaScript環境を用意するために[こちら] (https://nodejs.org/ja/)からNode.jsをインストールしてください。
yarnとは、javaScriptのパッケージを簡単に管理してくれるパッケージマネージャーです。


```sh:
$ brew install yarn
```
※Homebrewをインストールしていない人は別途インストールしてから実行してください。
下記コマンドでインストール出来ているか確認しましょう。

```sh:
$ yarn --version
```
####○yarnローカル環境にビルドする
tfjs-modelsフォルダに入った状態で下記コマンドを実行してください。

```sh:
$ cd posenet
$ yarn
$ yarn build && yarn yalc publish
```

```sh:
$ cd demos
$ yarn
$ yarn yalc link @tensorflow-models/posenet
```

ここまで成功したら

```sh:
$ yarn watch
```
でローカルサーバーが起動してPoseNetがのでもが起動します。
あとはcamera.htmlとcamera.jsを修正して開発していきましょう！
【自分メモ】ストロングパラメータ

外部からの不正なアクセスを受け付けないようにするものです。

例えば、新規投稿したデータをデータベースに保存する際、新規投稿ではない別のデータを保存するように書き換える人がいました。そうすることで、本来なら公開されないはずの情報を操作されてしまい、不正に情報が流出してしまうきっかけになります。
そのような不正なアクセスを受けなくするため、ストロングパラメータにて「カラムを登録したモデル(オブジェクト)しかデータは持って来れませんよ〜」と記入し、加えてprivate下に置くことで特定のコントローラーでしか呼び出せないようにしました。(また、private下に定義することでストロングパラメータはアクションとして認識されなくなります)

また、ストロングパラメータはマスアサインメント脆弱性というセキュリティ上の問題を解決するために設定するものになります。


※自分の考えをメモとして残していますので、間違っていたり修正した方が良い点がございましたら、ドシドシつっこみいただけると嬉しいです！
vimをアップデートするスクリプト

# vimをアップデートしたい
　とあるパソコン詳しい友人に勧められてvimを使い始めて半年くらい経つ。
　最初は友人が作ったdotfilesのvimrcをまんま使っていたけど、少しづつ自分用にカスタマイズした。
　そしてある日友人に自分の設定を見せた。
　そして言われた。

「vimのバージョン古くね？」

　そう言われりゃそうだ。osのリポジトリからaptで入れてるんだから最新であるはずがない。だったらgithubから落としてコンパイルしよう。
# vimコンパイル
　まずはvimのリポジトリ探そうって思ったら一瞬で見つかった。
[vim/vim](https://github.com/vim/vim)
　なるほど、ものすごく頻繁にアップデートされているようだ。
　まずはREADMEを熟読。ファイルをいくつか辿ってわかったことは、 /path/to/vimsource/src で

```
$ ./configure
$ make
$ sudo make install
```

するだけということ。ただしPythonとかを有効にするには、 ./configure のときにオプションが必要らしい。
　とりあえずやってみよう。

```
$ mkdir ~/github/
$ cd ~/github/
$ git clone https://github.com/vim/vim.git
$ cd ./vim/src/
$ ./configure --enable-multibyte \
    --enable-luainterp \
    --enable-perlinterp \
    --enable-pythoninterp \
    --enable-python3interp \
    --enable-rubyinterp \
    --enable-luainterp \
    --disable-gui
$ make
$ sudo make install
```

特にエラーとかも無くできた。コンパイルオプションは、1つ目の --enable-multibyte で日本語を表示出来るようにして、 --enable-*interp で各言語のインタプリタ(？)を有効化して、 --disable-gui でguiを無効化した。vimが最新。嬉しい。
　ひとつ問題がある。前述した通りvimはめっちゃ頻繁に更新される。できるだけ最新でいたいから頻繁にアップデートしたい。そうなるといちいちこのコマンドを実行するのはめんどくさい。
　よし、スクリプトにしてしまおう。
# vim更新スクリプト
以下が完成形。

```text:update-vim
#!/bin/bash
#インターネットに繋がるか確認
Exec=`nslookup github.com | grep 'timed out' | wc -l`
if [ ${Exec} -ne 0 ]; then
    echo "${Exec}[Error] No Internet Connection!"
    exit
fi
echo "[Info] Updating Repository"
cd ~/github/vim
git pull origin master
echo "[Info] Configuring"
cd ~/github/vim/src
make distclean
confop="--enable-multibyte "
confop="${confop}--enable-luainterp "
confop="${confop}--enable-perlinterp "
confop="${confop}--enable-pythoninterp "
confop="${confop}--enable-python3interp "
confop="${confop}--enable-rubyinterp "
confop="${confop}--enable-luainterp "
confop="${confop}--disable-gui"
./configure ${confop}
echo "[Info] Making"
make -j2
echo "[Info] Installing"
sudo make install
echo "[Info] Finished!"
```

　~/github/vim にvimのリポジトリがあるのを前提としている。
'make -j2' となっているのはスレッド数を表しているから環境によって変える。
　あとはこれを ~/bin/update-vim に保存して、

```
$ chmod a+x ~/bin/update-vim
```

として、 ~/bin にパスを通してやれば完成！
次からは

```
$ update-vim
```

としてやればいい。
(sudoが使えない環境ではrootでログインして実行しなきゃだけど。)
# さいごに...
　別の日に友人に
「vimの設定みせて」
って言って、バージョンを見たら自分より低かったから、
「vimのバージョン古くね？(ドヤッ)」
と言ってやった。
ログイン時のデータ取得について書いてみた

ログインしている人がフォームで何かデータを入力することが多いと思いますががそのデータ入力時に
ログインしている人のidも取得したいと思うことがある。そんな時のやり方がわからなかったので
ここに忘備録として書いておきます。

```
 <form method="post" action="{{route('post.store')}}">
 @csrf

 <input type="hidden" id="user_id" value="{{Auth::id()}}">

 <textarea name ="message"class="form-control" id="exampleFormControlTextarea1" 
 rows="3"></textarea>
 </form>
```

type="hidden" を使うことでフロントには表示されずにフォームに登録することができます。
また、value="{{Auth:id( )}}"とありますがこれは今現在ログインしている人のidをフォームに入力しているという意味になります。


いやー。Auth::idの書き方を知らなかったので解決するのに１日かかってしまいました。
基礎がしっかりしていないと大変な目に遭いますね。これでみなさんも
ログイン時のid検出の仕方忘れた場合は利用してみてください。
【Java】戻り値についてのメモ

# 戻り値 ( 返り値 )
[メソッド]には、[メソッド]の呼び出し元に[メソッド]からの特定の情報を返すという仕組みがあり、その返される特定の情報のことを 「戻り値( 返り値 )」return 値 の部分 といいます。

##戻り値とは？
個人的に一番わかり易い例えだったのが「 **ググる** 」という行為に例えた場合です。

1. 「[引数]」:入力された検索ワード
2. 「[メソッド]」を実行:検索ボタンを押す
3. 「**戻り値**」：条件に合う記事情報が **配列**として返却

戻り値の型 = return文に指定する処理結果の型

## 戻り値の返し方
「戻り値」がある場合は、**「処理の結果を返す必要」**があります。

返し方は以下です。

```
1. return文 を記述
2. 処理結果を呼び出し元へ返す
```

その時、 戻り値の型 と return文に指定する処理結果の型 が合ってなければなりません。


## void

メソッドの処理結果を呼び出し元へ返す必要がない場合は、
戻り値の型を**「 void 」** と記述して、戻り値なしの[メソッド]にします。
### voidとは 
**「この[メソッド]の戻り値は返しません（ありません）」** という意味のキーワードになります。

### 【voidを記述しない】 戻り値があるメソッド例
こちらは、[引数]に渡された x と y の値を加算し、加算結果を呼び出し元へ返す[メソッド]です。
「計算結果をほかの計算に使う」ため、voi

```java
//計算結果は、別の計算に用いる予定があるため、void を記述しない

public int plus(int x, int y) {
    return x + y;
}
```

### 【void を使用する】 戻り値のないメソッド例
こちらは、 **フィールド「message」の内容を画面に表示するメソッド**
です。「表示をするだけで、結果を他に使用しない」ので、戻り値をなしにします。

```java

public void print() {
    System.out.println(message);
}
```

### 使用例
「こちらは、商品の税抜き価格に消費税を足して、税込価格と税抜き価格の両方を表示する」プログラムです。

```java
public class Main {

    public static void main(String[] args) {

        double price = 980; // 商品の値段
        final double taxRate = 1.1; // 消費税率 10%

        double inTaxPrice = calcInTax(price, taxRate);

        printAllPrice(price, inTaxPrice);

    }

    public static double calcInTax(double price, double taxRate) {
        // TODO 自動生成されたメソッド・スタブ
        return price * taxRate;
    }

    public static void printAllPrice(double price, double inTaxPrice) {
        System.out.println("税抜き価格は " + price + "円です。");
        System.out.println("税込み価格は " + inTaxPrice + "円です。");
    }

}
```
実行結果

```
税抜き価格は 980.0円です。
税込み価格は 1078.0円です。
```

### コード解説

1. 税込価格計算に必要な「税抜き価格」と「消費税率」を格納。消費税率は final を記述して定数に。
2. 1で用意した変数、定数を calcInTaxメソッド で計算してもらい、返り値を inTaxPrice(税込価格)に格納する
3. price と intaxPrice をprintAllPriceメソッドに渡して、メッセージを表示する。

[メソッド]には、戻り値があって[引数]がないパターンや、
戻り値がなくて[引数]があるパターンなど、自由自在に作成することが可能です。
プログラミングの用途に合わせて、自分自身でどのパターンのメソッドにするか決めて作成します。

[インスタンス]:https://qiita.com/takahirocook/items/ec01cdcbb440cf0d1cc4
[インスタンス化]:https://qiita.com/takahirocook/items/ec01cdcbb440cf0d1cc4
[アクセス修飾子]:https://qiita.com/takahirocook/items/e51b0b9d37d95ad587fe
[フィールド変数]:https://qiita.com/takahirocook/items/28df75a133049a74ece1
[new演算子]:https://qiita.com/takahirocook/items/00f9f97592bf50831d39
[カプセル化]:https://qiita.com/takahirocook/items/e469a7c0539a0012868e
[クラス]:https://qiita.com/takahirocook/items/50cbbdca8e21539170e9
[メソッド]:https://qiita.com/takahirocook/items/5bfe43576d87a2a4006c
[mainメソッド]:https://qiita.com/takahirocook/items/f4635915337303de338c
[メソッドの呼び出し]:https://qiita.com/takahirocook/items/f4635915337303de338c
[コンストラクタ]:(https://qiita.com/takahirocook/items/fa1822f2f22c3786593e)
[引数]:https://qiita.com/takahirocook/items/5e5b0ba79e869f4a592e
RでExcelに記述統計・画像を挿入する

# はじめに
Rで分析結果の提出を求められた際に、「Excelに分析結果の画像も貼って」と言われた対応したら案外時間がかかったので備忘録


# 概要

```r:test.r

# パッケージの読み込み
library(psych)
library(ggplot2)
library(reshape2)
library(openxlsx)
library(tablaxlsx)
library(imager)

# 縦書き関数（図軸ラベル用）
tategaki = function(x) {
  x = chartr("ー", "丨", x) # 長音符の処理
  x = strsplit(split="", x)
  sapply(x, paste, collapse="\n")
}


### 前準備 ###
# ディレクトリの設定（Passが作業場所、\→/に変換）
# 整理のために親ディレクトリ下部に「data（読み込み用データ）」「output（出力データ）」を作っている
Pass<-'C:/test'
DataPass<-paste(Pass,'data',sep = '/')
OutputPass<-paste(Pass,'output',sep = '/')
setwd(Pass) #デフォルトWD指定

# テストデータの読み込み（アヤメのがくの長さと幅）
data <- melt(iris[1:2]) #縦持ちに変換
setwd(OutputPass) #出力フォルダに移動

# 新規Excelワークブック・シート作成
wname <- paste('test', '.xlsx', sep = '') #ワークブック名
sname <- 'test' #シート名
gname <- paste('test', '.png', sep = '') #グラフの出力ファイル名

wb <- createWorkbook() #ワークブックの作成
addWorksheet(wb, sheetName = sname) #シートの作成


### 処理 ###
#テーブル描き出し（分析結果など）
escribirTabla(tabla = t(describe(iris['Sepal.Length'])), wb, hoja = sname,cabecera = '記述統計',
              fuente = '注記', fila = 2, columna = 2,
              limpiarFilas = F, cabecerasFila = T, limpiarColumnas = F, 
              bordes = c('TABLA', 'CABECERA', 'CABECERASFILA', 'CABECERASCOLUMNA', 'DATOS'))
writeData(wb, sheet = sname, x = '色々加筆可能', startCol = 2, startRow = 19)


#作図描き出し
g <- ggplot(data, aes(x = value, fill = variable))
g <- g + geom_histogram()
g <- g + ggtitle('ヒストグラム')
g <- g + xlab('長さ(cm)')
g <- g + ylab(tategaki('サンプル数'))
g <- g + theme(axis.title.y = element_text(angle = 0, vjust= 0.5))
g <- g + geom_histogram(position = "identity", alpha = 0.8, binwidth = 0.1)
# plot(g)  # 画面で確認

ggsave(file = gname, plot = g, width = 5, height = 3) #グラフを保存
pic <- paste(OutputPass,gname,sep = '/') #グラフのパスを取得
img <- load.image(gname) #imagerパッケージで画像情報を取得
#画像書き出し（横、高さはimagerパッケージで取得、適当な倍率で修正）
insertImage(wb, sname, pic, startRow = 2, startCol = 6, 
            units = "px", width = dim(img)[1]*1.2, height = dim(img)[2]*1.2)


### 後処理 ###
saveWorkbook(wb, file = wname, overwrite = TRUE) #ファイルの保存
setwd(Pass) # 親ディレクトリに戻す

```
# 終わりに
200ぐらいの変数について、基データを渡せず、集計結果だけしか開示できないというしばりがあったのでこんな感じに。しかも先方からExcelでの提出指定。データのやり取り方法をそもそも整備しておくことが必要だった…。
貼り付け時のグラフ比率を出力に任せたまま倍率を変更したかったのでimagerパッケージを使用。普通にggsaveで縦横を指定してもよかったけど、そのまま張り付けるとなんか縦横比が変…。

# 参考
- [Rで解析:エクセルへの表出力が簡単です「tablaxlsx」パッケージ](https://www.karada-good.net/analyticsr/r-417)
- [Rでグラフを描くときにY軸のタイトルを縦書きにする](https://id.fnshr.info/2017/03/13/r-plot-tategaki/)
- [insertImage](https://www.rdocumentation.org/packages/openxlsx/versions/4.2.3/topics/insertImage)
- [escribirTabla](https://www.rdocumentation.org/packages/tablaxlsx/versions/1.2.4/topics/escribirTabla)
Rails + Postgres + Docker でhello worldを表示するまでを簡単に

アプリ作成時に毎回調べている気がするので、備忘録的にまとめてみました。
下記の`app名`の箇所には適宜アプリ名を入力して下さい。

※間違いがありましたら変更しますのでコメント頂けると嬉しいです^^

## 新規ディレクトリ作成 〜 hello world!!まで  

まず、アプリの土台となるディレクトリを作ります。
さらに、touchコマンドで、2つの空ファイルを作成します。

``` terminal
$ mkdir app名 && cd app名
$ touch Gemfile Gemfile.lock
```  

私は、VScodeを使用して開発しているので
code コマンドを使用して起動しています。
ちなみに、code コマンドは起動と作成をしてくれます。

Gemfileを編集します。

```terminal
$ code Gemfile
```

```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5.2'
```

Dockerfileを作成して編集します。

```terminal
$ code Dockerfile
```

```ruby:Dockerfile

FROM ruby:2.5
RUN apt-get update
RUN apt-get install -y \ 
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn \
    vim

WORKDIR /app名
COPY Gemfile Gemfile.lock /app名/
RUN bundle install
```

docker-compose.ymlファイルを作成して編集します。


```terminal
$ code docker-compose.yml
```

```ruby:docker-compose.yml
version: "3"

volumes:
  db-data:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ".:/app名"
    environment:
      - "DATABASE_PASSWORD=postgres"
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db

  db:
    image: postgres
    volumes:
      - "db-data:/var/lib/postgresql/data"
    environment:
      - "POSTGRES_HOST_AUTH_METHOD=trust"
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=postgres"
```

コンテナの起動を行い、webコンテナに入って、rails new します。

```terminal
$ docker-compose up --build -d
$ docker-compose exec web bash
$ rails new . --force --database=postgresql
```
rails new で作成された database.yml ファイルに追記します。

```ruby:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db  #追記
  user: postgres  #追記
  port: 5432  #追記
  password: <%= ENV.fetch("DATABASE_PASSWORD") %>  #追記
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```

```terminal
$ rails db:migrate
$ rails s -b 0.0.0.0
```
Chromeの検索バーに、localhost:3000 と入力してアクセスするとhello worldが表示されているかと思います！
Simulinkでオフディレイ(OFF-delay)

# 概要
[オンディレイの記事](https://qiita.com/bunnyhopper_isolated/items/09ab551fdeadfdcf5920)
の続きです。

R2020bでは以下で実装されてますが、追加で金が掛かりそうです。
https://jp.mathworks.com/help/physmod/sps/powersys/ref/onoffdelay.html

今回はオフディレイを実装します。
オフディレイの詳細は以下を参考に。
[Panasonic解説サイト](https://ac-blog.panasonic.co.jp/%E3%82%BF%E3%82%A4%E3%83%9E%E3%81%AE%E3%82%AA%E3%83%B3%E3%83%87%E3%82%A3%E3%83%AC-%E3%81%A8%E3%82%AA%E3%83%95%E3%83%87%E3%82%A3%E3%83%AC-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

# 環境
| name | Ver |
|:-----------|------------:|
| OS       | Ubuntu 20.04LTS|
| CPU     | AMD Ryzen 9 3900XT      |
| matlab     | R2020b      |

# モデル設定
0.1秒のオフディレイを作ってみます。
ON delay1は[オンディレイの記事](https://qiita.com/bunnyhopper_isolated/items/09ab551fdeadfdcf5920)からそのまま持ってきています。

![Screenshot from 2020-11-23 14-23-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485117/623c6dc3-1e64-16ed-1cb3-dfce840ad9a3.png)

入力OFFトリガをSR-FFで保持し、それをオンディレイの時間差で折るという感じです。
連続の入力にも耐えられるように、入力のUPトリガでも保持を折るようにしています。

# テスト
狙い通りの動作をしています。
意地悪で0.09秒の入力ONの谷間を入力してます。意図通り、最後のOFF後0.1秒後に出力OFFになってます。

![Screenshot from 2020-11-23 14-24-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485117/2ec4697c-478a-af93-3786-b75d3a9abe76.png)

ただし、ループエラー回避のためにオンディレイの出力にdelayブロックを使っているので、以下のように出力OFF際を拡大すると、、、
![Screenshot from 2020-11-23 14-37-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485117/3190e309-556f-34e2-f464-b2ea8d864bdb.png)

厳密には0.1ディレイではなく、サンプル時間として指定した0.001秒のズレが発生しています。

# あとがき
オフディレイって言葉に表すと簡単ですが、実装はこれほど複雑になってしまうのは興味深いですね。
あと、SR-FF使う上で懸念するべき不定状態に関しては対応出来ていないので、利用する際はお気をつけください。
Prettier(フォーマッタ) => ESLint(静的解析)の設定

## これはなに

タイトルの内容についての2020年11月23日時点でのメモ。

## やること

プロジェクトのディレクトリにてCLIで

```
$ npm init -y //package.json
$ npm install -D prettier eslint eslint-config-prettier
```

次に、`./node_modules/.bin`のPATHを通す

PATHを通したら、

```
$ code -r .eslintrc.json .prettierrc
```

`.eslintrc.json`は以下のようにする（ミニマルな形）

```json:.eslintrc.json
{
  "env": {
    "es6": true
  },
  "extends": ["prettier"]
}
```

**注意**として、`extends`の配列に`"eslint:recommended"`を入れると失敗しました

`.prettierrc`は以下のようにする（わたしのばあい）

ESLintはフォーマッタとして使用しないので、このファイルに細かいルールを書いていく

ちなみに`tabwidth`はデフォルトで2なので書かなくてもいい

```json:.prettierrc
{
    "tabWidth": 2,
    "singleQuote": true
}
```

最後に、`settings.json`に以下を追加

```json:settings.json
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
```

ここまでやって、

VSCodeの右下にある`ESLint`と`Prettier`にチェックがついて、ファイルを保存したときに両方行われていればOK.


## 参考

- [VS Code で ESLint × Prettier のベストかも知れないプラクティス](https://qiita.com/iShinkai/items/6f65b042618b76525659)
- [VSCodeでESLint+typescript-eslint+Prettierを導入する](https://qiita.com/madono/items/a134e904e891c5cb1d20)
【自分用】マイグレーション関連【ロールバック、カラムの追加、型の変更】

完全に自分用の書き殴りです。  
誤り等ございましたら、コメント下さい！

## ロールバック

- `rails db:migrate:down VERSION=20190611235049`
  - `VERSION`で指定した箇所まで戻れる
- `rails db:rollback STEP=3`
  - 現在の migration ファイルから遡って、`STEP`で指定した回数戻れる

## カラムの追加

1. `rails g migration Addカラム名Toテーブル名 @@@:integer @@@:string`
2. `rails db:migrate`

- Add 以下はキャメルケースで記載
- カラム名のところは何を書いてもいいが、追加したいカラム名の複数形に統一しておく
- テーブル名にはカラムを追加するテーブル名の**複数形**を書く
- `@@@`はカラム名を**単数形**で記入

以下は user テーブルにふりがなを追加したときの例。

```ruby
class AddKanaToUser < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :kana, :string
  end
end
```

## カラム型の変更

`rails g migration change_data_<カラム名>_to_<テーブル名の複数形>`

```ruby
class ChangeColumnToUsers < ActiveRecord::Migration[5.2]
  def change
  end
end
```

上記のように空の migration ファイルが作成されるので、下記のように編集

```ruby
class ChangeColumnToUser < ActiveRecord::Migration[5.2]
  def up
    change_column :users, :detail, :text
  end

  def down
    change_column :users, :detail, :string
  end
end
```

## 注意点

**カラムの追加**と**カラム型の変更**では、方法がやや異なっていて、migration ファイルを触る時は、追加(up)するだけでなく、削除(down)するときのことも考えなければならない。  
つまり、**カラムの追加**では、change で書いても rollback 時など down する際にもよしなにしてくれるが、**カラム型の変更**で change を使ってしまうと、up 時は良くても、down 時に rollback できないというようなことが起こってしまう。ということ。  
簡単なことだが、ここを理解したときに、migration ファイルに対する怖さが一気に消えた。

## おまけ

これからは上記の様に書くとして、これまでに書いてしまった箇所を rollback するさいはどうすればいいのか...  
これは簡単で、今ある migration ファイルの change と記載している箇所を、up に上書き変更して、その下に down 時の動作を追記すればよい。down 時の動作は変更前のカラム型のこと。  
なんとなく、migration ファイルを上書きするのは怖かったが、これで問題なく動作した。
実務経験で身につけた技術　～PHP編～

#はじめに
未経験から実務経験２か月ちょっとを経て、1つのサイトを完成させることができたので（もちろん色々な人の手助けあってですが）、今後に生かすインプットと自分の備忘録としてPHP、JavaScript・jQuery、HTML・CSSの３つに分けて記録していきます。
この記事では、**PHP(FWのEthna含む)について**書いていきます。
なお、身につけた技術は随時、記録・更新していきます。
他の記事については、下記のリンク先からご覧ください。

<details><summary>別の記事のリンク</summary>
<div>
[実務経験で身につけた技術　～JavasScript・jQuery編～](https://qiita.com/hx_kei/items/ff8ff0e98b2545b5e37e "実務経験で身につけた技術　～JavasScript・jQuery編～")
[実務経験で身につけた技術　～HTML・CSS編～](https://qiita.com/hx_kei/items/2079aa122f779081271c "実務経験で身につけた技術　～HTML・CSS編～")
</div>
</details>

#PHP
###foreach
```
//$test_listは多次元配列
foreach($test_list as $key=>$value){
 $test_list['user'] = $value['user'];
}
$this->af->setApp('test',$test);
```
多次元配列（配列に配列を持つもの）の`$test_list`を`$value`で置き換えることで、本来は`$test_list[$key]['user']`を`$value['user']`で取り出すことができる。
[キー]の部分をforeachが0,1,2~と当てはめているイメージ。
最後にsetAppとすれば呼び出し時、`{{foreach from=$app.test_list item=value key=key}}`で呼び出せる。
itemにforeachと同じvalue、keyにkeyで呼び出し時も`$value.user(PHPは['user'])、配列のキーも$key`で呼び出せる。

```
$test_list = array('name1_'.$key,'name2_'.$key<中略>);
foreach($test_list as $form_name){
  //配列のエラー処理
}
```
普通の連想配列である`$test`の中身を一つずつエラー検証するために利用。
上記の処理なら```'name1_'.$key```としているので、name1_0、name1_1~に該当する複数の値に対してもエラーチェックすることができる。

###explode
```
//$test_listは多次元配列
$tel = explode('-',test_list[$key]['tel']); //'-'を基準に文字列を分割
$test_list[$key]['tel1'] = $tel[0];
$test_list[$key]['tel2'] = $tel[1];
$test_list[$key]['tel3'] = $tel[2];
```
explode(引数1、引数2、引数3)。
引数1：区切り文字(separator)
引数2：文字列(string)
引数3：戻り値として返す、配列の最大要素数(delimiter)
上記により、-で文字が区切られ、電話番号であれば、3つの配列を`$tel`は与えられる。
よって一つ目を呼び出すときには、`$tel[0]`と指定する。

###変数定義
```
class Web_Form_FormAdd extends Web_ActionForm
{
    protected $form = array(
    	'test' => array(
			'type'      => VAR_TYPE_STRING,
			'name'      => 'テスト',
			'required'  => true,
    	),
<中略>
}
```
値の定義。ethnaでは、DBでのテーブル設計と同じように値を定義したり、required 属性をつけることができる。
trueでエラーが起きたらSmartyのプラグインで作成したfunction message.phpのエラーメッセージを表示させる。



#最後に
まとめることでなんとなく理解していた箇所をクリアに理解することができました。
まだ全然書ききれていないので、随時更新します。
今後もアウトプットした分だけインプットするよう心掛けていきます。
Visual Transformersを動かして、Cifar10で87%は超えた、しかし、その程度。

#概要
以下のgithubに、Visual Transformersの実装が示されていたので、動かしてみた。いわゆるViTとは、違います。

https://github.com/tahmid0007/VisualTransformers

対象、cifar10とした。

#結果

87.31%は出た。↓。

```
Epoch: 146
[    0/50000 (  0%)]  Loss: 0.1898
[10000/50000 ( 20%)]  Loss: 0.2894
[20000/50000 ( 40%)]  Loss: 0.2176
[30000/50000 ( 60%)]  Loss: 0.2305
[40000/50000 ( 80%)]  Loss: 0.1947
Execution time: 415.95 seconds

Average test loss: 0.4371  Accuracy: 8675/10000 (86.75%)

Epoch: 147
[    0/50000 (  0%)]  Loss: 0.2177
[10000/50000 ( 20%)]  Loss: 0.1389
[20000/50000 ( 40%)]  Loss: 0.1795
[30000/50000 ( 60%)]  Loss: 0.1196
[40000/50000 ( 80%)]  Loss: 0.2700
Execution time: 415.79 seconds

Average test loss: 0.4492  Accuracy: 8617/10000 (86.17%)

Epoch: 148
[    0/50000 (  0%)]  Loss: 0.1744
[10000/50000 ( 20%)]  Loss: 0.2637
[20000/50000 ( 40%)]  Loss: 0.1871
[30000/50000 ( 60%)]  Loss: 0.1839
[40000/50000 ( 80%)]  Loss: 0.1576
Execution time: 415.13 seconds

Average test loss: 0.4565  Accuracy: 8668/10000 (86.68%)

Epoch: 149
[    0/50000 (  0%)]  Loss: 0.2141
[10000/50000 ( 20%)]  Loss: 0.1347
[20000/50000 ( 40%)]  Loss: 0.2369
[30000/50000 ( 60%)]  Loss: 0.1768
[40000/50000 ( 80%)]  Loss: 0.2369
Execution time: 416.12 seconds

Average test loss: 0.4136  Accuracy: 8731/10000 (★87.31%)
```

#まとめ
特にありません。
ViTもそうだが、あまり、いい結果はでない。
コメントなどあれば、お願いします。

#リンク
[ViT(Vision Transformer)を動かしてみた(4つ)、うっ、Cifar10で80%超えた、ぼちぼちくるかー。すべて他力です。cifar10、imagenet_resized/32x32、結果はまだ「？」付き。](https://qiita.com/hitonimonarukurohyo/items/b2812188d3ad24a1b629)
小ネタ：複数列での並び替え｜Power Query

最近までGUIではできないと思いこんでいたので、メモ。:sweat:

##結論
並び替えを書ける順で、列を指定しては並び替えボタンを押す、という操作を繰り返せばよい。
こうすると、最初の並び替え指示はリセットされずに合成され、複数列の並び替えとして処理される。
##例1：直感的な操作⇒上手くいかない。
複数列を指定した状態では、グレーアウトされて、並び替えボタンが押せません。
僕はここでGUIを諦めてしまっていました。一種の罠ですね。:expressionless:
![無題1123_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/43196991-7514-1871-1c36-5962212adfb2.png)
##例2：1個1個操作する⇒上手くいく。
こんなテーブルがあり、地域の昇順、金額の降順で並び替えたいとします。
![無題1123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/fcfe2e00-79b2-b545-41e4-a475725c2f69.png)

まず、地域列を選択して、並び替えの昇順ボタンを押します。
![無題1123_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/8d41fd62-3ae5-64f3-c4ce-7ac8d8c5a071.png)

次に、地域列で並び替えされたステップのまま、金額列だけを選択して、並び替えの降順ボタンを押します。
![無題1123_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/4bf162df-e0c3-941b-69ef-03486ac84a04.png)
すると、めでたく2列基準での並び替えになります。ちゃんと並び替え順の番号も出ていますね。
![無題1123_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/e125cfaf-f5fa-5bbc-7b9c-80dd8b820ca0.png)

画像にも出ていますが、生成されるコードは複合的な並び替え指示になっています。（`#"Changed Type"`は前のステップです）

```
= Table.Sort(#"Changed Type",{{"地域", Order.Ascending}, {"金額", Order.Descending}})
```


##テストした環境
Microsoft365のExcel（バージョン2011、64bit）
Power Query　2.87.224.0（64bit）
Pythonで設定ファイルを作ってみた

#Pythonベースで設定ファイル作ってみた
色々なファイル形式を使ったが、jsonとyaml、toml以外は可読性が低いことjsonはコメントが書けないことが不満だったのと、ラムダ式が入れれないのが不満なので作ってみた。

※以下の**Pyson**は**PY**thon **S**etting **O**bject **N**otationから。

```pyson.py
import sys
import argparse

class File(dict):
    @classmethod
    def Load(cls,path):
        data = None
        with open(path,'r',encoding="utf-8") as fln:
            var = []
            for f in fln.read():
                if(f.strip() == "" or f.strip()[0:1] == '#' or f.strip().split('(')[0] == '__import__'):
                    continue
                else:
                    var.append(f)
            data = cls.__Ld(var)
        ret = eval(data)
        return ret

    @classmethod
    def __Ld(cls,var):
        ret = ""
        for val in var:
            ret += val
        return ret

load = File.Load
```

```Classes.pyson
{
    "Vector3":lambda:[0 for var in range(3)],
    "Vector4":lambda:[0 for var in range(4)],
    "Matrix3x3":lambda:[[0 for x in range(3)]for y in range(3)],
    "Matrix4x4":lambda:[[0 for x in range(4)]for y in range(4)],
    #単位行列化
    "Identity":lambda mat:[[1 if x==y else 0 for x in range(len(mat[y]))]for y in range(len(mat))],
    "is_liveing":True
}
```

```Setting.pyson
(
    "1",True,3.5
)
```

```app.py
import pyson
ldfil = pyson.load("Classes.pyson")
stngfil = pyson.load("Setting.pyson")
mat = ldfil["Identity"](ldfil["Matrix4x4"]())
print("単位行列(4x4):",mat)
print("設定出来ている?:",stngfil[1])
```

```
単位行列(4x4):[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]
設定出来ている?:True
```

## 感想
結構満足できるものが作れられたので良かった。改良もやってみたい。
Djangoで「Invalid HTTP_HOST header」が出たときの対処

## 事象
```
Invalid HTTP_HOST header: '*.*.*.*:8000'. You may need to add '*.*.*.*' to ALLOWED_HOSTS.
```

## エラー内容
* 受け取ったサイト名とDjangoで設定しているサイト名が異なる。

## 原因
* 下記が未設定

```settings.py
ALLOWED_HOSTS = []
```

## 対処①
* アスタリスク(*)を設定する。
* セキュリティ的に望ましくないため検証などで利用する。

```settings.py
ALLOWED_HOSTS = ['*']
```

## 対処②
* 公開するサイトのFQDNを指定する。
* 本番サイトなどサイト名が決まっていればこちらが望ましい。

```settings.py
ALLOWED_HOSTS = ['www.example.com']
```

## 公式ドキュメント
* [ALLOWED_HOSTS](https://docs.djangoproject.com/en/3.1/ref/settings/#allowed-hosts)
ubuntu:20.04 dockerコンテナ内でホスト側にGUIを出力（xeyesを出力）する検討メモ

xhostの設定、ubuntu:20.04 dockerコンテナ起動

```
xhost local:
docker run -it -e DISPLAY="$DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix ubuntu:20.04
```

xeyesをインストールして実行

```
apt-get update -y; apt-get install -y x11-apps;
```

ホスト側にxeyesを出力できた

![Screenshot from 2020-11-23 11-37-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/dda65bd2-f61b-9ea4-7c9b-14d8f3765323.png)


# 追記、以下のnvidiaコンテナでもできた（nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04）

例１　nvidiaコンテナに変更

```
xhost local:
docker run -it -e DISPLAY="$DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04
```

例２　例１＋オプション追加

```
xhost local:
docker run -it -e DISPLAY="$DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix --gpus 1 nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04
```

以下は、nvidiaコンテナ利用手順
>参考
>[Docker(Ubuntu18.04+CUDA10.1+cudnn7)でOpenCV4.1.1インストールするメモ](https://qiita.com/nakasuke_/items/ec1b0636416df3c72db3#comments)
[Installation (Native GPU Support)](https://github.com/nvidia/nvidia-docker/wiki/Installation-(Native-GPU-Support))

```
sudo apt install curl
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey |   sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list |   sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt update
sudo apt-get install -y nvidia-container-toolkit
```

以下は、runして内部のコマンドを実行する場合の参考（nvidia-smiを実行）

```
docker run --gpus 1 nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04 nvidia-smi
```

# 参考
[Dockerコンテナの中でGUIアプリケーションを起動させる ](https://unskilled.site/docker%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%AE%E4%B8%AD%E3%81%A7gui%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%82%8B/)
[Ubuntu on Docker on UbuntuでGUIを表示する方法](https://qiita.com/mocobt/items/726024fa1abf54d843e1)

[DockerコンテナのホストでGUIを起動する](https://qiita.com/161abcd/items/9aa0d3dc3b38d7bf3f26)
[Dockerを導入してGUI操作可能なLinux(Ubuntu)コンテナを作成する](https://qiita.com/ryoya-s/items/ee1daf9cab18c100c990)
[dockerでGUIアプリ起動可能な環境構築 [クライアント <--> リモートサーバ <--> dockerコンテナ]](https://qiita.com/Neteru141/items/a6c9ec380a28220ef367)
[dockerでデスクトップ環境(GUI)を構築してみる。](https://qiita.com/tayusa/items/fe3e6490a0aeceea5ddb)
[DockerコンテナのホストでGUIを起動する](https://qiita.com/161abcd/items/9aa0d3dc3b38d7bf3f26)
Rubyで文字列を大文字（upcase）にする、又は小文字にする(downcase)方法

Ruby 2.7.0の記事です

- upcase　全ての小文字を対応する大文字に置き換えた文字列を返す<br><a href="https://docs.ruby-lang.org/ja/latest/method/String/i/upcase.html">公式ドキュメントStringクラスupcase</a>
- downcase　全ての大文字を対応する小文字に置き換えた文字列を返す<br><a href="https://docs.ruby-lang.org/ja/latest/method/String/i/downcase.html">公式ドキュメントStringクラスdowncase</a>

```ruby
puts "STring".upcase # => "STRING"
puts "STring".downcase # => "string"
```