OmniAICreator/Qiita-1.07M huggingface dataset:
[Ruby] DelegateClass を使って僕だけの Logger を実装する (追記あり)

# 例

標準出力に出力するための Logger オブジェクトを作りたい :raised_hands_tone1:

```rb
require 'logger'

logger = Logger.new(STDOUT)
logger.formatter = Logger::Formatter.new
logger.datetime_format = '%Y/%m/%d %H:%M:%S '

logger.info('BONFIRE LIT')
logger.error('YOU DIED')
```
```stdout
I, [2019-07-09T21:40:12.663123 #18929]  INFO -- : BONFIRE LIT
E, [2019-07-09T21:40:13.036144 #18929] ERROR -- : YOU DIED
```

このような形で毎回 logger オブジェクトを作るのは大変だから、クラス化しよう :smirk_cat:

```rb
require 'forwardable'
require 'logger'

class StdoutLogger
  extend Forwardable

  def_delegators :logger, :debug, :info, :warn, :error, :fatal

  private

  def logger
    @logger ||=
      Logger.new(STDOUT).tap do |logger|
        logger.formatter = Logger::Formatter.new
        logger.datetime_format = '%Y/%m/%d %H:%M:%S '
      end
  end
end

logger = StdoutLogger.new
logger.info('BONFIRE LIT')
logger.error('YOU DIED')
```

以前はこのように「Logger オブジェクトである `logger` を所有し、`info` や `error` などのメソッドを `logger` に委譲する」というクラスを実装していました。しかし、この方法では委譲したいメソッドが増えた場合、例えば Logger#unknown も委譲したい場合などに `def_delegators` に追記しなくてはいけません :weary:

そこで便利なのが [Kernel#DelegateClass](https://docs.ruby-lang.org/ja/latest/method/Kernel/i/DelegateClass.html) です。

```rb
require 'delegate'
require 'logger'

class StdoutLogger < DelegateClass(Logger)
  def initialize
    super(logger)
  end

  private

  def logger
    @logger ||=
      Logger.new(STDOUT).tap do |logger|
        logger.formatter = Logger::Formatter.new
        logger.datetime_format = '%Y/%m/%d %H:%M:%S '
      end
  end
end

logger = StdoutLogger.new
logger.info('BONFIRE LIT')
logger.error('YOU DIED')
```

`DelegateClass(Logger)` を継承することで、Logger のインスタンスメソッドはすべて `logger` に委譲されます。

ちなみに `Logger` クラスを継承する方法では

# 最後に

`DelegateClass` は非常に便利で、例えば Array のラッパークラスを定義したい場合にも使えます。これについては以前書いた

* [Enumerable を include する代わりに Enumerator オブジェクトを活用する](https://qiita.com/QUANON/items/d84fcf417c285721837d)

という記事を参照してください。

Logger 関連でよろしければこちらの記事もご覧ください。

* [Logger のログファイルへの出力を標準出力にも出力したい](https://qiita.com/QUANON/items/8b212c04f2f3457eec87)

# 追記: 通常の継承の方がいいような……

この場合 Logger クラスを継承する方法でもいいような……。

```rb
require 'logger'

class StdoutLogger < Logger
  def initialize
    super(STDOUT, formatter: Formatter.new, datetime_format: '%Y/%m/%d %H:%M:%S ')
  end
end

logger = StdoutLogger.new
logger.info('BONFIRE LIT')
logger.error('YOU DIED')
```

違いのひとつとして、Logger クラスのサブクラスかどうかが異なる。

```rb
# DelegateClass(Logger) を継承する場合
logger.is_a?(Logger)
#=> false

# Logger を継承する場合
logger.is_a?(Logger)
#=> true
```

この場合、むしろ Logger オブジェクトであると見なしたほうが適切かもしれない。
EDINET APIをpythonで実行するまわりを調べてみた

##EDINET APIを実行する
　有報キャッチャーAPIは、証券コードを指定すると該当書類のZIPファイルが取得できるが、任意の日付にどの会社がどういう書類をEDINETに提出したかが分からない（任意の指定した日付で有報キャッチャーAPIが実行できない）ので、2019年春にEDINETのAPIがローンチしているので、そちらのAPIを試してみた。

```python:edinet_api.py
import json
import requests
import datetime

def fn_getzipfile(docid):
      url2 = "https://disclosure.edinet-fsa.go.jp/api/v1/documents/" + docid
      params2 = { "type" : 1}
      fname = docid + ".zip"
      print('■'+ str(fname))
      
      # EDINET API_2:提出書類のZIP取得
      res = requests.get(url2, params=params2)

      # ファイルへ出力
      if res.status_code == 200:
           with open(filename, 'wb') as f:
                   for chunk in res.iter_content(chunk_size=1024):
                         f.write(chunk)

def fn_rtrv_edinet(ymd):
  
      url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"
      params = {"date": str(ymd), "type": 2}
  
      # EDINET API_1:提出書類の取得
      res = requests.get(url, params=params) 

      #print(res.text)
      #print(len(json_form["results"]))

      i = 0
      json_form = json.loads(res.text)
      for jsn in json_form["results"]:
            if str(jsn["docDescription"]).find("有価証券報告書")>-1 :
                if str(jsn["docDescription"]).find("内国投資信託受益証券")==-1 :
                    if str(jsn["docDescription"]).find("訂正")==-1 :
                        docid = jsn["docID"]
                        print('■' + str(docid))
                        i = i +1

                        #print(jsn)
                        
                        lst = ['docID','SecuritiesCode','edinetCode','secCode','filerName']
                        lst = lst + ['submitDateTime','periodStart','periodEnd','docDescription']
                        for l in lst:
                              x= [print(jsn[l]) for j in jsn if l in j]
                        #fn_getzipfile(docid) 
      return i        
        
if __name__ == '__main__':
      
      # 日付
      date =  datetime.datetime.today().strftime("%Y-%m-%d")
      #
      date = "2018-06-28"
      print( date)
      
      r=fn_rtrv_edinet(date)
      print(r)
```
・まず任意の日付を指定してEDINET API（documents.json）を実行すると、その日に提出された提出書類一覧が取得できる。各書類にはdocidがあるので、このdocidを引数として再度APIを実行して提出書類のZIPを取得する。
・過去の提出書類も取得可能のようである。

※参考
http://itref.fc2web.com/lang/python/edinet.html
初心者が10分で実装するコメント機能

#初めに
実務なんかで使えません。
フレームワークとか高尚なものは使いません。
というか使えません。

めっちゃ簡単にできたので投稿

#コメント機能
フォームを作り、その下にコメントを表示するだけ
![chrome.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397212/00ca1e7a-a5d6-b064-44f8-b296ba07d11b.png)
コメントを入力、送信
![chrome2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397212/3a09e195-7eb4-4231-85f2-f76be20edc16.png)
コメントが表示される
![chrome3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397212/45d66d79-ac3a-ceed-623a-114d347be560.png)

#手順
1.適当なディレクトリ(Aとする)にcgi-binディレクトリを作る。
2.その中に以下のプログラムをコピペし、comment.pyと名付ける。


```python:comment.py
#! /usr/bin/env python3

import sqlite3
import csv
import cgi
import sys
import io
from datetime import datetime

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")

db_path = "./comment.db"

con = sqlite3.connect(db_path)

con.row_factory = sqlite3.Row

cur = con.cursor()

htmlText = ""

try:
   cur.execute(
       "create table if not exists commentTable(id integer primary key autoincrement, comment text, date datetime);"
   )
except sqlite3.Error as e:
   print("ERROR:", e.args[0])

form = cgi.FieldStorage()
input_comment = form.getvalue("comment")

try:
    if input_comment is not None:
        date = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
        cur.execute("insert into commentTable(comment, date)values(?, ?);", (input_comment, date))

except sqlite3.Error as e:
    print("ERROR:", e.args[0])

def show_database():
    try:
       cur.execute("select * from commentTable;")
    except sqlite3.Error as e:
       print("ERROR:", e.args[0])
       debug = "except completed"
    return 0

show_database()

rows = cur.fetchall()

if not rows:
   htmlText = "コメントはありません。"
else:
   for row in rows:
       if str(row["id"]):
           htmlText += str(row["date"]) + "<br>" + str(row["comment"])+ "</br>"

con.commit()
con.close()

print("Content-type: text/html; charset=utf-8")

print(
   f'''
    <!DOCTYPE html>
    <html lang="en" dir="ltr">
      <head>
        <meta charset="utf-8">
        <title>コメント</title>
      </head>
      <body>
        <div id="comment-div" class="">
          <h1>コメント</h1>
          <p>コメントを入力して下さい。</p>
          <form name="comment-form" class="" action="comment.py" method="post">
            <textarea name="comment" rows="8" cols="80"></textarea><br>
            <input type="submit" name="" value="送信">
          </form>
          <p>コメント</p>
          {htmlText}
        </div>
      </body>
    </html>
     '''
)
```

3.ディレクトリAで次のコマンドを実行する。

```
$ python -m http.server --cgi
```
これでローカルサーバが立つ。
やめるときは`ctrl-c`
4.以下のurlにアクセスする。
http://localhost:8000/cgi-bin/comment.py
Makefileを作ってビルドしよう（超初級編）

##Cの入門書を進めてる途中（進捗だめです）
もう何回目の入門だよって感じですけどこれやってます

[C言語本格入門 ~基礎知識からコンピュータの本質まで](https://www.amazon.co.jp/C%E8%A8%80%E8%AA%9E%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80-%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98%E3%81%8B%E3%82%89%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%81%AE%E6%9C%AC%E8%B3%AA%E3%81%BE%E3%81%A7-%E7%A8%AE%E7%94%B0-%E5%85%83%E6%A8%B9/dp/4774196169)

##make……？makefile?
巷によくある入門書みたいにただ単にコンパイルするだけじゃなくてmakefileを作成してコンパイルを通すやり方で進んでいくので、実践に近い形になってます。（なってるそうです）

##無知だった自分
実際にmakeでコンパイルを業務でしたことがあるにもかかわらず、読み進めて「これ実行ファイルの名前を変えてるだけなのにわざわざMakefile作る必要なくね？」と思ってしまったのですが、それをツイッターで呟いたら[ソースファイルが数百数千個あるでっかいプロジェクトでは便利](https://twitter.com/iruka3/status/1147157721487069186)というありがたいツッコミがございました

全く恥ずかしいことにこれまで現場で散々（といっても半年くらいですが）makeのお世話になってたはずなのに、どう書くかもどんなメリットがあるかも知らずにいました

###Makefileをどうやって書くのか

```Makefile.hoge
PROGRAM = hoge
OBJS    = hoge.o
SRCS    = $(OBJS:%.o=%.c)
CC      = gcc
CFLAGS  = -g -Wall
LDFLAGS =

$(PROGRAM):$(OBJS)
     $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LDLIBS)
```

※PROGRAM行のCCの後ろはタブです。
どんな意味があるかを上から解説します。
PROGRAM：プログラム名で、実行ファイルの名前になります
OBJS：リンクするオブジェクトファイル名をスペース区切りで列挙。hoge.o fuga.oみたいに続けて書くことで複数ファイルを指定できる……って認識であってますかね？
SRCS：ソースコードのファイル名指定。ここではOBJSの拡張子を.cにすることでコンパイル対象をhoge.cにしています。
CC：Cコンパイラのコマンド名。ここではgcc
CFLAGS：コンパイルのオプション指定。ここではデバッガ用の-gと警告を厳しくする-Wallを指定してます。
LDFLAGS:リンカのオプション指定（よくわかってないので割愛。特殊なライブラリのリンク等をする際に使用するそうです）
$(PROGRAM)：プログラムの生成方法の記述

Makefileの書き方は他にもあるようなので、まだまだ勉強が必要ですね……

###Makefileを使ってビルド
```
$ make -f Makefile.hoge
```
ビルドの過程はこんな感じです

```
gcc -g -Wall -c -o hoge.o hoge.c
gcc -g -Wall -o hoge hoge.o
```

これで実行ファイルhogeが出来るので以下で実行できます。

```
$ ./hoge
```

#まとめ
・Makefileは大規模開発で便利
・書き方多種多様

……でも、makeいろんな書き方あるってことだけどググっても書籍が[オライリー本](https://www.amazon.co.jp/GNU-Make-%E7%AC%AC3%E7%89%88-Robert-Mecklenburg/dp/4873112699/ref=asc_df_4873112699/?tag=jpgo-22&linkCode=df0&hvadid=295678107984&hvpos=1o2&hvnetw=g&hvrand=26528690058319140&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009247&hvtargid=aud-828501354917:pla-523848454026&psc=1&th=1&psc=1)しか出てこないのはどういうことなの。調べ方が悪い？
放課後のtoioあそび：VisualProgrammingでキューブの前後左右操作（基本＆座標制御）


（本投稿は個人的趣味で書いています。また[Noteの記事](https://note.mu/akichika/n/n4b72eab1793d)からの転載です。試験的に両方で書いています。）

![rectangle_large_type_2_fb1cc49e779915db3a46aaa57acbc7a5.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33040/a1b7f4e4-6f3e-86a5-cec5-93ba6ccd5842.jpeg)


toioのVisual Programmingはとても簡単にロボットプログラミングが出来て、動かしているだけでも楽しいので、基本的なところから紹介していきたいと思います。体系的な説明にこだわらず、ネタ的な物も気ままに書きたいと思います。

# 本記事の概要

まずはロボットを動かす基本中の基本、「前後左右にマニュアルで動かす」ところから（いわゆるラジコン操作）、ということで遠隔操作のサンプルです。キーボードの矢印キーで上下左右キー前後左右の動きを割り当てます。いくつかハマりがちなポイントがあるのでそちらも紹介します。
後半では、toioならではとも言える、絶対座標を使ってマットからはみ出ないように制御する例や、マスの面を使って上下左右に１マスずつ正確に動く例など、普通のロボットではなかなか出来ない絶対位置制御を用いた例を簡単に紹介します。


・・・と言ってみたものの、QiitaはいくらやってもYouTube動画の埋め込みがいまいちうまくいかず、正直なところYouTube動画満載の記事が読みづらいので、ここからはNoteの方が読みやすいと感じましたので、ぜひ詳細は下記Noteをご覧下さい。中途半端な見出しで申し訳ありません。


続きはこちら・・・
https://note.mu/akichika/n/n4b72eab1793d
TensorFlow, keras メモ

keras.layers.Embedding()
この層はEmbedding（埋め込み）層です。この層は、整数にエンコードされた語彙を受け取り、それぞれの単語インデックスに対応する埋め込みベクトルを検索します。埋め込みベクトルは、モデルの訓練の中で学習されます。ベクトル化のために、出力行列には次元が１つ追加されます。その結果、次元は、(batch, sequence, embedding)となります。
テスト9

```vb

'ユーザーフォームに設定
Sub CommandButton2_Click()
UserFormA.WebBrowser1.Silent = True

Dim ie As InternetExplorer
Dim txtInput As HTMLInputElement
Dim anchor As HTMLAnchorElement

Set txtInput = WebBrowser1.document.getElementById("msthdsbox")
txtInput.Value = "AAA"

For Each anchor In WebBrowser1.document.getElementsByTagName("A")
    If anchor.innerText = "プロ野球" Then
        anchor.Click
        Exit For
    End If
Next

Do While WebBrowser1.Busy = True Or WebBrowser1.readyState < READYSTATE_COMPLETE
    DoEvents
Loop

For Each anchor In WebBrowser1.document.getElementsByTagName("A")
    If anchor.innerText = "個人成績" Then
        anchor.Click
        Exit For
    End If
Next

End Sub

Private Sub UserForm_Initialize()
'HTMLソースの全てを取得
'参照設定
'「Microsoft HTML Object Library」、「Microsoft Internet Controls」
UserFormA.WebBrowser1.Silent = True

Dim ie As InternetExplorer
Dim txtInput As HTMLInputElement
Dim anchor As HTMLAnchorElement

WebBrowser1.Navigate "https://sports.yahoo.co.jp/"

End Sub

'--------------------------------------------------------------------

Private Sub UserForm_Initialize()
'HTMLソースの全てを取得
'参照設定
'「Microsoft HTML Object Library」、「Microsoft Internet Controls」
UserForm1.WebBrowser1.Silent = True
WebBrowser1.Navigate "https://mypage.blogmura.com/login/"

End Sub

Private Sub CommandButton1_Click()
keyword = "AAA"
keyword2 = "BBB"

With WebBrowser1.document
    .getElementById("email").Value = keyword
    .getElementById("password").Value = keyword2
End With

Dim button As HTMLInputElement

For Each button In WebBrowser1.document.getElementsByTagName("input")

    If button.Value = "ログイン" Then
        button.Click
    End If

Next
End Sub


Sub マクロ1()
On Error GoTo マクロ1_Err
DoCmd.NavigateTo "ユーザー設定", "ユーザー設定のグループ 1"
 
マクロ1_Exit:
Exit Sub
マクロ1_Err:
MsgBox Error$
Resume マクロ1_Exit
 
End Sub


```
Rustのrecursion_limit

# はじめに

Rustで非常にネストの深いstruct/enum（例えば大規模な抽象構文木とか）を書いていると以下のようなコンパイルエラーが出ることがあります。
（実のところ再帰的なマクロを書いて失敗するとよく出るエラーなのですが、特にマクロを書いてなくても出るよ、という話です）

```console
error: reached the recursion limit while instantiating `...`
```

この記事ではこのエラーの理由と解決方法を書きます。

# 何のエラーか

Rustコンパイラには`recursion_limit`という制限値があります。

[The recursion_limit attribute](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)

> The recursion_limit attribute may be applied at the crate level to set the maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference. It uses the MetaNameValueStr syntax to specify the recursion depth.

要するに「コンパイル時の処理（マクロの展開やDerefの自動追加）の際に無限再帰にならないよう最大値を設けている」ということで、これに引っかかったときに出るのが冒頭のエラーです。

単にstruct/enumのネストが深いだけなら特に関係ないのですが、例えば`#[derive(Debug)]`などを付けるとこのマクロの展開時に引っかかります。

現在のデフォルト値は64のようです。

# 解決方法

以下のように制限値を増やすことができます。

```rust
#![recursion_limit = "128"]
```

このアトリビュートはクレートレベルアトリビュートとなっていて、クレートのトップレベルでしか宣言できません。`lib.rs`か`main.rs`に書けばOKです。
Python 画像の縦横幅をチェックする簡易ツール

## 前書き

以下のような画像群がありました。

![スクリーンショット 2019-07-09 20.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379795/dde412ea-31e5-0ec9-c2b9-3c668da9f786.png)

ここから画像サイズに誤りあるもの（赤い画像）を検出しないといけない。

普通にGUIで見たらこんな感じです。
![スクリーンショット 2019-07-09 20.51.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379795/0aae957f-ccb5-076a-8bbd-495aa7561232.png)

赤い画像がサイズ違いの画像。
実際の画像は全て違うデザインなので、これだけでは画像の判別がつかないです。

こういうのを見れるGUIツールはいくらでもありそうですが、
画像の数が多いので、GUIツールが重かったり見にくかったり。


## 何がしたいのか

なるだけラクにチェックしたいです。


## 何をやるのか

簡単な処理で対処してしまおう、と思いました。


## やったこと

Python で対処しました。
Pythonの画像処理ライブラリPillowを使ってます。
pip などで簡単にインストールできます。
https://pillow.readthedocs.io/en/stable/

`````
import glob
from PIL import Image

# 処理
def main(x, y, type_str, path, file_type):
    files = glob.glob(path + file_type)
    ng_cnt = 0
    ok_cnt = 0

    for file in files:
        sample = Image.open(file)
        sizestr = str(sample.size)
        chkstr_yoko = '(' + str(x) + ', ' + str(y) + ')'
        chkstr_tate = '(' + str(y) + ', ' + str(x) + ')'

        if sizestr != chkstr_yoko and sizestr != chkstr_tate:
            print('NG:' + file)
            ng_cnt = ng_cnt + 1
        else:
            ok_cnt = ok_cnt + 1
        #    print('OK:' + file)
        # print(chkstr)

    print()
    print(type_str)
    print('Tate: W = ' + str(y) + ', H = ' + str(x) +
          ' / Yoko: W = ' + str(x) + ', H = ' + str(y))
    print('OK：' + str(ok_cnt))
    print('NG：' + str(ng_cnt))

# チェックする画像サイズを定義
x = 150
y = 100
path = '/Users/sawai/images/'
file_type = '/*.png'
type_str = '# Test_Image'

# 処理呼び出し
main(x, y, type_str, path, file_type)
`````

画像サイズやパスはロジック内に書きましたが、
別ファイル定義やコマンドライン引数にしても良いと思います。

## 実行結果

こんな感じでサイズが違う画像をピックアップできました。
処理速度も苦にならず、数秒で完了します。
![スクリーンショット 2019-07-09 20.52.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379795/b4dbdb5e-19f7-b75d-65b2-95efc3018189.png)


## まとめ

自身は業務上PHPを書く機会が多いのですが、
ちょっとしたタイミングで、ちょっとしたことを、ちょっと理由作って、
興味ある言語で書いてみる機会を作るのも大事かも。
（じゃないと実務で使う機会ってあまりないんですよねぇ・・・）

もちろん、
他タスクのリソースを食いつぶすまで熱入れしない程度にですけども。
まぁロジック書くことは楽しいことだと思いますから（笑）
Debian に最新版NVIDIAドライバを入れる手順

DebianでもNVIDIA提供のグラフィックスドライバがパッケージとして提供されていて、それをインストールする[簡単な手順](https://wiki.debian.org/NvidiaGraphicsDrivers) が公式ウェブサイトで説明されていますが、安定版リリースに入っているドライバはいっこうに更新されません。最新版ドライバを公式パッケージを用いて入れるためには

```config:/etc/apt/sources.listに下記内容を追加
deb http://deb.debian.org/debian/ testing main non-free contrib
deb http://deb.debian.org/debian/ unstable main non-free contrib
deb http://deb.debian.org/debian/ experimental main non-free contrib
```

```/etc/apt/apt.conf.d/00mydefaultreleaseに下記内容を記入
APT::Default-Release "stable";
```

してから

```shell
apt-get update
apt-get -t experimental nvidia-driver
```

とすると最新版NVIDIA製ドライバが簡単にインストールされます。

なおUbuntuの場合[UbuntuグラフィックドライバーPPA](https://launchpad.net/~graphics-drivers/+archive/ubuntu/ppa) の手順に従えば簡単です。

**絶対にNVIDIAのウェブサイトからダウンロードしたものをDebian/Ubuntuに入れてはいけません**
[C#]正規表現で、ルールに一致した文字列かどうか調べる／一致した文字列を抜き出す

# やりたいこと
特定のルールに合致した文字列であるかどうかを確認したい。
また、ルールに合致した文字列を抜き出したい。

# やり方
[Regexクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.text.regularexpressions.regex?view=netframework-4.8)を使う。

# サンプルコード

```cs
using System;
using System.Text.RegularExpressions;

namespace ConsoleApp5
{
    class Program
    {
        static void Main(string[] args)
        {
            string org = "1dg4-fasd-kf5g-fsaa";

            // ①4桁の英数字を-でつなげたものかどうかを判定
            if (Regex.IsMatch(org, @"^[\da-zA-Z]{4}-[\da-zA-Z]{4}-[\da-zA-Z]{4}-[\da-zA-Z]{4}\z"))
            {
                Console.WriteLine("マッチしました！");
            }

            // ②4桁英数字にマッチしたものを探す
            var match = Regex.Match(org, @"[\da-zA-Z]{4}");
            Console.WriteLine("1個だけ探す：" + match.Value);

            // ③4桁英数字にマッチしたものを全部探す
            var matches = Regex.Matches(org, @"[\da-zA-Z]{4}");
            foreach (Match m in matches)
            {
                Console.WriteLine("全部探す：" + m.Value);
            }
        }
    }
}

```
こうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/15b2c1fb-62f3-9af4-3b58-943ee8e61355.png)

# 参照
.NET の正規表現
https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expressions

【C#入門】正規表現の使い方総まとめ(Match/Matches/Replace)
https://www.sejuku.net/blog/54508

【C#】正規表現の使い方
https://qiita.com/github129/items/5a2cd4d36abdf4ebe870

サルにもわかる正規表現
https://www.mnet.ne.jp/~nakama/
辞書型データのvalueの直積を返したい

#やりたいこと
pythonで、辞書が持つvalue同士の直積を、対応するkeyを変えずに辞書としてそれぞれ出力したい。

具体的には

```python
{'A':[1,2,3], 'B':[4,5]}
```

という辞書が存在するときに

```python
[{'A':1, 'B':4}, {'A':1, 'B':5},
 {'A':2, 'B':4}, {'A':2, 'B':5},
 {'A':3, 'B':4}, {'A':3, 'B':5}]
```

といった具合のリストが得られるようにしたい。

#前提知識
itertools.product()で直積を求められます。

> https://docs.python.org/ja/3/library/itertools.html#itertools.product

#実装
```python:test1.py
import itertools

test1 = {'A': [1, 2, 3], 'B': [4, 5]}

product = [x for x in itertools.product(*test1.values())]
result = [dict(zip(test1.keys(), r)) for r in product]
for r in result:
    print(r)
```

```console:console
{'A': 1, 'B': 4}
{'A': 1, 'B': 5}
{'A': 2, 'B': 4}
{'A': 2, 'B': 5}
{'A': 3, 'B': 4}
{'A': 3, 'B': 5}
```

valueの型が異なっていてもOK

```python:test2.py
import itertools

test2 = {'A': ['TEST', 1, 2.5], 'B': [[3, 4], 5]}

product = [x for x in itertools.product(*test2.values())]
result = [dict(zip(test1.keys(), r)) for r in product]
for r in result:
    print(r)
```

```console:console
{'A': 'TEST', 'B': [3, 4]}
{'A': 'TEST', 'B': 5}
{'A': 1, 'B': [3, 4]}
{'A': 1, 'B': 5}
{'A': 2.5, 'B': [3, 4]}
{'A': 2.5, 'B': 5}
```

# 注意点

直積を求めたい辞書のvalueはlist型でなければなりません。
例えば以下の様な辞書を変換しようとするとエラーとなります。

```python:test3.py
import itertools

test3 = {'A': 1, 'B': [2, 3], 'C': [4, 5, 6]}

product = [x for x in itertools.product(*test3.values())]
result = [dict(zip(test1.keys(), r)) for r in product]
for r in result:
    print(r)
```

```console:console
Traceback (most recent call last):
  File "test3.py", line 5, in <module>
    product = [x for x in itertools.product(*test1.values())]
TypeError: 'int' object is not iterable
```

この様な場合は一旦valueを舐めてlistでなければlistに変換してあげれば良いです。

```python:test4.py
import itertools

test4 = {'A': 1, 'B': [2, 3], 'C': [4, 5, 6]}

test4_after = dict([(key, val if type(val) is list else [val]) for key, val in test4.items()])

product = [x for x in itertools.product(*test4_after.values())]
result = [dict(zip(test4_after.keys(), r)) for r in product]
for r in result:
    print(r)
```

```console:console
{'A': 1, 'B': 2, 'C': 4}
{'A': 1, 'B': 2, 'C': 5}
{'A': 1, 'B': 2, 'C': 6}
{'A': 1, 'B': 3, 'C': 4}
{'A': 1, 'B': 3, 'C': 5}
{'A': 1, 'B': 3, 'C': 6}
```

# key値を捨てる場合
key値を捨ててvalueの直積だけ欲しい場合はzipの部分を消せばOK。

```python:test5.py
import itertools

test5 = {'A': [1, 2], 'B': [4, 5, 6]}

product = [x for x in itertools.product(*test5.values())]
for r in product:
    print(r)
```

```console:console
(1, 4)
(1, 5)
(1, 6)
(2, 4)
(2, 5)
(2, 6)
```
CloudFormationでDynamoDB streamを設定する

前回の投稿[【初心者向け】CFnでAPI Gateway＋LambdaなAPI作成をまとめてみた](https://qiita.com/hk41/items/c5c0ca61658d4c8949c2)
に引き続きCloudFormationネタです

CFnでDynamoDB stream trigger eventを設定します

環境は

```
dev% aws --version                                                                            
aws-cli/1.16.180 Python/3.7.3 Darwin/18.2.0 botocore/1.12.170

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
```

ストリームを設定するlambda

```ruby:template.yaml
  HogeFunction:
    Type: AWS::Serverless::Function
    Properties:
      Timeout: 10
      CodeUri: xxxxxxxxxx
      Handler: app.lambdaHandler
      Runtime: nodejs10.x
      Role: !GetAtt LambdaRole.Arn
      Events:
        Stream:
          Type: DynamoDB
          Properties:
            Stream: !GetAtt DataTable.StreamArn
            BatchSize: 100
            StartingPosition: LATEST
  LambdaRole:
   Type: AWS::IAM::Role
   Properties:
     AssumeRolePolicyDocument:
       Version: '2012-10-17'
       Statement:
       - Effect: Allow
         Principal:
           Service:
           - lambda.amazonaws.com
         Action:
         - sts:AssumeRole
     Path: "/"
     Policies:
       - PolicyDocument:
         Version: '2012-10-17'
         Statement:
         - Effect: Allow
           Action:
           - dynamodb:DescribeStream
           - dynamodb:GetShardIterator
           - dynamodb:GetRecords
           - dynamodb:ListStreams
           Resource: "*"      
         - Effect:
           Action:
           - logs:CreateLogGroup
           - logs:CreateLogStream
           - logs:PutLogEvents       
           Resource: arn:aws:logs:*:*:*       
```

これでcloudformationコマンドを実行するだけ。素敵
LeafletとFlaskでシンプルなWebGISをつくった話


![1hz9g-wru3l.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/4d5d0966-0875-6ce6-941b-d681b99a0666.gif)

## はじめに
オープンソースのGISにはQGISというド定番・大正義が存在しますが、インストールの手間、投影法など、若干敷居が高いです（初心者にとって）。ウェブ上で公開されている多数のオープンGISデータ（国土数値情報など）の内容をすぐに確認出来る、シンプルなWebGISがあれば便利なんじゃないかと思い開発したのがVanillaGISです。

## VanillaGIS
[Vanilla GIS](https://vanilla-gis.herokuapp.com/)
[GitHub - Kanahiro/vanilla-gis](https://github.com/Kanahiro/vanilla-gis)

##使用例（北海道のバス・鉄道路線図）
![スクリーンショット 2019-06-23 16.52.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/f6e10d5d-0a64-2f74-90a3-2ea945adce4e.png)


## 技術概要
###主な使用ライブラリ


- Leaflet(JavaScript)
- Flask(Python)

###フロントエンド
Leafletと以下の外部プラグインを使用しています。

- Leaflet.Control.Custom
- Leaflet.Control.Draw
- Leaflet.Control.Appearance（自作プラグイン）

###バックエンド
- Flask
- SQLite
- SQLAlchemy

##技術詳細
###バックエンド（Flask）
前提としてRESTful APIを意識し、URLはリソースを参照する形式になっています。

#### /（ルート）
- GET

地図画面の表示。

- POST

外部ファイル（.zip（シェープファイル）, .geojson）を投げるとjsonデータを返します。
.zipファイルの中身はシェープファイル（.shp, .shx, dbf）である必要があります。
pyshpモジュールを利用し、内部的にjsonに変換しています（LeafletはGeoJSONを読み込めるため）。
オープンデータで提供されるシェープファイルの多くはShift-JISエンコーディングですが、UTF-8やその他のエンコードである場合も踏まえ、通常利用されるすべてのエンコードに対応させています。Pythonでデコードする際、エンコードが相違しているとUnicode Errorが発生します。事前に主要なエンコードをリストにしておき、デコードでエラーが発生しなくなるまで各エンコードを順番にトライします（以下の記事で紹介しています）。


[シェープファイルをGeoJSON形式に変換する - Qiita](https://qiita.com/kigchi999/items/816611dc7ceccbd11d05)


#### /user_map/<map_id>

- GET 

ユーザーが作成し保存したカスタムマップの、レイヤーデータ以外を返します。

- PUT

ユーザーが作成し保存したカスタムマップの、レイヤーデータを返します。
GETで返すと、レイヤーデータが読み込むまでページ全体の読み込みが完了しないため、GETとはレスポンスを分離しています。Fetchにより非同期でレスポンスを取得します。

- POST

ユーザーが作成したカスタムマップをDBに保存します（公開されているアプリでは実装していません）。

#### /export
これだけnot RESTfulです。

- POST

ユーザーが作成し保存したレイヤーを投げるとjsonデータが返ってきます。
フロントでは、返ってきたデータを.geojsonとしてダウンロードさせます。

[FlaskとJavaScriptのFetch通信でダウンロードさせる方法 - Qiita](https://qiita.com/kigchi999/items/ae89393fa649d0b1acd8)

### フロントエンド
シングルページアプリケーションで、常にindex.htmlが表示されます。
/user_map/<map_id>では、index.htmlにDBから取得したデータを渡しています。
Leafletと外部プラグイン（各種Control）を組み合わせる事でGUIを実装しています。

####使用しているControl

- L.control.scale

純正プラグイン。地図の縮尺を表示。

- L.control.custom

外部プラグイン。htmlを記述する事でかなり自由にGUIを作成可能。

- L.control.draw

外部プラグイン。手書き図形の作図機能。

- L.control.Appearance

自作プラグイン。純正のL.control.layerと、外部プラグインのL.control.Opacityを参考に作成。
ベースマップ切り替え、オーバーレイのオンオフ、レイヤーごとの透過度設定、オーバーレイごとの色設定、オーバーレイの削除。
各レイヤーをひとつのプラグインで管理したくて作成（Chromeで動作確認済み）。
※レイヤーのプロパティにcolorを設定しないと、色設定機能は動作しないなど、まだ未完成です。


[GitHub - Kanahiro/Leaflet.Control.Appearance](https://github.com/Kanahiro/Leaflet.Control.Appearance)



####外部ファイル読み込み
ウィンドウにドラッグドロップする事で、ファイルを読み込みます。
対応している形式は.zip（.shp, .shx, .dbfのアーカイブ）か.geojsonです。
すべてFetchでサーバーに投げて、返ってきた.jsonをLeafletマップに追加します。
Django migration ざっくり基礎知識

# 基礎知識箇条書き
詳しくは[こちら](http://note.crohaco.net/2018/django-migration/)参照


## DjangoとMySQLの連携
最低限の連携手順
### Django
DB接続設定

```settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '', # 接続先DB
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
    }
}
```

### MySQL
version.8
1. 接続用ユーザー作成
どこからでもアクセス可能。

```
create user 'user' identified by 'user';
grant all privileges on django.* to 'user';
```

## マイグレーションClass
マイグレーションファイルにはMigrationClassが必要

- initial 最初のマイグレーション指定
- replaces 置き換え対象マイグレーションを指定
- dependencies 依存マイグレーション指定
- atomic ロールバック指定
- operations 操作方法指定
 
## 履歴
django_migrationsテーブルで管理されている。
適用の可否は、このテーブルの状態で判断されている。

## 依存関係
適用順序を守るのは絶対。
シーケンスは必ずしも適用順ではない。
依存パターンは、以下ふたつ
- アプリの依存
- 外部アプリ依存
依存先が欠けていると、正しく動作しない。
常にマイグレーションを使用する事が必須条件。

## 適用方法
順序としては２つ。

- 照準適用
- 降順適用
 - Operationに操作方法が定義されている必要がある
 - 緊急処置で使用するべき方法であり、常用してはいけない

# 使い方
コマンド

## マイグレーションファイル作成
*makemigration*

自動生成時は、既存マイグレーションとモデルの構造の差分で、マイグレーションが生成される。

- app_label引数でアプリ名を指定
- アプリ名省略時には、INSTALLED_APPS に登録されているアプリの差分に対して作成される
  - 初回でアプリ名を指定しないとマイグレーションが作られない


## マイグレーションファイル適用

*migrate*

引数はapp_labelと、migration_nameがあるが、省略可能

- 省略時は未適用マイグレーションが全て適用される
- app_labelのみ指定時は、アプリ内のマイグレーションのみ適用
- app_label、migration_name指定時は、アプリのマイグレーションまで適用される
 - 指定マイグレーションによって適用順が変わってしまうので注意
- 擬似的にマイグレーション適用済みにするオプションがある
 - 移行用オプションとしての利用
 - 扱いには注意する。テーブルが正しく作成されない場合がある。

## 適用、未適用状態の表示
*showmigrations*
マイグレーションファイルと、テーブルの突き合わせ情報の表示。

## マイグレーションの統合
*squashmigrations*

マイグレーションファイルを統合するコマンド。
AWS S3バケット名からCloufFrontのキャッシュをクリア(CreateInvalidation)するAPIをコールする

# はじめに
以前、[CloudFrontの配信元のファイル(S3)が更新されたら自動的にキャッシュをクリアする仕組みを作る](https://qiita.com/Shi-nakaya/items/e6ac79dd35506d4c9fbc)という記事を作成しました。

その対応の中で「CloufFrontのキャッシュをクリア(CreateInvalidation)するAPIをコールするLambdaFunction」が必要です。

当記事では具体的な実装方法を紹介します。

# 実装の概要
1. 配信元となるS3バケット名からCloudFrontのIDを取得する
2. CloudFrontのIDをキーにしてCloufFrontのキャッシュをクリア(CreateInvalidation)する

CloudFrontのIDはAWSのマネコンから確認できるので
「配信元となるS3バケット名からCloudFrontのIDを取得する」の処理はマストではありません。
しかし、バケット名からCloufFrontのキャッシュをクリアできた方が汎用性が高くなる為、CloudFrontの一覧を取得し、バケット名からCloudFrontのIDを取得する処理も実装します。

# 実装
```go:CreateInvalidation.go
	//cloudfrontのクライアントを作成
	svc := cloudfront.New(session.New())

	//cloudfrontの一覧の情報を取得する為のインプットを作成
	ListDistributionsInput := &cloudfront.ListDistributionsInput{}

	//cloudfrontの一覧の情報を取得
	ListDistributions, _ := svc.ListDistributions(ListDistributionsInput)

	S3Domain := "s3.amazonaws.com"
	S3Buket := "cloudfrontの配信元のバケット名" + "." + S3Domain

	for _, DLItems := range ListDistributions.DistributionList.Items {
		for _, OriginsItems := range DLItems.Origins.Items {
			//cloudfrontの一覧からcloudfrontの配信元のバケット名の一致を判定
			if S3Buket == *OriginsItems.DomainName {
				//キャッシュ削除(CreateInvalidation)コール用のIDを取得
				callerReference := time.Now().Format("200601021504")

				//cloudfrontのキャッシュを削除するパスを指定
				Path := "/*"
				PathItems := []*string{&Path}

				//キャッシュ削除用(CreateInvalidation)のクライアントを作成
				CreateInvalidationInput := &cloudfront.CreateInvalidationInput{
					DistributionId: aws.String(*DLItems.Id),
					InvalidationBatch: &cloudfront.InvalidationBatch{
						CallerReference: &callerReference,
						Paths: &cloudfront.Paths{
							Quantity: aws.Int64(1),
							Items:    PathItems,
						},
					},
				}
				//キャッシュ削除(CreateInvalidation)を実行
				result, _ := svc.CreateInvalidation(CreateInvalidationInput)
			}
		}
	}
```

# 終わりに
目的のバケット名がcloudfront一覧の奥の方の構造体に入り込んでいた為、
取得するのに2重にループする必要があり、思ったより面倒でした。
改良の余地としては、cloudfrontのキャッシュを削除するパスが指定可能である為、オブジェクト名で検索をかけて対象のオブジェクトだけキャッシュクリアする方法もありますね。
追加のオブジェクトはキャッシュクリアの必要はない為、更新されたオブジェクトだけクリアしてあげてもいいですね。
[C#]StopWatchで処理にかかる時間を測る

# やりたいこと
時間がかかってそうな処理があるときに、その処理にどれくらいの時間がかかっているかを調べたい。

# やり方
Stopwatchクラスを使う。

# サンプルコード
測りたい処理を挟んで、Stopwatchをスタート～ストップして、時間を測る。

```cs
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp5
{
    class Program
    {
        static void Main(string[] args)
        {
            // ストップウォッチを作成
            Stopwatch sw = new Stopwatch();

            // ストップウォッチをスタート
            sw.Restart();

            // 測りたい処理
            Thread.Sleep(5000);

            // ストップウォッチを止める
            sw.Stop();

            // 経過時間をsw.Elapsed や sw.ElapsedMilliseconds で取得
            Debug.WriteLine(" 経過時間：" + sw.ElapsedMilliseconds + " ms");
        }
    }
}
```

# メモ
個人的に、スタートするときはRestart()を使う。
Start() → Stop() → Start() → Stop()とすると、一回目の時間をそのまま引き継いでしまうので、それに気づかないと間違った計測結果を採ってしまうので。


# 参考
Stopwatch Class 
https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.stopwatch?view=netframework-4.8
Karte 接客サービスの実装での注意点

Karteの接客サービスを利用するAppの実装で困った事象について、同じ問題で悩む方に参考にして欲しいので、メモして置きます。

開発用のKarteとリリース用のKarte接客サービスで送信されるPush通知のPayloadのキー値が異なる件。　例え、今度の"gcm.notification.url”キー

上記事象について、Karteのサポーターに質問したよると
KARTEから接続可能な FCM（Firebase Cloud Messaging
） API は、Legacy API と V1 API の 2種類ございますが、それぞれ Legacy APIかV1 APIの設定により、送信されるキーの設定が異なる模様です。
特にV1 API では ”gcm.notification.url”キーは付与されない仕様となっていますね。

最初はPush通知のPayloadから接客サービスのDeepLinkのURLを解析するように実装したが、Karteサポーターはペイロード仕様が変わる可能性が存在する為、なるべくKarteのスキーマURLの取得メソッドを利用して接客サービスのDeepLink　URLを取得するように推奨していましたので、注意が必要だと思われます。

因みに、Karteから案内する仕様のリンクを貼って置きますので、ご参照ください。
【iOS】
https://developers.karte.io/reference#retrieveurlfromuserinfouserinfo

【Android】
https://developers.karte.io/reference#extractkarteattributescontext-context-remotemessage-message
https://developers.karte.io/reference#getlink
Leaflet.jsのパフォーマンス改善について

##はじめに
Leafletは実装が簡単でカスタマイズ性も高く、非常に使いやすいWeb地図ライブラリですが、デフォルトの設定だと、多数の地物で構成されるベクターレイヤーの描画に、パフォーマンス上の問題がありました。要はポリゴンが多くなると途端に動作が重くなります。色々調べたところ、ある程度改善したのでその方法を示します。

##オプションをいじるだけ
https://stackoverflow.com/questions/23745436/leaflet-js-with-a-vector-layer-is-very-slow
たどり着いたのがこのStackoverflowのスレッド。マップのpreferCanvasオプションを変えてみろ、と言っています。

##実装
https://leafletjs.com/reference-1.5.0.html#global
公式ドキュメントによれば、preferCanvasオプションにより、SVGレンダラーかCanvasレンダラーか、どちらで地物を描画するか設定可能とのこと。デフォルト値はfalseで、SVGレンダラーに設定されている。一般にどっちが重いか軽いか、わかりませんがとりあえず試してみるとかなり改善しました。つまりCanvasによるレンダリングの方が軽いということですね。

```javascript
var map = L.map('map_container',{
	preferCanvas:true, //trueとし、Canvasレンダラーを選択
});
```
FlaskとJavaScriptのFetch通信でダウンロードさせる方法

##はじめに
Flaskのレスポンスによってファイルをダウンロードさせる方法は以下のリンクのとおり3つあるようです。
https://qiita.com/5zm/items/760000cf63b176be544c

しかしながら、Fetch通信によるPOSTに対するresponseにはこれらの方法だけでは対応出来ませんでした。解決した方法を以下に載せておきます。

##前提
①Fetch通信で、Flaskサーバに対しPOSTリクエスト
②Flaskサーバでデータを処理し、ファイルを生成、responseヘッダに添付
③Fetchでresponseを受け取って、ダウンロードしたい

③で引っかかっていました。単なるinputによるPOSTとは勝手が違うようで、responseはメモリ上で受けるだけです。

##解決方法
```javascript
    fetch("/export", {
        method:"POST",
        body:formdata //データを添付
    })
    .then(response => response.blob()) //blobで読み込む
    .then(blob => {
        //DOMでダウンロードファイルを添付したアンカー要素を生成
        let anchor = document.createElement("a");
        anchor.download = String(Date.now()) + '.geojson'
        anchor.href = window.URL.createObjectURL(blob);
        //アンカーを発火
        anchor.click();
    })
    .catch(function(err) {
        console.log("err=" + err);
    });
```

要はresponseをblobで読み込んでアンカーリンクを踏ませた事にするというわけですね。
シェープファイルをGeoJSON形式に変換する

##前提
zip圧縮されたシェープファイル群（.shp, .shx, .dbf）を、GeoJson形式で出力する関数です。
当然、シェープファイル群のファイル名が共通している必要があります。
また、.geojsonファイルを出力するのではなく、メモリ上で処理します。
事前にpyshp(shapefile)が必要になります。

##コード

```python
import shapefile, io, zipfile

#zipファイルからshpファイルを探してファイル名を取得
def find_shpfile_inzip(zipped_shp):
	zip_infolist = zipped_shp.infolist()
	for info in zip_infolist:
		if not info.filename.startswith('__MACOSX/'): #Mac-ZIP対応
			if info.filename.endswith('.shp'):
				return info.filename
```

まずこのように、zip圧縮されたshapefileのファイル名を取得する関数を定義します。
この関数を用いて

```python
#ZIP保存されたSHP群をGEOJSON形式で返す
def zipped_shp_to_geojson(zipped_shp):
	zipped_files = zipfile.ZipFile(zipped_shp)

	#zipファイルからshpファイルを探してファイル名を取得
	shp_name = find_shpfile_inzip(zipped_files)[:-4]

	#shapefile読み込みと適合判定
	try:
		shp_file_bytes = zipped_files.read(shp_name + '.shp')
		shx_file_bytes = zipped_files.read(shp_name + '.shx')
		dbf_file_bytes = zipped_files.read(shp_name + '.dbf')
	except:
		print("Imported file was not apropriate Shape-Zip-File.")
		return None

	geojson = dict(type="FeatureCollection", features=[])
	#pyshpはライブラリ内部でデコードするので、正しいエンコーディングでデコード出来るまでループ
	for codec in CODECS:
		try:
			reader = shapefile.Reader(shp=io.BytesIO(shp_file_bytes),
					                    shx=io.BytesIO(shx_file_bytes),
					                    dbf=io.BytesIO(dbf_file_bytes),encoding=codec)

			fields = reader.fields[1:]
			field_names = [field[0] for field in fields]
			for sr in reader.shapeRecords():
				atr = dict(zip(field_names, sr.record))
				geom = sr.shape.__geo_interface__
				geojson['features'].append(dict(type="Feature", \
				 geometry=geom, properties=atr))
			print(codec + 'encoding is correct.' )
			break
		except UnicodeDecodeError:
			print(codec + 'is not suitable for this file.')
			continue
	return geojson
```

これでgeojsonに変換されます。
エンコーディングについてはコメントのとおりです。pyshpではデフォルトだとUTF-8でデコードされますが、オープンデータで提供されるシェープファイルは、大半がcp932（Windows環境のShift-JIS）です。エンコーディングの指定が間違っているとUnicode errorが発生します。それならcp932を指定してデコードすれば良いのでは、と考えますが、当然ながらUTF-8等にも対応しておきたいところです。したがって、メジャーなエンコーディングのなかから適合するまでデコードし続けるようになっています（このモジュールの冒頭で、CODECS定数を定義してある）。
electronメモ

# electronメモ

# electronでHello Worldアプリ作成

```sh
$ npm i electron -g
$ npm i electron-packager -g
```

```
$ vi main.js
```

```js
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;
app.on('ready', () => {
  // mainWindowを作成（windowの大きさや、Kioskモードにするかどうかなどもここで定義できる）
  mainWindow = new BrowserWindow({width: 400, height: 300});
  // Electronに表示するhtmlを絶対パスで指定（相対パスだと動かない）
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  // ChromiumのDevツールを開く
  mainWindow.webContents.openDevTools();

  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});
```

```sh
$ vi index.html
```

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    Hello World!
  </body>
</html>
```


## Mac用に実行ファイルを生成

```sh
$ electron -v
v5.0.6
```

```sh
$ electron-packager . electron-sample --platform=darwin --arch=x64 --electron-version=5.0.6 
```

これでelectron-sample.appというアプリケーションが作成されます。


# 参考
https://qiita.com/umamichi/items/6ce4f46c1458e89c4cfc
python3でtimestampをhash化した日

#Timestampをsha256でhash化

###まず下準備
```下準備
from datetime import datetime,date
import time
import hashlib
```

###encodeできるように型を変える&&取り出したい形に整える。

```
t_today = datetime.now()
s_today = t_today.strftime('%Y/%m/%d %H:%M*%S')
```

###sha256でhash化
```
crypto = hashlib.sha256(s_today.encode('utf-8')).hexdigest()
```

###SUCCESS !




---------------------------------------------------------
###参考
https://docs.python.org/ja/3.8/library/datetime.html
https://pg-chain.com/python-hash-hashlib
https://note.nkmk.me/python-datetime-usage/
[Swift][iOS]TableViewのセル再利用の罠

##はじめに
iOSアプリでGUIを作る際にはTableviewを使うことが非常に多いと思います。
このTableview、デフォルトだとセルのクラスはUITableViewCellで、表示出来るUIが事前に定められています（テキスト、サブテキスト等）。
たとえば画像を表示したかったり、ボタンを表示したかったり、実装したいUIによってはデフォルトのクラスを継承したカスタムクラスを作ってやる必要があります。
そんな際にバグってしまったセルの取扱いについてまとめておきます。

##バグった実装
例によってカスタムクラスをつくって、内部にはUITextFieldを設置して、ユーザーの入力を受け付けるようにすると、以下のようなバグが発生しました。
①1行目のセルのTextfieldに文字列を入力すると
![IMG_2413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/8897376a-09b8-fba0-7105-835955372a5e.png)
②下にスクロールすると7行目くらいのセルに文字列が入力されてしまっている
![IMG_2414.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/38d67a60-10b9-7e51-2ecb-7657eac32152.png)

##バグの内容
実装したUIはセルの数が一定ではなく、ユーザーの入力によりセルが増減するものになります（初期状態はセルはひとつ）。セルを増やした際、1番目のセルに文字列を入力すると、それが「画面外の7番目くらいの別のセルにも反映されてしまう」バグに遭遇しました。

##原因
ぐぐったら以下のQiitaの記事に辿りつきました。

UITableViewのあるセルに設定した値が、他のセルにも反映されてしまう
https://qiita.com/shikatani/items/88dff6ecf9684027862e

要は画面外にあるセルは内部的には描写されておらず、必要に応じて描写されるようになっているようです。
画面外から画面内に入ってくるセルは、画面内から画面外に出ていくセルを再利用しているのです。

##対策
セルに登載されるデータはcellForRowAtで指定する訳ですが、事前にデータが固定されていないと実装が複雑になる感があります。今回の件は動的に登載されるべきデータが変更されることから、単純な実装ではうまくいかなかった訳です。上記のQiita記事では、バグは発生しているものの登載されるべきデータは静的に事前に指定されているので、セルを初期化すれば解決しています（∵画像の読み込み先URLは事前に決定されているから）。しかしながら本件のようなユーザーの入力にデータが依存するケースだと、入力されるデータを逐次保存しておかないと対応出来ないと思います。すなわち、予めセルに登載するデータ（=配列）を指定しておき、その配列の中身が更新される、という実装が必要になるかと。

##終わりに
具体的な解決策は提示出来てませんが、Tableviewのセルに登載するデータは事前に指定してあげないと予期せぬ動作をするという事と、ググれば何でも出てくるという事を伝えたかった。
Railsにおける新規アプリ作成手順まとめ

#はじめに
この記事のRailsのバージョンは5.2.2.1です。
自分の備忘録としてメモします。

今回は「memo-app」というアプリを作成する想定で書きます。

##具体的な手順

<b>新規アプリ作成コマンド</b>

```terminal:terminal
$ rails new アプリケーション名
  # アプリケーションを新規作成

  $ rails new アプリケーション名 -オプション名
  # オプションを付けてアプリケーションを作成
```


この新規ファイル全体の事を
Railsアプリという。

<b>新規アプリ作成コマンドの具体例</b>

```terminal:terminal
$ cd ~/projects
  # projectsディレクトリに移動
  $ rails _5.2.2.1_ new memo-app -d mysql
  # 「memoapp」を「mysql」オプションで作成。バージョンを5.2.2.1で作成。

  $ cd memo-app
  # 「memo-app」ディレクトリに移動

  $ pwd
  # 現在のディレクトリのパスを表示
```

続いてデータベースの作成を行う。

<b>データベース作成コマンド</b>

```terminal:terminal
$ rake db:create
#database.ymlというファイルに基づいて作成される
```

続いてルーティングの設定を行います（ルーティングに関するファイルはrails newコマンドですでに作成されている）

<b>ルーティング設定の具体例</b>

```ruby:routes.rb
Rails.application.routes.draw do
    get 'memo' => 'memos#index'
  end
```

続いてコントローラーの作成を行います。

<b>コントローラー作成コマンド</b>

```terminal:terminal
$ rails g controller コントローラ名
# コントローラを作成
```

<b>コントローラー作成コマンドの具体例</b>

```terminal:terminal
$ rails g controller memos
# memosコントローラを作成
```

<b>コントローラーファイル設定</b>

```ruby:memos_controller.rb
class MemosController < ApplicationController

    def index
    end

  end

#indexアクションを定義
```

後はビューファイルの作成を行います。
今回はindex.html.erbというファイル名で作成します。
この際拡張子がerbになっている事に注意。（rubyを埋め込めるHTMLだと思っておけばOK）

<b>モデルの作成</b>

```terminal:terminal
$ rails g model memo
  #  Memoモデルを作成→モデルクラス名(全て小文字)
```

この後にマイグレーションファイルで作成するカラムの設定などを行う。

<b>マイグレーションファイルの作成</b>

```terminal:terminal
$ rake db:migrate
# マイグレーションファイルの実行
```

DB上にmemosテーブルが作成される。

あとはrails sコマンドでサーバーを立ち上げればアプリとしての最低限のモノが。
各人カスタマイズして良いアプリを創っていきましょう。
Java 配列

##学習ログ

###配列
配列とは同一種類の複数データを並び順で格納するデータ構造。
配列の各要素には同一種類のデータしか格納できない。
配列の要素は0から始まる。
配列も変数と同様にデータ型を指定する。

```java:
配列変数の作成（宣言）
要素の型[] 配列変数名

//例
int[] score;         //scoreをint型の配列変数として宣言。
score = new int[5];  //配列変数scoreにnew演算子で生成したint型の要素を5つ代入している。

//配列変数の宣言と要素の作成と代入は同時に行うことも可能
int[] score = new int[5];  

//配列の中の要素を取り出す方法
score[0]; //配列変数scoreの中の１番目の要素を取得

//配列内の要素を変更する
score[0] = 50; //配列変数scoreの中の1番目の要素に30という値を代入することができる

//配列の要素数の取得
score.length; //配列変数にlengthというメソッドを使用すると配列内の要素の数を取得できる。
//lengthメソッドは文字列にも使用できる。String型変数名.length()という形になる。

//配列の省略記法
int[] score1 = new int[] {10, 20, 30, 40, 50};
int[] score2 = {10, 20, 30, 40, 50};
```

####配列をforループで回す

```java:
//従来のfor文
for(int i = 0; i < 配列変数名.length; i++) {
  処理..
}
//従来のfor文 例
public class Main {
  public static void main(String[] args) {
    int[] score = {20, 30, 40, 50, 60};
    for(int i = 0; i < score.length; i++) {
      System.out.println(score[i]);
    }
  }
}

//拡張for文
for(要素の型 任意の変数名:配列変数名) {
  処理..
}
//拡張for文 例
public class Main {
  public static void main(String[] args) {
    int[] score = {20, 30, 40, 50, 60};
    for(int value : score) {
      System.out.println(value);
    }
  }
}
```
####メモリ変数と配列
コンピュータは使用するデータをメモリに記録する。
メモリの中は碁盤の目のように区画整理されており、各区画には住所(アドレス)が振られている。
そして変数を宣言すると、空いている区画(どこが選ばれるかはわからない)を変数のために確保する(変数の型によって何区画を使用するか異なる)。
変数に値を代入するとは、確保していた区画に値を記録することである。

```java:
public class Main {
  public static void main{String[] args) {
    int[] a = {1, 2, 3};
    int[] b = b;
    b = a;
    b[0] = 100;
    System.out.println(a[0]); //100と出力される
  }
}
```
####ガベージコレクション
javaの仕組みの一つ。
実行中のプログラムが生み出したメモリ上のゴミ(＝どの変数からも参照されなくなったメモリ領域)を自動的に探し出して片付けてくれる。

####NULL
「何もない」という意味。
nullが代入されると、参照型の変数はどこも参照していない状態になる。
・int[]型などの参照型変数に代入すると、その変数は何も参照しなくなる。
・int型などの基本型変数には代入することができない。

```java:
int[] score = {1,2,3}
score = null;
score[0];
```
####2次元配列
2次元配列とは要素が縦横に並んでいるイメージ。

|[0][0]|[0][1]|[0][2]|[0][3]|
|:---|:---|:---|:---|
|[1][0]|[1][1]|[1][2]|[1][3]|
|[2][0]|[2][1]|[2][2]|[2][3]|

```java:
//２次元配列の宣言
要素の型[][] 配列変数名 = new 要素の型[行数][列数]

//２次元配列の要素の取得
配列変数名[行の添字][列の添字]
//例
int[][] scores = new int[2][3]; //2行3列の配列
scores[0][0] = 40;
scores[0][1] = 50;
scores[0][2] = 60;
scores[1][0] = 70;
scores[1][1] = 80;
scores[1][2] = 90;
System.out.println(scores[1][1]); //８0
```
SQLでテーブルコピー(Postgresql)

# 概要

SQLのみで既存のテーブルと(<b>ほぼほぼ</b>)同構造・同データのテーブルを新しく作成する手順になります。

# 環境

```
psql --version
psql (PostgreSQL) 9.5.14
```

# ちょっとハマった件

CREATE TABLE ~ AS では完全なテーブル複製はおこなわれません。

```
CREATE TABLE #{new_table_name} AS SELECT * FROM #{origin_table_name}
```

上記SQLはフィールドの型やデータを複製したテーブルを簡単に作成できるのですが、型制約やプライマリキー・インデックスなどの定義までは複製することができません。

# 手順

## 1. CREATE TABLE + LIKEを使ってテーブル構造をコピー

```
CREATE TABLE #{new_table_name} (LIKE #{origin_table_name} INCLUDING ALL)
```

上記SQLを実行するとコピー元テーブルで定義されていたプライマリキーやインデックスキーも新しいテーブルに複製されます。

複製するにあたって論理名は新しいテーブルの名称を元に

プライマリキーは[new_table_name]\_pkey
インデックスキーは[new_table_name]\_[column_name]_idx

といった具合に自動的に命名されていました。


## 2. INSERTを使ってデータをコピー

```
INSERT INTO #{new_table_name} SELECT * FROM #{origin_table_name}
```

## 3. シーケンスオブジェクトを作成する

「CREATE TABLE + LIKE」では、シーケンス番号に関する設定はコピー元のテーブル設定がそのまま反映されるため、それぞれのテーブルでデータを登録していくと一方のテーブルに反映される値が飛び番になってしまいます。
よって、必要に応じて新しいテーブル用にシーケンス番号を新規作成し関連付けする必要があります。

まずはシーケンスオブジェクトを作成しましょう。

```
CREATE SEQUENCE #{new_table_name}_#{colmn_name}_seq start SELECT COUNT(*) FROM #{new_table_name};
```

## 4. シーケンス番号をカラムのデフォルト値に関連づける

```
alter table #{new_table_name} alter #{colmn_name} set default nextval('#{sequence_object_name}');
```

## 5. テーブル制御と連動するように変更を加える

```
alter sequence #{sequence_object_name} owned by #{new_table_name}.#{colmn_name};
```

owned byを定義しておくと、設定列または対象テーブルを削除ときにそのシーケンスオブジェクトも削除されます


## 6. 開始値を設定する

```
select setval('#{sequence_object_name}', [コピーしたデータ数 + 1], false);
```

## 7. シーケンス番号の設定を確認してみる

```
select * from #{sequence_object_name}
```

以上でコピー元とほぼ同構造で同データの新しいテーブルが作成されます。

# 参考資料

[PostgreSQL 9.3.2文書 - CREATE TABLE](https://www.postgresql.jp/document/9.3/html/sql-createtable.html)
[既存のカラムをSerial型へ変更する](https://qiita.com/s0208_wataru/items/3f56bfea05f50d6e80f8)
Pythonでパスワード付きのPDFを、パスワード無しのPDFとして別名保存するスクリプト

##はじめに
パスワード付きのPDFは開くたびにパスワードの入力を求められてストレスが溜まります。そのストレスをぶつけたらスクリプトが出来ましたので紹介します。

##PythonにおけるPDFの扱い
おそらくPythonでPDFを読み書きしようとすると、まずPyPDF2というライブラリを使う事になると思います。しかしながらパスワードロック解除については、限定された条件のPDFにしか対応していないため、C++のライブラリのqpdfなどとの合わせ技にせざるを得ません。

##pikepdf
マイナーなライブラリでpikepdfというものがあり、MPL　ライセンスなのでたぶんライセンス表記しておけば怒られないんだろうと思います。このライブラリはqpdfを内蔵？しているようなので、前述のケースとは違い、ライブラリはpikepdfだけで完結します。
pip install pikepdf　でインストール可能です。

##完成品
https://github.com/Kanahiro/PDFUnlocker
こちらにスクリプトの完成品をアップしてあります。こきたないコードですが許してください。
zipファイルの中身はWindows32bit環境で動作する（であろう）実行ファイル一式です。Pyinstallerで作成しました。ほんとは--onefileで使いたかったんですけど、ライブラリ周りでこけたので諦めました。PDFファイル名を「(パスワードの文字列).pdf」として、.exeにドラッグドロップすると、パスワードが解除されたPDFファイルが「decrypt.pdf」として出力されます。

##おわりに
ライブラリは神、ライブラリを作る人は神の上か!?
ぼくもライブラリかけるようなおとなになりたいと思いました。
Autoprefixer導入時に「-webkit-box-orient」が消える問題への対応

## まえがき

「複数行の枠に対して、長過ぎる文字列の末尾を省略して三点リーダー（…）を表示したい」と思って調べると、おそらく以下の記事で紹介されているような `-webkit-box` を使った方法が出てくるかと思います。

- [【CSS】複数行でも3点リーダーをきかせる](https://qiita.com/yoshida-hi/items/055c36e015f0bf8fe4f6)
- [【複数行にも対応】長過ぎる文字列を省略して末尾を三点リーダー（…）にする方法いろいろ](https://tech.recruit-mp.co.jp/front-end/tips-ellipsis/)


ところが、gulpやwebpackでSCSSをコンパイルしている環境においては少し罠があります。
フロントエンドに詳しくない私は小一時間ほどハマってしまったので、同じような状況で困っている方がいたらと思いメモを残します。

## 「-webkit-box-orient」消える問題

早速私も下記のSCSSをコピペしてきてビルドしてみたのですがどうもうまくいきません。

```scss
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
```

Developer Toolで確認してみたところ、 `-webkit-box-orient: vertical;` が消えているようです。
なぜかというと、プロジェクトに導入していた[Autoprefixer](https://github.com/postcss/autoprefixer)によって削除されてしまっていたのです。

Autoprexierとは、対応したいブラウザとバージョンを指定すると、それぞれの仕様に合わせたベンダープレフィックス(-webkit-、-ms-、-moz-など)を自動的に追加してくれる便利なツールです。
詳細は[こちらの記事](https://qiita.com/tonkotsuboy_com/items/377913c51b1ac00deffe)を読んでいただくと良いかと思います。（というか私もこれを読んで初めて知りました...笑）

そこで、次の3つの対応方法を紹介いたします。

## 対応方法

### ① 一時的にAutoprefixerを無効にする方法

これが一番簡単で手っ取り早い方法です。
SCSS中で直接Autoprefixerを有効・無効を指定します。

```scss
  display: -webkit-box;
  /* autoprefixer: off */
  -webkit-box-orient: vertical;
  /* autoprefixer: on */
  -webkit-line-clamp: 3;
```

ただし、バージョンが8.4以降であれば次のように書く方が良いでしょう。

```scss
  display: -webkit-box;
  /* autoprefixer: ignore next */
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
```

また、SCSSコンパイル時のoutputStyleを `compressed` にしていると、このコメント自体が削除されてしまうので、 `/*! コメント */` としてあげましょう。

- [Sass Document (Comment)](https://sass-lang.com/documentation/syntax/comments)

### ② gulpやwebpack側の設定を変える方法

複数の箇所でこの対応をする必要があった場合には、この方法もありかもしれません。
ただ残念ながら私はどちらにも詳しくないため、解説は他の方にお譲りしたいと思います。

- [gulp-sassのコンパイルがうまくいかないと思ったらautoprefixerが消してた話](https://qiita.com/oratake/items/07c3bdd9761736623c22)

### ③ Autoprefixerのバージョンを上げる方法

なんと、私がこの問題について調べていたちょうど3日前に、[Autoprefixer側がこの問題に対応しました](https://github.com/postcss/autoprefixer/releases/tag/9.6.1)！
コミットログは[こちら](https://github.com/postcss/autoprefixer/commit/69ed8a0d35cd3d8445c1a713f63ccfc32db29bb9)です。
なので、プロジェクトとしてバージョンを上げることができそうであれば、 `9.6.1` 以降にアップデートするのが一番良いでしょうか。

## あとがき

フロントエンド難しい。。。
（皆さんブラウザ対応とかレスポンシブとかライフサイクルとかSEOとかトレンドだとか本当に全部気にしてるの...？~~PRにスクショ貼っただけで満足してるのは私だけ...？~~）
複数出力のnnを学習させたら、効率悪かった。機械学習で商品分類と対象性別判断

# 複数のカテゴライズを一つのnnで行いたい

（複数出力のやり方は、たくさんあるので書きません）

ファッションサーチファンネル（ファッション画像検索エンジン）
https://funnel-service.com
のセラーデータベースを構築するために商品紹介文から売っている服の分類をしている。

男女の判別も行いたいので、複数出力でやってみた。

モデルの構築コードはこんな感じ

```py

cat_inputs = tf.keras.Input(shape=(max_words,))
sentence_inputs = tf.keras.Input(shape=(max_words,))

# 結合

c = tf.keras.layers.concatenate([cat_inputs,sentence_inputs ])

x2 = tf.keras.layers.BatchNormalization()(c)
x2 = tf.keras.layers.Dense(128, activation='relu')(x2)
x2 = tf.keras.layers.BatchNormalization()(x2)
x2 = tf.keras.layers.Dense(128, activation='relu')(x2)
x2 = tf.keras.layers.Dense(3, activation='sigmoid',name="gend")(x2)

x = tf.keras.layers.BatchNormalization()(c)
x = tf.keras.layers.Dense(128, activation='relu')(x)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.Dense(128, activation='relu')(x)
x = tf.keras.layers.Dense(num_classes, activation='sigmoid',name='class')(x)


model = tf.keras.Model(inputs=[cat_inputs,sentence_inputs], outputs=[x,x2])


```



![Figure_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185049/8ce7d3b3-448a-af9a-1cc9-a4df5408a8f8.png)

↑二つのval線（緑と赤）のスイートスポットがずれている。こりゃだめだ。。。別々に学習してみる。


![11Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185049/0f5aabb3-4a83-9a83-c591-104ee66c5092.png)

↑商品分類だけで学習。

![123Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185049/57a50b0a-0205-6ad8-2e32-77c3aaed710b.png)

↑性別分類だけで学習。

# 結果

スイートスポットがとりやすいので別々のモデルとして学習したほうがいい。
他のケースではわからないけど、今回の複数出力は効率が悪いことが分かった。
ページ遷移時の「このサイトを離れますか？」を意地でも表示しない方法

フォームの入力値を編集したときなどに表示される「このサイトを離れますか？」というポップアップを非表示にする方法です。

色々と調べましたが、`Object.defineProperty`の setter で検知して値を上書きすると確実でした。

```js
Object.defineProperty(window, 'onbeforeunload', {
  set(newValue) {
    if (typeof newValue === 'function') window.onbeforeunload = null;
  }
});
```

ちなみに `if (typeof newValue === 'function')` 等のチェックがないと変更を検知し続けて無限ループになり、スタックが大変なことになるで気をつけましょう。

また、もし他に良い方法をご存知の方がいたらコメントで教えてください🙏

## 参考
- [Object\.defineProperty\(\) \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
- [JavaScriptのプロパティの上書きを検知する \- kitak's blog](https://kitak.hatenablog.jp/entry/2015/08/26/221110)