OmniAICreator/Qiita-1.07M huggingface dataset:
code-insidersコマンドをCUIから設定する方法

# code-insidersコマンドをCUIから設定する方法

Macの環境移行をスクリプトで行いたかったのでcode-insidersコマンドを使えるようにターミナルから設定したかったが、ドキュメントの方法ではうまくいかなかったのでメモ

結果的に、パスに新たに追記することなくコマンドを有効にできたので、副次的な利点も得られる。
codeコマンドに応用することも可能

## 結論
[解決方法](https://qiita.com/HIJIKI/items/0b0a523b1f3f15a8b68d#code-insidersコマンドをcuiから設定できないときの解決方法)

## vscodeとvscode insidersのコマンド
[VisualStudio Code](https://code.visualstudio.com/)と[VisualStudio Code Insiders](https://code.visualstudio.com/insiders/)はシェルから操作することができる。コマンドはそれぞれ`code`と`code-insiders`である。

### GUIから設定する方法
codeコマンドもcode-insidersコマンドもGUIのコマンドパレットからは正常に設定できる。
方法は公式ドキュメント[^1]参照

### CUIから設定する方法
#### 普通のvscodeの場合 (公式)
CUIから設定するには、ドキュメント[^1]の通り以下のコマンドを実行する。

```bash
echo 'export PATH="$PATH:/Applications/Visual Studio Code.app/Contents/Resources/app/bin"' >> ~/.bash_profile
source ~/.bash_profile
```

#### vscode insidersの場合 (失敗)
vscode insidersのcode-insidersコマンドをCUIから使えるようにする方法はドキュメントに載っていない(たぶん)。
codeコマンドと同じ方法でやってみる。

```bash
echo 'export PATH="$PATH:/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin"' >> ~/.bash_profile
source ~/.bash_profile
```
しかし、以下のように確認してみると使えないことがわかる。

```bash
code-insiders --version
```
> `bash: code-insiders: Command not found`

shellを再読み込みしても変わらず...

##### 考察
どうやら、GUIで設定した場合の内部的な処理はCUIと異なる。
CUIで設定した場合、コマンドの実行ファイルが存在しているディレクトリを直接PATHに追加している。
一方、GUIで設定した場合は/usr/local/binに実行ファイルへのシンボリックリンクを貼っている。/usr/local/binはデフォルトで$PATHに記述されているので、パスの追加を行う必要はない。

## code-insidersコマンドをCUIから設定できないときの解決方法
以下のコマンドで設定できる。

```bash 
ln -s "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code" "/usr/local/bin/code-insiders"
```

### 普通のvscodeの場合
ちなみにcodeコマンドも同じ方法で設定することができる。

```bash 
ln -s "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" "/usr/local/bin/code"
```

### メリット
PATHに追加せず設定できるため、ドキュメントに載っている方法と比較してこちらのほうはシェルを再読み込みする必要がないというメリットがある。


[^1]: [Running Visual Studio Code on macOS](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line)
NestJSでOpenAPI(Swagger)定義をファイル出力する

[公式ドキュメント](https://docs.nestjs.com/recipes/swagger)には起動しているサーバからJSON出力するサンプルしかなかったので調べてみました
単純に `OpenAPIObject` をYAMLなりJSONなりに出力すればよい模様

```typescript:exportOpenAPIDocument.ts
import yaml from 'js-yaml';
import fs from 'fs-extra';
import path from 'path';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { NestFactory } from '@nestjs/core';

const exportOpenAPIDocument = async () => {
  const app = await NestFactory.create(AppModule);

  const documentBuilder = new DocumentBuilder()
    .setTitle('xxxxx')
    .setDescription('xxxxx')
    .setVersion('1.0')
    .build();

  const document = SwaggerModule.createDocument(app, documentBuilder);
  const yamlDocument = yaml.safeDump(document, {
    skipInvalid: true,
    noRefs: true,
  });
  const yamlPath = path.join(__dirname, 'path_to', 'openapi.yml');

  await fs.writeFile(yamlPath, yamlDocument);
};

(async () => await exportOpenAPIDocument())();
```

`package.json` には以下の感じで書いておくと便利でしょう

```package.json（抜粋）
{
  "scripts": {
    "openapi:export": "ts-node src/exportOpenAPIDocument.ts"
  }
}
```

```terminal
$ npm run openapi:export
```

お試しを！👳‍♂️
kaggleをAWS/SageMakerで実践する

# Kaggleを一人でやることの苦しみ
自分のプログラムが合っているのか、不安になる。。
CVの組み方すら間違っていたら、指針が全てパー

ソロ金とったことないが、とるなら2-3ヶ月は時間とって集中しないと難しい感覚。
(1ヶ月では無理だった。ソロ銀）

・リサーチの時間が足りない
・実装の時間が足りない
・検証の（以下略）

圧倒的な実装力 + 最短の最善手を選ぶセンス　が必要。
（一人だと時間が足りないので、できれば3ヶ月前から参加する）

# 2020/7/1 M5感想
https://www.kaggle.com/c/m5-forecasting-accuracy

・検証を効率的に実施するために、MLパイプラインの整備は重要。
・モデリングはデバッグが難しい（コード的には通るので発見しにくい）ので、
なるべく自分のコードを書かないよう、既存のライブラリを有効活用しながら、進める必要がある。
・スパースな時系列は本質的に予測が難しい（ポアソンlossを利用）
・平均の寄与度が高かった。
・recursive forecastはやめたほうがいい。day to day modelが王道。（日数ごとにモデル作成）
・学習データが4000万行とかだと、学習に1h以上かかってしまう。ノートブックインスタンスで通信が切れた時にプログラムが止まってやり直しになることがある。10分以上かかるものは、ジョブにして外に投げる方がいいと感じた。


#vanilla resnetってなんだ？
Vanillaとは、正則化なしのことらしい
http://www.m.cs.osakafu-u.ac.jp/publication_data/1628/miru2018.pdf


#下記をtrainingジョブで学習する。くらいはやりたい。
https://medium.com/@akichan_f/efficientnet-b6-autoaug%E3%81%A8%E5%90%8C%E7%AD%89%E7%A8%8B%E5%BA%A6%E3%81%AE%E7%B2%BE%E5%BA%A6%E3%81%A75%E5%80%8D%E6%97%A9%E3%81%84assemble-resnet-c3b8b846e0a2



#SageMakerに移植するためにトライした手順
1.Sagemaker ノートブックインスタンス上で、作者のgithubのチュートリアルを実行。
2.データをKaggleコンペのものに変えて実行。
3.train.pyに落とし込み

# kaggle tips
【随時更新】Kaggleテーブルデータコンペできっと役立つTipsまとめ
https://naotaka1128.hatenadiary.jp/entry/kaggle-compe-tips


# EC2を使う場合
SageMakerノートブックインスタンスでは、librosaなどのライブラリが入らないことがある。（Amazon Linuxとの相性？）
なので、EC2のUbuntuで実行したいことがある。その場合の手順を記しておく。


1.iterm2からログインできるようにする。
インスタンス作成時に、XXX.pemを作成する。
XXX.pemを ~/.sshに配置する。
$ chmod 400 ~/.ssh/XXX.pem
$ ssh -i ~/.ssh/XXX.pem ubuntu@ec2-X-XX-XX-X.us-east-2.compute.amazonaws.com

2.ログインしたら、jupyterをインストールする。
こちらのブログを参考に、実行していけばOK
https://dev.classmethod.jp/articles/ubuntu-jupyternotebook/

EC2のセキュリティグループの、inboundルールで8888ポートを開けることを忘れない（上記blogに記載されている）
Railsでhamlファイルに動画を埋めこむ

今回はhamlファイル内に動画を埋め込む方法をご紹介します！
背景に動画を流したいときにオススメです。


## publicフォルダにvideosフォルダを作成

## 上記で作成したフォルダ内にあらかじめ用意した動画ファイルを保存

今回は拡張子mp4のファイル、sample.mp4を用います。

## hamlファイルに以下を記述

```○○.html.haml
= video_tag("/videos/sample.mp4", autoplay: true, loop: true, muted: true, class: 'content__box__video')
```

#### video_tag
ビデオタグを用いて動画ファイルを呼び出します。

#### /videos/sample.mp4
参照先のフォルダを指定します。
publicフォルダは指定する必要ありません。

#### autoplay: true
ページ更新時に自動再生されます。

#### loop: true
繰り返し再生になります。

#### muted: true
無音になります。

#### class: 'content_\_box_\_video'
クラス名をつけてscssファイルでレイアウトを調整します。

</br>
## 参考
[【videoタグ】HTMLで動画を埋め込む方法を徹底まとめ](https://webliker.info/52510/)


### → 投稿した動画を表示するにはまた別の方法が必要なので次回ご紹介します！
PyTorch学習メモ

## PyTorchとは

> PyTorchは、コンピュータビジョンや自然言語処理で利用されているTorch（英語版）を元に作られた、Pythonのオープンソースの機械学習ライブラリである。最初はFacebookの人工知能研究グループAI Research lab（FAIR）により開発された。PyTorchはフリーでオープンソースのソフトウェアであり、修正BSDライセンスで公開されている。Pythonインターフェイスの方が洗練されており、活発に開発が行われているが、C++インターフェイスも存在する。

> さまざまなディープラーニングのソフトウェアがPyTorchを利用して構築されており、その中には、UberのPyro、HuggingFaceのTransformers、Catalystなどがある。

> PyTorchは次の2つの高度な機能を備えている。

> ・強力なGPUサポートを備えた（NumPyのような）テンソル演算ができる
> ・テープベースの自動微分システムの上に構築された深層ニューラルネットワークが利用できる

https://ja.wikipedia.org/wiki/PyTorch

## Dockerで環境構築


<details><summary>Dockerfile</summary><div>

```Dockerfile
FROM pytorch/pytorch:1.3-cuda10.1-cudnn7-runtime

RUN pip install --upgrade pip setuptools \
  && pip install matplotlib jupyter
```

</div></details>

<details><summary>docker-compose.yml</summary><div>

```yml

version: '3.3'
services:
  pytorch:
    container_name: pytorch
    build: .
    tty: true
    stdin_open: true
    ipc: host
    ports:
      - "8889:8889"
    volumes:
      - .:/opt/pytorch
    environment:
      - JUPYTER_CONFIG_DIR=/opt/pytorch
    working_dir: /opt/pytorch

```

</div></details>

<details><summary>jupyter_notebook_config.py</summary><div>

```python
c = get_config()
c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8889
c.NotebookApp.token = ''
```

</div></details>



**Jupyter起動までの手順**

```
$ docker-compose up -d pytorch
Creating pytorch ... done

$ docker exec -it pytorch bash

# pwd
/opt/pytorch

# jupyter notebook --allow-root &
```

**後片付けの手順**

```
# exit

$ docker-compose stop
Stopping pytorch ... done

$ docker-compose rm
Going to remove pytorch
Are you sure? [yN] y
Removing pytorch ... done
```

## DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ

**[DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ](https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html)** を用いて、基本的な操作からCIFAR10のデータセットを用いた画像分類までを実施。

このチュートリアルは5つに分かれていて、それぞれどんな内容なのかというと、

### What is PyTorch?

- 基本的なTensorの操作について
- Numpy Array <=> Tensor

### Autogad: Automatic Differentiation

- Gradientsについて

### Neural Networks

- NNの定義について
- Loss functionについて
- バックプロパゲーションについて
- Optimizerについて

### Training a Classifier

- CIFAR10データセットについて
- データセットの準備
- CNNを定義
- Loss function と Optimizerを定義
- ネットワークを学習させる
- テストデータを使って分類
- モデルの保存、読み込み
- 全体のAccuracyの確認
- GPUを使うには

### Optional: Data Parallelism

- 複数のGPUを使用する方法について

## チュートリアルを実施したノートブック

チュートリアルを実施したノートブックは[GitHub](https://github.com/suaaa7/pytorch-tutorial/tree/master/notebook)にPush。

## 参考


https://qiita.com/creaith/items/92b00f5d03c8ecf3948c

https://qiita.com/taka4sato/items/2c3397ff34c440044978

https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html
GitHub Pagesに公開する静的ページを用意する方法

## はじめに
自分がGitHub Pagesを始める際に，調べたり試したことのメモです．

GitHub Pagesはリポジトリの内容を静的ページとしてホスティングしてくれるサービスです.
が，その中身のページを作成する手順は複数あるので，まとめました．

## 記事の構成
- リポジトリを公開するための設定
- 公開するページの作成方法の紹介

の順で説明します


## リポジトリの公開準備
リポジトリの内容を公開するためには設定が必要になります．

- リポジトリを作成する．リポジトリ名がURLに含まれます．
- Setting->（少しスクロールしたところにある）GitHub Pagesの欄のうち，公開するブランチとしてmasterを選択
- (任意で)Jekyllテーマの選択
  テーマを選択すると，自動的にコンフィグファイルとindex.mdが生成されます

設定前
![設定前](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283956/59431a8f-f0e6-edeb-0799-6f0151927a25.png)

設定後
![設定ページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283956/e26a6e55-1b9d-018f-aff9-674accf1fa5a.png)



以上の設定を行うことで公開されます．
作成したプロジェクトサイトのURLは'https://ユーザー名.github.io/リポジトリ名/' となります．

公開の対象となるブランチについて，従来はgh-pagesというブランチが必須でしたが，現在は必要ないです．
しかし，gh-pagesブランチを作成すると，Settingsの選択肢に追加されます．

### 補足：ユーザーページとプロジェクトページ
GitHub Pagesには3種類あります．
1つはユーザー，もしくは組織のサイト，もう1つはプロジェクトのサイトです．

違いはほとんどありません．ただし，下記の内容については違いがあります．

 - 作成できる個数（ユーザー・組織ページは1つまで，プロジェクトページは複数作成できる）
 - URL（リボジトリ名がない分，ユーザーページのほうが短い）


## 静的ページの作り方
はじめに でも書いたように，公開するページを作るためにはいくつかの方法があります．

- 自分でHTML,CSSファイルを用意する
- mdファイルを作成し，GitHubのJekyllでビルド
- ローカルのJekyllでビルドする
- ローカルのJekyll以外の静的サイトジェネレータでビルド

## 方法1：自分でHTML,CSSファイルを用意する
基本的ですが，今時やる人は少ないです．
HTMLファイルだけでなく，CSSを用いた装飾やJavascriptの実行も行えます．

BootStrapなどのCSSフレームワークは，ダウンロードしたもの，CDNのどちらでも利用することもできます．

## 方法2：mdファイルを作成し，GitHubのJekyllでビルド
GitHub PagesにはJekyllという静的サイトジェネレータが組み込まれており，自動的にmdファイルをhtmlに変換してくれます．

Settingからテーマを選択することでデザインを変更できます．一覧にないものでも，configを手で書き換えることで利用できます．

マークダウンを作成してプッシュするだけで，それなりのデザインのサイトが作成されるので一番手軽な方法です．

## 方法3：ローカルのJekyllでビルドする
Ruby製のツールのため，利用にはRubyのインストールが必要になります．

Rubyが使える環境で
```
$ gem install bundler jekyll
$ jekyll new {プロジェクト名}
```
上記のコマンドを実行することで雛形が作成されます．

また，ビルドしたファイルを公開する際には，_config.ymlのurlの項目を以下のように変更します．

```
baseurl: "/{リポジトリ名}"
url: "https://{ユーザー名}.github.io/"
```


## 方法4：ローカルでその他の静的ページジェネレータでビルドする
Jekyll以外にも多くのジェネレータが公開されており，それらを用いて生成したファイルを公開することもできます．
下記のリンクでは静的ページジェネレータが一覧で紹介されています．
https://www.staticgen.com/

この方法のみ，GitHubで自動実行されるJekyllとの衝突を防ぐため，.nojekyllという名前の空ファイルを作成する必要があります．

## おわりに
一口に静的ページと言っても，様々な作成方法がありました．
ポートフォリオや紹介サイトを作ることが目的ならば，Jekyllとイケてるテーマに頼るのが最も手軽そうです．


## 参考
公式ヘルプ https://help.github.com/ja/github/working-with-github-pages
Djangoテンプレートで呼び出し可能な変数を呼び出させないようにする

## 結論
オブジェクトに`do_not_call_in_templates = True`を付与する

```py
class SampleCallableClass:
    do_not_call_in_templates = True
    
    def __call__(self):
        pass

    def sample_method(self):
        pass
    sample_method.do_not_call_in_templates = True
```

## 概要
Djangoテンプレートでは、ある変数が呼び出し可能かどうかをまずチェックし、呼び出し可能であれば引数無しで呼び出します。

例えば、`{{ Hoge.fuga }}`において、`Hoge`が呼び出し可能である場合、これは`{{ Hoge().fuga }}`のように評価されます。

しかしながら、呼び出し可能なオブジェクトを呼び出さずにそのプロパティにアクセスしたいという場合があります。

例えば`Hoge`が列挙型である場合は引数無しでの呼び出し`Hoge()`が出来ずにエラーとなり、残りの要素`.fuga`は評価されず、最終的に空の文字列が出力されます。

こうした状況について、公式ドキュメントには以下のように記述されています。

> Occasionally you may want to turn off this feature for other reasons, and tell the template system to leave a variable uncalled no matter what. To do so, set a `do_not_call_in_templates` attribute on the callable with the value `True`. The template system then will act as if your variable is not callable (allowing you to access attributes of the callable, for example).
> 
> https://docs.djangoproject.com/en/3.0/ref/templates/api/#variables-and-lookups

呼び出し可能オブジェクトに`do_not_call_in_templates = True`を付与することで、呼び出し可能でないかのように振る舞わせることが出来るようになります。

## 余談
Django3.0で追加された`Choices`の実装を読んでいた際に、`ChoicesMeta`の`__new__`メソッドに`do_not_call_in_templates`が使われているのを見つけて記事にしてみました。
画面外の色を黒くしたい！（CSS）

個人アプリでシックな高級感のある感じを出したいと思い、黒基調の動画サイトを作成しています。

デフォルトだと画面外にスクロールすると端が白くなってしまいますが、
下記を追加するだけで他の色に簡単に変えられます！

```○○.css
html {
  background-color: black;
}
```

簡単ですね（笑）
是非試してみてください。
Linuxログイン時にターミナルでの操作ログを自動で取得する

久しぶりの投稿です。
最近はgpd-micropcにubuntu mateをインストールして遊んでいます。
# 経緯
ターミナルでの操作ログを自動で取得する方法がないか、探しいていました。
はじめは.bashrcにscriptコマンド書けばよいだろと思っていましたが、どうもうまくいかないようです。。
色々探した挙げ句、参考になる記事を発見しました。
[How do I log all input and output in a terminal session?](https://askubuntu.com/questions/161935/how-do-i-log-all-input-and-output-in-a-terminal-session)  
# 環境
gpd micropcにubuntu-mateインストールしたものです  

```
OS: Ubuntu 19.10 eoan                                                                                                   
Kernel: x86_64 Linux 5.3.0-40-generic
Shell: bash
DE: MATE 1.22.2
CPU: Intel Celeron N4100 @ 4x 2.4GHz
GPU: Mesa DRI Intel(R) UHD Graphics 600 (Geminilake 2x6)-
```
# やったこと
## 1. rsyslog設定ファイル作成
`logger`コマンドでログを出力させる形になるので、以下に設定ファイルを作成

```
vim /etc/rsyslog.d/bash.conf
```
```/etc/rsyslog.d/bash.conf
local6.*    /var/log/commands.log
```

## 2. `.bashrc` 追記
操作ログ取得対象のユーザのホームディレクトリ配下の`.bashrc` に以下を追記

```
vim /home/hoge(対象ユーザ)/.bashrc
```
```/home/hoge(対象ユーザ)/.bashrc
whoami="$(whoami)@$(echo $SSH_CONNECTION | awk '{print $1}')"export PROMPT_COMMAND='RETRN_VAL=$?;logger -p local6.debug "$whoami [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" ) [$RETRN_VAL]"'
```
## 3. rsyslogサービス再起動
rsyslogサービスを再起動する

```
systemctl restart rsyslog.service 
```
## 4. ログローテート用設定ファイル作成
`logrotate.d` で日次でローテートするように、設定ファイルを作成する

```
vim /etc/logrotate.d/commands
```
``` /etc/logrotate.d/commands
/var/log/commands.log*
{
»-rotate 7
»-daily
»-dateext
»-missingok
»-notifempty
»-compress
»-postrotate
»-»-/usr/lib/rsyslog/rsyslog-rotate
»-endscript
»-su root root                                                                                                          
}
```
# 確認
`.bashrc` を読み込んで

```
source .bashrc 
```
以下のようにファイルが `/var/log` 配下にできていることを確認

```
ls -la /var/log/commands.log*
-rw-r----- 1 syslog adm 4753  3月 15 19:34 /var/log/commands.log
```
```/var/log/commands.log
Mar 15 19:34:29 hoge hoge: hoge@export [3457]: 2020-03-15 19:34:29 cd [0]
Mar 15 19:34:39 hoge hoge: hoge@export [3457]: 2020-03-15 19:34:37 source .bashrc  [0]
Mar 15 19:36:56 hoge hoge: hoge@export [3457]: 2020-03-15 19:36:56 ls -la /var/log/commands.log* [0]
```
## 所感
logrotateできてるかあやしい。。
後、scriptコマンドみたいに出力もほしい。。
Golangでwebアップローダーを作る

とりあえず作成したので、アップロード
https://github.com/karosuwindam/goupload

重要部分を抜き出し
アップロードの関数部分

```go:upload.go
package main
import (
	"fmt"
	"net/http"
	"os"

)

const UPLOAD = "upload"

func upload(w http.ResponseWriter, r *http.Request) {
	var data []byte = make([]byte, 1024)
	var tmplength int64 = 0
	var output string
	urldata := ""
	searchdata := ""
	if r.Method == "POST" {
		file, fileHeader, e := r.FormFile("file")
		if e != nil {
			fmt.Fprintf(w, "アップロードに失敗しました。")
			return
		}
		writefilename := fileHeader.Filename
		fp, err := os.Create(UPLOAD + "/" + writefilename)
		if err != nil {
		}
		defer fp.Close()
		defer file.Close()
		for {
			n, e := file.Read(data)
			if n == 0 {
				break
			}
			if e != nil {
				return
			}
			fp.WriteAt(data, tmplength)
			tmplength += int64(n)
		}
		fmt.Printf("POST\n")
	} else {
		fmt.Printf("GET\n")
                fmt.Fprintf(w, "GET読み込み")
		return
	}
	fmt.Fprintf(w, "ファイルアップロード")
}
```

サーバのスタート部分

```go:main.go
package main

import (
	"net/http"
	"fmt"
)

const Port = "8080"
const Ipdata = ""


func webstart() {
	http.HandleFunc("/upload/", upload)
	http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("./html"))))
	http.ListenAndServe(Ipdata+":"+Port, nil)
}

func main() {
	fmt.Printf("%v:%v Webserver start\n", Ipdata, Port)
	webstart()
}

```

index部分ファイルアップロードはブラウザのPOST命令に任せる

```html:index.html
<html>
    <head>
        <title>upload</title>
    </head>
    <body>
        <form action="/upload/" method="post" enctype="multipart/form-data">
        <input type="file" name="file" id="up_loadfile" multiple="multiple">
        <input type="submit" value="send">
        </form>
    </body>
</html>
```

メモ書き程度なので、githubのアップロードファイルをビルドした方が多機能かも
Send Mail from laravel using SMTP on XSERVER

## Environment

```.env
MAIL_DRIVER=smtp   
MAIL_HOST=sv[YOUR_NUM].xserver.jp           
MAIL_PORT=587
MAIL_USERNAME=[YOUR_MAIL]
MAIL_PASSWORD=[PASSWORD_FOR_YOUR_MAIL]
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=[ADDRESS_YOU_WANT]
MAIL_FROM_NAME=[ANYTHING_YOU_WANT]
```
※Domain name of MAIL_FROM_ADDRESS have to be same as MAIL_HOST.

## Controller

```

<?php                                                                                                                                                                                                                                     
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Mail;
 
class SendmailController extends Controller
{
    public function sendMail() 
    {   
        Mail::send('mail', array(), function($message){
            $message->to('address@example.com', 'Title')->subject('Test mail');
        }); 
    }   
}

```

## SPF Record

If you can't send mail from xserver, please check your spf record on xserver.

## CAUTION

If you put your server without Japan.
You need to change setting like below.

![Artboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256447/ba192bda-a777-3ac7-256c-95cbc552f005.png)
DjangoのChoiceFieldを列挙型で指定する

Djangoの`models`における`TextField`や`IntegerField`、そして`forms`における`ChoiceField`に用いる`choices`には、これまでは以下のような形式の値が必要でした。

```py
YEAR_IN_SCHOOL_CHOICES = [
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
]
```

Django3.0からは`TextChoices`と`IntegerChoices`というクラスが追加され、以下のような書き方が出来るようになりました。

```py
class YearInSchool(models.TextChoices):
    FRESHMAN = 'FR', 'Freshman'
    SOPHOMORE = 'SO', 'Sophomore'
    JUNIOR = 'JR', 'Junior'
    SENIOR = 'SR', 'Senior'
    GRADUATE = 'GR', 'Graduate'

YEAR_IN_SCHOOL_CHOICES = YearInSchool.choices
```

`TextChoices`や`IntegerChoices`は`Enum`クラスを継承しているので、それに近い感覚で書くことが出来るようになりました。

もちろんただ列挙型として扱うことが出来るだけでなく、ラベル(フォームで表示される文字列、各タプルの2要素目の値)の値も保持しています。

## プロパティ
### `names`, `values`, `FIELD.name`, `FIELD.value`
```py
>>> YearInSchool.names
['FRESHMAN', 'SOPHOMORE', 'JUNIOR', 'SENIOR', 'GRADUATE']
>>> YearInSchool.values
['FR', 'SO', 'JR', 'SR', 'GR']
>>> YearInSchool.FRESHMAN.name
'FRESHMAN'
>>> YearInSchool.FRESHMAN.value
'FR'
```

`name`では列挙型のフィールド名が、`value`ではDBに格納される文字列が返されます。

これは`Enum`の実装によるものです。

### `labels`, `FIELD.label`
```py
>>> YearInSchool.labels
['Freshman', 'Sophomore', 'Junior', 'Senior', 'Graduate']
>>> YearInSchool.FRESHMAN.label
'Freshman'
```

ラベルが返されます。モデルのフィールドに対しては`get_FOO_display`(`FOO`はフィールド名)というプロパティが自動生成され、これを呼び出すことでもラベルが取得できます。

https://docs.djangoproject.com/en/3.0/ref/models/instances/#django.db.models.Model.get_FOO_display

### choices
```py
>>> YearInSchool.choices
[('FR', 'Freshman'), ('SO', 'Sophomore'), ('JR', 'Junior'), ('SR', 'Senior'), ('GR', 'Graduate')]
```

以前の`choices`で指定する形式でのタプルのリストが返されます。

## 文字列からラベルを取得する
```py
>>> YearInSchool('FR').label
'Freshman'
>>> YearInSchool['FRESHMAN'].label
'Freshman'
```
上記のようにして`Enum`のフィールドを取得し、`name`, `value`, `label`が取得可能です

## ラベルを指定しない場合
```py
class Vehicle(models.TextChoices):
    CAR = 'C'
    TRUCK = 'T'
    JET_SKI = 'J'

>>> Vehicle.JET_SKI.label
'Jet Ski'
```

アンダースコア(`_`)を半角スペースに変換し、タイトルケース(各単語の先頭を大文字にする)を適用してラベルにするようです。

## 公式ドキュメント
https://docs.djangoproject.com/en/3.0/ref/models/fields/#choices
シュノア署名

###　使用される記号と意味
| 記号 | 意味 |
|---|----|
| $G$ |集合|
| $g$ |ジェネレーター|
| $q$ |ジェネレーターの位数|
| $s$ |秘密鍵|
| $h$ |公開鍵 $\,h=g^s\,$|
| $H$ |ハッシュ関数|
| $m$ |メッセージ|

### シュノア証明
ゼロ知識証明を改良して、手順の繰り返しの必要をなくしたもの。

##### 例
証明者が、ESDSAの秘密鍵を$\,s\,$を知っていることを、秘密鍵が検証者にもれない形で、検証者が確かめる。

1. 証明者は、$Z_q\,$から$\,r\,$をランダムに選択し、$x = g^r$を計算して、検証者に送る。
1. 検証者は、ゼロ知識証明とは違って$c\,$を$\,0, 1\,$からではなく、$Z_q\,$から選択して、証明者に送る。← **ゼロ知識証明との違いはここだけ**
1. 証明者は、$y = r + sc \bmod q\,$を計算して検証者に送る。
1. 検証者は、$g^y = xh^c\,$が成り立つかを調べる。

証明者が秘密鍵を知っていれば、
$$
y = r + sc\,,\;
g^y = g^{r+sc} = g^r g^{sc} = xh^c
$$

となるので、検証式（ステップ４）は成り立つ。
また、この手順では、検証者に秘密鍵は漏れない。

証明者が秘密鍵を知らない場合に、検証式が成り立つ確率は$\,1/q\,$なので、$\,q\,$を大きくすることで、その確率を無視できる程度に小さくできる。

### シュノア証明の非対話化
検証者から証明者にランダムな数値を送るステップを省き、証明者が代わりにその数値を作成することで、対話的なやりとりをゼロにすることが出来る。

以下は、上の例を非対話化したもの。現実には、証明者がランダム数値の代わりに、$\,x\,$にハッシュ関数を適用した値が使われるので、その形で変えてある。

1. 証明者は、$Z_q\,$から$\,r\,$をランダムに選択し、$x = g^r$を計算して、検証者に送る。
1. 証明者は$\,c = H(x)\,$を計算して、検証者におくる。← **上の例との違いはここだけ**
1. 証明者は、$y = r + sc \bmod q\,$を計算して検証者に送る。
1. 検証者は、$g^y = xh^c\,$が成り立つかを調べる。

####　通信の効率化
上の手順では、証明者から検証者に$\,x, c, y\,$がバラバラに送られているが、一度に送っても問題ない。また、$\,x = g^y/h^c\,$なので、$\,x\,$を送らないことで、データー量を削減できる。

### シュノア署名
非対話型のシュノア署名のハッシュ関数の入力にメッセージを含めると、デジタル署名として使うことが出来る。

1. 証明者は、$Z_q\,$から$\,r\,$をランダムに選択し、$x = g^r$を計算する。
1. 証明者は、$\,c = H(x || m)\,$を計算する。
1. 証明者は、$y = r + sc \bmod q\,$を計算して、署名を$\,\sigma = (c, y)\,$とする。
1. 証明者は、検証者に$\,(m, \sigma)\,$を送る。
1. 検証者は、$\,x = g^y/h^c\,$を計算する。
1. 検証者は、$\,c = H(x || m)\,$が成り立つかを調べる。成り立てば署名は正しい。

###参考文献
暗号技術のすべて/IPUSIRON
日本語でfortuneを呟かせる

古の「格言を発する」コマンド、fortuneをgoogle先生の力で邦訳にしてもらいます。
便利な世の中になりました。

[LinuxのCUIを使ってgoogle翻訳を実行する](https://qiita.com/YuiM/items/1287286386b8efd58147)
を参照しつつ

```shell
fortune |trans -b :ja
```
XSERVERのSMTPをECS（EC2）から使おうとすると送信できない

## 問題

XSERVERのSMTPを使ってメールを送りたいのだが、送れなかった。
認証情報は合ってる、ローカルからもその情報で送れる。
ECSに上げるとエラーとなる。


## エラー内容

```
Swift_TransportException
Expected response code 354 but got code "554", with message "554 5.5.1 Error: no valid recipients "
```

## 原因

**サーバの置き場所がソウルでした**

ということでアクセス制限設定を変更。

![Artboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256447/fd428c47-94e4-95cb-8059-4b67ebbd293a.png)


無事送信できた。
【Laravel】 外部制約キーを migration で設定しようとしたらエラー

## 何が起きたか

`hoge` テーブルに `users` テーブルの`id` で外部制約キーを設定しようと migrate 実行時にエラーが

## 結論
`bigInteger`で制約を付けたいカラムにを定義しないと、 `migration`ファイル作成時に記述されている `$table->id()` と型が異なってしまう

知っていればつまづくポイントにもならないと思いますが、自分の備忘録として・・・

## エラーパターン

### migration

```php
// users テーブル

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('login_id');
        $table->string('password');
        $table->timestamps();
    });
}
```

```php
// hoge テーブル

public function up()
{
    Schema::create('hoge', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->integer('user_id')->unsigned();
        $table->timestamps();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}
```

### エラー内容

エラーを見ると 
`Cannot add foreign key constraint`

...エラーが起きたのどこだろ

MySqlの場合下記実行でエラー内容の詳細が見れる。

```sql
SHOW ENGINE INNODB STATUS;
```

`status` カラムの `LATEST FOREIGN KEY ERROR` とある部分を見ると

```
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
```

エラーに従って `users` の `id` と `hoge` の `user_id` をチェックすると
`users.id` は `BIGINT`
`hoge.user_id` は `INT` 

型が違った

### 修正内容

`hoge` テーブルの `user_id` 定義を変更してやればOK

```php
// hoge テーブル 修正後

public function up()
{
    Schema::create('hoge', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->bigInteger('user_id')->unsigned();
        $table->timestamps();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}
```
TerraformでGCPの操作(踏み台サーバーの作成)

# 概要

Terraformを使ってGCPを操作する方法

# やること

GCP上に下記構成のVM(GCE)をつくり、SSHでログインする。

![DeepinScreenshot_select-area_20200315190544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40665/a5327090-e4cf-a429-8b87-517a59c6c483.png)


# 実行方法

- [コード](https://github.com/AtsushiKitano/assets/tree/master/terraform/gcp/bation)
    - terraform.tf: terraformバージョンなど実行環境
    - provider.tf: resource,dataなど実行するsdkバージョンの情報
    - vpc-network.tf: vpcネットワークの作成
    - subnetwork.tf: サブネットワークの作成
    - firewall.tf: ファイアウォールの作成
    - gce.tf: gceの作成

システムのデプロイ

```
$terraform apply
```

GCEへのログイン

```
$ gcloud compute ssh bastion
```

システムの破棄

```
$terraform destroy
```
【Rails】where

#whereメソッド
与えられた条件に対して合っていたレコードを全て返す。

```rb
#titleが「test」にマッチするレコードを全て取得
Book.where(title: "test")
=> [#<Book:0x007f978ebe0960
  id: 2,
  title: "test",
  price: 960,
  publish: "test",
  created_at: Sat, 05 May 2018 05:58:20 UTC +00:00,
  updated_at: Sat, 05 May 2018 05:58:20 UTC +00:00>,
 #<Book:0x007f978ebe0780
  id: 10,
  title: "test",
  price: 800,
  publish: "fuga",
  created_at: Mon, 17 Sep 2018 15:30:55 UTC +00:00,
  updated_at: Mon, 17 Sep 2018 15:30:55 UTC +00:00>]
```
Vue.extend で TypeScript がエラーを吐いたときに確認すべきこと

Vue の単一ファイルコンポーネントを TypeScript で書く方法はいくつかある。僕はなるべく JS に近い書き方をしたくて、`Vue.extend` を使っているのだが、時々下のような型エラーが発生する。

```
Property 'XXX' does not exist on type 'Vue'.
```

なお、ここで言う `XXX` とは、SFC 内にある `computed` の変数だったり `methods` にある関数だったりする。このようなときに確認するべき場所を自分の備忘録も兼ねてまとめておく。

## computed や methods の関数にアノテーションをつけているか

`Vue.extend()` で型の推論を行っている場合、引数として書いたオブジェクトをもとに、そのオブジェクト内で使われる `this` の推論が行われる。そのため、型推論に頼っていると、しばしば失敗して `this` の型が正しく認識されなくなるのである。(雑な理解なので、詳しい方いたら教えてください:bow:)

対処法としては、`computed`や`methods`に書いた関数には、しっかり下のようにアノテーションを書いてあげれば良い。これは Vue の TypeScript サポートに関するページにも記載があるが、ちょくちょくフォーラムでも同様の質問があり、案外見落としがち（自分もハマった）。

```typescript
import Vue from 'vue';

export default Vue.extend({
  data() {
    return {
      msg: 'Hello'
    };
  },
  methods: {
    // アノテーションをしっかり書く
    greet(): string {
      return this.msg + ' world';
              //  ~~~ ← 書かないとここがエラーになることがある
    }
  },
  computed: {
    // ここもアノテーションをしっかり書く
    greeting(): string {
      return this.greet() + '!';
              //  ~~~~~ ← 書かないとここがエラーになることがある
    }
  }
});
```

[TypeScript のサポート — Vue.js](https://jp.vuejs.org/v2/guide/typescript.html#%E6%88%BB%E3%82%8A%E5%80%A4%E3%81%AE%E5%9E%8B%E3%81%AB%E3%82%A2%E3%83%8E%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E3%81%A4%E3%81%91%E3%82%8B)

## オプションなどをスペルミスしていないか

昨日ハマったのはこっち。例えば、下のようにpropsのオプションを書き間違えたとする。

```typescript
export default Vue.extend({
  props: {
    imageUrl: {
      type: String as PropType<string>,
      require: true    // ← 本当は require"d" !!!
    }
  },
});
```

この場合にも、冒頭に書いたエラーがthisに生えている変数や関数すべてに発生してしまう。同様に `type` を `tyep` にスペルミスしたときとかにも起こるので気をつけたい。

参考: Vue/Typescript 3.5.1 Error: 'property' does not exist on type 'Vue' - Get Help - Vue Forum
https://forum.vuejs.org/t/vue-typescript-3-5-1-error-property-does-not-exist-on-type-vue/65591

## まとめ

エラーメッセージが直接的ではない分、原因の特定に時間を食いがちなので気をつけましょう😇
単純換字暗号方式（シーザー暗号）について

# 単純換字方式とは?
単純換字方式とは最も基本的で簡易な暗号方式の一つであり、平文で用いられる26個のアルファベットと暗号文で用いられるの26個のアルファベットをランダムに一対一対応させて暗号化していく方法である。

例を持ち出すのがわかりやすいので以下に紹介する。

### 例
アルファベットの対応テーブル

| 平文   | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z |
|--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 暗号文 | d | i | q | m | t | b | z | s | y | k | v | o | f | e | r | j | a | u | w | p | x | h | l | c | n | g |

上のテーブルに従って平文のアルファベットを換字していくと、以下のような暗号化が行われる。
>平文　： get home
>暗号文： ztp srft　

## 鍵（_カギ_）について
暗号化された文章を平文に戻すには専用の_カギ_が必要になります。単純換字方式では、特別な場合を除いて、上記のようなアルファベット対応テーブルが_カギ_の役割を果たします。
しかし、この鍵は人間にとって非常に覚えづらいですよね。そこで人間にとって覚えやすい_カギフレーズ_というものを用いて_カギ_を作る方法があります。

### _カギ_の作り方
_カギフレーズ_を`vanity is my favorite sin`とする。この_カギフレーズ_から重複するアルファベットを削除すると、`vanitysmfore`というアルファベット列ができる。
これに残りのアルファベットを付け足すと`vanitysmforebcdghjklpquwxz`という26文字のアルファベット列ができるので、このアルファベット列を`abcdefghijklmnopqrstuvwxyz`に対応させて暗号化すれば良い。
>平文　： hello world
>暗号文： qtttj xjkto

つまり、_カギフレーズ_と_カギ_を作成するこのアルゴリズムさえ分かっていれば、26組もあるアルファベットの１対１対応を覚えておく必要はなくなる。

## シーザー暗号
ジュリアス・シーザーがガリア戦争で用いたことで知られる、シーザー暗号も単純換字暗号方式の一つです。
下のテーブルでは平文のアルファベットが4つ先のアルファベットに置き換えられて暗号文が作られる。（シーザーが実際に用いたのは３つ先のアルファベットに置き換えられる。）

| 平文   | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z |
|--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 暗号文 | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z | a | b | c | d |

上のテーブルを用いて平文をシーザー暗号に暗号化してみると以下のようになる。
>平文　：　hello world
>暗号文：　lioos asvph

### シーザー暗号の鍵（_カギ_）について
シーザー暗号においては、_カギ_は1~26の整数によって表すことができる。この整数はアルファベットのシフト回数（何個先のアルファベットに置き換えるか）を示していて、上の例では_カギ_は４である。1~26に限られるのは、27回のシフトが１回のシフトと同値であることから理解いただけると思います。
KotlinでもPythonみたいに文字列操作したい！

kotlinの文字列操作も便利だけどやっぱりPythonみたいに文字列操作したいなぁ

というわけで、kotlinでもPythonと同等の文字列操作ができるようになるライブラリを作りました。  

## ktPyString
https://github.com/ChanTsune/ktPyString

Stringに対して拡張関数を定義することで、kotlinでもpythonみたいな文字列操作ができるようにしています。  

## 導入  

### Gradle

```groovy:build.gradle
dependencies {
    ...
    implementation 'dev.tsune:ktPyString:0.0.0'
    ...

}
```

### Maven
```xml
<dependency>
  <groupId>dev.tsune</groupId>
  <artifactId>ktPyString</artifactId>
  <version>0.0.0</version>
  <type>pom</type>
</dependency>
```

依存ライブラリに追加します。  


## 文字列操作

### スライス
```kotlin
val str = "0123456789"
str[0,5]
// 01234
str[0,8,2]
// 0246
str[null,null,-1]
// 9876543210
```

Pythonista御用達のスライス操作です。  
一度慣れると他の言語でもやりたくなるやつです。  

ちなみに同じ動作をPythonで書くと以下のようになります。  

```python
str = "0123456789"
str[0:5]
# 01234
str[0:8:2]
# 0246
str[::-1]
# 9876543210
```

#### 文字列検索  
```kotlin
// 先頭からの検索  
"123412312312345".find("123") // 0

// 開始位置を指定して検索
"123412312312345".find("123",start:2) // 4

// 終了位置を指定して検索
"123412312312345".find("123",end:1) // -1

// 末尾からの検索
"123412312312345".rfind("123") // 10

```
末尾からの検索も同様に開始位置と終了位置を指定して検索できます。  

#### 文字列結合  
```kotlin
val array = ["abc","def","ghi"]
"".join(array) // "abcdefghi"
"-".join(array) // "abc-def-ghi"
"++".join(array) // "abc++def++ghi"
```

#### 文字列分割  
##### 行ごとの分割  
```kotlin
"abc\nabc".splitlines() // ["abc", "abc"]
"abc\r\nabc\n".splitlines() // ["abc", "abc"]

// 改行文字を残して分割
"abc\nabc\r".splitlines(true) // ["abc\n", "abc\r"]
"abc\r\nabc\n".splitlines(true) // ["abc\r\n", "abc\n"]
```

#### トリミング  
```swift
// 右端のみ
"rstrip sample   ".rstrip() // "rstrip sample"
"rstrip sample   ".rstrip("sample ") // "rstri"
"  rstrip sample".rstrip() // "  rstrip sample"

// 左端のみ
"  lstrip sample".lstrip() // "lstrip sample"
"  lstrip sample".lstrip(" ls") // "trip sample"
"lstrip sample".lstrip() // "lstrip sample"

// 両端
"   spacious   ".strip() // "spacious"
"www.example.com".strip("cmowz.") // "example"
```

#### 出現回数カウント  
```swift
"abc abc abc".count("abc") // 3

// 開始位置の指定
"abc abc abc".count("abc", start:2) // 2

// 終了位置の指定
"abc abc abc".count("abc", end:1) // 0
```


#### ゼロ埋め  
```swift
"abc".zfill(1) // "abc"
"abc".zfill(5) // "00abc"

// 符号付きの場合
"+12".zfill(5) // "+0012"
"-3".zfill(5) // "-0003"
"+12".zfill(2) // "+12"
```
符号付きの場合は符号の後ろにゼロが入ります。  


### さいごに  
全部書いていると長くなってしまうので、紹介はこの辺りで。

このほかにも、Pythonのstr型で利用できるメソッドは言語機能的に実現不可能または、実現が難しいもの以外ほとんどサポートしています。  


Pythonからプログラミングを始めたという人なら、慣れ親しんだPythonの文字列操作ができるようになるので比較的便利ではないでしょうか？

このメソッド実装できるよ、とかこっちの実装の方がパフォーマンスいいんじゃない？  
 kotlinだったらこう書くと綺麗だよ等ありましたら教えてください。

プルリクお待ちしております。

もしあれば、バグ報告とかも嬉しいです。

余談ですが、Swift版のライブラリも過去に作っているので、iOSとAndroidで文字列操作周りの処理をほとんどコピペで動かすこともできるかも知れません。(Swiftとkotlin の文法が割と似ているので)
https://qiita.com/ChanTsune/items/bd611a4c778c0fb338e6
C言語でスタック


# はじめに
C言語は標準ライブラリにコンテナを扱う様な機能を持たないので、自作する必要があります。
本記事はC言語によるシンプルなスタックの実装です。

スタックの主な用途は以下の通りです。

- 空きリソース（メモリプール等）管理
- 深さ優先探索の探索先管理

PopもPushも定数オーダーなので気軽に使えます。

# 実装例
```C
#include <stddef.h>
#include <stdint.h>
#include <limits.h>

#define MAX_ELEMENTS (255U)

#if UINT8_MAX < MAX_ELEMENTS
#error
#endif

typedef struct Stack_ {
    void* stack[MAX_ELEMENTS];
    uint8_t sp;
} Stack;

void Stack_Construct(Stack* stack_instance)
{
    stack_instance->sp = 0U;
}

int Stack_Push(Stack* stack_instance, void* element)
{
    uint8_t sp = stack_instance->sp;
    if (sp == MAX_ELEMENTS) {
        return 0;
    }
    stack_instance->stack[sp] = element;
    stack_instance->sp = sp + 1U;
    return (!0);
}

void* Stack_Pop(Stack* stack_instance)
{
    uint8_t sp = stack_instance->sp;
    void* element;
    if (sp == 0U) {
        return NULL;
    }
    stack_instance->sp = sp - 1U;
    element = stack_instance->stack[sp - 1U];
    return element;
}
```

# 備考
ペイロード型の値のうち、向こう値が存在するのであれば、要素数ゼロの時の``Stack_Pop``の戻り値を無効値とすることで「要素を取り出せなかった」事を表現できます。
一方、ペイロード型の値が全て有効値の場合、``Stack_Pop``は値とは別に要素を取り出せたのか、取り出せなかったのかを表すブール値を返す必要があります。
もしくは、要素数ゼロの時の``Stack_Pop``呼び出しを不正呼び出しとして``assert``で保護し、代わりに要素数を取得するAPIを用意しても良いです。

```C
#include <assert.h>

uint8_t Stack_GetNumberOfElements(Stack const* stack_instance)
{
    return stack_instance->sp;
}

void* Stack_Pop(Stack* stack_instance)
{
    uint8_t sp = stack_instance->sp;
    void* element;
    assert(0U < sp);
    stack_instance->sp = sp - 1U;
    element = stack_instance->stack[sp - 1U];
    return element;
}
```
SASで複数の変数を縦持ち変換にする

# 複数の変数を縦持ち変換にしたい
　臨床試験のデータを集計する前に、変数が横持ちになっているRawデータを縦持ちに変換(整形)するという作業が必要です。
臨床試験周りのDBの設計は横持ちになっていることが多く、何はともあれとりあえず縦持ちにしなければ何もできません。

# やりたいこと
こうなっているデータを

| SUBJID      |   WBC01 |  WBC02| WBC03|LYMP01|LYMP02|LYMP03|
|:---:|:-------:|:-----------:|:--------:|:-----------:|:-------:|:--------:|:---------:|
|01-0001|6500 |5500| 3200 |3400 |3500| 1780|
|01-0002|4500 |3200| 2000 |2000 |2800| 1280|
|01-0003|5500 |7000| 6400 |3600 |4350| 5090|
|01-0004|3300 |2900| 1500 |1500 |1400| 700|

こうしたい

| SUBJID      |   WBC|LYMP|
|:---:|:-------:|:-----------:|
|01-0001|	6500|	3400|	
|01-0001|	5500|	3500|	
|01-0001|	3200|	1780|	
|01-0002|	4500|	2600|	
|01-0002|	3200|	2800|	
|01-0002|	2000|	1200|	
|01-0003|	5500|	3640|	
|01-0003|	7000|	4350|	
|01-0003|	6400|	5090|	
|01-0004|	3300|	1550|	
|01-0004|	2900|	1400|	
|01-0004|	1500|	700|

# 方法1. proc transpose

proc transposeを使用して実現する場合、

```sas:transpose.sas
*---白血球数とリンパ球数の架空のデータを作成---;
data lbset0１;
 input SUBJID:$10. wbc01:$8. wbc02:$8. wbc03:$8. LYMP01:$8. LYMP02:$8. LYMP03:$8.;
 cards;
 01-0001 6500 5500 3200 3400 3500 1780 
 01-0002 4500 3200 2000 2600 2800 1200 
 01-0003 5500 7000 6400 3640 4350 5090 
 01-0004 3300 2900 1500 1550 1400 700
 ;
run;

*---WBCのみ転置----;
proc transpose data=lbset01　out=wbc PREFIX=WBC;
  var wbc01 wbc02 wbc03;
  by SUBJID;
run;

*---LYMPのみ転置----;
proc transpose data=lbset01　out=lymp PREFIX=LYMP;
  var LYMP01 LYMP02 LYMP03;
  by SUBJID;
run;

*--マージKeyでソートしておく---;
proc sort data=wbc;
 by SUBJID;
run;

proc sort data=lymp;
 by SUBJID;
run;

data Lbdata;
 merge trlbset01 trlbset02;
 by SUBJID;
run;

```
## 一見良さそうだけど
　今回は白血球数とリンパ球数の2項目だったが、実際、業務で扱う臨床検査値はもっと多い。
　10項目あれば、10項目分transposeする必要がある。

# 方法2. proc sql(union all)

sql(union all)を使ってみる

```sas:union_all_1.sas
*---白血球数とリンパ球数の架空のデータを作成---;
data lbset0１;
 input SUBJID:$10. wbc01:$8. wbc02:$8. wbc03:$8. LYMP01:$8. LYMP02:$8. LYMP03:$8.;
 cards;
 01-0001 6500 5500 3200 3400 3500 1780 
 01-0002 4500 3200 2000 2600 2800 1200 
 01-0003 5500 7000 6400 3640 4350 5090 
 01-0004 3300 2900 1500 1550 1400 700
 ;
run;

*---union allを使わないと重複データが削除されるので注意----;
proc sql;
 create table lbdata as
 select SUBJID,WBC01,LYMP01 from lbset01
 union all select SUBJID,WBC02,LYMP02 from lbset01
 union all select SUBJID,WBC03,LYMP03 from lbset01
 ;
quit;
```
## 一見良さそうだけど
　今回は1レコードあたりの白血球数とリンパ球数のデータ数が同じだったが、
　異なる場合は工夫する必要がある。

```sas:union_2.sas

data lbset02;
 input SUBJID:$10. wbc01:$8. wbc02:$8. wbc03:$8. LYMP01:$8. LYMP02:$8. LYMP03:$8. LYMP04:$8.;
 cards;
 01-0001 6500 5500 3200 3400 3500 1780 1500
 01-0002 4500 3200 2000 2600 2800 1200 1000
 01-0003 5500 7000 6400 3640 4350 5090 4900
 01-0004 3300 2900 1500 1550 1400 700 1000
 ;
run;

*---WB04は存在しない変数のため""を取得するようクエリを書く---;
proc sql;
 create table lbdata as
 select SUBJID,WBC01,LYMP01 from lbset02
 union all select SUBJID,WBC02,LYMP02 from lbset02
 union all select SUBJID,WBC03,LYMP03 from lbset02
 union all select SUBJID,"",LYMP04 from lbset02
 ;
quit;
```

# 結論
普段はmysqlを触っていることもあり個人的な好みはsqlですが、
実行速度を考えると悩ましいですね。

# 最後に
まだまだSASを触りたての初心者なので、もっと良いやり方があれば是非教えてくださると嬉しいです。
「Azure Stack」とは？

「[Azure SDK for Go のドキュメント](https://docs.microsoft.com/ja-jp/azure/go/)」サイトの「[Azure SDK for Go のインストール](https://docs.microsoft.com/ja-jp/azure/go/azure-sdk-go-install)」ページの「[Azure SDK for Go を入手する](https://docs.microsoft.com/ja-jp/azure/go/azure-sdk-go-install#get-the-azure-sdk-for-go)」セクションにて、Azure SDK for GoはGo 1.8以上をサポートしているが、Azure Stack環境だとGo 1.9以上が必要だと書かれてあります。

「[Azure Stack](https://docs.microsoft.com/ja-jp/azure-stack/)」は初めて見聞きするサービス名なので少し調べました。

Azure Stackは、グローバル Azureを利用できない企業などがオンプレミス環境で利用できる様にしたAzureの拡張機能です。

自社内にMicrosoft 認定 ハードウェア パートナーから提供されたAzure Stackをセットアップした物理 サーバーを構えることで、オンプレミスで利用したりグローバル Azureと連携させたりできます。

Azure Stackには3つの製品ファミリーがあります。

[Azure Stack Hub](https://docs.microsoft.com/ja-jp/azure-stack/operator/azure-stack-overview)

- 仮想マシン、Webアプリ＆関数、コンテナーなどを実行するサーバー製品。
- 運用はオンプレミスで、グローバル Azureとの連携も可能。

[Azure Stack Edge](https://docs.microsoft.com/ja-jp/azure/databox-online/data-box-edge-overview)

- 主にAI/ML向けでFPGAが組み込まれた1Uラックマウント型サーバー製品。
- 処理したデータはネットワーク経由でグローバル Azureに転送。

[Azure Stack HCI](https://docs.microsoft.com/ja-jp/azure-stack/hci/overview)

- Azure HCIを採用したサーバー製品。
- サービスは仮想マシンとして実行してグローバル Azureと連携する。

個人的には、自社でサーバー用 Azureがインストールされた物理 サーバーを購入して運用するソリューション サービスだと解釈しました。

【用語の補足】

グローバル Azure：パブリック クラウド版 Azureのこと
オンプレミス (on-premise)：自社内にハードウェアやソフトウェアを構築して情報システムを運用する形態。
HCI (Hyper Converged Infrastructure)：CPU処理、ストレージ、ネットワークを仮想化して統合した基盤
rbenvの基本的な使い方まとめ

# rbenv
rubyをプロダクト毎にバージョンを管理する必要性は以下の2つにあると考えています。

- ローカルを汚さない
- 複数のプロダクトを落とす毎に毎度毎度バージョンを切り替えるのは大変

gemsetを併用して使うと尚、いいと推測します。下記のリンクはrbenv-gemsetの使い方です。
[rbenv-gemsetを使ってプロジェクト毎のgemを管理して、railsプロジェクトを開始する
](https://qiita.com/Nedward/items/95af1d5da4171879878b)

## rbenvをbrewでインストールする

```
$ brew installl rbenv
```

## rbenvの基本コマンド群

```
インストールできるrubyのパッケージを確認
$ rbenv install -l

インストールしてあるrubyのバージョンを管理できる
$ rbenv versions

rbenvの初期化
$ rbenv init

rubyをインストールする
$ rbenv install バージョン

インストールしたrubyのバージョンを反映させる
$ rbenv rehash

システム全体のrubyバージョンを設定する
$ rbenv global rubyバージョン

プロダクト毎にrubyバージョンを設定する
$ rbenv local rubyバージョン
```

基本的なコマンドはざっと上記の通りです。

## プロダクト毎にrubyバージョンを管理する

### 必要なrubyバージョンを手に入れる

```
$ rbenv install rubyバージョン

$ rbenv rehash
```

### 初期化する

```
$ rbenv init
# Load rbenv automatically by appending
# the following to ~/.zshrc:

eval "$(rbenv init -)"
```

initして出てきた内容を.zshrcに書き込み、反映させる

```
$ echo 'eval "$(rbenv init -)"' >> .zshrc

$ source ~/.zshrc
```

ここまではglobalでrubyバージョンを反映させる時も行う動作。

```
$ which ruby
/usr/bin/ruby
```

と出てくる場合はまだ参照先がシステムのrubyに向いているので、initを行って設定ファイルをsourceコマンドで反映させた後に

```
$ which ruby
/Users/あなたのユーザー名/.rbenv/shims/ruby
```

のようなパスが返ってくれば、rbenvでinstallしたrubyを見るようになっている。


### 管理するプロダクトへ移動し、localへセットする

```
$ cd プロダクト名

$ rbenv local rubyバージョン

下記のようなファイルができているはずです
$ cat .ruby-version
2.5.4
```

### rubyのバージョンが変わったことを確認する

```
プロダクト内部では下記のバージョンに
$ ruby -v
ruby 2.5.4p155 (2019-03-13 revision 67245) [x86_64-darwin19]

$ rbenv versions
  system
* 2.5.4 (set by /Users/naoya.ohsaki/gx_community_admin/.ruby-version)
  2.7.0

$ cd

プロダクトの外部では下記のバージョンに
$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]

$ rbenv versions
* system (set by /Users/naoya.ohsaki/.rbenv/version)
  2.5.4
  2.7.0
```

上記のように切り替わっていたら完了です。お疲れ様でした。
SlackのReminder機能をTeamsで実現する

Slackで利用できるreminderのような機能をTeamsで実現したいのですが、公式にはないみたい。

ないみたいなのでAWS Lamda + cloud watchの組み合わせで実現しました
今回はPythonで実装しました。


MicrosoftのFeeoback Forumに同じように思ってる人もいるみたい。
https://microsoftteams.uservoice.com/forums/555103-public/suggestions/17062255-add-team-wide-reminders
今作ってるのかな？
コメント見た限り、待望してる人は多そう。


## 作業手順
①teamsの特定チャンネルにincoming web hookを設定し、post先URLを作成
②作成したURLへ特定文字列をpostするlamda関数を実装
③cloudwatchに作成したLamda関数を呼び出すルールを追加
※下記の「参考にした記事」で読んだとおりに作業したので、詳細はリンク先の記事を参照してください。

lamda関数を実装する際requestsモジュールを利用するのですが、Pythonの標準モジュールではないのでpipインストールしたプロジェクトをzip形式でアップして利用できるようにしました。

postする際に、文字コードの指定がないので怒られます。
`data="Teamsに送信するテキスト".encode("utf-8"))      `
上記のように、文字コード指定しておくと問題ありません。

## 実装コード
```python
import json
import requests

def lambda_handler(event, context):
    data = '{"text": "Teamsに送信するテキスト"}'.encode("utf-8")
    response = requests.post('https://outlook.office.com/webhook/f5～(この部分可変)', data=data)
```

## Lamdaコンソールイメージ
実装したソースと、requestsモジュールインストールしたのでフォルダがいくつか存在している状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258493/55b1c377-0bc2-4d31-e195-f7c639abd160.png)


## 参考にした記事
#### TeamsへのWeb Hook導入方法
https://qiita.com/wataash/items/72b49509c3964294dd67

#### ラムダへモジュール追加
https://qiita.com/SHASE03/items/16fd31d3698f207b42c9

#### postした時のエンコードエラー対応
https://qiita.com/yuji38kwmt/items/c6885cd7caa6b2fc195f

#### claod watchの時間設定方法
https://www.suzu6.net/posts/136-lambda-cron-rate/
「Azure SDK for Go」とは？

Azure SDK for Goは、マイクロソフト社のパブリッククラウド「[Azure](https://azure.microsoft.com/ja-jp/)」をGoでコーディングして扱うためのSDK（ソフトウェア開発キット）です。

2021年4月1日のv53.0.0からMIT、それまではApache License 2.0のライセンスのオープンソースソフトウェアであり、GitHub上で管理および開発されています。

- [GitHub - Azure/azure-sdk-for-go: Microsoft Azure SDK for Go](https://github.com/Azure/azure-sdk-for-go)

最初のコミットは2014年8月11日で、2016年、2017年とベータ期間を経て、2018年2月12日のv14.0.0で正式リリースとなりました。

- [Azure で Go アプリを構築: Azure SDK for Go の一般提供を開始 | Azure のブログと更新プログラム | Microsoft Azure](https://azure.microsoft.com/ja-jp/blog/build-go-apps-for-azure-with-the-go-sdk-now-generally-available/)

おおよそ毎月末にメジャーバージョンのアップデートが行われます。

現在では、日本語ドキュメントも公開され、サポートされるAzureサービスも増えています。

- [Go 開発者向けの Azure | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/go/)

当時、他のプログラミング言語のSDKやドキュメントが出揃っていた中、Goだけがなかなか正式リリースされずヤキモキしたり、ベータ期間中にストレージ系のパッケージが本家から出たり戻ったりしていたのを眺めていたも良い思い出です。

まずは「Azure/azure-sdk-for-go」の [README.md](https://github.com/Azure/azure-sdk-for-go/blob/master/README.md) や「Go 開発者向けの Azure」のドキュメントを読み進め、どんなものなのか？何ができるのか？を見て行きます。
HDInsightを一部廃止した話

# はじめに

HDInsightを使っててイラッとした話です。

# やりたいこと

バッチ処理を作成していました。1日1回バッチを回して結果をグラフ化、レポートを作成する処理を作ってました。俗に言うETLとかいうやつですね。

![やりたいこと.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233578/d113a3e8-f98c-06ca-49f9-60198de97a6a.jpeg)


データがストレージに1日分溜まったらHDInsightでデータを処理、結果をまたストレージやSQLSERVERに転送、あとは分析官が解析したりレポートやグラフを作成していました。

HDInsight(後HDIと表記)とは簡単にSparkクラスタを作成できるAzureのサービスです。AmazonのEMRとかと同じです。これを使えばデータが少なくなったときはクラスタの台数を削減し、データが大きくなったらクラスタを大きくすればいいわけですね。

バッチ処理は1日1回しか回さないので、料金を節約するために必要なときHDIを作成、処理が終わったら削除していました。

バッチ処理はきれいに完成し、末永く幸せに暮す予定でした。

# HDIのここが嫌

しかし、2年ほど運用していくにつれ、HDIに不満がでてきました。

## 不満1:  HDIの作成に時間がかかる

HDIの作成には15分から20分かかります。
たまに分析官が「マスターデータがまちがっていたから今日のバッチ処理をもう一度回してくれないかね。」などと言ってきたときは、もう一度バッチを回すことがあります。また、テストのときには手動でHDIの削除、作成などを頻繁に繰り返すときがあります。このたびにいちいち20分ほど待たされることにイライラしました。AzureVMではStopモードがあり、VMを停止、起動が素早く行うことができ、しかもStop中は課金されません。しかしHDIにはそのような機能はなく、料金を節約しようとすると、HDIを削除するしかありませんでした。しかしこれは待てばよいだけなので、特に問題にはなりませんでした。

## 不満2:  HDIの作成にときどき失敗する

分析官が、「おやおや、今日のバッチ処理ができてないよ。これでは解析業務ができないじゃないか。」と言ってきました。慌てて本日の処理を見ると、HDIの作成に失敗していました。この現象は月に数回は起きました。HDIの作成に失敗したときは、HDIを一度削除して、何分か経ったらもう一度HDIを作成するよう、リトライ機能を強化しました。このリトライ機能の強化はうまくいきました。一時はどうなるかと思いましたが、また平穏な日々を取り戻しました。

## 不満3:  中身が勝手にアップデートされる

### エラーその1
ある日突然バッチ処理が意味不明なログを大量に吐いてログサーバーを圧迫し始めました。バッチ自体は正常に終わっていましたのでなんとかなりました。慌ててマイクロソフト(後MSと表記)のサポートセンターに問い合わせました。当日は解決しなかったので、ログの削除ローテーションの期間を短くしてログがサーバーを圧迫しないよう調整しました。MSは何日かあとに、HDIのイメージが更新されたせいだと言いました。
自分は「おいおい、こっちは毎回同じ設定ファイルでHDIを作成しているんだよ。毎回同じバージョンのHDIを指定したら同じものができあがってもらわないと困るじゃないか。アップデートするなら新しいバージョンを作って別物としてくれよ。せめてサイレントアップデートはやめて通知しれくれるとかできないのか？」と言いましたが、
MS「すみません今後はデバッグをきちんとやりますが、どうしても全部の機能をカバーしきれません。」とのことでした。

いまだにサイレントアップデートはされているようです。

MSはHDIのイメージを修正してくれ、謎のログは出力されなくなりました。

### エラーその2

ある日バッチ処理がエラーを吐くこともなく、宙ぶらりんの状態でいつまでも終わらない現象が起こりました。gitのソースコード履歴には誰もコードを変更した経歴はありません。慌ててMSに緊急度Aで問い合わせました。
「おい、HDIのジョブが終わらないのだが。こちらではHDIを作成する設定ファイルも実行するソースコードも全く変えていない。HDIが勝手にアップデートされたのではないかね？それならもとにもどしてくれ。」
MS「こちらでHDIのイメージがアップデートされた履歴はありません。Sparkのオープンソースのバグと考えられますので、こちらではわかりかねます。」
「そんなわけないだろ。昨日まで全く同じ設定で動いていたんだ！」
MS「こちらでHDIのイメージが（以下同文）」
とても疲れました。

中身が勝手にアップデートされる（と疑われる）ことによるエラーは頻発するわけではありませんが、年に数回あります。

# 解決策

## その1 VMを使う
AzureVMはこの2年でとても大きなメモリーやCPU数を持っているものが登場しており、HDIを使わずともこれで十分なのではと思いました。VMにはStopモードがあり、Stopさせていれば課金されません。しかもStopからstartにするのは30秒から1分ほどで終わります！stopからstartの移行に失敗することもほとんどありません。VMにSparkをインストールしてしまえば勝手に中身がアップデートされてしまう不安からも解消され、上記の3つの不満から解消されます。

## その2 Spark Standaloneモードを使う
それでもログ数が増えてVMの上限以上のパワーが必要になったらどうすればよいのでしょうか？
SparkにはStandaloneモードというのがあり、簡単に複数台のサーバーを用いてクラスタが組めるようになっていますので、VMを複数台立ててStandaloneモードを使いましょう。HDIにはYARNとかJupyterNotebookとかhdfsストレージとか様々な便利機能がありますが、日次バッチを回すだけならそんな機能いらないです。

参考：
https://dev.classmethod.jp/business/bigdata/construct-spark-cluster/

# まとめ

- HDIを毎日削除、作成を繰り返す運用はミッションクリティカルな業務にはおすすめできない。一回作ったら消すな。消さなければイメージが勝手にアップデートされることはない。
- 最近はVMのサイズはでかいものが用意されている。それで済むならそれが便利。
- それでもマシンパワーが足りなければSparkStandaloneモードで自力でクラスタを組もう。

# 追記

AzureならdatabricksもSparkが使えます。databricksはバージョン管理がしっかりしてます。
databricksでもクラスタの作成に失敗するときはあるので、リトライの作り込みはHDIと同様に必須です。
クラスタの起動はdatabricksのほうが速いように感じます。
Railsアプリをcloneした後にDocker上で動かすまで

GitHubからソースをcloneした後、Dockerを使った開発環境を構築するまでにやることをまとめます。
`Dockerfile`や`docker-compose.yml`はすでにあるものとします。

##Docker for Macを起動
忘れずに起動しましょう。

##git管理外の必要なファイルを作成
- `database.yml`
- `.rspec`
- `.env`
- `master.key`
- `node_modules`

などのファイルを必要に応じて作成

##ビルド
Dockerfileを元にDockerイメージを作成します

```terminal
$ docker-compose build
```

##コンテナを立ち上げる
```terminal
$ docker-compose up -d
```

##データベースを作成
```terminal
$ docker-compose exec <サービス名> /bin/bash
$ rails db:create
$ rails db:migrate
$ rails db:seed
```
ここでブラウザにアクセスして、表示を確認しましょう。テストが書いてあればテストを走らせる。

##DBクライアントアプリでDBに接続
`docker-compose.yml`や`database.yml`の記述を参考に、データベースとTablePlusやSequelProなどのアプリを接続します。

##デプロイ周りの環境を構築する
Herokuとの接続や、capistranoを使ったデプロイができるように調整します。
form_withの記述

##form_with
form_tagとform_forというのもあるのですが、Rails 5.1系以降ではform_withが推奨されています。
自動でパスを選択してくれて、HTTPメソッドを指定する必要がありません。
コントローラーから渡された、ActiveRecordを継承するモデルのインスタンスが利用できます。
inputタグは入りません。
これらの特徴はform_forとform_withの共通する部分です。
##そもそもform_tagとform_forとは
簡単にいうとモデルの有無です。例えば検索機能の場合はモデルが必要ないのでform_tagを使います。
【例】form_tag

```
<%= form_tag('XXXX_path', method: :post) do %>
   (中身)
<% end %>
````
上記みたいにパスを指定したりします。まだいろいろと記述の仕方はあるのですが今回はform_withなので省きます。
【例】form_for

```
%= form_for @XXXX do |form| %>
  (中身)
<% end %>
```
コントローラーで@XXXXを定義しています。内容はこちらも省いていきます。
##form_withの記述
form_withは、form_forとform_tagの機能を組み合わせたものです。なのでform_withひとつでどちらも対応できます。
【例】form_with

```
<%= form_with(model: @XXXX, local: true) do |form| %>
      <h3>
        投稿する
      </h3>
      <%= form.text_field :name, placeholder: "ニックネーム" %>
      <%= form.text_field :image, placeholder: "Url" %>
      <%= form.text_area :text, placeholder: "text", rows: "10" %>
      <%= form.submit "送信" %>
    <% end %>
```
コントローラーで@XXXXを定義しています。
##local: trueオプション
form_withでは、デフォルトの状態ではremote: trueというajaxでの通信が行われる設定になっています。それをキャンセルするためにlocal: trueというオプションを付与します。local: trueオプションを付与すれば、Railsのフォームと同様に使用することが出来ます。
[Python] 複数行にわたる文字列の代入

SQLの操作などで長い文字列を変数に代入することがありますが，主に以下の2通りの方法があります．

- 丸括弧`()`→非明示的な行継続の使用
- トリプルクォート`'''`や`"""`の使用

[Kosei Kitahara's Works: Google Python スタイルガイド]
(http://works.surgo.jp/translation/pyguide.html#id73)によると前者の方が推奨されています．
後者は以下の通りインデントするとその空白も文字列に含まれてしまうためです．

<!---
============================================================================================
-->


# 丸括弧`()`→非明示的な行継続の使用

```Python
text = ('a' # カンマは不要
        'b')
print(text) # ab

# 以下と同じ
text = 'ab'

# 註1: カンマを付けると2つの文字列のタプルとして認識されてしまう
text = ( 'a',
         'b')
print(text) # ('a', 'b')

# 註2: 実用性があるかは分かりませんが1行にまとめることが可能
text = ('a' 'b')
print(text) # ab

# 註3: これも実用性は不明ですが，行継続とタプルを併用することも可能
text = ('a', 'b'
        'c')
print(text) # ('a', 'bc')
```

改行には`\n`が必要です．
またこの手法は文字列の代入のみならず関数のインポートなどにも有効です
（関数の引数が多くなったときには自然と使っている？）．

```Python
from some.deep.module.inside.a.module import (
    a_nice_function, another_nice_function, yet_another_nice_function)
```

[Python ヒッチハイク・ガイド - コードスタイル]
(https://python-guideja.readthedocs.io/ja/latest/writing/style.html#id8)


## formatとの併用

これとformatを併用するときは，最後にまとめて`.format()`を書く必要があります：

```Python
text = ( 'a = {0}, '
         'b = {1}'.format(1, 2))
print(text) # a = 1, b = 2
```

各行に`.format()`を書くと`SyntaxError`になります：

```Python
# 以下はSyntaxError: invalid syntaxになる
text = ( 'a = {}, '.format(1)
         'b = {}'.format(2))
```

あまりに`.format()`の中身が複雑になるときは，文字列のリストを作成→`str.join()`で結合する方が良い？



<!---
============================================================================================
-->

# トリプルクォート`'''`や`"""`の使用

「三連引用符」や「三重引用符」とも言うようです．
この場合，コード上で改行した箇所で改行されます．

```Python
text = '''hello
world'''
print( text )
# hello
# world

# 以下と同じ
text = 'hello\nworld'

# 註1: 改行したくないときは\を使う
text = '''hello\
world'''
print( text ) # helloworld

# 註2: 最初と最後を改行するとその分改行が含まれてしまう
text = '''
hello
world
'''
print( text )
# (改行)
# hello
# world
# (改行)

# 註3: コード上のインデントを合わせようとするとその空白も文字列として扱われてしまう
text = '''hello
          world'''
print( text )
# hello
#           world
```

[Let's プログラミング: 三連引用符を使った複数行の文字列の記述](https://www.javadrive.jp/python/string/index3.html)
[note.nkmk.me: Pythonで文字列生成（引用符、strコンストラクタ）](https://note.nkmk.me/python-str-literal-constructor/)