OmniAICreator/Qiita-1.07M huggingface dataset:
オープンソースのライセンスの選び方をガイドしてくれる、"choosealicense.com"というサイト

# TL; DR

* ソースコードを公開する時には、ライセンスを設定しよう
* GitHubが作った、[choosealicense](https://choosealicense.com/)というサイトを見るとライセンス選択の役に立つ
* 最終的には専門家にきちんと相談しよう


# GitHubのドキュメントとchoosealicense

GitHubのヘルプにある、以下のドキュメントを見ると、公開するリポジトリにはライセンスを付与しましょうという話が書かれてあります。

[Licensing a repository](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/licensing-a-repository)

この中で登場するのが、以下のサイトです。

[choosealicense](https://choosealicense.com/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/76e2d4e4-b3b1-9928-080e-47ec8f14b163.png)

自分のシチュエーションに合わせて、ライセンスを選択するようにナビゲーションしてくれます。

たとえば

* [シンプルで寛容なものが欲しい（I want it simple and permissive.）](https://choosealicense.com/licenses/mit/) … MIT License
* [コミュニティで働く場合（I need to work in a community.）](https://choosealicense.com/community/) … Apache License 2.0、MIT License、GNU GPL、etc
* [改善を共有することに関心がある（I care about sharing improvements.)](https://choosealicense.com/licenses/gpl-3.0/) … GNU GPLv3
* [プロジェクトがソフトウェアではない場合（My project isn't software）](https://choosealicense.com/non-software/) … CC0、CC-BY-4.0、CC-BY-SA-4.0
* [ライセンスを付与したくない場合](https://choosealicense.com/no-permission/)

などなど。

また、人気のライセンスの許可していること、条件、制限などもまとまっているので、合わせて見てみるとよいでしょう。

[Licenses](https://choosealicense.com/licenses/)

[Appendix](https://choosealicense.com/appendix/)


# とはいえ

このサイト自体は、オープンソースライセンスを包括的に網羅したものではありません。

[Abount](https://choosealicense.com/about/)

ソースコードに対して適切にライセンス付与を行うことと、その際に発生する法的問題については、ちゃんと専門家に相談しましょうね、と。

[Licensing a repository / Disclaimer](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/licensing-a-repository#disclaimer)

このサイトを管理しているGitHub自体も、ライセンス選択の助けになればよいとは考えてはいるものの、自分たちは弁護士ではないということを免責事項に挙げています。

> The goal of GitHub's open source licensing efforts is to provide a starting point to help you make an informed choice. GitHub displays license information to help users get information about open source licenses and the projects that use them. We hope it helps, but please keep in mind that we’re not lawyers and that we make mistakes like everyone else.

というわけで、ちゃんとライセンスは選んで付与しましょう、と。


# 参考

https://gigazine.net/news/20180607-choose-a-license/

https://devlights.hatenablog.com/entry/2018/06/08/103847

https://www.catch.jp/oss-license/2013/09/10/github/
github 複数アカウント

複数アカウント切り替えでRepository not foundエラー発生時に、下記記事参考にして対応したメモ。

実際にはcredential.helperからmanagerを削除した後、下記のように実行したら成功。urlを指定しない場合は試していない。

```bash
$ git push https://username@github.com/xxxxxxx/yyyyyy.git master
```


[GitHub – 複数のアカウントを追加してHTTPS接続で切り替える方法 \| Howpon\[ハウポン\]](https://howpon.com/4738)

>
アカウント切り替えの補足
以下、GitHubアカウントの切り替えでトラブルが発生しやすい箇所をまとめました。

>捕捉1: credential.helperが「manager」の場合は削除（Windowsのみ）
コマンド「git config –system credential.helper」の実行結果が「manager」である場合は、GitHubにpushした最初のユーザー名・パスワードが端末に保存されます。

>$ git config --system credential.helper

>manager
複数のアカウント接続を行う場合、サブアカウントが認識されなくなるので当該設定を削除する必要があります。

>削除するには、管理者権限でGit Bashを起動し次のコマンドを実行します。

>$ git config --unset --system credential.helper
🍰【CakePHP2】textareaの初期値に先月の初日と末日を設定する

## 環境

PHP 7.2.21
CakePHP 2.10.18

## やりたいこと

CakePHPのフォームヘルパで作るテキストボックスの初期値に先月の初日と末日をデフォルトで入力しておきたい

## やったこと

defaultオプションを追加し、それぞれ以下の値を設定

先月月初　：　date('Y-m-d', strtotime('first day of previous month'))
先月最終日　：　date('Y-m-d', strtotime('last day of previous month'))

```Hoge.ctp
        <?php
            echo $this->Form->input('start_date', [
                'id'       => 'start_date',
                'type'     => 'text',
                'class'    => 'datepicker',
                'div'      => false,
                'label'    => false,
                'required' => false,
                'default'  => date('Y-m-d', strtotime('first day of previous month')),
            ]);
        ?>
        ～
        <?php
            echo $this->Form->input('end_date', [
                'id'       => 'end_date',
                'type'     => 'text',
                'class'    => 'datepicker',
                'div'      => false,
                'label'    => false,
                'required' => false,
                'default'  => date('Y-m-d', strtotime('last day of previous month')),
            ]);
        ?>
```

## 結果

設定値がまんま英文なので忘れがちですが慣れると便利そう
Raspberry PiによるSOS発報システム その3 ～アルゴリズム設計

#もくじ
[その1 ～システム概要](https://qiita.com/maitech/items/a1497892c80826c12330)
[その2 ～GPIOを利用したスイッチの状態検知](https://qiita.com/maitech/items/d63a77dea72355f142b5)
その3 ～アルゴリズム設計 ←本記事です
[その4 ～ハードウェアの準備](https://qiita.com/maitech/items/58a1dc2aab50afe9c5ab)
[その5 ～自動メール送信でハマる](https://qiita.com/maitech/items/9cda9861fd59453fd66e)
[その6 ～キャリアグレードNAT下の端末に外部からSSHでアクセスする](https://qiita.com/maitech/items/b51abd1d78588acf3607)
[その7 ～総括](https://qiita.com/maitech/items/4864a1ddf991f48d728d)

#はじめに
<A HREF=https://qiita.com/maitech/items/d63a77dea72355f142b5>前回</A>はRaspberry PiのGPIOを利用したスイッチの状態検知について述べました。
今回は，実際にその状態検知機能を活用するプログラムのアルゴリズムについて書いてみようと思います。

#大方針
改めて今回やりたいことを書き出すと

- 宅内に複数設置されたSOSボタンが押されたときに，SOSボタンが押された場所（脱衣所，トイレ，台所，etc.）と緊急連絡先等の情報をあらかじめ設定された宛先にメールで送信する（緊急発報機能）
- 12時間ごとにドア（玄関，トイレ，冷蔵庫，etc.）が開かれた回数をあらかじめ設定された宛先にメールで送信する（定時発報機能。システムの動作確認を兼ねる）
- 遠隔地からソフトウェアのメンテナンスが可能

となります。3つ目はひとまず置いておいて，上の2つを考えてみると，ドアセンサやSOSボタンの状態を監視しつつ，その状態の変化に応じて動作させる機能（緊急発報機能）と，12時間ごとに動作させる機能（定時発報機能）とがあることになります。
状態監視はsleep関数を使って一定時間（例えば0.5秒おき）に実施するようなことをぼんやりと考えましたが，12時間ごとに行う定時動作を，例えば「状態監視を86400回行ったら実行する」などとして実現しようとすると，機器の負荷率によって発報間隔にばらつきが出たり，だんだんと発報時刻がずれていくことなどが考えられます。そこで今回は以下のような構成で開発を進めることにしました。

- 緊急発報，定時発報ともに同一のプログラム（メインプログラム）で実現する
- 定時発報は，定時発報要求フラグをたてるサブプログラムをcronで走らせ，それをトリガにしてメインプログラムで実現する

#メインプログラム
メインプログラムのアルゴリズムについては以下のようにしました。
![メインプログラムのフローチャート](https://i.imgur.com/HnFbDm6.png)
ドア回数についてはファイルに記録することで，途中の状態を確認できるようにしています。

緊急発報メールは，例えば「居間のSOSボタンが押されました」や「居間のSOSボタンがリセットされました」のような内容のものです。
今回はさらに追加の情報として，家主及びそのご近所さんの連絡先を含めることにしました。
これは，メールを受け取った側のアクションがスムーズに行われることを期待したものです。

定時発報メールは，例えば「過去12時間以内にトイレのドアが1度も開けられていません」や「過去12時間以内にトイレのドアが〇回開けられました」のような内容のものです。
前者の場合には，体調の異変で体が動かせない状態になっている可能性があるので，緊急発報メールの場合と同様に連絡先の記載を含めるようにしています。

#サブプログラム
サブプログラムについては，フロー図を描くほどのものでもないほどシンプルなものです。
![サブプログラムのフローチャート](https://i.imgur.com/ZlrqCpl.png)
このプログラムを，cronを使って決まった時刻に走らせます。

#小ネタ
Raspberry PiのSDカードの寿命を最大限に延ばすため，今回のシステムの運用中に生成/更新されるファイルについては，ログファイルを除いてRAMディスク領域（/dev/shm/）に置くことにしました。

#次回予告
プログラムの内容が固まったので，[次回](https://qiita.com/maitech/items/58a1dc2aab50afe9c5ab)はハードウェアについて紹介したいと思います。
Slack ワークフローで簡易おみくじを作る

## 初めに

みなさんSlackのワークフロービルダー、使っていますか？

ワークフロービルダーは、Slackの有償プランでのみ使用できる、簡易的なインテグレーション機能のようなものです
絵文字リアクション、ユーザーのチャンネルへの参加、ボタンの押下、その３パターンをトリガーとし、Botによるメッセージ、フォームを投稿できます

今回はそのワークフロービルダーを使っておみくじを作成します

## ワークフロー構造
1. おみくじ絵文字リアクションをしてワークフローを開始する
2. ワークフローがおみくじの選択肢を提示する
3. おみくじ引きたい人が選択肢からおみくじを選んで絵文字リアクションをする

ワークフローとしては１，３の部分、２つを作成する必要があります
１はアクションメニューボタンでも良いのですがなんとなく絵文字リアクションにします

## 作成しよう

左上のメニューより、「ワークフロービルダー」を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/0e21f356-71cf-7351-1db7-825c81a87289.png)

以下のような画面に遷移したら右上より「作成」を押下し、ワークフローを新規作成していきます
この画面が出なかった場合、管理者による権限の付与が必要な可能性があります

![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/9fef641e-a277-fd09-559a-15689b84d6a2.png)

ワークフローに名前をつけます
今回は「おみくじ」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/3078a990-192a-eff7-8e20-39b9e9fb72ee.png)

おみくじ開始のトリガーを選択します
今回は絵文字リアクションをされた時におみくじが引かれるようにしましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/b88f0ee3-aaab-8279-0784-66318aa4f13e.png)

チャンネルと絵文字リアクションを選択します
ワークフローは１つのチャンネルに紐づきます。選択しましょう
絵文字リアクションは複数選択可能ですが、今回は「くじ」が選択されたらおみくじ実行としましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/5047a679-3fba-8983-eec0-6f6e6316623b.png)

ワークフローで開始のステップが保存されました
続いておみくじの選択肢を提示するステップを作成しましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/11b16f37-9ed5-c0af-cc72-aa86a7fe6d5c.png)

ワークフローの反応としてメッセージ、フォームが選択できますが今回はメッセージで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/8050075f-d8e5-fa34-c1cb-fe1f334392fa.png)

メッセージの送信先に「リアクションが使用されたチャンネル」を選択することで、ワークフローが登録されたチャンネルにメッセージを投稿できます
メッセージのテキストにはおみくじの案内を書きましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/57d4ca96-ab60-d749-bbeb-8a6900c7b72a.png)

これで１つ目のワークフローの作成は完了です
右上の「公開する」ボタンより公開しましょう

続いておみくじ本体の方のワークフローを作成します
１つ目と同じ手順で作成していきましょう

タイトル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/eabd0837-a230-2054-0e65-8d93c971b33e.png)

絵文字リアクションによって引かれるように

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/c9cbaac5-f584-1517-3902-5b1faed0ccb2.png)

１つ目と同じチャンネルに設定しましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/aa8727c0-c3f2-53cb-2f8e-baf21c639c8e.png)

ステップを追加し、結果のメッセージを設定しましょう
このおみくじでは末吉しか出ません
反応に困りますね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/137edae1-ed79-ad23-9725-01157b351e45.png)

結果はこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200826/41eadf97-445d-ae58-d970-8ce98a01b2d7.png)

## 終わりに

いかがでしたでしょうか

ワークフロービルダー、簡単に作れるのはとてもいいですね
ただ最終的にメッセージを送信することしかできないので、業務のワークフローに含めるのは少々物足りないですね
メッセージの送信時に絵文字リアクションをすることができれば、複数のワークフローを連携させることができそうですが、現状それもできないようです（通常投稿では`+:grin:`等で絵文字リアクションできますが、ワークフローでは絵文字リアクション判定されない）

手の混んだことをしたい場合はBotを作り、簡単なことはワークフロービルダーですます、等の使い方が良さそうです
Railsでの開発ルールを考えてみた

# 推奨リスト

## テーブルのカラムにコメント

* 何のためのカラムなのかを明確にするため
* Rails6系から使用可能
* 設定値を管理する際にあると便利

ex) db/migrate/YYYYMMDD_create_members.rb

```rb
class CreateMembers < ActiveRecord::Migration[6.0]
  def change
    create_table :members do |t|
      t.string :name, null: false, default: '', comment: '名前'
      t.string :email, null: false, default: '', comment: 'メールアドレス'
    end
  end
end
```

## メソッドにコメントアウト

* メンテナンス性の向上のため

ex)

```rb
# サイトのURLを返却する
def site_url
end
```

## なるべくRailsの機能 (scope, active_support, association) を使用

* テストコードを最小限にするため

## Rspec書く (単体テスト)

* gemやRubyのアップデートを定期的に行うため
* 不具合を極限まで抑えるため

## 定期的にRubyとRailsアップデート

* 最新バージョンに追従するため
* ライブラリにセキュリティホールが存在したり、サポート終了した際にすぐにアップデートできるようにするため

## メソッド名や変数名は長くなっても意味が通るように

* 可読性向上のため

# NGリスト

## コールバック

* メンテナンス性が著しく落ちるため

## STI

* 異なる振る舞いをするオブジェクトを同一テーブルに保持するケースが多いため
* STI化しても結局typeカラムの値で条件分岐する記述が出てくるため

ex)

```rb
return if type == "Server::Web"
```

## エラーメッセージの二元管理 (ex: モデルレイヤー + validationEngine)

* 受け入れテストや単体テストがしづらくなるため
* jQuery等に依存するため
* モデルレイヤーに記述せず、validationEngineのみバリデーションを定義すると、検証ツール等でvalidationEngineの記述を外して容易に500エラーを起こせてしまうため

## SQL直書き

* Railsの良さが出なくなるため
* 他の人が開発するときに効率が落ちるため

## 文字列足し算

* nilになった瞬間に500エラーになるため
* 式展開を利用する

ex)

```rb
# NG
# `host` がnilの場合、500エラーが発生する
def site_url
  'https://' + host
end
 
# OK
def site_url
 "https://#{host}"
end
```

## Ruby Syntax

* 可読性向上のため

### unless

* if !(condition) を代わりに使用する

ex)

```rb
# NG
unless user_signed_in?
 
# OK
if !user_signed_in?
end
```

ex)
 
```rb
# NG
def hoge
  return if (condition1)
  return if (condition2)
  return unless (condition3)
end
 
# OK
def hoge
  return if (condition1)
  return if (condition2)
  return if !(condition3)
end
```

### nil? または blank?

* present? を代わりに使用する
* カラム名のアクセサであれば ActiveRecordの(column_name)? メソッドを使用する

ex)

```rb
# NG
@user.name.nil?
 
# OK
@user.name?
```

```rb
# NG
@shop.company.nil?
@shop.company.blank?
 
# OK
@shop.company.present?
```

### none?

* any? を代わりに使用する

```rb
# NG
@shop.web_servers.none?
 
# OK
!@shop.web_servers.any?
```
jQueryでAngularっぽいフィルターを3行で実装

## jQueryでSPA的なことは実はかなりできる

私は相変わらずwebpackやらのNodeJS環境を用意することに億劫でjQueryを使ってしまいます。

今回はjQueryで簡単にテーブルの内容をフィルタリングするコードを共有します

## $.filterは超強力

以下がそのコードです。[元ネタ](https://www.w3schools.com/jquery/jquery_filters.asp)

``` index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
  $("#myInput").on("keyup", function() {
    var value = $(this).val().toLowerCase();
    $("#myTable tr").filter(function() {
      $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
    });
  });
});
</script>
<style>
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td, th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}
</style>
</head>
<body>

<h2>テーブルをフィルターする</h2>
<p>テキスト入力すると検索条件となりフィルタリングします。</p>  
<input id="myInput" type="text" placeholder="Search..">
<br><br>

<body>
<table>
  <thead>
  <tr>
    <th>姓</th>
    <th>名</th>
    <th>Email</th>
  </tr>
  </thead>
  <tbody id="myTable">
  <tr>
    <td>テスト</td>
    <td>太郎</td>
    <td>test1@example.com</td>
  </tr>
  <tr>
    <td>テスト</td>
    <td>花子</td>
    <td>test2@mail.com</td>
  </tr>
  <tr>
    <td>テスト</td>
    <td>三郎</td>
    <td>test3@test.com</td>
  </tr>
  <tr>
    <td>テスト</td>
    <td>次郎</td>
    <td>test4@test.com</td>
  </tr>
  </tbody>
</table>
</body>
</html>
```

tbodyにID名をつけることでテーブルのヘッダーを残したままにできます。
タイトルの3行というのは

***「$("#myTable tr").filter(function() {」***

以降から3行という意味です。

##更新履歴
- 2020/1/6 新規作成
kvm+kickstart

# qemu-img create -f raw /home/hiroki/vm/hiroki-kickstart.img 20G


# sudo virt-install \
--name hiroki-kickstart \
--hvm \
--os-variant=rhel8.0 \
--vcpu=1 \
--ram 1024 \
--graphics none \
--serial pty \
--console pty \
--disk=/home/hiroki/vm/hiroki-kickstart.img \
--location=/home/hiroki/vm/CentOS-8-x86_64-1905-dvd1.iso \
--initrd-inject /home/hiroki/vm/ks/anaconda-ks.cfg \
--extra-args "inst.ks=file:/anaconda-ks.cfg console=ttyS0,115200n8"


#version=RHEL8
ignoredisk --only-use=vda
# Partition clearing information
clearpart --all --initlabel
# Use graphical install
#graphical
text
cmdline
skipx
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream
# Use CDROM installation media
cdrom
# Keyboard layouts
keyboard --vckeymap=jp --xlayouts='jp'
# System language
lang ja_JP.UTF-8

# Network information
network  --bootproto=dhcp --device=enp1s0 --ipv6=auto --activate
network  --hostname=hiroki-kickstart
# Root password
rootpw --iscrypted $6$4myf402P9EDDeU6Y$K3NSp7lJryOeEM2GKj8Fk7hpjPwfpKgSS.LPYn8kNxitEPlXGUzpTDEKn7utsbFmbgtEaxlHh1CAmc.axaCFQ.
# X Window System configuration information
xconfig  --startxonboot
# Run the Setup Agent on first boot
firstboot --disabled
# System services
services --disabled="chronyd"
selinux --disabled
firewall --disabled

# System timezone
timezone Asia/Tokyo --isUtc --nontp
user --groups=wheel --name=hiroki --password=$6$/2KfmGnHvg5i6oRp$NFNGF4UmBkMbOuQMt7H8fhpFdt9SXGKm80KG5Zi4DEgw3hsG.mOYyqVdci8/2I.aTxW3WEx5VD8oyjSobk3of1 --iscrypted --gecos="hiroki"
# Disk partitioning information
part pv.221 --fstype="lvmpv" --ondisk=vda --size=19455
part /boot --fstype="ext4" --ondisk=vda --size=1024
volgroup vg00 --pesize=4096 pv.221
logvol swap --fstype="swap" --size=2047 --name=swap --vgname=vg00
logvol / --fstype="xfs" --grow --size=1 --name=root --vgname=vg00

reboot --eject

%packages
@^graphical-server-environment
@debugging
@development
@dotnet-core
@ftp-server
@legacy-unix
@performance
@remote-system-management
@rpm-development-tools
@security-tools
@virtualization-client
@virtualization-hypervisor
@virtualization-tools
@web-server
kexec-tools

%end

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
【PHP】リクエストセッションの値が取得出来ないことがあるパターン【Laravel】


同僚がハマっていたのでヘルプで入って見たらこうなってたよ　っていうメモ

#問題
コントローラーで保存したはずのリクエストセッションが取得出来ない。
（そもそも保存出来てない？）

##コード

```ruby:hoge.blade.php

@extends('base')
@section('content')

<form>
 <input type="text" name="name">
 <input type="text" name="age">

 <button type="button" onclick="postNext()">Next</button>
</form>

@endsection

@section('js')
  <script type="text/javascript" src="js/hoge.js"></script>
@endsection

```

```ruby:hoge.js
function postNext() {
  $('form').attr('action', postUrl);
  $('form').submit();
}
```

色々と端折っているものの、正常に動く形です。

#原因
chromeのdeveloper toolsでNextを押下した時のNetworkタブを確認していたら画面遷移直前でerrorのpostを発見。

継承している`base.blade.php`の中に`<form> ~ </form>`が存在していた。
その状態でタグ指定でsubmitしていたため、正常なsubmitと不正なsubmitを同時に行っていた。
（成功するパターンもあったのが、ここら辺の判断をどうやっているかまでは追っていない）

#修正
本来postされるべきformにIDを付けてJSファイルをタグ指定ではなく、ID指定でsubmitするようにした。

#あとがき

同僚がなぜこのような実装したかまでは言及していない。（めちゃくちゃ切迫したスケジュールの中で頑張ってるので聞けなかった）
個人的にはjsでsubmit記述する必要があるのかな？とも思った。

submit前に処理を入れたかったとしても以下の形で良い気がする

```
$('#hoge_form').submit(function() {
  ~
});
```

あんまりこういう事はないと思うけど、一体験談として。
PostgreSQL を Docker 環境で日本語ロケールで動作させる

Docker 環境で、PostgreSQL を日本語ロケールで動作させたかったので調べてみました。
今回は、Dockerfile で、PostgreSQLを作成し、 docker-compose.yml ファイルで使用するロケールを指定します。

## 注意事項

ここで紹介するのは、いったん作成したPostgreSQLデータベースのロケールを変更する方法ではありません。PostgreSQL のDocker イメージ作成時に日本語ロケールで作成して実行する方法です。

## Dockerfile を作成する

PostgreSQL の Dockerfile を作成します。
今回は、公式イメージを使います。 素直に公式サイトの説明に従います。
ただし、使用する言語は、 `docker-compose.yml` ファイル側で指定したいので、 `ARG` を使います。
ここでは、 `docker-compose.yml` 側で、言語が指定されなかった場合のデフォルト値として、 `en_US` を指定するため、`ARG DB_LANG=en_US` とします。

```dockerfile:dockerfiles/postgresql/Dockerfile
FROM postgres:12.1
ARG DB_LANG=en_US
RUN localedef -i $DB_LANG -c -f UTF-8 -A /usr/share/locale/locale.alias $DB_LANG.UTF-8
ENV LANG $DB_LANG.utf8
```

## docker-compose.yml を作成する

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

PostgreSQL のイメージ作成 ( `build` ) 時に、言語を引き渡せるように `args` を使います。

```yaml:docker-compose.yml
version: '3'

services:
  db:
    build:
      context: .
      dockerfile: ./dockerfiles/postgresql/Dockerfile
      args:
        - DB_LANG=ja_JP
    volumes:
      - pgsqldb:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD

volumes:
  pgsqldb:
    driver: local
```

## 立ち上げて確認する

ビルドして実行します。

```shell
$ env POSTGRES_USER=xxx POSTGRES_PASSWORD=yyy docker-compose up -d`
```

実際に確認してみましょう

```shell
$ docker-compose exec db bash
# psql non_exist_db -U postgres
psql: エラー: サーバに接続できませんでした: FATAL:  データベース"non_exist_db"は存在しません
```

エラーメッセージが日本語になりました。

## DB_LANG を指定しなかった場合

`docker-compose.yml` で `args` を指定しなかった場合は、 `en_US` になります。

## 参考情報

* [postgres Docker Official Image](https://hub.docker.com/_/postgres)
* [Dockerfile Reference ARG](https://docs.docker.com/engine/reference/builder/#arg)
* [Compose file reference ARGS](https://docs.docker.com/compose/compose-file/#args)
V-Calendarの導入とスタイルが効かなかった問題の解決

# v-calendarの導入

導入の方法は下記のドキュメントの通りです。
[vcalendar公式ドキュメント](https://vcalendar.io/installation.html#npm)

##### npmでインストール（CDNもあるけど…）

```
npm install v-calendar
```

##### main.js的なところでこれを指定

```js
import Vue from 'vue';
import VCalendar from 'v-calendar';
Vue.use(VCalendar)
```

##### vueファイルで使う

```vuejs
<template>
  <!-- ごめんなさい。テキトーに書いてます。詳しくはドキュメントを --!>
  <v-calendar
    is-double-paned
  >
  </v-calendar>
</template>
```

## 何故かstyleが当たらない問題（この記事のメイン）

困ったのでGitHubのREADMEを眺めてると…
[vcalendar GitHub README](https://github.com/nathanreyes/v-calendar-docs/blob/master/README.md)

なにかcssを読み込んでいそうな記述を見つける…。


```js
import Vue from 'vue';
import VCalendar from 'v-calendar';
// ↓↓↓ これは!?!? ↓↓↓
import 'v-calendar/lib/v-calendar.min.css';
Vue.use(VCalendar)
```

追記してみるとうまくstyleが読み込めた。
一件落着
JavaScript ES6 変数⓵ 宣言、初期化

#はじめに
この記事では、JavaScriptES6の変数の基礎的なことについて解説します。

#ES6
ESの正式名称は、ECMAScriptです。
ECMAScriptとは、Ecma International(エクマ インターナショナル)が定めているJavaScriptの標準の書き方です。後ろの数字は、その標準の書き方のバージョンです。
したがって、ES6とはJavaScriptの標準の書き方の6番目のバージョンとなります。

#変数の宣言
```JavaScript:sample.js
let number; //変数numberを定義する
const string; //変数stringを定義する
```
JavaScriptでの変数は、このように宣言できます。

#初期化
```JavaScript:sample.js
let number = 0; //変数numberを定義し、0を代入する
const string = "鈴木"; //変数stringを定義し、"鈴木"を代入する
```
変数は、このように宣言と代入を同時に行うことができます。
これを初期化といいます。

#let
```JavaScript:sample.js
let number = 1; //変数numberを宣言し、1を代入する
number = 2; //変数numberに2を代入する
let number; //エラー
```
letで宣言した変数には、値を再代入できます。
また、一度宣言した変数をもう一度宣言しようとすると、エラーになります。
#const
```JavaScript:sample.js
const number = 0; //変数numberを宣言し、0を代入する
const string; //エラー
const number = 0; //エラー
number = 2; //エラー
```
constで宣言した変数は、値を再代入できず、再代入しようとすると、エラーになります。
また、constの場合、宣言のみすることはできません。必ず初期化します。
一度宣言した変数を再度宣言できないのは、letと同じです。
#まとめて宣言・初期化
```JavaScript:sample.js
let number = 0, //変数numberを宣言し、0を代入する
string; //変数stringを宣言する

const name = "田中"; //変数nameを宣言し、"田中"を代入する
const num = age = 5; //変数ageとnumを宣言し、それぞれに6を代入する
```
このように、宣言した後に;ではなく,をつけると、まとめて宣言・初期化ができます。

#参考文献
JavaScriptとECMAScriptの違いって何？その背景を徹底解説！
https://www.sejuku.net/blog/101695

JavaScript コードレシピ集
https://gihyo.jp/book/2019/978-4-297-10368-2

JavaScript ショートコードテクニック集(ES6含む)
https://qiita.com/ichimonji_haji/items/f602f6c437be9e7daa88
クロムブックで Alpine を使う

こちらで行ったの同じ方法で Alpine をインストールします。
[クロムブックで Arch Linux を使う](https://qiita.com/ekzemplaro/items/f7737b410b6ec72bba7f)

インストール

```text
(termina) chronos@localhost ~ $ lxc launch images:alpine/edge alpine
Creating alpine
Starting alpine
(termina) chronos@localhost ~ $
```

状況の確認

```text
(termina) chronos@localhost ~ $ lxc list
+--------+---------+-----------------------+----------------------------------------------+------------+-----------+
|  NAME  |  STATE  |         IPV4          |                     IPV6                     |    TYPE    | SNAPSHOTS |
+--------+---------+-----------------------+----------------------------------------------+------------+-----------+
| alpine | RUNNING | 100.115.92.212 (eth0) | 2001:240:28d5:4900:216:3eff:fe02:b081 (eth0) | PERSISTENT | 0         |
+--------+---------+-----------------------+----------------------------------------------+------------+-----------+
```

root のパスワードを設定

```text
$ lxc exec alpine -- ash
~ # passwd
Changing password for root
New password: 
```

root でログイン

```text
(termina) chronos@localhost ~ $ lxc console alpine
To detach from the console, press: <ctrl>+a q

Welcome to Alpine Linux 3.12
Kernel 5.4.72-10084-g023bf751fdc7 on an x86_64 (/dev/console)

alpine login: root
Password: 
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <http://wiki.alpinelinux.org/>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

alpine:~# cat /etc/alpine-release
3.12.0
alpine:~# 
```

ユーザーの作成

```text
alpine:~# adduser -u 1200 uchida
Changing password for uchida
New password: 
Retype password: 
passwd: password for uchida changed by root
alpine:~#
```
OpenLiteSpeedのCache設定が保存できない場合の回避策

参考: https://forum.openlitespeed.org/threads/cache-so-module-disappeared.4013/

ver 1.5.10時点でキャッシュモジュールが存在しないバグがあるようで、管理画面からModule Parametersを変更しようとすると

**「cannot find external module: /usr/local/lsws/modules/cache.so」**

というエラーが出る。
https://openlitespeed.org/kb/openlitespeed-cache-module/
The page cache is built into the server core in v1.4.52, v1.5.10, v1.6.4, and all newer versions.
ページキャッシュは1.4.52以降ではビルトインされているが、/modules/にないので参照できない、ということか？

とりあえずの対応として、
/usr/local/lsws/modules/
に空のcache.soを作ることで、管理画面から設定の保存、キャッシュの有効化が可能。

enableCache         0
↓
enableCache         1

にして保存後、ブラウザのヘッダにて
X-LiteSpeed-Cache: hit, private
が出ればOK。
お試しマルチコア(Spresense)

この記事は[リンク情報システム](https://www.lis.co.jp/)の2020新春アドベントカレンダー Tech Connectのリレー記事です。
engineer.hanzomon のグループメンバによってリレーされます。
（リンク情報システムのFacebookは[こちら](https://ja-jp.facebook.com/lis.co.jp/)から）

2020新春アドベントカレンダー Tech Connect インデックスは[こちら](https://qiita.com/dgkz/items/5131349d56354b33ee97)

#はじめに
最初の記事を担当します、mk-takahashiです。
当初はあれやこれやと企画を考えていたんですが、
結局いつも通り時間が取れなかったので簡単な記事を書きたいと思います。

2019年6月5日にSpresenseのArduino IDE環境においてマルチコアプログラミング環境が使えるようになりました。
今後この機能を使ってみたいなぁと思っているので、とりあえずお試しでマルチコア機能を使った簡単なコードを作成します。
ちょっと試して今後の使い方が見えてくるかなと思っているので、難しいことは一切していないです。

#とりあえず作るものの構想
Spresenseには1つのmaincoreと5つのsubcoreがあります。
Spresenseメインボード上にある4つのLEDをそれぞれsubcoreに制御させ、
maincoreはシリアル通信、各subcoreの制御を行います。

ユーザーはシリアルモニターを使い、
制御するLEDの番号(1~4)と点灯間隔([1~255]*10ms)で指定できます。

これにより4つのLEDを異なるタイミングで、
しかも簡単にLチカできるようになるはずです。

#コード
コードの先の方に出てくるsetupとloopはsubcore用の処理です。
後の方に出てくるsetupとloopはmaincore用の処理です。

同じソースコード上に書いていますが、
書き込みは各coreに対して行うので注意してください。
（詳しい書き込み方は[こちら](https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_multicore)）

```c:mp_test.ino
#include <MP.h>

#ifdef SUBCORE

#if   (SUBCORE == 1)
#define LED LED0
#elif (SUBCORE == 2)
#define LED LED1
#elif (SUBCORE == 3)
#define LED LED2
#elif (SUBCORE == 4)
#define LED LED3
#endif

byte interval;

void setup()
{
  MP.begin();
  MP.RecvTimeout(MP_RECV_POLLING);
}

void loop()
{
  int        ret;
  int8_t     msgid;

  ret = MP.Recv(&msgid, &interval);

  ledOn(LED);
  delay(interval*10);
  ledOff(LED);
  delay(interval*10);
}

#else  /* MAINCORE */

void setup()
{
  int ret = 0;
  int subid;

  Serial.begin(115200);
  while (!Serial);

  /* Boot SubCore */
  for (subid = 1; subid <= 4; subid++) {
    ret = MP.begin(subid);
    if (ret < 0) {
      printf("MP.begin(%d) error = %d\n", subid, ret);
    }
  }

  /* Polling */
  MP.RecvTimeout(MP_RECV_POLLING);
}

void loop()
{
  byte     subcore = 0;
  byte     interval = 0;
  int8_t   msgid = 0;
  int      len = 0;

  Serial.print("LED NUMBER:");
  while(Serial.available() <= 0);

  subcore = Serial.read()-48;
  Serial.println(subcore);

  Serial.print("Lighting interval:");
  while(Serial.available() <= 0);
  len = Serial.available();

  while(len){
    interval = interval*10 + Serial.read()-48;
    len--;
  }
  Serial.println(interval);
   
  MP.Send(msgid, interval, subcore);
}

#endif
```

#最後に
今までのシングルコアでは実現させるのが面倒だった処理が、
割とあっさりと実装できました。
ArduinoとSpresenseのおかげで簡単にマルチコア処理を実現できるので
今後の趣味プログラミングには積極的に取り入れていこうかなと思います。
[Dart] whereで取り出した部分集合でindexOfが使えないときの対処方法


リストから `where` で部分集合を得た後、 `.indexOf` で要素の位置を取得したかったが、次のようなエラーが出た。

```dart
final sentencesInThisSection = allSentences
        .where((sentence) => sentence['section'] == thisSectionNo)
final sentencePositionInThisSection =
        sentencesInThisSection.indexOf(thisSentence);
```

```
════════ (2) Exception caught by widgets library ═══════════════════════════════════════════════════
Class 'WhereIterable<dynamic>' has no instance method 'indexOf'.
Receiver: Instance of 'WhereIterable<dynamic>'
Tried calling: indexOf(_LinkedHashMap len:5)
```

`where` で取り出した部分集合は`List`でなく、`WhereIterable` という型らしい。
次のように`toList`で`List`に変換することで、`indexOf`が使用可能になる。

```dart
final sentencesInThisSection = allSentences
        .where((sentence) => sentence['section'] == thisSectionNo)
        .toList();
final sentencePositionInThisSection =
        sentencesInThisSection.indexOf(thisSentence);
```
よく見る文字列の扱い方

プログラミング中によく見かける文字列とその扱い方。

文字列の末尾が `=` で終わっている場合は Base64 エンコードされた文字列なのでデコードする。

```
$ echo aGVsbG8sIHdvcmxkCg== | base64 -D
hello, world
```

`ey` で始まる文字列は Base64 エンコードされた JSON なのでデコードする。JWT などで頻出。

```
$ echo eyJuYW1lIjogImdyb2hpcm8hIn0K | base64 -d | jq .
{
  "name": "grohiro!"
}
```

文字列が16進数っぽい(`[0-9a-f]`) ときは `xxd` でバイナリ変換してみる。

```
$ echo 68656c6c6f2c20776f726c64210a | xxd -r -p > hatena.txt
$ cat hatena.txt
hello, world!
```

意味不明なファイルが送られてきたときは先頭の文字列を調べる。

```
$ hexdump -C hatena.dat
00000000  50 4b 03 04 0a 00 00 00  00 00 17 7f 65 4f c0 df  |PK..........eO..|
00000010  31 b6 0e 00 00 00 0e 00  00 00 09 00 1c 00 68 65  |1.............he|
00000020  6c 6c 6f 2e 74 78 74 55  54 09 00 03 2e 1d c1 5d  |llo.txtUT......]|
....
```

先頭文字列が `PK` で ZIP ファイルということがわかるので `unzip` してみる。

```
$ unzip hatena.dat
Archive:  hatena.dat
 extracting: hello.txt
$ cat hello.txt
hello, world!
```

先頭文字列の例（必ずしも先頭ではなく1〜2行目付近にある）

- `PK` ZIP ファイル
- `PNG` PNG ファイル
- `JFIF` JPEG ファイル

16進数の `0d` `0a` は改行。

```
$ echo -n -e "\r"  | hexdump
0000000 0d
0000001

$ echo -n -e "\n"  | hexdump
0000000 0a
0000001

$ echo -n -e "\r\n"  | hexdump
0000000 0d 0a
0000002
```

----
（WAVE_DASH とか FULLWIDTH TILDE の 0xなんちゃら についても追記したい）
PythonでGoogleDriveへアクセス

https://news.mynavi.jp/article/zeropython-16/


client_secrets.jsonファイルが必要

```
{
  "installed": {
    "client_id": "ここにclient_IDを記述する",
    "project_id": "mapapp-1350",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "ここにclient_secretを記述する",
    "redirect_uris": [
      "urn:ietf:wg:oauth:2.0:oob",
      "http://localhost"
    ]
  }
}
```
Redshiftの運用をしていて思ったこと。

# Redshiftで思うことつらつら。


## はじめに
昨年、Redshiftを触り始め、思ったことなどをまとめます。
基本情報は、AWSの公式情報が一番です。
[AWS Redshift ガイドライン](https://docs.aws.amazon.com/ja_jp/redshift/latest/mgmt/welcome.html)
そして、サポートに問い合わせても、ガイドライン以上の情報は手に入りませんでした。。


なお、2019年末時点の情報です。
変化の速いサービスのため、今後の情報次第では解消されているかもしれません。

思ったことをつらつらと。


## SQLのコンパイル問題。
いまだ何ともならないRedshiftの唯一の欠点。
BI製品などで裏でSQLが自動生成される場合に、SQL文が長い（1000行以上）と、数秒で終わるSQLがコンパイルで数分近くかかるため、性能問題になる。
⇒対応策：あらかじめSQLを流しておくしかない。
（過去に流れたSQLを抽出して、起動時に流す、自動打鍵ツールで流すようにするなど工夫が必要）

また、このコンパイルはあくまでキャッシュされた状況のため、
Redshiftのバージョンアップやスナップショットからの復元（疑似的に停止運用などをする場合）にも、削除されるため、その都度ケアが必要。


```
データウェアハウスとしてRedshiftは今後も選択肢に入り続けるかと思うが、
この部分が残り続ける以上、BI製品との相性はPOCなどは必要。
Redshift側でできるものは何もないため、BI製品側で頑張ってもらうしかない。
```


## 値段が高い！
スペックが高いに越したことはないが、Auroraなどと比べるとvCPU単位の値段がとにかく高い。
特にリーダーノードはスケールアップの選択肢が少なく、ボトルネックとなった場合のスケールアップの値段が大きいため、テストなどで確認が必要



## Postgreのバージョンが古い！
postgre 8 で動いているため、物理DBの設定に癖がある。
作者はpostgre SQLのバージョン9.6 以降から触り始めたため、今までのユーザー定義や構文が使えないことに非常にストレスを感じた。
なお、SQLの構文等でも差異はある。ローカル環境でRedshiftを用意することは困難のため、早めにCI環境の構築が必要。


## SQLチューニングの余地がほとんどない！（いいこと！）
分散キーとソートキーの設定のみのため、RDBであるいわゆるヒント句追加などのパフォーマンスチューニングがほとんどない。だいたい、分散キー、ソートキーの設定でうまくいかない場合、テーブル設計を要件等。
OracleやPostgre（RDB）などのDatabaseスペシャリストの出番があまりない。
ただし、テーブル設計は他のDatabaseと変わらず常に重要！

（補足）
- RDBに比べて、SQLの結合に弱いと聞くが、その影響をほとんど感じないほど、性能は良い。
分散キーの設定の影響か、特に問題なく利用できている。
- マスタテーブルの分散タイプについて、機能特性上ALL（各ノードそれぞれに配置）にすべきのようにみえるが、パフォーマンス観点上、EVEN(ラウンドロビン）でも影響なし。データ件数の問題か。（数千件クラスなら問題なし）、それ以外はKEYで指定する。
- 最近出てきたソートキーのinterleavedは、バキュームを個別対応に実施したり、同時実行スケーリングが効かないなどの問題があるため、特別必要でなければ避けたほうが良い。


## データ挿入（移行作業など）
S3からファイルのインポートが可能だが、インポート後に別スレッド？（非同期）で、データの分散が始まるため、
瞬間的にディスクフル（OutOfMemory が出る）場合がある。
その場合、時間をおいてから実行すると、スケールアップせず、移行作業が続行可能。

ファイルのインポート、アップロードは、psql のPG_COPY コマンドは対応しておらず、公式に書かれている方法で実施するしかない。メトリクスを注視しながら、最適な並列実行を見極めると作業時間の短縮が可能。


## 耐障害性
よくあるAZ構成ができないため、耐障害性の要件定義がしづらい。実情として意外と落ちない。
むしろ、Auroraのほうが突然フェイルオーバーする回数が多い。（なぜ？）

サポート曰く、停止後の時間が早いとのこと。AZ障害などのNW起因を除けば、ノード単位の障害発生時は問題にならないかもしれない。とはいえ、非機能要件の定義の際に、他のAWSのサービスと同じように記載しないように気を付けること。


## バージョンアップ
Redshiftはとにかくバージョンアップが速く、3か月に1回強制的なアップデートで、再起動が走る。
コンパイルの挙動など微妙に違うなど、リリースノートに記載できていないアップデートがある。過去、トラブルにはなったことはないが、詳細な挙動抑えていると「あれ」と思うことはある。
(個人的には特定のバージョンで確定していただけると安心。)

そもそもマネージドサービスのため割り切る必要があるが、運用として、バージョンアップ内容の確認、再起動のタイミング調整などが必要。


## ディープラーニングの機能など、時代の技術を多く採用
動的ワークロード管理 (WLM)（各SQLが流れるときのキューの設計・管理が不要）、
Short Query Acceleration（過去実績のあるSQLで実行時間が短い処理は専用の別スレッドで流れる）の搭載、
同時実行スケーリング（起動直後に待機時間はあるものの、Select文は同時実行数の制御が増やせたり）と、ユーザーにとって使いやすくかつ時代の最新の技術が入っているので、率直にいって評価できるサービスである

AWSの開発現場の内部はわからないが、積極的に機能追加や技術採用などしていることを思うと、ワクワク現場なのかなと思ってしまう。
Pythonのデフォルト引数は呼び出しごとに初期化されない

Pythonでコード書いてて「マジかよ」と思ったんだけど:

```python
def wrap_list(value, base_list = []):
    base_list.append(value)
    return base_list
```

みたいなコードがあるとする。これを第2引数を省略して何度も呼び出すと:

```python
print(wrap_list(1)) # => [1]
print(wrap_list(2)) # => [1, 2]
```

という結果になる。2回目は`[2]`となってほしいのに。

試しに`id`関数でオブジェクトIDを表示してあげるとどうなっているかよく分かる。

```python
def wrap_list(value, base_list = []):
    print(id(base_list)) # debug print
    base_list.append(value)
    return base_list

wrap_list(1) # => 4373211008
wrap_list(2) # => 4373211008
```

どちらの呼び出しにおいても、`base_list`のオブジェクトIDは同一。つまり、呼び出しごとに空のリストが生成されているわけではなく、たった1度だけ生成されている、ということになる。

ちなみにRubyでも試してみたが:

```ruby
def wrap_list(value, base_list = [])
  puts base_list.object_id
  base_list << value
end

wrap_list(1) # => 70218064569220
wrap_list(2) # => 70218064588580
```

こっちは呼び出しごとに生成されているっぽい。

Pythonで上記のようなコードを書くことはないと思うが:

```python
class WrappedList(object):
    def __init__(self, initial = []):
        self.list = initial

    def append(self, value):
        self.list.append(value)
```

みたいなケースでも当然同様のことが起きるので、注意する必要はありそう。

根本の問題としては、「呼び出しごとに初期化されない」という点で、回避策としては「破壊的な操作は行わない」に尽きる。もし破壊的な操作が必要なのであれば、デフォルト引数自体は`None`にしておき、`None`ならば空のリストで初期化、みたいなコードにしてあげれば良さそう。
限定共有投稿について

自分用コピペ
⬇️
URLを知っているユーザーのみアクセスでき、Googleの検索でも表示されなくなる機能です。ちょっとしたメモや、 自分のためにまとめておきたい内容なども限定共有投稿を利用すれば気軽に投稿ができます。

限定共有投稿を行う方法

Qiitaにログインし、Qiitaトップページにアクセス
[投稿する]をクリックし、投稿内容を書く
右下にある[Qiitaに投稿] の右にあるメニューから [限定共有投稿] をクリック
その投稿は、投稿者本人及びURLを知っているユーザーのみアクセスすることができます。
※記事を限定共有から公開することは出来ますが、一旦投稿した記事を限定共有にすることは出来ません。
UnityでGitするときのignoreメモ@202001

UnityでGitしたいときのignoreメモ
若干mac時も考慮してるつもり。。

### .gitignore

```
# Unity generated
[Ll]ibrary/
[Tt]emp/
[Oo]bj/
[Bb]uild/
[Bb]uilds/
[Ll]ogs/

# Never ignore Asset meta data
![Aa]ssets/**/*.meta

# Uncomment this line if you wish to ignore the asset store tools plugin
# [Aa]ssets/AssetStoreTools*

# Visual Studio cache directory
.vs/

# Gradle cache directory
.gradle/

# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db

# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta

# Unity3D generated file on crash reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

# Crashlytics generated file
crashlytics-build.properties

# OS generated
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db

```

###参考サイト
https://github.com/github/gitignore/blob/master/Unity.gitignore
PHP while文まとめ

# 目的

- while文の書き方をまとめる

# 書き方の例

- while文は条件式がtrueの場合に無限に当該処理をループ実行する。
- 回数以外の条件に応じた繰り返し処理を実行する。(if文と一緒に使用した場合)
- 下記にwhile文の書き方を記載する。

```php
変数の初期化;
while (ループ処理の条件){
  ループで実行する処理;
  変数の更新;
}
```

# より具体的な例

- 変数`$i`に3の倍数が格納されている時のみ出力する処理を下記に記載する。

```php
//変数の初期化
$i = 1;

//ループ処理を$iが100になるまで実行する
while ($i <= 100){
  //$iを3で割った時のあまりが0になる時
  if ($i % 3 == 0){
    echo $i;
    echo "<br>";
    }
  //$iに1を足す(ifの条件に関係なく$iは足される必要があるためif文の外で$iを更新する。)
  $i++;
}
```

- 0~9までを連続して出力するwhile文を記載する。
- 初期化された変数が既にwhile文の繰り返し条件を超えていたら何も表示されない。

```php
$i = 0;
while ($i < 10) {
  echo $i;
  $i++;
}
```

- 0~9までを連続して出力するdo while文を記載する。
- 初期化された変数が既にwhile文の繰り返し条件を超えていても初回のみ出力される。

```php
$i = 0;
do {
  echo $i;
  $i++;
} while ($i < 10);
```
serverspecでWindowsをテストするための設定

仕事でWindowsサーバをserverspecでテストするぞ！ということがあったので、その時の設定をまとめておきます。
同じようなことをやろうとしている人の助けになれば幸いです。
#前提条件
Gemfileにserverspec、winrm等、必要なgemを書いてインストールする。
今回はserverspec(2.41.3)を使用しています。
テスト対象のWindowsサーバにWinRM(Windows Remote Management)がインストールされ、初期設定が完了していること。
#serverspecの設定
serverspecを実行する環境にserverspecをインストールする。
serverspec用のディレクトリを作る。

```
$ mkdir serverspec
$ cd serverspec
```
serverspec-initコマンドを実行し、初期設定を行う。
Select OS typeは「2」、Select a backend type「1」を選択する。

```
$ serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 2

Select a backend type:

  1) WinRM
  2) Cmd (local)

Select number: 1

Vagrant instance y/n: n
Input target host name: test

 + spec/
 + spec/test/
 + spec/test/httpd_spec.rb
 + spec/spec_helper.rb
```
spec_helper.rbはこのままでは使えないので、書き換えます。

```spec/spec_helper.rb
require 'serverspec'
require 'winrm'

set :backend, :winrm

#対象ホストのIPアドレス、またはサーバ名
host = "test_server"

opts = {
  user = "（WIndowsユーザー名）",
  pass = "（ユーザのパスワード）",
  endpoint = "http://"+ host +":5985/wsman",
  operation_timeout: 300 ,
}

winrm = WinRM::Connection.new(opts)
Specinfra.configuration.winrm = winrm
```

デフォルトで作成されるhttpd_spec.rbは使わないので削除しちゃってください。
とりあえず確認用の簡単なシナリオを作成しておきましょう。

```spec/test/test_spec.rb
require 'spec_helper'

describe command('hostname') do
  its(:stdout) { should match /test-server/ }
end
```
#テスト実行
以下のコマンドでテストを実行

```
rake spec
/usr/local/rvm/rubies/ruby-1.9.3-p448/bin/ruby -S rspec spec/test/test_spec.rb
.

Finished in 0.64601 seconds
1 example, 0 failures
```
これでserverspecでWindowsのテストが出来るようになるはずです。
後はserverspec-runnerなどを使えばさらに使いやすくなるのではないでしょうか。

#参考
[serverspecでWindowsのテストをお試しする](https://qiita.com/uchiunyo/items/46d02605315f6b146c14)
それPLSQLで出来るよ（その１ PLSQLでZipファイルを作成する）

OracleでSelectした結果をCSVで出力したいなんてケースは結構多いと思いますが、Oracle単品で出力から圧縮までしたいと思ったことはありませんか？

私はしたいとは思いませんでしたが、お客さんから「したい」と言われました。

# PLSQLでZipファイルを作成する。

Oracleには「[UTL_COMPRESS](https://docs.oracle.com/cd/E16338_01/appdev.112/b56262/u_compr.htm)」というパッケージがあり、圧縮、解凍が可能ですが、残念ながらZipには対応していません。

「AS_ZIP」と呼ばれるパッケージを導入することで簡単に対応することができました。
gunzipとZipの違いはヘッダーの違いだけなので、バイナリでゴリゴリ直せばZipになるそうです。（素晴らしい）

<a href="https://github.com/yallie/as_zip"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/yallie/as_zip.png" width="460px"></a>

## AS_ZIPを使ったZIP作成のサンプル

### Zip作成プロシージャ

基本的には必要なファイルを add1file して finish_zip で作成、 save_zipで書き出しするだけ。

書き出し先はOracleDirectoryを指定しています。

```CREATE_ZIP.sql
CREATE OR REPLACE PROCEDURE CREATE_ZIP
IS
  -- OracleDirectory
  DIRECTORY_NAME  CONSTANT VARCHAR2(100) := 'DIR';
  -- 直接記述時、書き出し文字コード
  TXT_CODE        CONSTANT VARCHAR2(100) := 'JA16SJIS';
  
  vFileName1 VARCHAR2(256);
  vFileName2 VARCHAR2(256);
  vZipName   VARCHAR2(256);
  bZipped    BLOB;
BEGIN
  -- csvファイルを作成する
  vFileName1 := 'test.csv';
  create_csv(vFileName1);
  
  -- 作成したファイルを追加
  as_zip.add1file( bZipped, vFileName1, as_zip.file2blob (DIRECTORY_NAME,vFileName1));
  
  -- ディレクトリの指定も可能
  vFileName2 := 'dir/test.txt';
  
  -- テキスト内容を直接記述して追加
  as_zip.add1file( bZipped, vFileName2, utl_i18n.string_to_raw( 'dirの中にいる' , TXT_CODE ) );
  
  -- ファイルの追加を終了
  as_zip.finish_zip( bZipped );
  
  vZipName := 'test.zip';
  
  -- 書き出し
  as_zip.save_zip( bZipped, DIRECTORY_NAME, vZipName);
END CREATE_ZIP;
/
```

### Csv作成プロシージャ

おそらくよくやるSJISのCSVの作成プロシージャも公開。
utl_fileはputでもできますが、駄目文字で死ぬ場合があるためput_rawを使用してます。

```CREATE_CSV.sql
CREATE OR REPLACE PROCEDURE CREATE_CSV(
  vFileName IN VARCHAR2
)
IS
  -- OracleDirectory
  DIRECTORY_NAME  CONSTANT VARCHAR2(100) := 'DIR';
  
  -- CSV作成時に利用する定数
  CSV_CODE        CONSTANT VARCHAR2(100) := 'JA16SJIS';
  CR_CODE         CONSTANT VARCHAR2(10)  := CHR(13);
  LF_CODE         CONSTANT VARCHAR2(10)  := CHR(10);
  NEW_LINE_CODE   CONSTANT VARCHAR2(100) := CR_CODE||LF_CODE;
  
  -- ファイル作成時に利用するファイルハンドル
  vHandle  UTL_FILE.FILE_TYPE;
BEGIN
  vHandle := utl_file.fopen(DIRECTORY_NAME, vFileName, 'WB', 32767);
  
  -- Testテーブルの中身を明細行として出力
  for rec in (
    select col1 || ',' || col2 as var -- csvの明細行を作成
    from test
    order by col1
  ) loop
    -- 文字コードを指定して改行コードと共に出力
    utl_file.put_raw(vHandle, utl_i18n.string_to_raw( rec.var || NEW_LINE_CODE , CSV_CODE ), TRUE );
  end loop;
  
  utl_file.fclose(vHandle);
END CREATE_CSV;
/
```

### 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461050/2adf1da2-1718-f2d5-f538-cb1827203e1d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461050/5eb8ae5f-abe3-f79d-3014-3318b35869e7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461050/2c7a88fa-6bb0-ff63-5755-783e500d1048.png)

きちんとできてますね。
【Power BI】同一条件で複数の値がヒットするとき、TOPNの値を連結して表示するDAX関数

# TOPのみ表示

```
Top = 
		CONCATENATE(
			CONCATENATEX(
				TOPN(
					1,
					VALUES('data'),
					'data'[order by 1],DESC,
                    'data'[order by 2],ASC
				),
				'data'[target],
				", ",
				'data'[order by 3],
				DESC
			),
			""
		)
```

# 上位N個を連結して表示

```
Sources = 
VAR __DISTINCT_VALUES_COUNT = DISTINCTCOUNT('data'[target])
VAR __MAX_VALUES_TO_SHOW = 5
RETURN
	IF(
		__DISTINCT_VALUES_COUNT > __MAX_VALUES_TO_SHOW,
		CONCATENATE(
			CONCATENATEX(
				DISTINCT(SELECTCOLUMNS(TOPN(
				__MAX_VALUES_TO_SHOW,data,data[sort by this column],DESC),"target",data[target])),
                [target],
				", ",
				[target],
				DESC
			),
			",  など"
		),
		CONCATENATEX(
		DISTINCT(SELECTCOLUMNS(data,"target",data[target])),
			[target],
			", ",
			[target],
			DESC
		)
	)
```
# コードの見方
[column]
DESC/ASCは任意に選択
dataは任意のテーブルに置換
PILでBoundingBoxを表示するスクリプト例


# 何をしたいか
メモ。

# 更新
- 20200116
    - y座標が0に近い時でも画面内にラベルを表示できるようにした

# 結果のBBをPIL画像に表示する関数

```
def show_bb(img, x, y, w, h, text, textcolor, bbcolor):
    draw = ImageDraw.Draw(img)
    text_w, text_h = draw.textsize(text)
    label_y = y if y <= text_h else y - text_h
    draw.rectangle((x, label_y, x+w, label_y+h), outline=bbcolor)
    draw.rectangle((x, label_y, x+text_w, label_y+text_h), outline=bbcolor, fill=bbcolor)
    draw.text((x, label_y), text, fill=textcolor)
```

# サンプル

![lena_std.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207596/edf60d5d-3381-de5c-cbff-3801b2f1a6cd.jpeg)
↓
![lena_eye.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207596/8252ab9d-6bda-27d1-2c6f-4c1858bdc97f.jpeg)


```
from PIL import Image, ImageDraw

img = Image.open(path_to_image)
show_bb(img, 244, 249, 47, 30, "eye", (255, 255, 255), (255, 0, 0))
img.show()
```
LaravelのupdateOrCreateでUnknown column 'id' in 'where clause' でエラーが出た

##概要
Laravel5.5を使用していて、UpdateOrCreateという関数を使用した実装を行おうとしたところ
指定していない`id`がNULLになっているとエラーが出てきた。
[Laravel公式ドキュメント](https://readouble.com/laravel/5.5/ja/eloquent.html)

```
$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99]
);
```

###結果
`id`以外のプライマリキーを使用する場合、
モデルに`primaryKey = 'id以外' `を記入しないと`id`を使ってSQLが叩かれるみたい
GCP アップデート (12/27/2019 - 1/2 2019)



### Dataproc: [Dec 16, 2019](https://cloud.google.com/dataproc/docs/release-notes#December_16_2019)
- クラスタ内で利用されるCPUの最低の世代を指定できるMinimum CPU platformがGAになったよ。

### Dataproc: [Dec 20, 2019](https://cloud.google.com/dataproc/docs/release-notes#December_20_2019)
- updateClusterする際のクォータを確認するロジックのバグを修正したよ。
- stackdriver loggingのautoscaler recommendationsに最低、最大ワーカ数やスケールダウン時の待機時間等の情報を追加したよ。
- 新しいサブマイナーバージョンのリリース (1.2.87-debian9, 1.3.47-debian9, 1.4.18-debian9, 1.5.0-RC3-debian10, 1.3.47-ubuntu18, 1.4.18-ubuntu18, 1.5.0-RC3-ubuntu18)
- 新しいイメージで最新のlinuxカーネルバージョンをDebian backportsリポからlinux-image-amd64をインストールするようになったよ。
- YARM TimelineサーバのJerseyログを無効にしたよ。
- 1.5プレビューの更新(色々)

### Dataproc: [**重要な更新**](https://cloud.google.com/dataproc/docs/release-notes#important_announcements)
- 2020/1からコントロールプレーンのIdentity(GCPが自動的に作成するアカウント)に明示的に権限をつけることが必須になったよ。
  - スケジュール削除ではdataproc.clusters.delete、オートスケールではdataproc.clusters.update、ワークフローテンプレートではdataproc.clusters.*とdataproc.jobs.submitが必要。

### ディスクレーマ
- アップデートの内容はあくまでも個人の理解していることを書いています。正しい内容はリリースノート等を確認下さい。
- リリース内容できるだけ拾うようにしているのですが、抜けていそうなリリースノートが追加するのでぜひ教えて下さい！(一覧[ここ](https://qiita.com/kenzkenz/items/ac18a359b803dbb6b490)で更新してます。)
Windows OS PCからRaspberry PiにSSH接続

Raspberry PiにPCからSSH接続したいことが何度もあったので自分用メモ。

■環境
　- PC : Windows 10, Tera Term
　- Raspberry Pi 3

■手順
１．Raspberry PiとPCを有線LANケーブルで接続
２．Raspberry Piを起動
３．PCのコマンドプロンプトからRaspberry PiのIPアドレスを調べる
　　```ping raspberrypi.local```
４．Tera Termを起動し、下の設定でssh接続
<img width="358" alt="tt.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226926/2cb63f88-82e5-969b-fd01-78d317073b8b.png">
５．ユーザー名「pi」、パスワードでログイン
　※パスワードの初期値は「raspberry」
Laravel hasManyThrough　メモ

#決済情報テーブル

|id  | user_id|決済情報2  |
|---|---|---|
|1  |1 |hoge1 |
|2  |2 |hoge2  |

#中間テーブル(購入した商品と購入者)
|id  |アイテム_id  | 決済情報_id |
|---|---|---|
|1  |1  |1  |
|2  |1  |2 |
|3  |2  |2  |

#商品テーブル

|id  | 商品名 |商品説明  |
|---|---|---|
|1  |huga1  |huga1 |
|2 |huga2  |huga2  |


```
class Settlement extends Model
{
　　
　　　　public function getItems()
　　　　{
　　　　　　　　return $this->hasManyThrough(商品::class, 中間::class, '決済情報_id', 'id', null, '商品_id');
　　　　}
}

```

```
Settlement::with('getItems')->where('user_id', Auth::id())->get();
```


とかとかで、購入ユーザーごとの購入商品の情報が商品テーブルから取得できる。
buttonタグをクリックした時にlocation.hrefが正常に機能しない問題の原因と解決

私の環境だけだと思うんですが、不可解な現象に出くわしたので備忘録。

# TL:DR 原因と解決
buttonタグはonclickを書いてもsubmitを無効にしないとスクリプトが実行されない。
そのため、`<button type='button' onclick='...'>`としなければならなかった。

# 経緯と再現
ボタンをクリックするとページジャンプ！をやりたいので、
`location.href='(ジャンプ先)'`を指定。
サクッとサンプルページを作りたいので、ローカルで環境を作ってVivaldi2.10...で実施。
ディレクトリ構造は以下の通り。

```
# tree
.
├── index.html
└── jump.html
```

たとえば、index.htmlからjump.htmlにリンクさせたいケースがあったとする。
aタグで指定した時はjump.htmlにジャンプできているとして、問題は

- `<input type='button' onclick='...'>`ならjump.html
- `<button onclick='...'>`ならindex.html **?**

にジャンプする。
幾つかのサイトを参考にしたが、**submitについて言及されておらず気付かないとハマるため**、書き残しておく。
LeetCode: 141. Linked List Cycle

# 問題の要約
連結リストにサイクルがあるか判断する問題
※サイクル:連結リストのループがあり、次のリストへ辿っていくと一度通ったリストへ戻る

# 問題
[問題へのリンク](https://leetcode.com/problems/linked-list-cycle/description/)

# 回答１　ブルートフォース的な末尾確認
リストの次要素へ１万回遷移して末尾確認。1万回遷移後に末尾がなければ、サイクルはあるとみなすやり方で回答

```cpp
bool hasCycle(ListNode *head) {
    for(int i=0;i<10000;i++){
        if(head == NULL){
            return false;
        } 
        head = head->next;
    }
    return true;
}
```

Runtime: 12 ms
Memory usage: 9.7 MB
提出でAcceptされたが、力任せの実装であり、サイクルがあるかどうかは具体的に判断してないので達成感なし

 
# 回答２　リストの書き換え
次に、通過した連結リストの中身は書き換えるやり方で回答。次リストへの遷移で書き換えた内容に当たったら、サイクルはあるとみなす。

```cpp
class Solution {
public:
    bool hasCycle(ListNode *head) 
    {
        if(head==NULL || 
           head->val==NULL) {
            return false;
        }
        while (head->next!=NULL) {
            if(head->val==NULL) {
                return true;
            }
            head->val=NULL;
            head = head->next;
        }
        return false;
    }
}
```

Runtime: 12 ms
Memory Usage: 9.7 MB

提出でAcceptされた。Runtime時間は意外にも回答１と変わらなかったです。
クロムブックで CentOS 8 を使う

こちらで行ったのと同じ方法で CentOS 8 をインストールします。
[クロムブックで Arch Linux を使う](https://qiita.com/ekzemplaro/items/f7737b410b6ec72bba7f)

インストール

```text
(termina) chronos@localhost ~ $ lxc launch images:centos/8/amd64 centos
Creating centos
Starting centos
```

状況の確認

```text
$ lxc list centos
+---------+---------+-----------------------+------+------------+-----------+
|  NAME   |  STATE  |         IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
+---------+---------+-----------------------+------+------------+-----------+
| centos  | RUNNING | 100.115.92.206 (eth0) |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
```

root のパスワードを設定する

```text
(termina) chronos@localhost ~ $ lxc exec centos bash
[root@centos ~]# passwd root
Changing password for user root.
New password: 
BAD PASSWORD: The password is shorter than 8 characters
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@centos ~]# exit
exit
(termina) chronos@localhost ~ $ 
```

root でログイン

```text
(termina) chronos@localhost ~ $ lxc console centos
To detach from the console, press: <ctrl>+a q

CentOS Linux 8 (Core)
Kernel 4.19.79-07511-ge32b3719f26b on an x86_64

centos login: root
Password: 
[root@centos ~]# cat /etc/os-release 
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

[root@centos ~]# 
```

ユーザー、グループの追加、パスワードの設定

```text
[root@centos ~]# useradd -u 1200 -m -g wheel uchida
[root@centos ~]# groupadd -g 1200 uchida
[root@centos ~]# passwd uchida
Changing password for user uchida.
New password: 
BAD PASSWORD: The password is shorter than 8 characters
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@centos ~]#
```