OmniAICreator/Qiita-1.07M huggingface dataset:
FlaskでPost / Redirect / Getパターンを実装する

WebフォームなどでPOSTリクエストを送信した後、ブラウザをリフレッシュすると「フォーム再送信の確認」みたいなアラートが出ます。
ユーザーは「なんのこっちゃ？」ってことが多いと思うので、フォーム送信後にリフレッシュしてもアラートが出ないようにする方法に「POST後、リダイレクトしてGETリクエストでページを再取得する」といったものがあります。

ちなみにリダイレクトとはhtmlコードを含む文字列を返す通常のレスポンスとは異なり、URLを返すレスポンスです。

<a href=https://qiita.com/__ugatsukun__/items/00ecbbbca82856559072>別記事</a>で使ったフォームの素材をそのまま使います。

※以前書いたコード

```Python
@app.route('/', methods = ['GET', 'POST']
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form = form, name = name)
```

フォームを以前作った際はview関数のローカル変数にフォームから入力されたデータを格納していたのですが、これだとリクエストを跨いでデータを保持できません。

そこでユーザーセッションの中にデータを保持することとします。
ここでいうユーザーセッションとはクライアントサイド側のCookieに格納される、クライアントサイドのプライベートストレージを指します。

では実装するにあたり、まずflaskモジュールからsession, redirect, url_forをインポートします。

```Python
from flask import session, redirect, url_for
```

あとはフォームから取得したデータをセッションに格納し、フォームから受け取った時はリダイレクトし、テンプレートをレンダリングするタイミング（GETでアクセスした際）でセッションからデータを取り出して変数nameとしてテンプレート側へ渡します。
なおridirect()はURLを引数に取るので、URLジェネレータのurl_for()でview関数名を渡してURLを作成しています。

```Python
@app.route('/', methods = ['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form = form, name = session.get('name'))
```

以前の記事で書いた元コードではフォームのデータを空文字でクリアしていましたが、今回はリダイレクト時に入力されたデータはリセットされるので、フォーム欄に残ることはありません。
本の新刊データをJSONで取得できるようにする。

# はじめに
　コミックやラノベの新刊データ取得で、JSON形式で無料で取得しようとするAPIが見つからなかったので、[ゲーム、アニメ、CD発売日一覧](https://calendar.gameiroiro.com/)というサイトからスクレイピングして、JSONで出力するようなプログラムを作る

# プログラム概要
[ゲーム、アニメ、CD発売日一覧](https://calendar.gameiroiro.com/)というサイトから、
新刊の発売日、名称、作者、画像が引っ張ってこれるので、これらのデータをJSONで出力するようにする
また、実行結果は標準出力するようにする。

# プログラム内容

```go:calendarscriping.go
package main

import (
	"fmt"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

type BookList struct {
	Type   string `json:type`
	Months string `json:months`
	Days   string `json:days`
	Img    string `json:img`
	Title  string `json:title`
	Writer string `json:writer`
	Bround string `json:bround`
	Ext    string `json:ext`
}

const (
	BOOKURL      string = "https://calendar.gameiroiro.com/"
	COMICURL     string = "manga.php"
	LITENOVELURL string = "litenovel.php"
	MAGAZINEURL  string = "magazine.php"
)
const (
	COMIC     = 0
	LITENOVEL = 1
	MAGAZINE  = 2
)

func GetComicList(year, month string, booktype int) []BookList {
	var output []BookList
	mounth_tmp := month

	url := BOOKURL
	switch booktype {
	case COMIC:
		url += COMICURL
	case LITENOVEL:
		url += LITENOVELURL
	case MAGAZINE:
		url += MAGAZINEURL
	}
	if (year != "") && (month != "") {
		url += "?year=" + year + "&month=" + month
	}
	doc, err := goquery.NewDocument(url)
	if err != nil {
		fmt.Println(err.Error())
		return output
	}

	if mounth_tmp == "" {
		mounth_tmp, _ = doc.Find("input.month").Attr("value")
	}
	doc.Find("div#content-inner").Each(func(i int, s *goquery.Selection) {
		s.Find("tr").Each(func(j int, ss *goquery.Selection) {
			days := ss.Find("td.day-td").Text()
			ss.Find("div.div-wrap").Each(func(k int, sss *goquery.Selection) {
				var tmp BookList
				tmp.Days = days
				tmp.Months = mounth_tmp
				sss.Find("div.product-image-left").Each(func(l int, image *goquery.Selection) {
					tmp.Img, _ = image.Find("img").Attr("src")
				})
				sss.Find("div.product-description-right").Each(func(k int, data *goquery.Selection) {
					tmp.Type = strings.TrimSpace(data.Find("p.p-genre").Text())
					tmp.Title = strings.TrimSpace(data.Find("a").Text())
					data.Find("p.p-company").Each(func(i int, data2 *goquery.Selection) {
						if tmp.Bround == "" {
							tmp.Bround = strings.TrimSpace(data2.Text())
						} else if tmp.Writer == "" {
							tmp.Writer = strings.TrimSpace(data2.Text())
						} else if tmp.Ext == "" {
							tmp.Ext = strings.TrimSpace(data2.Text())
						} else {
							tmp.Ext += "," + strings.TrimSpace(data2.Text())
						}

					})
				})
				output = append(output, tmp)
			})

		})
	})
	return output
}

```

```go:main.go
package main
import (
	"fmt"
)
func main(){
	fmt.Println(GetComicList("", "", COMIC))
}
```

実行すると、今月のコミックスの取得結果がJSONで得られる
# まとめ

これらのプログラムを応用して、WebAPIにするとブラウザ処理が楽になる。
また、SQLサーバと連携して、ローカルにキャッシュを持つことで高速化や
細かい出力に変更できるように改造すると楽になる。
コの業界で老害にならないようにするためには

3度に渡り、これからIT業界を目指す大学生対象に、業界の中身をざっくりと書いてみました。
<a href="https://qiita.com/KLaboratory/items/30bbc880b0547c9f89b7">コの業界を目指す大学生へ(前編)</a>
<a href="https://qiita.com/KLaboratory/items/85f0d197f425a8c5f736">コの業界を目指す大学生へ(後編)</a>
<a href="https://qiita.com/KLaboratory/items/d4e41b24c4ee9029383f">コの業界を目指す大学生へ(おまけ)</a>

しかしながら、書いた当人は引退までをカウントダウンする50代になっています。<b>プログラマの定年は35歳だと</b>すれば、20年近く定年を延長していることになります。今思うと35歳定年説って当てはまることもあるかも知れないと思う今日このごろです。

<h2>35歳で引退させられるプログラマ</h2>
人材不足の業界ですから、戦力外となってクビになることはまずありません。しかし、そのぐらいの年齢で先が見えてしまう人も少なからずいます。そして、そういう人は本当に戦力外としたいくらい使い物にならなかったりもします。

プログラミングを社会人になって初めて習ったとして、実務で取り組み始めて35歳になるとだいたい10年前後のキャリアということになります。10年もやっているとおそらく、初めて習った言語以外に数個の言語をマスターしているはずです。特に現代は新しい言語が次々生まれます。ですから、PHPだけ、Javaだけということではできる業務の幅が広がりません。

<h2>COBOL一筋20年</h2>
筆者が入社した頃は、C言語、C++言語が主流で業務もほぼ99%がこの2つでした。たまにVisual Basicが来るくらいでした。新入社員の私も当然のようにC/C++チームに入れられました。もちろんそれ以外にもCOBOL、FORTRAN、アセンブラなどもそれなりの仕事があり、プログラマも多かったです。ただ筆者はC/C++にあてがわれたということです。時代は1995年で、インターネットが一般に普及し始めたときです。次第にPerl、Java、Javascriptなどが出てきました。

私は若かったこともあり、それらにもすぐに飛びつきました。今後仕事になるかならないかはまだわからなかったにもかかわらず。しかし・・・

COBOLプログラマの中には、COBOL以外やらない、やりたくないという人が少なからずいたようです。COBOLの腕は高かったのかも知れませんが、プログラミング言語にも流行り廃りがあります。筆者が今でもC/C++以外は触りたくないと言っていたら、おそらく意に沿わない案件ばかりでとっくに引退していたかも知れないでしょうね。

当時はCGIを動かすのにはPerlかC言語というのが一般的でした。そしてかなり仕事も多かった記憶があります。そこにCOBOLプログラマが応募してきたことがありました。COBOLに関しては20年のキャリアがあり自信はあるとのことです。しかし・・・

<b>CGIをCOBOLで書きたい</b>

といって譲ってくれません。プログラミング言語には流行り廃りの他に得意不得意もあります。COBOLがCGIに向いた言語であるという話は聞いたことありませんでした。もしそうなら実例もあったはず。もしかしたら実現できるのかも知れませんが、それよりもPerlかC言語を覚えてもらったほうが絶対いいです。結局その人はプロジェクトからすぐに外されましたが、使える言語が一つだけというのは非常にリスキーです。

<h2>言語の横展開</h2>
プログラミング言語は外国語と違って、一つマスターすると2個めをマスターするまでのハードルがものすごく下がります。時間もエネルギーも少なくてすみます。しかし、それでも20代、30代の頃と比べて50代になるとどうしても集中力と体力が落ちてきてしんどくなってきます。もしかしたらCOBOLのベテランさんもそれが苦痛だったのかもしれません。しかし、<b>新技術の取得が苦痛になると思ったときが引退のとき</b>であると思います。筆者もそれはそう遠くないと思っています。

ですから、若いときには好き嫌いを言わずに色々と取り組むことは大いにおすすめしています。もっともそれについては心配はいらなさそうですが。

逆に、いくつか武器となる言語をマスターしたならば、潔く捨てるものも必要だと思っています。
筆者で言えば、人工知能(Python)、スマホ(kotlin/swift)、ゲーム(Blueprint、C#)は仕事ではやらないと決めました。BlueprintはQiitaで記事を書いたりはしていますが、趣味のレベルで深くは突っ込まないということです。

これらに将来性がないわけではなく、むしろ一番有望なものですが、今から取り組んでも最先端で戦うエネルギーがないので若い人の邪魔になってしまうと考えるからです。そのかわり自分が持っている武器は最大限に使おうと。

<h2>業務の縦展開</h2>
もう一つはこの歳になると、開発で手を動かすよりもPL、PMでの仕事を求められる事が増えるというのがあります。私はエンジニアでもありますが、経営者でもあります。やはり40～50代の人に求めるのはリーダーの業務になります。ベテランエンジニアでもリーダー業務が苦手でいつまでも開発でプログラムを書いていたいという人もいるかもしれません。エンジニアの視点から見ればそれもわかります。もしかしたら若い人より開発スピード、バグの少なさなど品質面で上かもしれません。しかし、それは<b>実際に書いてもらわないとわからない</b>事が多いです。それならばやはり若い人に仕事は回ります。今はプログラムを書いていたとしても、いずれはリーダー業務をやるつもりでいることが50代でもこの業界にいられることに繋がるかと思います。

もし、ずっと独身で自分のためだけに仕事をすることができるなら、収入の多寡はそんなに問題にならないかもしれません。しかし、結婚して家族が増えると収入については無視することはできません。そういう意味でもリーダー業務は無視することはできないと考えます。

私がこれだけ長くこの業界にいられたのは、決して人並み外れたプログラミングスキルがあったわけではなく(人並み以上ではありましたが)、年齢に応じて適応してきたことに尽きると考えています。
若い人にはまだ実感はわかないことと思いますが、40代が近づいてきたらちょっと考えてみてください。
flutter#2 AppBarをグラデーションにする

この記事の内容は動画でも説明しているので参考にしてください。
https://youtu.be/EJ9lZcsutBE


最初にコードを載せます。今回はAppBarをグラデーションにする。テキストを追加する。この二つをやります。

```dart:main.dart

import 'package:flutter/material.dart';

// MyAppのアプリを起動
void main() {
  runApp(MyApp());
}

// MyAppの説明
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // ここを変えるとアプリの色が変わる（green➡red, blueとか、知ってる色を試してみて）
        primarySwatch: Colors.green,
      ),
      // 上のタイトル　''で囲まれたところが表示される
      home: MyHomePage(title: 'こんにちは'),
    );
  }
}

// MyHomePageの説明
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

// _MyHomePageStateの説明
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // アプリ上部のバー（色がついているところ）
      appBar: AppBar(
        // widget.titleというのは、上のclass MyAppの中に書いてあることを読み込んでいる
        title: Text(widget.title),
      ),
      // AppBar以外のアプリの中身
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

```

まずはAppBarにグラデーションを付けます。様々な方法があるのですが、今回はパッケージをインストールして行います。

パッケージはこれです。
https://pub.dev/packages/new_gradient_app_bar

インストールの仕方ですが、サイトのGetting Startedに書いてある通りに進めます。まずはpubspec.yamlに書く。

```dart:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  new_gradient_app_bar: ^0.2.0
```
ちなみに、どこのファイルに記述してあるかはコードの左上に小さく表示されているので参考にしてください。
次にimportする

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:new_gradient_app_bar/new_gradient_app_bar.dart';

// MyAppのアプリを起動
void main() {
  runApp(MyApp());
}
```

AppBarをNewGradientAppBarに変える

```dart:main.dart
return Scaffold(
      // アプリ上部のバー（色がついているところ）
      appBar: NewGradientAppBar(
          title: Text('Flutter'),
          gradient:
              LinearGradient(colors: [Colors.blue, Colors.purple, Colors.red])),
      // AppBar以外のアプリの中身
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
```

これでうまくいくと思います。エラーが出た場合はそのエラーをコピーしてネットに張り付けて検索してみてください。
ターミナルで、モジュールのインストールが完了したら、通知をもらいたい



## 課題

マイクロサービスの環境構築をするときに、
複数のプロジェクトのモジュールをインストールする必要がある。
インストール中に別の作業をしていると、別の作業に集中してしまって、環境構築が進まないことがある。(私が過集中してるだけかもしれない)

# 解決策
ターミナルで、コマンドを実行し、
5秒以上かかる処理が終わったら通知してくれればいい。

![スクリーンショット 2021-05-13 23.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264684/ccec6465-085a-27db-9d1e-b245deb7e357.png)



# 対応環境
Mac OS
Zsh(Bashじゃない)
Homebrewが入っている

# 設定方法

1. `brew install terminal-notifier`

2. `vi ~/.zshrc`で下記の内容を追記

```sh:.zshrc
local COMMAND=""
local COMMAND_TIME=""
precmd() {
    if [ "$COMMAND_TIME" -ne "0" ] ; then
        local d=`date +%s`
        d=`expr $d - $COMMAND_TIME`
        if [ "$d" -ge "5" ] ; then
            COMMAND="$COMMAND "
            which terminal-notifier > /dev/null 2>&1 && terminal-notifier -message "${${(s: :)COMMAND}}" -m "$COMMAND" -sound Glass;
        fi
    fi
    COMMAND="0"
    COMMAND_TIME="0"
}
preexec () {
    COMMAND="${1}"
    if [ "`perl -e 'print($ARGV[0]=~/ssh|^vi/)' $COMMAND`" -ne 1 ] ; then
        COMMAND_TIME=`date +%s`
    fi
}
```

3, `source ~/.zshrc` で設定を反映

4, 実行に時間がかかるコマンドを実行して、通知が来ることを確認しましょう


![スクリーンショット 2021-05-13 23.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264684/ccec6465-085a-27db-9d1e-b245deb7e357.png)
バケットソートとは　Python競プロメモ⑥

バケットソートとは、あらかじめデータがとりうる値すべての容器を順番通りに並べて用意しておき、値を対応する容器に移すことでソートを行う整列アルゴリズムのことである。

このアルゴリズムを使う際に注意すべき点として、データがとり得る値が分かってなければ、ソートのためのバケットを準備することができないため、このアルゴリズムを使うことができない。

今回はバケットソートの考え方を用いてリスト内に含まれている重複した数を取り出すコードを書いたので備忘録として記載しておく。

```
#dataがとり得る値の範囲は0以上200未満である
data = [123,23,123,123,0,0]
buckets = []
count_list = []
for i in range(200):
  buckets.append(i)
  count_list.append(0)
for k in data:
  for i in range(200):
    if buckets[i] == k:
      count_list[i] += 1
      break
count_list = list(set(count_list))
count_list.pop(0)
print(count_list)

=>[1,2,3]
```
これで重複した値がそれぞれ何個あるかが可視化できるようになった。
愚直にforやsetで無理やり求めることももちろん可能だが、このバケットソートの考えを使うことで高速化を図ることができた。

今回は何の数字がいくつ重複しているのか、という情報はいらなかったので、このような記述にしたが、もしなんの数字がいくつ重複しているのか、という情報が欲しいときは先ほどのコードと途中までは一緒で

```
#dataがとり得る値の範囲は0以上200未満である
data = [123,23,123,123,0,0]
buckets = []
count_list = []
for i in range(200):
  buckets.append(i)
  count_list.append(0)
for k in data:
  for i in range(200):
    if buckets[i] == k:
      count_list[i] += 1
      break
num = []
count_num = []
for i in range(len(count_list)):
  if count_list[i] != 0:
    num.append(i)
    count_num.append(count_list[i])
print(num)
print(count_num)

=>[0,23,123]
  [2,1,3]
```
このようにnumとcount_numを対応させることで、何の数字がいくつ重複しているのか、という情報を得ることができた。
【祝！初投稿】LINEbotを利用し、GO言語で書いたプログラムから自分のLINEアカウントにメッセージ送信してみた

## はじめに
はじめまして。初めて投稿します。

何を投稿するか悩んだのですが、少し前からLINEbotを触っていて、色々試していたら
「LINEbotにHTTPリクエストを送ったら、オウム返しで自分のLINEアカウントにメッセージを送れる。」
のがちょっと面白かったので、この内容にしてみました。

## LINEbotについて
- LINEが提供するボットサービスです
- LINEアカウントをお持ちでしたら、[LINE Developers](https://developers.line.biz/ja/)から作成できますので、<br>興味ある方は色々試してみてください

## LINEbotを使用するための準備
1. LINEbot用のチャネルを作成（手順は[こちら](https://developers.line.biz/ja/docs/messaging-api/getting-started/)）
2. LINEbot作成（手順は[こちら](https://developers.line.biz/ja/docs/messaging-api/building-bot/)）

## 作成したプログラム
1. 超絶シンプルな画面から、適当なメッセージを入力して送信ボタンを押すと、

![temp4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519408/532f9b5d-91ae-24c0-e187-c2e3c4043110.png)

2.LINEに通知されるだけの、簡単かつ特になんの役にも立たないプログラムです。

![temp5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519408/cdf160a0-b87c-89d0-c1c4-bc5553d309a8.png)

## ソースコードについて
ここで紹介しているプログラムは[こちらのリポジトリ](https://github.com/mytysoldier/golang_linebot_messaging)に公開しています。

●LINEbotメッセージ送信
[GO言語用SDK](https://github.com/line/line-bot-sdk-go)を使用しています。SDKの使い方は左記リンクのREADMEに記載されています。
ほかにもJavaやPHPなどのSDKも提供されているようです。
[こちら](https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/)にリンクがまとめられています。

```markdown:message.go#LINEbotメッセージ送信部分
// 構造体：LINE接続設定を管理
type LineConfig struct {
	UserId             string `json:"userId"`
	ChannelSecret      string `json:"channelSecret"`
	ChannelAccessToken string `json:"channelAccessToken"`
}

// LINEbotメッセージ送信処理
func SendMessage(w http.ResponseWriter, r *http.Request) {
	// リクエスト値を取得
	var message string = r.FormValue("message")
	// プロパティファイル読み込み
	var config LineConfig = LoadConfig()
	// LINEbotオブジェクト初期化（チャネルシークレット、第二引数にチャネルアクセストークンを指定）
	bot, _ := linebot.New(config.ChannelSecret, config.ChannelAccessToken)
	var messages []linebot.SendingMessage
	messages = append(messages, linebot.NewTextMessage(message))
	// メッセージ送信（第一引数に宛先、第二引数に送信するメッセージを指定）
	_, err := bot.PushMessage(config.UserId, messages...).Do()
	if err != nil {
		panic(err.Error())
	}
}

func LoadConfig() LineConfig {
	// 設定ファイルの読み込み
	file, err := os.Open("resources/conf/config.json")
	if err != nil {
		panic(err.Error())
	}
	defer file.Close()

	var config LineConfig
	err = json.NewDecoder(file).Decode(&config)
	if err != nil {
		panic(err.Error())
	}
	return config
}
```

- LINEbotのチャネル作成時に発行したチャネルシークレットとチャネルアクセストークンを使用します
- `bot.PushMessage({宛先LINEユーザーID}, {送信するメッセージ}).Do()`  
  でメッセージが送信されます


## 終わりに
LINEbotに入門しました。

今回は画面から入力したメッセージをそのまま送信するだけのものでしたが、
天気情報や近隣のスーパーのお買い得情報を通知したりなど、もう少し実用的なものを作成してみたいと思います。（すでにそういうアプリありますが・・）
AIボットも面白そうですね。

以上、初投稿でした！
何か少しでも参考になることがあれば嬉しいです。
CSSでスマホのアドレスバーの高さに合うように実装する方法。100vhで困った人へ

***スマホの画面上のURLが書いてある部分のせいで、heightを100vhにしても意図したデザインにならない問題を解決する方法の備忘録***

解決方法は、javascriptのwindow.innerHeightを使用すること

```
var windowHeight=window.innerHeight;
document.getElementById('section').style.height=windowHeight+'px';
```

として、100vhでsectionの高さを設定するのではなく、window.innerHeightを使用することで、
アドレスバーの下から画面最下部の大きさで１画面となる。

こちらの記事がとてもわかりやすいです。
https://877.design/smartphone-height/
next_permutationの実装

順列の全探索を行うときに使うライブラリのnext_permutationを実装して、内部の処理を理解します。

<h3>実行結果</h3>

```cpp

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
  int r[] = {1, 2, 3};

  do
  {
    for (int i = 0; i < 3; i++)
    {
      cout << r[i] << " ";
    }
    cout << endl;
  } while (next_permutation(r, r + 3));

  return 0;
}

```
実行結果

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

このように値が小さい順（このような順番を辞書順という）にすべての順列を出力することができています。

<h3>実装</h3>
next_permutationを実装していきます。

```cpp

bool next_permutation(int *array, int num)
{
    for (int i = num - 2; i >= 0; i--)
    {
        if (array[i] < array[i + 1])
        {
            int j = num;

            do
            {
                j--;
            } while (array[j] < array[i]);

            swap(array[i], array[j]);
            sort(array + i + 1, array + num);
            return true;
        }
    }
    return false;
}

```

ゴールは最初昇順に並んでいるものを、辞書順に並び替えながら最終的に降順にソートすることです。
(例)1234のゴールは4321です。

１：昇順になっているところで一番奥のところを探します。
（例）1432ならi=0のa[i] = 1 < a[i + 1] = 4が一番奥です。
これは言い換えれば、i+1以降は降順になっているということです。(この例では後ろ三つの432)
降順になっているということはどんなにいじっても超えることはできません。（4321をいじっても4321を超える数字を作ることはできない。）

２：a[i]を超える最小のa[j]を見つける。
（例）a[i] = 1を超えるの最小の数字はa[j] = 2 （j = 3）です。i + 1以降は降順になっているので一番奥から探していけばよさそうです。

３：a[i]とa[j]を入れ替える。

４：i + 1以降をソートして昇順にする。

５：trueを返す。

main関数のdo-whileが終わるのはfalseを返した時です。falseを返すのはi = 0のとき。これは降順になっていて、もうゴールに達した状態になっているということです。

<h2>まとめ</h2>

https://atcoder.jp/contests/abc183/tasks/abc183_c

この問題を解いているときにこのアルゴリズムに行きつきました。類題もたくさんありそうなのでしっかりマスターしたいと思います！
[AWS_13.2]必須モジュール gd がインストールされていないか、無効化されています。

##環境
AWS EC2 t2.micro
PHP 8.0.2
WordPress 5.7.2

##エラー
![スクリーンショット 2021-05-13 23.46.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758644/0dc234e3-7f9e-5f42-37da-e545ce710841.png)

##原因
phpのアップデートで`php`のつく諸々を削除したが、phpを再インストールする際にその諸々は再インストールしていなかった。

##解決法

```terminal
yum -y install mysql httpd php-mbstring php-xml gd php-gd
```
コピー先のファイル名が存在した場合、ファイル名の後ろに採番（ナンバリング）してコピーする方法

コピー先に同名ファイルが存在していた場合、ファイル名を採番（ナンバリング）してコピーする方法を備忘録として残します。
# やりたいこと
別のフォルダへコピー（コピー先に同名ファイルが存在しない場合は同じファイル名でコピー）
`c:¥テスト.txt`　→　`c:¥サブフォルダ¥テスト.txt`
上記のコピー後に、再度コピーした場合（同名ファイルが存在するためナンバリングでリネーム）
`c:¥テスト.txt`　→　`c:¥サブフォルダ¥テスト (1).txt`

# 環境
VB2019 (.Net 5.0)
Windows 10


```vb
Imports System.IO

Module Program
	Sub Main()
		fileCopy("D:\ソース\てすとふぁいる.txt", "D:\コピー先")
		' D:\コピー先\てすとふぁいる.txt
		fileCopy("D:\ソース\てすとふぁいる.txt", "D:\コピー先")
		' D:\コピー先\てすとふぁいる (1).txt
		fileCopy("D:\ソース\てすとふぁいる.txt", "D:\コピー先")
		' D:\コピー先\てすとふぁいる (2).txt
	End Sub

	''' <summary>
	''' ファイルコピー（同名が存在する場合は採番）
	''' </summary>
	''' <param name="inSource">コピー元のフルパス</param>
	''' <param name="inCopyPath">コピー先パス</param>
	Private Sub fileCopy(ByVal inSource As String, ByVal inCopyPath As String)
		Try
			Dim wkExt As String = System.IO.Path.GetExtension(inSource)
			Dim wkFile As String = System.IO.Path.GetFileNameWithoutExtension(inSource)
			Dim wkPath As String = System.IO.Path.GetFullPath(inCopyPath)

			' 同名ファイルが存在する時は、ナンバリングしたファイル名で存在チェック
			Dim i As Integer = 0
			While System.IO.File.Exists(wkPath & "\" & wkFile & numStr(i) & wkExt)
				i += 1
			End While

			' ファイルコピー
			System.IO.File.Copy(inSource, wkPath & "\" & wkFile & numStr(i) & wkExt, True)

		Catch ex As Exception
			Console.WriteLine(ex.Message)
		End Try
	End Sub

	''' <summary>
	''' ナンバリング
	''' </summary>
	''' <param name="inNum">採番</param>
	''' <returns></returns>
	Private Function numStr(ByVal inNum As Integer) As String
		Return If(inNum = 0, "", " (" & inNum & ")")
	End Function

End Module
```
PennyLaneでサンプリングしてヒストグラムプロット(TIPS)

# PennyLaneでのサンプリング

PennyLaneでは、以下の構文で量子回路出力をサンプリング出来ます。

`return qml.sample(qml.PauliZ(0))`

例えば以下のようになります。

```python
import pennylane as qml
from pennylane import numpy as np

@qml.qnode(dev)
def circuit(params):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
        
    for i in range(n_qubits):
        qml.CNOT(wires=[i, (i + 1) % n_qubits])
        qml.RZ(2*params[1],wires=(i + 1) % n_qubits)        
        qml.CNOT(wires=[i, (i + 1) % n_qubits])
        
    for i in range(n_qubits):
        qml.RX(2*params[0], wires=i)
    return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)), qml.sample(qml.PauliZ(2)), qml.sample(qml.PauliZ(3))
```

この場合は$Z \otimes Z \otimes Z \otimes Z$ をサンプリングします。
実行すると、戻り値は 量子ビット数×Shot数　の(+1,-1)の配列です。
このままだと使い勝手が悪いので、ヒストグラムを書くために、これを集計する必要があります。
今回はこのスクリプトを書いたので公開します。

# 集計スクリプト

ゴリ押しにもほどがありますが、とりあえず動きます。

```python
def sample_to_counts(sample):
    n_qubits, n_shots = np.shape(sample)
    sample_bin = (1+sample)/2
    weights = [2**i for i in range(n_qubits)]
    sample_dec = np.average(sample_bin,axis=0,weights=weights)*np.sum(weights) # sum b_n*2^n
    sample_dec = sample_dec.astype('int8')
    u, freq = np.unique(sample_dec, return_counts=True) # count frequency
    counts=dict()
    for i,j in zip(u,freq):
        counts.setdefault(format(i, '0'+str(n_qubits)+'b'),j)
    for i in range (2**n_qubits):
        counts.setdefault(format(i, '0'+str(n_qubits)+'b'),0) # zero-padding
    return counts
```

やっていることとしては、

- +1を1に、-1を0に置換
- 2進数を10進数に変換(2^n重み付き和)
- 集計する
- dict型にまとめる

です。 出力は、

`{'0000': 11,
 '0001': 16,
 '0010': 14,
 '0011': 78,
 '0100': 15,
 '0101': 275,
 '0110': 73,
 '0111': 11,
 '1000': 8,
 '1001': 90,
 '1010': 292,
 '1011': 12,
 '1100': 74,
 '1101': 20,
 '1110': 18,
 '1111': 17}`

このようになります。

# ヒストグラム

```python
params = [1.17809152, 0.39269362] #beta,gamma
sample = circuit(params)
counts = sample_to_counts(sample)
```

集計したものをヒストグラムにするには、


```python
import matplotlib.pyplot as plt
plt.bar(counts.keys(), counts.values());
plt.xlabel('bitstrings');
plt.ylabel('counts');
plt.xticks(rotation=90);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/39dbf264-bbd2-3336-a213-52867ce550a6.png)

ちゃんとヒストグラムになっています。

#ぶっちゃけ

PennyLaneを使った理由は、本SDKからならionqでもrigettiでもibmqでも何でも動かせるからだからでした。
ただ、blueqatが上記マシン全てに対応してしまったので、その意味はなくなりました。
blueqatのほうが使いやすいです。。
PennyLaneのよさは、自動微分ですかね・・・。

# まとめ

qml.sampleからヒストグラムまでの道のりは意外と長い。
Alpine Linux をisoからインストールする

# 環境
・VMware ESXi 6.5 / メモリ384MB、HDD8GB
＃仮想環境である必要は全くありません。手元に空きパソコンがなかっただけです
＃推奨環境は、メモリ100MB(!)、HDD700MBです。
・Alpine Linux 3.13.5 x86

#原典
https://wiki.alpinelinux.org/wiki/Installation

#操作
CDを入れて起動するとログインを求められますので root で入ります（パスワードは空です）。

```:alpine-standard-3.13.5-x86_64.iso
boot:
...
Welcome to Apline Linux 3.13
Kernel 5.10.29-0-lts on an x86_64 (/dev/tty1)

locahost login: root
Welcome to Alpine!
...
locahost:~#
```

セットアップコマンドを実行します。

```
# setup-alpine
```

最初はキーマップを設定します。

```
...
Select keyboard layout: [none] jp   <=== 日本語キーボードの場合
...
Select variant (or 'abort'): jp-kana  <=== 適当にそれっぽいのを入力
```

次はホスト名を設定します。

```
...
Enter system hostname (short form, e.g. 'foo') [locahost] myhost
```

FQDNではなく単語を入力します。"myhost"は適当に変えてください。
次はインターネットに繋がっているネットワークインターフェースを尋ねられます。たいていはそのままでいいです。

```
...
Which one do you want to initialize? (or '?' or 'done') [eth0]
```

次はIPアドレスを設定します。今回はDHCPに頼ることにします。

```
..
Ip address for eth0? (or 'dhcp', 'none', '?') [dhcp]

```

ここでIPアドレスを入力すると、続いてネットマスクとデフォルトゲートウェイを尋ねられます。
で、次にもっと細かい設定を手動設定するか尋ねられます。

```
...
Do you want to do any manual netowrk configuration? (y/n) [n] 
```

"y" で答えるとエディタが起動して /etc/networks/interfaces の設定ができるようになります。
次は root のパスワードを設定します。

```
Changing password for root
New password:
Retype password:
```

次はタイムゾーンを設定します。

```
...
Which timezone are you in? ('?' for list) [UTC] Japan    <=== JSTにしたいので"Japan"を指定します
```

次はプロキシサーバを設定します。

```
...
HTTP/FTP proxy URL? (...) [none]
```

手元の環境にプロキシはないのでそのまま進みます。
次はntpサービスをどこのを使うか指定します。特にこだわりがなければ busybox 内のものでいいと思います。

```
...
Which NTP client to run? (...) [vhrony] busybod
```

次はどのサイトからパッケージをもらうか指定します。

```
...
Enter mirror number (1-60) or URL to add (or r/f/e/done) [1] 
```

"f"とするとリストにある全サイトの到達時間を測り始めます。これまたこだわりがなければ1番目でいいと思います。

```

次はsshサービスをしています。これも特にこだわりがなければ openssh でいいと思います。

```
...
Which SSH server? (...) [openssh]
```

次にインストール先のディスクを指定します。

```
...
  sda   (8.6GB ...)
Which disk(s) would you like to use? (...) [none] sda    <=== 上段で自動発見されたディスクを指定します
```

次にそれをどのように使うか指定します。今回は一台しかないので"sys"を指定します。

```
...
How would you like to use it" (...) [?] sys
```

ディスクを初期化していいかの確認です。

```
...
WARNING:Erase the above disks(s) and continue" (y/n) [n] y
```

バーグラフが延びて、プロンプトが戻ってきて作業終了です。
再起動して動作を確認してください。

```
# reboot
...
#myhost login:
```

お疲れさまでした。
思考停止で口にしていた関数とメソッドの違いを掘り下げる

#結論
実際のコードで見てみましょう

```kotlin
val a = listOf("あ","い","う","え","お")
println(a.size)
```
例えば、こんな処理があるとして…。
printlnは、関数です。
sizeは、メソッドです。

分かりましたかね？
単独で呼び出すのが関数で、何かの値に付けて呼び出すのがメソッドです。

誰かの役に立ちますように…
【Node.js】ダウンロードアプリ版のアンインストール、nvmでの再インストール（mac版）

#### Node.jsのインストールはどのように行いましたか？
[公式サイト](https://nodejs.org/ja/)からアプリをダウンロードしてインストールするのは簡単な方法ですが、あまりオススメしません
理由はバージョンコントロールが面倒になるからです。**nvm**または**nodebrew**を使ってインストールする方法がオススメです。

既にダウンロードアプリ版でNode.jsをインストールしてしまった方向けに、
既存のNode.jsのアンインストールから、nvmで再インストールする方法について紹介します。


## Node.jsのアンインストール

#### npmのアンインストール

npmのアンインストール

~~~bash
npm uninstall -g npm
~~~

ホームディレクトリに移動して`.npm`フォルダの削除

~~~bash
cd ~
rm -rf .npm
~~~

`node`コマンドのフルパスを探してこちらも消しておく

~~~bash
which node
rm -rf /usr/local/bin/node
~~~

消えていることを確認
(いずれも`-bash: **: command not found`となる)


~~~bash
node -v
npm -v
~~~

## nvmを使ったNode.jsの再インストール

nvmのインストール

~~~bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.0/install.sh | bash

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13527  100 13527    0     0  45392      0 --:--:-- --:--:-- --:--:-- 45240
=> Downloading nvm from git to '/Users/***/.nvm'
=> Cloning into '/Users/***/.nvm'...
remote: Enumerating objects: 286, done.
remote: Counting objects: 100% (286/286), done.
remote: Compressing objects: 100% (252/252), done.
remote: Total 286 (delta 32), reused 110 (delta 21), pack-reused 0
Receiving objects: 100% (286/286), 146.78 KiB | 514.00 KiB/s, done.
Resolving deltas: 100% (32/32), done.
=> Compressing and cleaning up git repository

=> Appending nvm source string to /Users/***/.bash_profile
=> Appending bash_completion source string to /Users/***/.bash_profile
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
~~~

`.bash_profile`に追加されていることが確認できたらコマンドの有効化

~~~bash
source ~/.bash_profile
~~~

nvmのバージョン確認

~~~bash
nvm --version
0.35.0
~~~

Node.jsのバージョン確認

~~~bash
nvm ls-remote
       
       ...
       v14.15.4   (LTS: Fermium)
       v14.15.5   (LTS: Fermium)
       v14.16.0   (LTS: Fermium)
       v14.16.1   (LTS: Fermium)
       v14.17.0   (Latest LTS: Fermium)
        v15.0.0
        v15.0.1
        v15.1.0
        v15.2.0
        v15.2.1
        v15.3.0
        v15.4.0
        v15.5.0
        v15.5.1
        v15.6.0
        v15.7.0
        v15.8.0
        v15.9.0
       v15.10.0
       v15.11.0
       v15.12.0
       v15.13.0
       v15.14.0
        v16.0.0
        v16.1.0
~~~

バージョンを選択してインストール（必要に応じて複数バージョンをインストール）

~~~bash
nvm install v14.17.0
~~~

インストールされたバージョンの確認

~~~bash
nvm ls

       v12.22.1
       v14.17.0
->      v16.1.0
default -> v14.17.0
node -> stable (-> v16.1.0) (default)
stable -> 16.1 (-> v16.1.0) (default)
iojs -> N/A (default)
unstable -> N/A (default)
lts/* -> lts/fermium (-> v14.17.0)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.1
lts/fermium -> v14.17.0
~~~

使用するバージョンを選択（必要によって切り替え）

~~~bash
nvm use v14.17.0
~~~

バージョンが切り替わっていることを確認

~~~bash
node -v

v14.17.0
~~~
知らない人に勝手に出品した商品を編集させない！

##はじめに##

現在フリマアプリを作成中です。

商品の出品者ではない人が編集できるURLを直接打ち込み、編集できるという問題を解決していきます。

想像してみて下さい。
自分が30,000円で出品した商品が勝手に1,000円に編集されて売れてしまった場合...

そんな事にならないように利用して下さるユーザーが安心して使えるように記述していきましょう！

##現在のコントローラの状況##
itemテーブルには出品された商品情報が入っています。
(名前・値段・商品説明・商品状態など)
編集できる*edit*アクションと更新ができる*update*アクションを見ていきます。

```.rb
 def edit
    @item = Item.find(params[:id])   
 end

  def update
    if @item.update(item_params)
      redirect_to item_path
     else
      render :edit
    end
```

editアクションでは編集したいレコードを@itemに代入し、ビューに受け渡すことで編集画面で利用できるようにします。
findはデータベースからデータを取り出したり、検索したりするためのメソッドです。
idを取得して編集ページは/items/[:id]/editとなります。

今のままでは直接上記のURLを打ち込むと出品者ではない人が編集できてしまいます。

##unless文とdeviseのヘルパーメソッド！##

まずは*unless*文の紹介.
if文が条件式がtrueの時に実行したのに対し、unless文は条件式がfalseの時に実行する構文です。

そして*devise*メソッド

```.rb
current_user 
#deviseのヘルパーメソッドde"現在ログインしているユーザー"という意味

current_user == @item.user
#現在ログインしているユーザーは商品を出品ユーザーと同じという意味
```

この2つを用いて記述すると以下になります

```.rb
 def edit
    @item = Item.find(params[:id]) 
    #もし、現在ログインしているユーザーは商品を出品ユーザーではなかった時、トップページに遷移する
    unless current_user == @item.user
      redirect_to root_path
    end
 end

  def update
    if @item.update(item_params)
      redirect_to item_path
     else
      render :edit
    end
```

このような記述になります。
もちろんこれはupdateアクションにも使うので*before_action*でまとめて記述するとより可読性が上がります。

```.rb
before_action :contributor_confirmation, only: [:edit, :update]

def edit
end

  def update
    if @item.update(item_params)
      redirect_to item_path
     else
      render :edit
    end
  end

  private
def contributor_confirmation
    redirect_to root_path unless @item.user == current_user
end
```
作業中に作った、parentしたりdeleteしたりするだけのmel

右目→左目の順に選択して実行

```c
global proc deleteMyObjects()
{
    string $sl[] = `ls -sl`;
    string $list_L[] = `listRelatives -ad -f -type "transform" $sl[1]`;
    string $list_R[] = `listRelatives -ad -f -type "transform" $sl[0]`;
    
    int $i = 0;
    for($n in $list_L)
    {
        if(`gmatch $list_R[$i] "*whiteEye_L_geo"`)
        {
            delete $list_R[$i];
        }
        else if(`gmatch $list_R[$i] "*eyeHighlight_L_geo_grp"`)
        {
            delete $list_R[$i];
        }
        else if(`gmatch $list_R[$i] "*blackEye_L_geo"`)
        {
            delete $list_R[$i];
        }
        else if(`gmatch $list_L[$i] "*whiteEye_R_geo"`)
        {
            delete $list_L[$i];
        }
        else if(`gmatch $list_L[$i] "*eyeHighlight_R_geo_grp"`)
        {
            delete $list_L[$i];
        }
        else if(`gmatch $list_L[$i] "*blackEye_R_geo"`)
        {
            delete $list_L[$i];
        }
        $i++;
    }
    
    string $list_L[] = `listRelatives -ad -f -type "transform" $sl[1]`;
    string $list_R[] = `listRelatives -ad -f -type "transform" $sl[0]`;
    $i = 0;
    for($n in $list_L)
    {
        if(`gmatch $list_L[$i] "*eyeHighlight_L_geo_grp"`)
        {
            string $parentName = $sl[0]+"|eyeHighlight_geo_grp";
            parent $list_L[$i] $parentName;
        }
        else if(`gmatch $list_L[$i] "*blackEye_L_geo"`)
        {
            string $parentName = $sl[0]+"|blackEye_geo_grp";
            parent $list_L[$i] $parentName;
        }
        else if(`gmatch $list_L[$i] "*whiteEye_L_geo"`)
        {
            string $parentName = $sl[0]+"|whiteEye_geo_grp";
            parent $list_L[$i] $parentName;
        }
        $i++;
    }
}
deleteMyObjects();
```
有向木と有向全域木について調べて知ったこと。

# 有向木には根となる頂点が必要

まず下図のグラフは、有向木とは**呼べない**グラフの例である。
でももし無向グラフだったら[**木**](https://ja.wikipedia.org/wiki/%E6%9C%A8_(%E6%95%B0%E5%AD%A6))と呼べそうな形をしている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600213/a6e62ceb-a76e-33ab-2b4a-ebf48e60fd98.png)

「木の各辺を有向にしたもの」だから「有向木」と呼びたくなるが、いろいろググってみたところ、どうやら有向木には**根から各頂点へのパスが存在しなければならない**という暗黙のルールがあるらしいのだ。
上図のグラフは根になれる頂点がないため、有向木とは呼べない。
（上図のグラフは[**閉路**](https://ja.wikipedia.org/wiki/%E9%96%89%E8%B7%AF)がない有向グラフなので、[**DAG**](https://ja.wikipedia.org/wiki/%E6%9C%89%E5%90%91%E9%9D%9E%E5%B7%A1%E5%9B%9E%E3%82%B0%E3%83%A9%E3%83%95)の一種ではある。）

一方、例えば下図のグラフなら、頂点４から出発して任意の頂点へ到達可能なので**頂点４を根とする有向木**と呼べる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600213/e26ed8d2-2301-429f-76ac-632822296124.png)

# 有向グラフにクラスカル法やプリム法は使えない

無向グラフの最小全域木を求めるアルゴリズムといえば[**クラスカル法**](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%AB%E3%83%AB%E6%B3%95)や[**プリム法**](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AA%E3%83%A0%E6%B3%95)が有名である。
しかしこれらのアルゴリズムを有向グラフに使ってみても、結果は有向木にはならない（それどころか全域木にならないかもしれない）。

例えば下図のグラフでイメージしてみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600213/b91edaae-da22-2819-0e1e-4c15e441df9e.png)

上図のグラフに対してクラスカル法をやってみると、コスト1の辺⇒コスト3の辺⇒コスト6の辺と採用したあと、コスト7の辺を採用しようとする。しかしコスト7の辺を採用してしまうと、**頂点５に侵入する辺が２本存在してしまい、有向木にならなくなる。** クラスカル法を改造して「採用すると有向木にならなくなるような辺は採用せずスキップする」とすればうまくいくかもしれないが、改造したらそれはもはやクラスカル法ではない…気がする。

次に、頂点１を根としてプリム法をやってみる。コスト3の辺⇒コスト6の辺⇒コスト7の辺⇒コスト8の辺と採用したところでアルゴリズムが終了する。いちおう有向木は得られたが、**合計コストが最小になっていない（コスト7の辺の代わりにコスト1の辺を使ったほうが合計コストは小さくなる）。** プリム法の性質上、コスト8の辺が邪魔でコスト1の辺に手が届かないのである。

では有向全域木を求めるにはどうしたらいいのかというと、[**Chu–Liu/Edmondsのアルゴリズム**](https://en.wikipedia.org/wiki/Edmonds%27_algorithm)というものがあるらしい。
このアルゴリズムはまず、根以外の各頂点について「その頂点に侵入する辺の中でコストが最小のものを探す」という操作をする。探し出した辺の集合がもし木だったら、それが有向全域木。もし木になっていなかった（どこかに閉路があった）ら、ちょっとずつ集合の中身を変えて探索を続けていく。


# 参考にしたページ（一部）
* https://stackoverflow.com/questions/22478372/prims-algorithm-for-weighted-directed-graph
* https://www.geeksforgeeks.org/why-prims-and-kruskals-mst-algorithm-fails-for-directed-graph/
* https://ark4rk.hatenablog.com/entry/2017/09/15/011937

# 補足
* この記事に載せているグラフの画像は「[**generate DOT**](http://emkjp.github.io/WebTools/dot.html)」というツールで作成したものである。このツール、とても便利。[**作者さん**](https://twitter.com/EmKjp)ありがとうございます。
* 「有向木には**根から各頂点へのパスが存在する**という暗黙のルールがあるらしい」などと書いたが、暗黙のルールではなく、有向木という言葉にはちゃんとした数学的な定義があるのかもしれない。今度調べておきます。

　

今日はここまで。
総合振込の全銀フォーマットファイルを作成する方法（Ruby）

総合振込で使用する「全銀フォーマット（全銀協規定形式）」のファイル作成方法をまとめてみました。
全銀フォーマットはどの銀行も似通っているかと思いますが、実装する際は必ず該当銀行の資料を読み込む事をお勧めします。

※ 下記は [GMOあおぞらネット銀行](https://gmo-aozora.com/support/guide/tranfer-upload.pdf) のフォーマットになります。だいぶ愚直に書いた例です。

```ruby
File.open("payout-example.txt", "w", encoding: "Shift_JIS") { |f|
  # 1. ヘッダー・レコード
  h_01 = 1                           # データ区分（固定値）
  h_02 = 21                          # 種別コード（固定値）
  h_03 = 0                           # コード区分（固定値）
  h_04 = 9999999999                  # 振込依頼人コード（固定値）
  h_05 = "#{振込依頼人名}".ljust(40)   # 振込依頼人名
  h_06 = Date.today.strftime("%m%d") # 振込実施日
  h_07 = "0310"                      # 仕向銀行番号（固定値）
  h_08 = "ｼﾞｰｴﾑｵｰｱｵｿﾞﾗﾈﾂﾄ"              # 仕向銀行名（固定値）
  h_09 = "#{仕向支店番号}"             # 仕向支店番号
  h_10 = "#{仕向支店名}".ljust(15)     # 仕向支店名
  h_11 = 1                           # 預金種目(依頼人)（固定値）
  h_12 = "#{口座番号}"                 # 口座番号(依頼人)
  h_13 = "".ljust(17)                # ダミー

  f.write("#{h_01}#{h_02}#{h_03}#{h_04}#{h_05}#{h_06}#{h_07}#{h_08}#{h_09}#{h_10}#{h_11}#{h_12}#{h_13}\r\n")

  # 2. データ・レコード
  payouts = ...
  payouts.each do |payout|
    d_01 = 2                                      # データ区分（固定値）
    d_02 = "#{payout.被仕向銀行番号}".rjust(4, "0") # 被仕向銀行番号
    d_03 = "".ljust(15)                           # 被仕向銀行名
    d_04 = "#{payout.被仕向支店番号}".rjust(3, "0") # 被仕向支店番号
    d_05 = "".ljust(15)                           # 被仕向支店名
    d_06 = "".ljust(4)                            # 統一手形交換所番号（固定値）
    d_07 = 1                                      # 預金種目
    d_08 = "#{payout.口座番号}".rjust(7, "0")      # 口座番号
    d_09 = "#{payout.受取人名}".ljust(30)          # 受取人名
    d_10 = "#{payout.振込金額}".rjust(10, "0")     # 振込金額
    d_11 = 1                                      # 新規コード
    d_12 = "".ljust(10)                           # 顧客コード1
    d_13 = "".ljust(10)                           # 顧客コード2
    d_14 = "".ljust(1)                            # 振込指定区分
    d_15 = "".ljust(1)                            # 識別表示
    d_16 = "".ljust(7)                            # ダミー

    f.write("#{d_01}#{d_02}#{d_03}#{d_04}#{d_05}#{d_06}#{d_07}#{d_08}#{d_09}#{d_10}#{d_11}#{d_12}#{d_13}#{d_14}#{d_15}#{d_16}\r\n")
  end

  # 3. トレーラ・レコード
  t_01 = 8                                         # データ区分（固定値）
  t_02 = payouts.count.to_s.rjust(6, "0")          # 合計件数
  t_03 = payouts.sum(:振込金額).to_s.rjust(12, "0") # 合計金額
  t_04 = "".ljust(101)                             # ダミー

  f.write("#{t_01}#{t_02}#{t_03}#{t_04}\r\n")

  # 4. エンド・レコード
  e_01 = 9             # データ区分（固定値）
  e_02 = "".ljust(119) # ダミー

  f.write("#{e_01}#{e_02}\r\n")
}
```

## 参照
- [総合振込 -アップロードファイル作成ガイド - Ver 1.0.4 | GMOあおぞらネット銀行](https://gmo-aozora.com/support/guide/tranfer-upload.pdf)
- [全銀協規定形式（振込ファイル）| 住信SBIネット銀行](https://www.netbk.co.jp/contents/resources/pdf/doc_sofuri_zenginformat.pdf)
【Ruby on Rails】郵便番号にバリデーションをかけたい！【正規表現】

## はじめに
Ruby on Railsの学習中です。携帯番号は下記の参考文献と出会えたので解決しましたが、正規表現で郵便番号にいい感じのバリデーションをかけたいと思ったのですが、なかなかベストな文献が見当たりませんでした。そこでこちらの文献を参考に郵便番号正規表現を作成しました。

#### 参考文献
https://qiita.com/shungo_m/items/14e64e1adbcdbc87ff7f

#### テストするならココ
https://rubular.com/
## 今回の理想
- 郵便番号は以下ならOKとします。
 - 000-0000(数字7桁と間にハイフンが含まれる)
 - 0000000(数字7ケタのみ)

## テスト環境
- Rails 5.2.5
- ruby 2.6.3

## ①正規表現を作る
#### 郵便番号の正規表現

``` 
\A\d{3}[-]?\d{4}\z
```
これで<font color="DarkOrange">\A</font>から始まり<font color="DarkOrange">\z</font>に終わる<font color="DarkOrange">\d{3}</font>3桁と<font color="DarkOrange">\d{4}</font>4桁の数字で<font color="DarkOrange">[-]?</font>間にハイフンが入っていても入ってなくてもOK
という意味になります。

## ②正規表現を試す
[rubular.comに移動](https://rubular.com/)
①Your regular expression:に先ほどの正規表現を記載する
②Your test string:にテストしたい文字列を入れる
③Match result: マッチするか確認する

## ③モデルに実装する

``` models/user.rb

  VALID_POSTAL_CODE_REGEX = /\A\d{3}[-]?\d{4}\z/ #正規表現を//で/正規表現/とサンドすることを忘れないよう
  validates :postal_code, presence: true, format: { with: VALID_POSTAL_CODE_REGEX }

```
以上で実装できました。
正規表現はPHP: preg_match() で何回か触れたことはありましたが、すぐ忘れるし、まだまだゼロから手書きはできません...
何かから見て学び、応用を効かせて、rubular.comで試すというルーティンで今後も正規表現と向き合って行こうと思います！
ちなみにハイフンの有り無しはDB上では統一したいのでjavascriptのinputイベントで足すという方法を考えています。(ということはハイフンありの完全一致のバリデーションでもいいのでは？)
Ruby 学習メモ

#シンボル
ハッシュ（連想配列）で使われることが多い

```ruby
exam = {'subject'=>'japanese', 'score'=>70}
```

これを

```ruby
exam = {:subject=>'japanese', :score=>70}
```

や

```ruby
exam = {subject: 'japanese', score: 70}
```

と記述することができる。

また取り出す時や更新するときは

```ruby
puts exam[:subject]
```

とする。

#キーワード引数
メソッド作成の引数指定のこと。

```ruby
def person_info(name:, age:, hometown:)
  puts "私の名前は#{name}で年齢は#{age}で出身は#{hometown}です"
end

person_info(name: "太郎", age: 23, hometown: "東京")
```

#attr_accessor
クラスのインスタンス変数を読み書きできるようにする

```ruby
class Person
  def initialize(name)
    @name = name
  end
end

a = Person.new('mike')
puts a.name
```

このように記述してもインスタンス変数は出力することができない。
読み書きを可能にするためにはattr_accessorメソッドでインスタンス変数を読み書き可能にしなければならない。
`attr_accessor :インスタンス変数もしくは'インスタンス変数'`
シンボルもしくは文字列で記述

```ruby
class Person
  attr_accessor :name #'name'でもよい  

  def initialize(name)
    @name = name
  end
end

a = Person.new('mike')
puts a.name
```
SANs ってなに？

## 勉強前イメージ

聞いたことないかも。。。
なんやろ

## 調査

### SANs とは

Subject Alternative Names の略で、CN(Common Name)の追加のことです。
SSL証明書は1つのFQDNに1つ必要ですが、
SANsを利用することで1つのSSL証明書で複数のFQDNを設定することもできます。

### イメージ

設定のイメージは以下になります。

- CN : www.sslsyoumeisyo.com
- SANs : sslsyoumeisyo.com
- SANs : sslsyoumeisyo.co.jp
- SANs : xxx.co.jp

ベンダーによっては、「www」を削除したCNを自動登録するところもあります。

試しにyahoo.co.jpの証明書を見てみると以下です。

![1証明書 2021-05-12 18.00.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/5388e9c7-04c4-76b3-5c27-3b9fc45f4ba1.png)

サブジェクトの代替名にはyahoo.co.jpだけでなく、
○○-yahoo.jpなども含まれています。

### ワイルドカード証明書との違い

ワイルドカード証明書は同じ階層のサブドメインを保護します。
CNが `sslsyoumeisyo.com` だとしたら
`www.sslsyoumeisyo.com` や `app.sslsyoumeisyo.com` など、 
○○○.sslsyoumeisyo.com が対象になります。
同じ階層のサブドメインはすべて使用できますが、ドメインが違うと使用できません。

SANsではCNと違うドメインでも対象とできますが、
ワイルドカード証明書では対象とできません。

## 勉強後イメージ

ドメイン名違うくても登録すれば使用できる証明書とかあるんだ・・・・
結構いろいろあるから複数ドメイン持ってる方はどっちがいいとか選ぶの大変そう

## 参考

- [SSL証明書の便利機能をご紹介（SNI、SANs、2way）](https://www.idcf.jp/rentalserver/aossl/basic/ssl-function/#:~:text=SANs%EF%BC%88Subject%20Alternative%20Names%EF%BC%89%E3%81%A8,%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E5%8F%AF%E8%83%BD%E3%81%A7%E3%81%99%E3%80%82)
- [【図解】SANs(サブジェクト代替名)とSNI(server_name indication),ワイルドカードの違い](https://milestone-of-se.nesuke.com/sv-advanced/digicert/wildcard-sans-sni/)
- [ワイルドカード証明書とマルチドメイン証明書の違いについて](https://www.ssl-secure.jp/news/20181020/)
【初心者でもわかる】効果が似ているHTML・CSSたち

#どうも7noteです。似ているけど意味は違うHTML・CSSを紹介

HTMLとCSSの中には似ているようで違う意味を持つものがいくつかあります。
差がわかりにくいものもあるので、一つずつ比較しながら見ていきます。




## 似てるけど違うHTML

### 「ul」と「ol」

**→ 決定的な違い: 連番か否か**

どちらも複数のアイテム(リスト)を定義するのに使われますが、違いは**連番かどうか**です。

例)
持ち物リスト→「ul」
名簿順リスト→ 「ol」


### 「div」と「span」

**→ 決定的な違い: ブロック要素かインライン要素か**

どちらも柔軟にどこでも利用できる要素です。
divはブロック要素です。横幅を指定したり、高さを指定することができます。
一方spanはインライン要素です。文章中で使ってもspan以降の文字が段送りになることがなく、装飾を入れたりできます。

例)
1つの大きなブロック(塊)として装飾などを利用する→ 「div」
文中などの一部に対して装飾を入れる→ 「span」


### 「strong」と「em」

**→ 決定的な違い: strong > em**

どちらも強調を表すHTML要素ですが、strongの方がより強い強調を表します。


## 似てるけど違うCSS

### 「padding」と「margin」

**→ 決定的な違い: borderの内側の余白か、外側の余白か**

これは最初は識別か難しい難問かもしれません。ボックスモデルと呼ばれるものなので詳しくは「ボックスモデル　css」とかで検索してもらうのがよいのですが、一言で違いを簡単に表すなら上の文の通りでしょう。
要素にborderを指定した場合、その内側に対して余白を取るのがpaddingです。逆に、そのborderより外側に対して余白を取るのがmarginになります。

例)
背景色の範囲を広げたり、borderと中の要素の間を広げたい→ 「padding」
要素同士の距離を広げたい→ 「margin」


### 「`textalign: center;`」と「`margin: 0 auto;`」（左右の中央寄せ）

**→ 決定的な違い: インライン要素に対してか、ブロック要素に対してか**

インライン要素の左右中央寄せには`textalign: center;`を使います。(指定するのは中央揃えにしたい親要素に対して。)
逆にブロック要素の中央揃えには`margin: 0 auto;`が使われることが多いです。

ブロック要素、インライン要素でそれぞれ中央寄せにする方法が違うので注意が必要です。


## まとめ

似ているものが多くあり覚えるのが大変ですが、一つ一つ違う意味がしっかり与えられているものしかありません。

ここで紹介したほとんどは頻出する重要なものが多いです。(strongとemは出番少なめ)
しっかり違いを把握しておくことで崩れにくいレイアウトを組むことができますし、個々の特性を知ることで作成できる幅が大きく広げることができます！

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
Flask-WTFでWebフォームを作る

Flask-WTFはPythonでWebフォームとそのバリデーションを簡単に実装できるフレームワークWTFormsのFlask版です。

まずはインストール

```console
pip install flask-wtf
```

次に秘密鍵を設定をします。 
Flaskで作成するアプリの設定はFlaskクラスのインスタンス（ここではapp）の.configに設定します。

```
app.config['SECRET KEY'] = 'hard to guess string'
```

今回はソースコードにベタ打ちしてますが、商用のアプリケーションなどでは環境変数から取得したり、端末ごとに変えたりする必要があります。
Flask-WTFではこの秘密鍵をCSRF攻撃などへの対策として利用します。

CSRF攻撃はざっくりとログイン状態にある（セッションにログイン情報を保持している）ユーザーが悪意のあるサイトにアクセスすることで、不正なリクエストがフォーム経由などで送信されるものです。
アカウント乗っ取りやなりすまし投稿などが被害例としてあります。

Flask-WTFでは正しいフォームからのリクエストなのかを確認するためにセキュリティトークンを発行し、ユーザーセッションの中にその情報を格納しますが、その際の暗号化に秘密鍵が使用されます。


では実際にフォームを作ります。
Flask-WTFではフォームをFlaskFormクラスを継承したクラスとして定義し、各項目をクラス変数として定義します。
なお各項目は入力されるデータ形式（string型など）ごとにwtformsが用意するFieldクラスのインスタンスとして作成されます。
※例えばStringField型の場合はhtmlでいうところのinput要素でtype="text"を指定した状態になります。

```python
from flask_wtf import FlaskForm
from wtforms import StringFields, SubmitField
from wtforms.validators import DataRequired

class NameForm(FlaskForm):
    name = StringField('What is your name?', validators = [DataRequired()])
    submit = SubmitField('submit')
```

Field型のオブジェクトは最初の引数に項目名（htmlでいうところのlabelに対応）をとることができます。
また上記の例ではバリデーターとしてDataRequiredを指定しています。これによってこの項目が入力されていない場合、フォームの送信がさせないようにすることができます。

あとはこのクラスを利用して、view関数経由でテンプレートをレンダリングする際にフォームオブジェクトを変数として渡してあげればOKです。

```Python
@app.route('/', methods = ['GET', 'POST']
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form = form, name = name)
```

変数nameにNoneを代入することで初期化し、NameFormクラスのインスタンスとして変数formを作ります。
NameFormクラスの（厳密にはFlaskFormクラスの）メソッドvalidate_on_submit()で先ほど設定してバリデーションを行います。
正の場合にはform.name.dataで入力されたデータを取得して変数nameに格納し、フォームのデータ自体は空文字でクリアします。
そうすることで再度フォームを読み込んだ際に入力されたデータをリセットすることができます。

テンプレートは下記です。

```html
<div class="page-header">
    <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name }}
    {{ form.submit }}
</form>
```
変数nameがNoneではない場合はその名前を表示し、Noneである場合にはStrangerを表示します。
フォーム自体はhtmlのform要素で作成し、中身をview関数から受け取ったformの各変数として書いてあげることでフォームを作ることができます。
LINE bot を作ってみた2（postback編）

[前回](https://qiita.com/soso555/items/770ec1f8c205c8653e8e) で味を占めたので、今度は postback を使用したアンケートを作ってみた

# 環境
- Google Spread Sheet
- Google Apps Script
- LINE Developers

# 経緯
- LINEbot と GAS だとすぐに作って動作確認できるし、インフラ準備とか必要ないからラクで楽しいなぁ
- もうちょっと LINEbot の種類を見てみよう

# 手順（概要）
1. LINE Developers でチャンネルの作成
2. GAS 構築
3. GAS 公開
4. LINE Developers に Webhook URL を登録
5. 動作確認

# 手順（詳細）
## 1. LINE Developers でチャンネルの作成
- https://developers.line.biz/console/channel/{id}/ で以下情報のチャンネルを作成する
    - Channel type：Messaging API
    - Provider：前回作成したやつ
    - その他の項目は任意
- 当該チャンネルでトークンを発行する
    - [MessagingAPI設定] > [チャネルアクセストークン] の「発行」を押下

## 2. GAS 構築
- 以下にソースを置きました
    - https://github.com/soso555BoBs/linebot2_with_gas
- 今回は GAS ファイルだけ作成
- その後、任意のスプレッドシートに結果を記載するようにした
    - 前回のやり方だといちいちスプレッドシートを開かないと GAS がいじれなかったのが面倒くさかったため

- なお、スプレッドシート ID やデバッグ用 LINEID など公開したくない情報は全てスプレッドシートの Properties に入れるようにした
    - 以下設定方法
        1. GAS エディタ右上にある [以前のエディタを使用] を選択

            ![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/b514c0a5-0c68-0948-3943-f3b9c5ed6721.png)
        2. 「なして古いの使うん？」ていうアンケートフォームが出てくるがそっ閉じ
        3. [ファイル] > [プロジェクトのプロパティ] と選択

            ![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/8c5eed74-5cf7-09dd-f973-5da7e6557800.png)
        4. [スクリプトのプロパティ] タブに以下 7 行を追加する
            - DEBUGID：デバッグ情報を送付するLINEID。ハッシュ値みたいなやつ。
            - PUSH_URL：LINEbot の PUSH URL
            - REPLY_URL：LINEbot の REPLY URL
            - SHEETID：アンケートの選択肢および結果を貯めるスプレッドシートのID
            - SHEETNAME：スプレッドシートの中のシート名称
            - TEMP_FOLDER_ID：グラフ画像を作成するフォルダ。作成した画像は削除されるため、一時的な出力先。
            - TOKEN：LINEbot のトークン

            ![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/8d6ecf6b-717a-7bd9-b8ee-e4385fd77050.png)


## 3. GAS 公開
- 前回の [ここ](https://qiita.com/soso555/items/770ec1f8c205c8653e8e#4-google-spread-sheet-%E5%85%AC%E9%96%8B) 参照のこと

## 4. LINE Developers に Webhook URL を登録
- 前回の [ここ](https://qiita.com/soso555/items/770ec1f8c205c8653e8e#5-line-developers-%E3%81%AB-webhook-url-%E3%82%92%E7%99%BB%E9%8C%B2) 参照のこと

## 5. 動作確認
- 動いた！

![4.png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/fa92be74-7ca6-2e21-2f42-f22588f163b1.png)


# 感想＆注意点
- 前回から引き続き、デバッグ方法がわからなかったので、以下 3 通りの方法を駆使した
    1. GAS エディタのデバッグ機能
    2. ターミナルから curl コマンドを叩く
        - GAS を公開した URL へ、期待する POST パラメータを付与して curl を叩く
        - すると、エラーの場合はエラー文言がレスポンスパラメータとしてもらえる
    3. デバッグしたい箇所に「DEBUGID 向けに LINE のトークを発出」するようにした
        - [ソースだとここ](https://github.com/soso555BoBs/linebot2_with_gas/blob/main/main.gs#L15-L16) みたいな感じ
        - 結局、Exception をキャッチしてスタックトレースを発出するようにした
            - [ここ](https://github.com/soso555BoBs/linebot2_with_gas/blob/main/main.gs#L46-L47)
- 今回はなんだかんだ完了までに 2 日間くらいかかった
    - デバッグ方法が確立できていないのが主たる原因
    - GAS の公開バージョンも 80 を上回った
- 何かのシミュレーションをして、その結果を画像配布するようなサービスに流用できそう
    - ただし GAS だと複数人同時問い合わせに耐えうる保証はない
        - し、そもそもやり方を調べていない
    - 簡単に動かしてみる、がテーマなのでとりあえずそこは保留にした
Dockerでデュアルロギングができるようになっていた件

# 結論
Docker 20.10からロギングドライバを `json-file` / `journald` 以外にしても、
 `docker logs` コマンドでコンテナログが見れます。（デュアルロギングというらしい）

詳細は[こちら](https://matsuand.github.io/docs.docker.jp.onthefly/config/containers/logging/dual-logging/)

# 背景
Dockerコンテナのログを見るコマンドとして `docker logs` がありますが、
例えばログをAWSやGCPに流したいとか、Fluentdに流したいとすると
「ロギング・ドライバ」というものを変更すればよいとのことでした。

そこで、`「docker ロギングドライバ」`とググると、以下のページに辿りつきます。(2021年5月時点)

[ロギング・ドライバの設定（Docker-docs-ja 19.03）](https://docs.docker.jp/config/container/logging/configure.html)

このページを眺めていると [ロギング・ドライバの制限](https://docs.docker.jp/config/container/logging/configure.html#limitations-of-logging-drivers) という項目があり、

> Docker Community Engine を使う場合は、 docker logs コマンドは以下のドライバのみ利用可能です。
> - local
> - json-file
> - journald

と記載されており、実際これまでは上記以外のロギングドライバを指定した状態で `docker logs` をすると

```
$ docker logs
Error response from daemon: configured logging driver does not support reading
```

みたいな表示がされていました。

例えば私はGCPにログを流していたので、GCPのログドライバでも調べたのですが、やはり

> This log driver does not implement a reader so it is incompatible with docker logs.

と記載されていました。（将来的にアップデートされると思います）

ところがDockerをアップデートして触っていると、
指定したロギングドライバの出力をした状態でも `docker logs` でログが出ることに気づきました。

最初はバグかと思っていろいろ試していたのですが、
結局のところ[Dockerのリリースノート](https://docs.docker.com/engine/release-notes/#logging-1)にたどり着き、

> Support reading docker logs with all logging drivers (best effort) 

つまり「すべてのロギングドライバと一緒にdocker logsが読めるよ！」というアップデートがあったことに気づきました。

やはり `docker logs`はデバッグには便利なので、非常にありがたいアップデートだと思います。

# 最後に
Docker 20.10がリリースされたのが2020年12月なので、
既に5か月経過しており「知ってるわ！」という方も多いと思いますが、
まだアップデートしてない方などの参考になれば幸いです。