OmniAICreator/Qiita-1.07M huggingface dataset:
Python超初心者の超初心者のためのPython #こんがらがりやすいとこ

環境
windows7　（Mac Book Pro 16inch欲しい）
Visual Studio Code
chrome

この記事はプログラミング初心者かつPython初心者に向けて記述します。

#こんがりやすい難解Pro用語
Pythonの学習を始めてProgateやドットインストールなどを見てコードを書いているとすぐに「？？？？」の連続になります。
その一つにPro用語やコードの書き方がProなので初学者には難解なところがいくつかあり、まずはそこをクリアーにしないと学習スピードが上がりません（でした）。

1.変数名

```python:confuse.py
str=str(123456)
print(str)
#=の左はstrという名前（変数名）。=の右はstr関数（変換ラベルのようなもの）の名前。
```

=の右のstrはstringの略で、Pythonでは数字（数値という）を文字（文字列という）に変換しますよーという決まりごと＝暗記ごとです。この界隈ではstr関数と言うそうです。
対して=の左の”str”はただの名前です。str関数を説明するために名前（変数名）”str”を使用したと思われますが、これがどっこい初学者には関数だか変数名だかわからないのでこんがります。（こんがる？こんがらがる？どっちにしてもこんがるという言葉は最近耳にしない・・・。）

次に行きましょう。

```python:confuse.py
for tool_item in tool_items:
#forの次は単数形。inのあとは複数形。
```

これは学習を進めていくと理解できるのですが、初めは「な、何いってるの！！？？」状態でした。
よく見ると”tool_item”はツールアイテムの単数形で、”tool_items”は複数形なんですよね。
何個かあるツールアイテムを「親方！こいつらをひとまとめにしちゃいやしょうぜ！」ってなことでひとまとめにしたのの名前が”tool_items(複数形)”で、それを”tool_item（単数形）”という変数に一つづつ取り出した形です。

とりま、ここまで。
編集にて加筆随時します。
【新入社員向け】サーバーについて

# 　【新入社員向け】サーバーについて

### 目次
1. サーバーとは
2. サーバーの役割
3. Webサーバーについて

## 1. サーバーとは
サーバーとは、サービスを提供するコンピュータ（ハードウェア）のことやそのコンピュータにある様々な機能(ソフトウェア)の事を指します。 
サーバー（server）とは、提供する側を指す言葉となります。
つまり、サーバーとは何かを提供してくれる物となります。

## 2. サーバーの役割
- 様々なデータを管理・保存をする**（データベースサーバー）**
- パソコン同士の通信を行う **（WEBサーバー）** 


様々なデータを管理・保存する役割はデータベースサーバーが担います。
パソコン同士の通信を行う役割はWEBサーバーが担います。また、**アプリケーションサーバー** を用いることにより、動的なWebアプリケーションを実現させています。

## 3. Webサーバーについて
今回はWebサーバーについて詳しく説明をします。
Webサーバーとは、クライアント（スマホ・パソコン）から送られきたリクエストに対して、リクエストに合ったレスポンスを返す仕組みを持ったハードウェアやソフトウェアのことを指します。
例えば、利用者(クライアント)がブラウザ上の「投稿するためのリンク」をクリックし、その情報をWebサーバーに送ったとします。
そして「投稿するためのリンクをクリックした」という情報をWebサーバーで「投稿するための画面に遷移する」という情報に置き換えてブラウザに送り返します（レスポンス）。
このようにWEBサーバーは、利用者の送ったリクエストに対して、情報を処理し、レスポンスをする役割を持ちます。

以上で新入社員向けサーバーについての説明となります。
VSCodeの保存拡張子をいちいち変更しなくていい方法

初投稿です:grinning:。拙い文章ですが、よろしければ見てください！
表題の方法だけ知りたい人は「きっかけ」、「この記事を読むべき人」を飛ばして読んでください。

###きっかけ
この記事を書いたきっかけは競プロを始めて、コードをVSCodeで書き始めたのですが、新しいファイルを開くたびに、そのファイルの形式を「.txt」から「.cpp」に変えるのがメンドクサイこと甚だし。。
何とかならないかと検索してみた結果、その方法があまり見当たらなかったため共有しようと思いました。

## この記事を読むべき人
1．新しく作成したファイルを保存するのに、いちいち拡張子をマウスで設定している人。
　　~~これは昨日までの僕ですね。~~。もっとも原始的で非効率なやり方ですネ。
　　具体的にどうやっていたかというと、、、

　　① 新しくファイルを開く（ctrl+N）
![スクリーンショット (185).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/5f38c059-0dee-75e3-e902-b1a11ced0621.png)
  　② コードを書き保存する(ctrl+S)
![スクリーンショット (186).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/8a813255-c332-bde7-eb28-25f9643ea256.png)
   ③ ファイルの種類をプルダウンを開き、選ぶ。そして保存する
![スクリーンショット (187).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/c7990336-26de-6048-f300-201a46dc8c81.png)
いかにも、高校の授業で習いそうなやり方ですよね（笑）

***
2．ファイルの種類をエディタの右下をクリックして設定している人
　　**こちらのやり方も、いろいろな言語を書いている人には適したやり方だと思うのでおすすめ**ですが、競プロをやっててC++しか使わないという人など、**特定の言語を集中して書いている人は後ほど説明するやり方をおすすめします**。まず、このやり方はというと、、

①やじるし(赤いやつ)をクリック
![スクリーンショット (185)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/bdbe366e-2b9b-4881-c6b2-c788198248d0.jpeg)
②言語を選択、コードを書く
![スクリーンショット (188).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/a509e73d-19a5-3317-3b11-af7eb4ef9277.png)
このやり方は保存する前に言語を設定できて便利で、実際に検索しているとよく出てきました。

#拡張子をVSCode側に覚えさせる
前置きが長くなりましたが、本題に入りましょう。
上の２つのやり方のように、新しいファイルを開くたびに拡張子を設定しなおす必要のない方法です。

１．まずコマンドパレットを開き(ctrl+shift+P)、
　　settings.jsonと打ち込み、
　　基本の設定(Preferences Open Settings(JSON))を選択。
![スクリーンショット (190).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/f1261807-693c-6a0a-c970-32ad52cd5b9f.png)

2.setting.jsonのなかにある、files.associationsのなかに以下のように、
　"Untitled-*": "使いたい拡張子(僕の場合はC++)"と打ち込む
![スクリーンショット (191).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473855/df2c53f0-c466-fd8c-a452-ec47b1dab52e.png)
3.setting.jsonを保存する。

以上で、新規ファイルは初めから指定した言語のファイルとなります。

##まとめ
こんなの知っているよという人が多いとは思いますが、初心者の自分の中では大発見だったので、今回はこのような時短テクニックを紹介しました。競プロをやるうえで、ほかにも便利な時短法があれば教えてもらえば幸いです！
【Rails】Catalinaでrails sコマンド実行時に「Could not find a JavaScript runtime.」とエラーが出る場合の対処法

# エラー内容
> Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)


# 対処法
gem 'therubyracer' はハマりやすいのでやめたほうが良い。
Node.jsをインストール
https://nodejs.org/en/
AWSのセキュリティ系サービスをごく簡単にまとめる

AWSは常に成長を続けています。
サービス数もすごい勢いで増えています。
すべてのサービスをそらで列挙できる人は、もはやほとんどいないかも知れません。

今回は、セキュリティ系のものに絞って、ごく簡単に紹介します。
（すべてのセキュリティ系サービスではありません。）

# 確認テスト
各サービスがどの部分に適用されるか、把握できていますでしょうか？
簡単なパズルゲームを作ってみたので、まずは試してみてください。

ごくシンプルなAWSアーキテクチャ図に対し、下の部分にあるセキュリティサービスのアイコンを、もっとも関連性が高い箇所（赤枠）にドラッグアンドドロップするパズルです。

https://aws-puzzle.pict3.org/aws-security-puzzle/index.html


# 各サービスの３行紹介
## AWS WAF
ALB, CloudFront, API Gatewayに簡単に適用できるサーバーレスなWAFです。
マネージドルールという提供された汎用ルール群を使うパターンと、自前でルール群を運用するパターン、そのハイブリッド構成があります。
2019年の年末に、大幅なアップデートが入りました。

## AWS Firewall Manager
AWS Organizationsをベースに複数アカウント間でのセキュリティルールを統合管理します。
セキュリティルールとは、AWS WAFのルール、セキュリティグループ、AWS Shieldのルールになります。
複数のアカウントを横断的に保護する必要がある場合に有効です。

## Amazon GuardDuty
アカウント内のログを機械学習にかけ、異常を検知するサービスです。
AWS CloudTrailイベントログやVPCフローログ、DNSログなどをベースに判断します。
攻撃通信に限らず、いつもと違う使い方をしても検知する可能性があります。

## Amazon Inspector
EC2インスタンスの脆弱性を診断するサービスです。
エージェントをインストールして使用します。
診断のスケジュール実行も可能です。

## Amazon Macie
S3バケット内に機密情報が保持されていないかを検査します。
機械学習とパターンマッチングにより、PIIや機密情報の疑いのあるデータを判断します。
カスタムパターンも設定可能です。

## AWS Security Hub
様々なAWSセキュリティサービスについて、集中管理できます。
いくつかのサードパーティー製品も連携可能です。
複数のAWSアカウントを一元管理することも可能です。

## AWS Shield
DDoS対策サービスです。
スタンダードとアドバンスドの2種類があり、スタンダードは標準的に全アカウントに導入されています。
前者はレイヤー3, 4、後者はレイヤー７を対象とし、より高精度で高機能になります。


# １枚図で表す（確認テストの答え）
![SecurityServices.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/2d147bb3-092b-1354-ab9f-11582a3f11fc.png)
GASの関数を実行可能APIじゃない方法で実行する

# はじめに
前にこんな記事を書きました。
[WebサイトのJSからGASの実行可能APIを最短最高で叩く](https://qiita.com/Cyber_Hacnosuke/items/acf730c246c7d2f58c0c)
内容は名前のまんま「実行可能APIを叩く」というものなんですが、自分が少し勘違いをしていたみたいで、自分が求めていた機能ではなかったみたいです。「実行可能API」は「API」ですから実行の主体はユーザー自身らしいのですよね。なのでDriveなどの操作をすると「ユーザーのDrive」に対して操作をしてしまい、共有の`Permission`などの関係で自分が意図した動作になりませんでした。私(開発者)の名義で関数を実行し、それをレスポンスしたいと思います。

# どうやって？
GAS側で普通に関数を作り、`doGet(e)`ですべてのリクエストを受け取り、パラメータによって実行する関数を変えてその結果を返すというような感じです。クライアント側は`jQuery`の`ajax()`を用いてリクエストを送るだけです。**`jQuery`は導入したという前提でいきます。**

# GAS側の実装
```javascript
function doGet(e) {
  var params = e.parameter;
  var res = {};
  switch(params.function) {
    case "exampleFuncA":
      res = exampleFuncA();
      break;
    case "exampleFuncB":
      res = exampleFuncB(params.parameters);
      break;
  }
  var callback = params.callback;
  var output = ContentService.createTextOutput();
  var responseText;
  if (callback) {
    responseText = callback + "(" + JSON.stringify(res) + ")";
    output.setMimeType(ContentService.MimeType.JAVASCRIPT);
    
  } else {
    responseText = JSON.stringify(res);
    output.setMimeType(ContentService.MimeType.JSON);
  }
  output.setContent(responseText);
  return output;
}
```

後述する`Cross-Origin Read Blocking(CORB)`によって値のレスポンスが少し特殊です。`e.parameter`でリクエストの`data`の部分を取得できます。今回はJSONです。`e.parameter.callback`にもし値が入っているならば「コールバック関数を呼んで引数として実行した結果(JSON)を渡します。」というレスポンスをします。なかった場合は結果をJSONでレスポンスするだけです。


**これを書いたら`公開>ウェブアプリケーションとして導入`でURLを取得してください。**

# クライアント側の実装
気を付けるのは`Cross-Origin Read Blocking(CORB)`です。さらっと読んだだけですので詳しくはわかりませんが、どうやら違うドメイン間の`ajax`などのリクエストは(連続でやると)攻撃になる可能性があるので注意が必要ですよということらしいです。ふつうに`ajax`したらエラーになります。そこで使うのが`JSONP`です。正直よくわからないですが、`dataType`を`JSONP`にすると`success:`が呼ばれなくなりその代わり`callback`としてパラメータになります。さらに`CORB`を回避できるみたいです。

```javascript:index.html
function callAppsScript(functionName, parameters, callbackFunc) {
  var request = { 'function': functionName, 'parameters': parameters };
  $.ajax({
    type:"get",
    url: GOOGLEAPPSSCRIPT_URL,
    data: request,
    dataType: "jsonp",
    success: function(data) {
      callbackFunc(data);
    }
  }).fail(function(jqXHR, textStatus, errorThrown ) {
    console.log("XMLHttpRequest : " + jqXHR.status + "\ntextStatus     : " + textStatus + "\nerrorThrown    : " + errorThrown.message);
  });
}
```
`data:`でパラメータたちを`JSON`として送信します。これはGAS側の`e.parameter`に当たります。わかりにくいですが`parameters`が関数に引数です。自分は1つしか渡さなくていいようになっていたのでただの文字列ですが第2引数以降が存在する場合はちょっと改造が必要です。自分が試した限りでは配列で渡すと失敗するので`第1引数,第2引数,...`という感じで渡してGAS側で`,`でsplitするのがいいと思います。下は実際に実行してみます。

```javascript
callAppsScript("exampleFancA", "", function(data) {
  // dataが返却値
});

callAppsScript("exampleFancB", "something", function(data) {
  // dataが返却値
});
```

# 最後に
今回はGASのウェブアプリケーションにリクエストを送って任意の関数を実行してみました。結局、ユーザーのMailAdressを取得するのに「実行可能API」を使い、何か実行させるときはAjaxで叩くという意味わからない？仕様になってしまいました。自分は`CORB`にめっちゃ時間かかりましたね...

Twitter→https://twitter.com/CyberHacnoshuke
Angular CLIをグローバルインストールしないでプロジェクトを作成する方法

`npm install -g @angular/cli`をしたくない人向けです。

## 実行手順
1. `npx -p @angular/cli ng new <name>`
2. `cd <name>`
3. `npm i -D @angular/cli`
4. `npm i`
5. `npx ng serve` or `npm start` でローカルサーバが起動する
DotStar(APA102)(RGBLED)をmbedで使う

# mbedでシリアル制御のフルカラーLEDを使ってみた
<img width="913" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135538/f79faacf-6a05-50d4-0e4e-a12dc0c50136.png">


Qitta書いたことないし、今までやった備忘録を書いておこうと思いました。
今回はフルカラーLEDのDotstarをmbedで使う為にに行くつか調べたことを書きたいと思います。
あとライブラリーも作りました。NeoPixelをmbedで使いたかったけど、動かないんだ！！って人は是非DotStarを使いましょう！！通信も簡単だし、ライブラリも作ったので是非使ってください。

[作ったライブラリ library for using DotStar with Mbed!!](https://github.com/TomiXRM/APA102-DotStar-for-Mbed　"library for using DotStar with Mbed!!")

# フルカラーLEDの種類
・普通のRGBに線があるタイプ
・NeoPixel(なぞのシリアル制御LED)
・Dotstar(APA102)(SPI通信で光らせられるLED,安定してる)
・ほかにも色々

#普通のRGBに線があるタイプ
<img width="836" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135538/12f3b6dd-b025-e988-94fd-8cd844de9872.png">
http://akizukidenshi.com/catalog/g/gI-03037/

RGBそれぞれに信号線が出ています。PWMかなんかでそれぞれに電気を入れてあげると光ります。
当然、LEDの使う個数 x 3本GPIOを使います。
16個光らせるなら16x3で48個のGPIOが必要です。おおすぎる

それでこの多すぎるからピン数を減らしたいよねーってでてきたのがシリアル制御のLEDになります。

# NeoPixel
https://www.switch-science.com/catalog/list/?keyword=neopixel
これは1本線シリアルでLEDにRED(256bit)GREEN(256bit)BLUE(256bit)のデータを送信して光らせます。1本でLED256個までならいけるらしいです。しかしGPIOにバッファ機能(?)がないとシリアルで文字を送るのは難しいらしく、mbedでは無理っぽいです。一応特殊なことをすればいけるらしいですが、僕が今回使おうとしてるマイコンでは動作しない様です。


# DotStar
https://www.switch-science.com/catalog/3239/
DotStarはSPI通信でLEDを制御するタイプです。2本線(MOSIとSCK)が必要です。上のNeoPixelと似ていますが、SPI通信なので大概のマイコンが標準搭載している通信方式ということもあり、NeoPixelよりもはるかに通信が楽です。しかし値段はNeoPixelよりも高いです。クロック同期なので通信も安定するっぽいです。値段が張ること以外はいいことがあるっぽいですね。あと、反応が早いとか。

今回はDotstarが手に入ったので実験することにしました。Switch Scienceで売っているDotStarの赤い基板を使います。

# 通信
APA102データシートより(https://cdn-shop.adafruit.com/datasheets/APA102.pdf)
1.0x00を4回送信
2.11100000から11111111までの数値(2の5乗の0~31+111)で明るさを設定する
3.RGB(使用上BGRの順番)の値を0~255 x3で送る。
4.0xFFをを4回送信

って感じです。
<img width="836" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135538/1d13fcfa-2ecd-1c58-a0c2-0261f6520cc1.png">


#DotStarのライブラリを作ったよ。
ライブラリを作りました。今回はインスタンスが生成された時に変数の配列の数を決定するっていうのをやってみたかったのでやってみました。
使ったLED(https://www.sparkfun.com/products/14353)

まずはincludeします。

```cpp:
#include  "LGDotStar.h"
```
次にインスタンス

```cpp:
LGDotStar LED(D11,D13,4);//mosi,sck,Number of leds used
```
LEDの設定

```cpp:
LED.set(255,0,0,0);//RED,GREEN,BLUE,Number of led
```

LEDにデータの送信

```cpp:
LED.write();
//or
LED.write(31);//set Brightness(0~31)
```

サンプルプログラム

```cpp:sample.cpp
#include  "mbed.h"
#include  "LGDotStar.h"

LGDotStar LED(D11,D13,4);

int main(){
        while (1) {
                LED.set(255,0,255,0);
                LED.set(255,255,255,1);
                LED.set(255,255,0,2);
                LED.set(0,255,255,3);
                LED.write(31);
        }
}
```

こんな感じです。
[作ったライブラリ library for using DotStar with Mbed!!](https://github.com/TomiXRM/APA102-DotStar-for-Mbed　"library for using DotStar with Mbed!!")
AndroidStudioでレイアウトをデザイン(layout_constraint)

#AndroidStudioでlayout_constraintを使ってレイアウトする
他の開発環境から**AndroidStudio**を初めて使った人にとってAndroid画面のレイアウトを作る面倒なことに驚く人が多いかと思います。

画面のレイアウト方法を理解しようとしても良いサイトや書籍が無いようなので、自己流ですがこうすればこうなりますよ、というのを説明していきます。

画面レイアウトの方法にはいくつかあって場面によって最適な方法を選ぶことになりますが、まずここでは**layout_constraint**というのを使ってレイアウトデザインを行います。

##Buttonを2つ置いてレイアウトを作る
ボタンを2つおいて下さい。デザイン方法は**コード、Split、デザイン**の3種類が用意されています。まずは**デザイン**の画面にします。

Hello World!のサンプルのTextViewがある場合は削除して**ConstraintLayout**だけがある状態にして下さい。**パレット**から**Button**を選んでデザイン画面かコンポーネントツリー画面へドラッグします。
これを2回繰り返してボタンを2つ配置します。
ボタンのidをそれぞれbtFrom、btTo という名称にします。idと同じものをtextにも入れてしまいましょう。警告が出ますがここはレイアウトのデザインを練習するだけなので無視します。

**Split**の画面に切り替えてレイアウトの変更がXMLのコードにどのように反映されるのか見て見ましょう。
**btTo**の方のボタンをクリックして選択した後ドラッグして場所を移動してみましょう。

**tools:layout_editor_absoluteX**と**tools:layout_editor_absoluteY**いう値が変化していることがわかります。デザイン画面での配置がtools:layout_editor_absoluteの X、Yに反映されるわけです。

###デザイン通りに表示されない
ここでコードを実行してデザインした通りに表示されるか確認してみましょう。するとデザイン通りにならないどころかボタンが重なって表示されてしまっているかと思います。

**AndroidStudio**に限りませんが表示の時には設定した内容に従って表示されているため、レイアウト画面で配置してもそれが表示には反映されていないのです。筆者も含めてこの段階で挫折しそうなのですが、簡単に思い通り配置出来るようにしていきます。

##レイアウトデザインの用語
4つほどですがレイアウトデザインの用語を覚えましょう。Height、WeightやX、Y以外に

![topstart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637460/b51c0668-6b72-df7e-6cf1-4bba9c45e097.png)

○白丸の部分Start、End、Top、Bottomを覚えます。

##ボタンを画面中央に配置する
まずはbtToのボタンを画面中央に配置しましょう。レイアウト画面は**Split**で行います。
1.btToのTopの○をドラッグして画面上端中央付近にドロップします。
2.btToのBottomの○をドラッグして画面下端中央付近にドロップします。
これで上下方向の位置が中央になりギザギザの波線の矢印が表示されれば成功です。

```layout.xml
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintTop_toTopOf="parent"
```

コードにはこの2行が追加されました。
btToのボタンの上端の位置は親(parent)の上端に依存します。
btToのボタンの下端の位置は親(parent)の下端に依存します。
との指示をしたのでこのような表示になったようです。
同じように左右も設定してしまいます。

```layout.xml
app:layout_constraintTop_toTopOf="parent" 
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
```

このようになれば成功です。画面中央に表示されます。実際に実行しても画面の中央に表示されます。
##依存先の指定して配置する
今度はbtFromボタンの配置をデザインします。
まずはbtToボタンの右側に表示させてみます。

1.btFromのTopの○をドラッグしてbtToボタンのTopの○にドロップします。
2.btFromのStartの○をドラッグしてbtToボタンのEndの○にドロップします。

```layout.xml
app:layout_constraintStart_toEndOf="@+id/btTo"
app:layout_constraintTop_toTopOf="@+id/btTo"
```

コードがこのようになれば成功です。
同様にbtToの上下左右、さらには右斜め上や左斜め下などにも配置されるように練習してみましょう。
【python】整数の組み合わせで２次元配列を作成するプログラム　

#【python】整数の組み合わせで多次元配列を作成するプログラム　

自分用のメモです。


▼設問

- 重複のない[i, j, k]の２次元配列を作成する。
- i, j, kの条件は、与えられる正の整数x,y,zで決まる
- 0<=i<=x, 0<=j<=y, 0<=k<=z
- ただし、i+j+kがnとなる場合の[i,j,k]は除外する。



[URL](https://www.hackerrank.com/challenges/list-comprehensions/problem)


▼sample input

```python:
x,y,z,n=1,1,1,2
```

▼sample output

```python:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]]
```

▼my answer

```python:
if __name__ == '__main__':
    x = int(input())
    y = int(input())
    z = int(input())
    n = int(input())

    res=[]

for i in range(x+1):
    for j in range(y+1):
        for k in range(z+1):
            if i+j+k != n:
                res.append([i,j,k])

print(res)
```


<br>
[i, j, k]に対し、一つづつfor文を回していく。（計３回まわす）


<br>
##内包表記で簡略化
`処理 for 変数 in イテラブル if 条件`
　└ **ifの条件を満たす場合のみ**処理を実行する。


```python:
if __name__ == '__main__':
    x,y,z,n = [int(input()) for _ in range(4)]
    
    print([[i,j,k] for k in range(z+1) for j in range(y+1) for i in range(x+1)if i+j+k != n])   
```


<br>
**▼普通のfor文との違い**
実行結果がlist型になる。
　└ appendなど、要素を追加したり足したりする作業が不要



・**for _ in range(n)**
処理をn回まわす。
変数不要なので、便宜上「 _ 」を入れておく。
　└ 空白はエラーになる

```python:空白のfor
i=-1
for  in range(4):
    i+=1
    print(i)

#出力
SyntaxError: invalid syntax
```
twitterアイコンをs3に保存する

# やること

twitterログインで取得してくるtwitterアイコンのリンクがすぐに切れてしまうのでs3に保存する。

# 実装内容

- rails
- 画像保存はcarrierwaveを経由でs3

## twitteromniauthの実装

https://qiita.com/puremoru0315/items/f1d459b663fd3b715dee

上記記事が分かりやすかった

## 新規登録時にのみ画像保存の処理

omniauthで下記の処理を書いている

```user.rb
class User < ApplicationRecord
  mount_uploader :image_url, ImageUploader
  #引数に関連するユーザーが存在すればそれを返し、存在しまければ新規に作成する
  def self.find_or_create_from_auth_hash(auth_hash)
  #OmniAuthで取得した各データを代入していく
      provider = auth_hash[:provider]
      uid = auth_hash[:uid]
      nickname = auth_hash[:info][:nickname]
      image = auth_hash[:info][:image]

      User.find_or_initialize_by(provider: provider, uid: uid) do |user|
        if user.new_record?
          user.nickname = nickname
          user.remote_image_url = image_url
          user.save
        end
      end
    end
end
```

find_or_initialize_byはuserを探してあったらそれを取得、なかったら新規作成するもの。find_or_create_byと違うのはfind_or_create_byは保存までやってくれる。新規登録のみの処理を入れたい場合、new_record?で新規作成かを条件分岐してからsaveできるfind_or_initialize_byでやる。


## 画像保存をcarrierwave

https://github.com/carrierwaveuploader/carrierwave#uploading-files-from-a-remote-location

画像保存でやっているのは下記の処理

- twitterからアイコンのurlを取得
- そのurlから画像をdl
- そしてその落とした画像をs3に保存

この処理をremote_xxxx_urlメソッドだと簡単にできる。
Helm v2 から v3 で何が変わるの？

この記事はHelm v2とHelm v3の違いを調査したまとめです。
## 背景
Helm v3がリリースされてから半年余りが経ちました。
しかしWebや書籍ではまだHelm v2の情報が多く、初学者にやさしくない為、重要な部分をまとめてみました。

## Helm v2からの変更点
[Helm公式-よくある質問](https://helm.sh/docs/faq/)より、変更点を一覧にしました。
　

- Tillerの削除
- 3 ways マージパッチ
- リリース名の範囲がnamespaceになった
- secretがデフォルトのストレージドライバーになった
- Goのimportパスが[k8s.io/helm]から[helm.sh/helm/v3]になった
- .Capabilitiesのレンダリング組み込みオブジェクトが簡素化された
- リリース名の範囲がnamespaceになった
- jsonスキーマを使用したチャート値の検証
- requirements.yaml → Chart.yaml
- requirements.lock → Chart.lock
- インストール時にリリース名が必須になった
- OCIレジストリへのchartのpush機能が追加された(実験的)
- helm serveが削除された
- Chart.yamlのapiVersionがv1からv2になった
- XDGベースディレクトリのサポート
- CLIコマンドの統合と名前変更
- [--create-namespace]フラグで指定しないとnamespaceの自動作成されなくなった


変更点が多いですね。

この中でも特に大切な３点**「Tillerの削除」「リリース名の範囲がnamespaceになった」「CLIコマンドの統合と名前変更」**について詳しく見ていきましょう。

## Tillerの削除
Helm v2までは、KubernetesクラスタへTillerポッドをデプロイする必要がありました。

**Helm v2の動作が以下の流れで実現しているからです。**

1. Helm コマンドを実行する
2. HelmClientがTillerポッドにgRPCプロトコルでやりとりを行う
3. TillerポッドがREST APIでkube-apiserverに指令を伝達する
4. kube-apiserverがKubernetesリソースの操作を行う

**Helm v3では以下のようになりました。**

1. Helmコマンドを実行する
2. HelmClientがkube-apiserverに指令を伝達する
3. kube-apiserverがKubernetesリソースの操作を行う

Helm v3では、kube-apiserverに対する認証情報はkubectlと同じ、kubeconfigを利用します。
(デフォルトだと$HOME/.kube/config)

これによって、kubectlが利用できる環境にHelm v3を導入するだけで、kubectlと同じ権限でKubernetesクラスタにアクセスすることが可能になりました。


## リリース名の範囲がnamespaceになった
最も影響ある部分でいうと、**helm listコマンドのみではすべてのリリースが表示されなくなった**ということです。
helm v3のhelm listコマンドでは現在のnamespaceのリリースのみが表示されます。

**helm v2のように全てのnamespaceを参照したい場合は[--all-namespace]フラグが必要です。**

以下詳しく説明します。

Helm v2では、リリースに関する情報はTillerと同じnamespaceに格納されていたようです。
そのため、リリース名が別のnamespaceにデプロイされていても、同じリリース名を使用することができませんでした。

Helm v3ではリリース名含めた情報はリリースと同じnamespaceに格納されるようになっています。
これによって**別のnamespace上で同じリリース名を使用できる**ようになりました。

その代わり、namespaceを指定しないとリリース名が表示されなくなってしまったというわけです。

## CLIコマンドの統合と名前変更
一番の初学者躓きポイントです。
色々な記事で解説されているコマンドがそのままでは利用できなくなっていることが多いです。

表でまとめてみました。

|Helm v2| Helm v3 |
|:-:|:-:|
|delete(--purge) | uninstall(デフォルトですべてのリリース履歴を削除)  |
|fetch|pull|
|home|削除|
|init|削除|
|install|リリース名もしくは(--generate-name)が必須に|
|inspect|show|
|reset|削除|
|serve|削除|
|temprate|-x/--executeオプションが-s/--show-onlyに変更|
|upgrade|--history-maxオプション追加|

これは初学者でなくても、ドキュメントを読み替えるのちょっと大変そうですね。
## おわりに
Helm V2とHelm V3では内部の動作が大きく変わっていることが分かりました。
Web上や書籍にはまだまだHelm v2の内容が多いので、
つまづいたらまずは**自環境のHelmのバージョン**と**ドキュメントのHelmのバージョン**をチェックしてみてください。
スムーズに学習するためには一旦Helm v2を利用するのもいいかもしれません。

また、弊社WebサイトにてHelm v3を使って[prometheus-operator]を導入した手順を公開していますので、Helm v3を試してみたい方はぜひご覧ください。
https://bit.ly/36CyaBP
Reactの環境構築


##経緯

progateのReactコースで学習した内容を、ローカル環境で復習したかったので構築する方法を調べました。

##手順

Homebrew経由でインストールする

以下の3つをインストールされているか確認する

```
$ brew -v
```

```
$ node -v
```
```
$ npm -v
```
または検索をする

```
brew search <パッケージ名>
```

入っていないパッケージはインストールする

```
brew install <パッケージ名>
```

##プロジェクトの作成

```
npm install -g create-react-app
```

```
create-react-app <プロジェクト名>
```

##ローカル環境で確認

```
npm start
```

上記コマンドでサーバーを起動させて http://localhost:3000/ を入れて

<img width="549" alt="スクリーンショット 2020-06-08 8.46.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381043/d945a142-f2d4-c15f-0e38-97640d9acaab.png">

確認できれば構築完成！

あとは、progateのコードを参考に修正すればサイトが完成します。


##参考サイト

環境構築

https://www.simpletraveler.jp/2020/04/25/react-programming-environmentsetup/

https://www.webprofessional.jp/create-react-app/

Homebrew

https://qiita.com/omega999/items/6f65217b81ad3fffe7e6
Dockerのコンテナ操作コマンド

# Dockerのコンテナ操作コマンド

イメージの取得(pull)

```sh:イメージの取得(pull)
$ docker pull centos
```

コンテナの実行(run)

```sh:イメージの実行(run)
$ docker run centos echo "hello world"
hello world
```

コンテナをデーモンとして実行(run -d)

```sh:イメージをデーモンとして実行(run-d)
$ docker run -d centos free -s 3
d6428ae88db3ded1764e6bc5a28f9d733cc8f10828c13680679c3f3f7cc2cf40
```

実行中コンテナの表示(ps)

```sh:実行中コンテナの表示(ps)
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d6428ae88db3        centos              "free -s 3"         11 minutes ago      Up 29 seconds                           stoic_bell
```

ログ等で動作確認(logs)

```sh:ログ等で動作確認(logs)
$ docker logs d642
              total        used        free      shared  buff/cache   available
Mem:       13001564      525996    11012892        1068     1462676    12249868
Swap:       4194304           0     4194304

              total        used        free      shared  buff/cache   available
Mem:       13001564      525992    11012892        1068     1462680    12249868
Swap:       4194304           0     4194304
```

コンテナの停止(stop/kill)

```sh:コンテナの停止(stop/kill)
$ docker stop d642
d642
```

再度、実行中コンテナの表示。停止したので表示なし。

```sh:実行中コンテナの表示(ps)
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

停止したコンテナはイメージとして残ってるので表示して確認。(ps -a)

```sh:停止したコンテナの表示(ps-a)
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                          PORTS               NAMES
d6428ae88db3        centos              "free -s 3"            12 minutes ago      Exited (137) 9 seconds ago
```

停止中コンテナの再開(start)

```sh:停止中コンテナの再開(start)
$ docker start d642
d642
```

ログ等で動作確認(logs)

```sh:ログ等で動作確認(logs)
$ docker logs d642
              total        used        free      shared  buff/cache   available
Mem:       13001564      525996    11012892        1068     1462676    12249868
Swap:       4194304           0     4194304

              total        used        free      shared  buff/cache   available
Mem:       13001564      525992    11012892        1068     1462680    12249868
Swap:       4194304           0     4194304
```
Linux コマンド　【read編】

#readコマンド
標準入力から読み込みを行います。標準入力から1行読み取り，読み込んだ内容をシェル変数に格納します。

```Linux:ファイル(pra1.sh)内容
#!/bin/bash

read -p 'ファイル名を入力してください' fh
echo $fh

```
-p : ユーザーの入力情報を標準入力とする
fh : 任意の変数名　標準入力の情報をこちらに格納
$fh :格納したユーザー入力情報を表示


```Linux:実行結果
$ ./pra1.sh
ファイル名を入力してくださいHello World
Hello World
```

#使用例
ファイルstring.txtの内容を読み込み，標準出力に出力します。

ジョブ定義スクリプトの内容

```Linux:使用例
while read LINE
do
 echo "$LINE"
done     < string.txt
```
brew doctorでprotobuf@3.7がdeprecatedなときの対処法

brew doctorしたらこのような表示が出てきた。


```zsh
~
❯ brew doctor

~(中略)~

Warning: Some installed formulae are deprecated or disabled.
You should find replacements for the following formulae:
  protobuf@3.7

```


#解決方法
the following formulae以下のパッケージ(今回はprotobuf@3​.​7)をアンインストールすればいい。

```zsh
~ 7s
❯ brew uninstall protobuf@3.7
Uninstalling /usr/local/Cellar/protobuf@3.7/3.7.1_1... (264 files, 18.5MB)

~
❯ brew doctor
Your system is ready to brew.
```
サーバレス運用試験

サーバレス環境でのサービスを、Rails関連のフレームワークを組み合わせて、開発運用する試験的な取り組み。

## 構成図

`jet` >- `rails` -< `database, redis, etc`


## 開発手順

RailsのAPIサーバを公開する。

Jetsのプロジェクトを公開する。

上記は、全てローカルでも良い。

git hub等の設定（CI CD）
かゆいところに手が届くgit stash

# 利用が想定される状況
　・コミットする前に別の機能を実装する必要ができた
　・今のコードの差分を別のコミットの後に回したい
　などが想定されます。
　
　そんな時に便利なのがgit stash 今ある差分を一時的に退避させることが可能です。

# 利用手順
　

``` ターミナル
$ git stash
Saved working directory and index state WIP on 02-setup: 8e4211a edit model
```
でコードを退避させ、別のコミットなどが終わった段階で、戻したいディレクトリに移動し、以下のコマンドでインデックスを確認します。

``` ターミナル
$ git stash list
stash@{0}: WIP on 02-setup: 8e4211a edit model
```


このstash@{0}が先ほど退避させたコードの番号で、複数あれば、stash@{1}などが確認できる。
今回は、直近で退避したstash@{0}を戻したいので以下のコマンドで戻せます。

```
$ git stash apply stash@{0}
On branch 02-setup
Your branch is ahead of 'origin/02-setup' by 1 commit.
  (use "git push" to publish your local commits)
```

以上が手順となります。コミットのし忘れなどの際に結構使う機会が多いように感じました。ジャンジャンgitを使いこなしてください:thumbsup_tone1:
Node.js: Lambda で MariaDB のデータを削除 (Delete)

フォルダー構造

```text
$ tree -a
.
├── .env
├── function_update.sh
├── index.js
└── test_local.js
```

```js:maria_delete/index.js
// ---------------------------------------------------------------
//	maria_delete/index.js
//
//					Jun/07/2020
//
// ---------------------------------------------------------------
var mysql = require('mysql2/promise')

// ---------------------------------------------------------------
async function main(id_in)
{
	console.error("id_in = " + id_in)
	const host = `${process.env.host}`
	const user = `${process.env.user}`
	const password = `${process.env.password}`
	const data_base = `${process.env.data_base}`

	console.error("host = " + host)
	console.error("user = " + user)
	console.error("password = " + password)
	console.error("data_base = " + data_base)

	try{
	var conn = await mysql.createConnection ({
		host: host,
		user: user,
		password: password,
		database: data_base
		})

	const command = "delete from cities where id = '" + id_in + "'"

	console.error (command)
	console.error ("*** before execute ***")
	await conn.execute(command)
	console.error ("*** after execute ***")
	} catch (ee) {
		console.log(ee)
		console.error ("*** error *** main ***")
		console.error(ee)
		return ''
	} finally {
		if (conn && conn.connection) {
		conn.end()
		console.error ("*** 終了 ***")
		}
	}
}

// ---------------------------------------------------------------
console.error ("*** 開始 ***")

exports.handler = async (event) => {
const key_in = event['key']
console.error (key_in)

console.error("***** start maria_delete PM 16:14 ***")
var rvalue = {}
rvalue['message'] = 'Hello from maria_delete'

await main(key_in)

    const response = {
        statusCode: 200,
        body: JSON.stringify(rvalue),
    }

    console.error("***** end maria_delete ***")
    return response
}


// ---------------------------------------------------------------
```

```js:test_local.js
#! /usr/bin/node
// ---------------------------------------------------------------
//	maria_delete/test_local.js
//
//					Jun/07/2020
//
// ---------------------------------------------------------------
var maria_delete = require('./')
// ---------------------------------------------------------------
console.error ("*** 開始 *** test_local.js ***")

const key_in = process.argv[2]

const event = {
	"key": key_in
}

rvalue = maria_delete.handler(event)
console.log(rvalue)

console.error ("*** 終了 *** test_local.js ***")
// ---------------------------------------------------------------
```

実行スクリプト

```bash
export NODE_PATH=/usr/lib/node_modules
node -r dotenv/config ./test_local.js t3323
```

AWS のプログラムを更新するスクリプト

```bash:function_update.sh
FUNCTION='maria_delete'
ZIP_FILE=$FUNCTION".zip"
#
rm -f *.zip
#
zip -r $ZIP_FILE index.js
#
aws lambda update-function-code \
	--function-name $FUNCTION \
	--zip-file fileb://$ZIP_FILE
#
```

AWS のプログラムを cli で実行する方法

```bash:cli_exec.sh
#
aws lambda invoke --invocation-type Event \
    --function-name maria_delete --region ap-northeast-1 \
    --payload '{"key": "t3322"}' \
 outputfile.txt
```
Python超初心者の超初心者のためのPython #Hello World

環境
windows7
Visual Studio Code
chrome

この記事はプログラミング初心者かつPython初心者に向けて記述します。

#Hello World!!!
まずは決まり文句"Hello World"です。
この呪文をPC画面にPythonを使って表示させるのは、テキストエディタというメモ帳のプログラミング版を使用します。
私はVisual Studio Code（以下VS Code）を使ってますが、使用できるまでの環境設定にゆうに20時間を超えています。
VS CodeをHTML&CSSで使っていましたが、Pythonで使うとなると一苦労・・・。

なので、まずは簡単なGoogle Colaboratoryをテキストエディタとして使用するのが早いです。
なおgoogle colaboratoryの使い方は以下のリンク先がわかりやすいです。
    [Google Colaboratoryの始め方](https://gammasoft.jp/blog/google-colaboratory-for-learning/)

さあ、私でも今では朝飯前のHello World!!!!を書いてみましょう。

```python:begin.py
"Hello World"
```

この文字列を画面に出力するには、print(”Hello world")と書きます。
記述出来たらGoogle colaboratoryの音楽再生ボタンのようなボタンをクリックします。

```python:begin.py
print("Hello World")

#Hello Worldと出力されます
```

画面にHello Worldと表示されましたでしょうか。
はて、コードを入力したときは"Hello World"とダブルクォーテーションを書いたのに画面に出力されたのはHello Worldとダブルクォーテーションが抜けています。
これは、Pythonが文字を書くときは日本語、英語、何語でもダブルクォーテーション、またはシングルクォーテーションで囲ってね♪という決まりごとなんです。

このようにプログラミングには決まり事を覚える作業と、関数のように覚えたことを考えながら使い回す作業があります。

```python:begin.py
print("続く")

#続く
```
Windows & US キーボードな環境で日本語 IME 切り替えを快適に行うキーマップ

## 完成形

以下ような Mac っぽい設定を目指す。

- CapsLock -> Left Ctrl
- Right Alt -> F13 (IME オフ)
- Right Win -> F14 (IME オン)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56321/2e8b5e9c-d349-bfa5-7ed4-de8b2233344c.png)

Windows 10 Pro 1909 で動作確認済み。

## レジストリの設定

まずレジストリをいじってキー割当を変更する。

フリーソフトの [AutoHotkey](http://ahkwiki.net/Top) や Windwos 公式の [Ctrl2cap](https://docs.microsoft.com/en-us/sysinternals/downloads/ctrl2cap) を使う方法が解説されている記事もあるが、オンラインゲームでチートツール扱いされることがある[^2]。実際それで困ったのでこの記事を書いた。レジストリの Scancode Map という値を編集する方法だと問題なかった。

以下のような内容の `keymap.reg` というファイルを作成し、ダブルクリックで適用すれば終わる。

```reg:keymap.reg
Windows Registry Editor Version 5.00
 
; left capslock (00_3a) to left ctrl (00_1d)
; right alt (e0_38) to f13 (00_64)
; right win (e0_5c) to f14 (00_65)
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:\
00,00,00,00,\
00,00,00,00,\
04,00,00,00,\
1d,00,3a,00,\
64,00,38,e0,\
65,00,5c,e0,\
00,00,00,00
```

[SharpKey](shttps://github.com/randyrants/sharpkeys) を使うと同じことが GUI でできる。

[^2]: https://loumo.jp/archives/25326

## IME の設定

IME で以下のように設定する。

- F13 -> IME オフ
- F14 -> IME オン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56321/42701e67-8ff0-a4eb-205f-11414cbfc372.png)
CloudflareでGraphQLを使った話

#経緯
Cloudflareを使っていると帯域幅が気になる事はよくあると思う。
APIを利用すると便利だけど、**古いAPIはそろそろ使えなくなる**らしい。
>https://api.cloudflare.com/#zone-analytics-dashboard
>Deprecation Warning
>End of life Date: 2020年11月2日
>Please use the new GraphQL Analytics API instead: https://developers.cloudflare.com/analytics/graphql-api/.

GraphQLなど聞いた事も無いが移行するしか無い。説明を見ながらテスト。
https://developers.cloudflare.com/analytics/migration-guides/zone-analytics/
https://developers.cloudflare.com/analytics/graphql-api/tutorials/build-your-own-analytics/

#結果
日毎の帯域幅まとめは以下のようにすると取得できた。

```php:CloudflareGraphQL.php
<?php
$authemail="username@example.com";  //アカウントのメールアドレス
$apikey="0123456789abcdef0123456789abcdef01234";  //APIキー
$zoneid="0123456789abcdef0123456789abcdef";  //ゾーンID

$datetime_geq = gmdate('Y-m-d', strtotime("-364 days")); //開始日
$datetime_lt = gmdate('Y-m-d', strtotime("now")); //終了日
$content = '{
  viewer {
    zones(filter: {zoneTag: "'.$zoneid.'"}) {
      httpRequests1dGroups(orderBy: [date_ASC], limit: 365,
        filter: {date_geq: "'.$datetime_geq.'", date_lt: "'.$datetime_lt.'"}){
        dimensions {
          date
        }
        sum {
          bytes
        }
      }
    }
  }
}';
$url = 'https://api.cloudflare.com/client/v4/graphql';
$ch = curl_init();
$defaultOptions = [
	CURLOPT_URL => $url,
	CURLOPT_POST => true, //GraphQLはPOST必須らしい
	CURLOPT_FOLLOWLOCATION => true,
	CURLOPT_RETURNTRANSFER => true,
	CURLOPT_POSTFIELDS => json_encode(array('query' => $content)),
	CURLOPT_HTTPHEADER => [
		"Content-Type: application/json",
		"X-AUTH-EMAIL: ".$authemail,
		"X-AUTH-KEY: ".$apikey,
	]
];
curl_setopt_array($ch, $defaultOptions);
$chContents = curl_exec($ch);
$curlInfo = curl_getinfo($ch);
curl_close($ch);
echo $chContents; //応答はJSONなのでjson_decodeでデコードして利用する
```
沢山オプションを付けるとタイムアウトする事があるので、期間を短くするとか配慮が必要。
Python3 での末尾再帰最適化

# バージョン3.11以降なら解決

久々に調べてみたら状況が変わっていた。

[Python 3.11で末尾再帰が書けるようになる - なんか考えてることとか](https://opaupafz2.hatenablog.com/entry/2022/09/17/185036)

素晴らしい副産物ですね。

# 結論

[Pythonのクロージャで末尾再帰最適化をする。 - tanihito’s blog](http://tanihito.hatenablog.com/entry/20110119/1295459297)
[Pythonで末尾再帰する - Blanktar](https://blanktar.jp/blog/2013/06/python-tail-recurusion)

上記を参考に Python3 で書き直してみる。

```python:tail_recursion.py
from functools import wraps

def tail_recursion(func):
  firstcall = True
  params = ((), {})
  result = func

  @wraps(func)
  def wrapper(*args, **kwd):
    nonlocal firstcall, params, result
    params = args, kwd
    if firstcall:
      firstcall = False
      try:
        while result is func:
          result = func(*args, **kwd) # call wrapper
          args, kwd = params
      finally:
        firstcall = True
        return result
    else:
      return func

  return wrapper

@tail_recursion
def fact(n, acc=1):
  return fact(n-1, acc*n) if n > 0 else acc

print(fact(10))
```
```sh:shell
> python3 tail_recursion.py
3628800
```

こんなこと、よく思いつくな。。。

# なにが起きているのか？

まずは基礎的なことから。

## デコレータ

`@tail_recursion` により、関数 `tail_recursion` がデコレータだと指示している。
デコレータとは「飾り付ける奴」。
デコレータは関数を引数に取り、新たな関数を返す。
その新たな関数は内部で、先に渡された関数を呼び出す。
`tail_recursion` は `wrapper` を返す。
`wrapper` は何かしらの飾り付けを伴って内部で `func` を呼び出す。

```python:
@tail_recursion
def fact(n, acc=1):
  return fact(n-1, acc*n) if n > 0 else acc
```

上記はこう解釈される。

```python:
def fact(n, acc=1):
  return fact(n-1, acc*n) if n > 0 else acc

fact = tail_recursion(fact)
```

左辺の `fact` は `wrapper` である。

## クロージャ

`wrapper` は `tail_recursion` のローカル変数を参照している。
Python はこの挙動をサポートしている。これをクロージャという。
`nonlocal` により更新可能にもなる。

## functools.wraps

`@wraps(func)` をコメントアウトし、
スクリプトの最後で `print(fact.__name__)` とすると、出力結果が `wrapper` になる。
いやいや `fact` と出力してくれよ、それが `wraps` の役割だそうな。
要するに `func` のメタ情報を引き継いでくれというものらしい。

## 関数 `fact` を実行すると

デコレータにより、今や `fact` は `wrapper` なのであった。
便宜上 `fact' = tail_recursion(fact)` とすると、

`fact'(0)`
=> `wrapper(0, {})`
=> `result = fact(0, {})`
-> `result = 1` （ループ終了）
=> `1` （finally）

`fact'(1)`
=> `wrapper(1, {})`
=> `result = fact(1, {})`
-> `result = fact'(0, 1, {})`
-> `result = wrapper(0, 1, {})` （２度目の呼出）
-> `result = fact` （ループ継続）
-> `result = fact(0, 1, {})` （引数のロード）
-> `result = 1`
=> `1`

`fact'(2)`
=> `wrapper(2, {})`
=> `result = fact(2, {})`
-> `result = fact'(1, 2, {})`
-> `result = wrapper(1, 2, {})` （２度目）
-> `result = fact`
-> `result = fact(1, 2, {})`
-> `result = fact'(0, 2, {})`
-> `result = wrapper(0, 2, {})` （３度目）
-> `result = fact`
-> `result = fact(0, 2, {})`
-> `result = 2`
=> `2`

すごーいっ
お陰様で寝不足だ。
AWS EC2でCron使うならタイムゾーンを意識する [for Ubuntu 18.04]

Cronを使ってLet's Encryptの自動更新とか設定したはいいものの，自動的にスクリプトが走っていないと感じた時とかに見直したい設定がある．それが**タイムゾーン**．
AWSでは作成したインスタンスではUTC（協定世界時．日本標準時より9時間前の時刻となる）になっているので，これをJST（日本標準時）に修正してあげる必要がある．ただし，OSの設定を変えるだけでは不十分なので，いくつか追加の作業が必要．

※ Cron自体の設定方法の記事はこの世界にありふれているため，この記事ではCron自体の設定方法は取り扱わない．

# タイムゾーンの確認

```bash
$ date  #現在時刻を確認する．
$ strings /etc/localtime  #設定されているタイムゾーンを確認．
```

`strings /etc/localtime`を実行した時に最後の行にUTCとかJSTとか書かれている．これが現在設定されているタイムゾーンとなる．ここが既にJSTである場合はCronの再起動や，Cron自体のタイムゾーンを確認する．

# タイムゾーンを設定する
```bash
$ sudo timedatectl set-timezone Asia/Tokyo
```

`timedatectl`を使ってタイムゾーンを設定する．JSTに設定したい場合は`Asia/Tokyo`を指定する．このコマンドを実行した時点で反映されているはずなので，うまく設定されたか確認したい場合は先述したコマンドを実行する．

# ※重要※ Cronを再起動する

```bash
$ sudo service cron restart
```

これが最も重要．OSの設定を変えたところでCron側は知らんぷりしているのでタチが悪い．このコマンドを実行することにより，初めてCronはJSTで実行されるようになる．めでたしめでたし．


# おまけ
簡単なTipsを掲載しておく．

## ユーザごとにスケジュールを作成する
```bash
$ sudo crontab -u root -e
# Cronの設定ファイルの編集画面が起動する．
# 編集画面ではCtrl + S で保存，Ctrl + X で終了する．
```
Cronを実行するときはスクリプトを実行するユーザを指定できる．上の例はCronにrootで実行してもらいたいスクリプトを記述する時に使用する．ユーザ（e.g., ubuntu）で実行したい場合は`sudo`をつけずに`crontab -u ubuntu -e`でCronのスケジュールを編集する．

## Cronに登録されているスケジュールを確認する

```bash
$ ls /var/spool/cron/crontabs/
```

`/var/spool/cron/crontabs/`のディレクトリ以下を確認することで，ユーザごとに作成したCronのスケジュールを確認できる．こんなことするよりも，該当ユーザで`crontab -l`をする方が早い．

## Cron実行時のログを残す
- [crontabのガイドライン - Qiita](https://qiita.com/onomame/items/71646c5517a39bcd01cc)
- [cronを実行したログを出力する設定 - Qiita](https://qiita.com/pyon_kiti_jp/items/31ab0840e8e67ffb2c3c)
- [cronログが突然出力されなくなった時に役立つ技術](https://tatsuhi10.hatenablog.com/entry/2018/11/09/001653)
初心者によるプログラミング学習ログ 338日目

#100日チャレンジの338日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
338日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>338日目　10h<br>・ポートフォリオ作成<br>・タブレット版、PC版作成<a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1269721060645072896?ref_src=twsrc%5Etfw">June 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Discord.jsで埋め込み(embed)をする時の注意点

\#大変お世話になったページ：[Discord.jsでembed (埋め込みメッセージ) を扱う](https://qiita.com/nedew/items/4e0c20c1a89e983a6992)

いきなりですが、discord.jsについてしばらく説明続きます。わかっている方は[こちら](#注意点)
### 環境
npm v6.14.4
node.js v12.18.0
discord.js v12.2.0

# Discord.jsでローカルの画像を埋め込む
どうも、Discord.jsを使ったBOTを作り始めて一週間の初心者です。
あ、あと初投稿です。(記事の稚拙さは大目に見てください)

## Discordでの埋め込みとは
　さて、discordで情報をまとめてカッコよく吐き出す手段に、embedという形式があります。(詳しくは[大変お世話になったページ](https://qiita.com/nedew/items/4e0c20c1a89e983a6992)をご覧になってください。)

　これを使うと、以下のようにカッコよく、クールでスタイリッシュ(ほとんど同じ意味)な感じで情報をまとめることができます。
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630781/ee08963f-62d8-b090-bd71-cc3604b8ecff.jpeg "アイコンのせいで台無し.png")
## ローカル画像を埋め込む
　本題です。embedに埋め込みたい画像を、ネットの海の中からurl指定するのではなく自分のPCから指定したい時、一手間必要です。具体的には、以下のようにする必要があります。

```javascript:discord_BOT.js
const discord = require('discord.js');
const client = new discord.Client();

// ～～～省略～～～

// 参加しているチャンネルにメッセージが送信された時に実行
client.on("message", message => {
// BOTが自分の投稿に反応しないように
     if(message.author.bot)return;
     message.channel.send({
        embed : {
            image : {
              url : "attachment://暫定ファイル名"
            }
        },
        files : [{ attachment : "ローカルのファイルパス", name : "暫定ファイル名"},
                 ..., /*使う画像の分だけ*/
                 ]                  
    }
// ～～～省略～～～
//サーバーにログインする
client.login("BOTのトークン", true);
```
　ごく単純な、メッセージが送られたら必ず画像埋め込んで送るという迷惑極まりないBOTです。
注目していただきたいのは、`url`の指定方法。`attachment://`ってついてます。ついでに`files`のなかにも`attachment`の文字があります。これは`files`の`name`で指定した変数に画像ファイルを入れているようなもの、と***私は***考えています(保険)。
`url`にて、`name`に`attachment://`と付けてローカル画像を指定できます。

###注意点
　さてさて、本当の本題です。この`name`、日本語に対応していないようです。

**`name`は半角英数字にしましょう！** 


　長々と周辺の説明をわかりにくくしてきた癖に言いたいことはこれだけです。
***変数名は英語にしようね？***

「何を今更…」という方もいらっしゃるでしょう。
 
　しかし、`name`を変数だと考えずに関数のタイポやバージョンの壁を疑って一日を無駄にしてしまう可能性を潰したかったのです。なんてもったいない時間の使い方だったのだろう。

***
　繰り返しますが ***初 投 稿***なもので、しきたりとか見やすさとかよくわかりません。
その中で拙文を読むという苦行に耐えてくださった皆様には軽く感謝を。
8色液晶モジュール F-51373GNC-LW-AUN 制御メモ

# はじめに
家から10年くらい前に買って放置していたLCDが発掘されたので制御方法をメモしておく。
確か秋葉原の電子部品関連の店で安く売られてたから買った気がする。
当初は新人だったので制御方法が分からず、フレキも電源も用意できずに封印した。
暇つぶしに動かしてみたところ、驚いたのがこれが8色だったことで
買った当初から動かすまで完全にフルカラーだと思っていた。

# F-51373GNC-LW-AUN について
F-51373GNC-LW-AUN は 240x320ドットの8色 液晶表示モジュールである。
メーカはオプトレックス(現：京セラディスプレイ)。
1ドットは赤緑青がそれぞれ1bitずつON/OFF可能であり、8通りの組み合わせができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/f3c51f6d-9751-9872-7f07-a9e6ae4a4fd6.png)
**仕様書:** http://www.furutaka-netsel.co.jp/pdf/optrex/optrex_F-51373GNC-LW-AJ.pdf

#ハードウェア仕様
裏に0.5mmピッチ 22ピンのフレキシブルフラットケーブルのコネクタがある。

- 電源 3
 - ロジック用電源: 2.7V ~ 5.5V
 - 液晶駆動用電源: 22.5V ~ 25.9V
 - バックライト用電源: ~ 12.4V
- 信号 12
 - FLM：フレームの開始
 - LP：1行の分のデータ転送
 - CP：D7~D0のデータ読み込みクロック
 - DISPOFF：H=点灯、L=消灯
 - D7~D0：8bitパラレル転送

#制御仕様
データ転送フォーマットは下記図の通り。
240ドット分のRGBデータを8bitずつ90回転送し、それを320回繰り返して1フレームとする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/7e104b38-03aa-b8c2-66de-f8924d0fe775.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/cab58fb1-6aaa-1821-a3ee-d6b145ca01ec.png)

#動作時のメモ
- MBED(LPC1768)で制御時、1フレームの転送時間は4ms
- データサイズは 90*320 = 28,800 byte
- 電源はUSBから取りたかったので液晶駆動電源もバックライト用電源もDCDCで5Vから昇圧した
- 消費電力の実測値はMBED側のUSBが5.1V 90mA、DCDC2個側のUSBが5.1V 210mAだった
 - DISPOFFをLにしても消費電力は下がらない
- VLCDが上がり切るまでDISPOFFをHにしてはならない仕様
 - DISPOFFを外付けの10kでプルダウン
 - VLCDを分圧して制御マイコンに入力しVLCDを確認
PythonとOpenCVで画像をアスキーアート化するプログラムを作った

# はじめに
先日、[ASCII Camera](https://andrei.codes/ascii-camera/)という面白いサイトを見つけました。
![picture_pc_3c309a4cbd82ecc52c545a04da630a0b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/14540b98-c93e-5269-2f32-c89e164881d5.png)
こんな風に、ブラウザからカメラ映像を取得してASCII文字列に変換してくれます。

このぐらいだったらもしかして自分で作れるんじゃないかと思ったので、画像をアスキーアートに変換するプログラムを作ってみることにしました。

# 仕組み
仕組みとしては、以下のようになります。

1. 画像をグレースケールに変換する
2. 各ピクセルの色の濃さを取得し、それに応じて文字を決定する
3. 列ごとに改行する

PythonとOpenCVを使えばこれらの処理をかなり簡単に行えます。

## グレースケールに変換
読み込む画像のパスはinputで取得するようにします。
これでグレースケールに変換され、grayには各ピクセルの濃度(0～255)が格納されます。

```Python
import cv2

imgpath = input("Path: ")
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
```

## ASCII文字を決定する
各ピクセルの濃度(0～255)ごとにASCII文字を決定する必要がありますが、実際に使えるASCII文字は256個もありません。
仕方がないので、使う文字を64個に厳選し、濃度を4ごとに区切って文字を選ぶことにしました。
例えば濃度が0～3なら「M」、252～255なら「 (空白)」、といった具合です。

以下が「濃度が高い」順番に並べた64個の文字です。

<pre>MWN$@%#&B89EGA6mK5HRkbYT43V0JL7gpaseyxznocv?jIftr1li*=-~^`':;,. </pre>

この順番を決めるのがけっこう大変でした。
順番は見た目で決めただけなので、超適当です。

変換処理はこんな感じになりました。

```Python

colorset = "MWN$@%#&B89EGA6mK5HRkbYT43V0JL7gpaseyxznocv?jIftr1li*=-~^`':;,. "

for gray2 in gray:
    output += "\n"
    for dark in gray2:
        output += colorset[dark // 4] * 2
```

濃度を4で割って切り捨てることで、ちょうどよくcolorsetのインデックスを取得できます。
ASCII文字の縦横比は2:1なので、書き込む文字を2倍にしています。

# 完成
完成したプログラムはこんな感じです。
結果はファイルに出力する形式にしました。

```Python
import cv2

colorset = "MWN$@%#&B89EGA6mK5HRkbYT43V0JL7gpaseyxznocv?jIftr1li*=-~^`':;,. "

imgpath = input("Path:")
img = cv2.imread(imgpath)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
output = ""

for gray2 in gray:
    output += "\n"
    for dark in gray2:
        output += colorset[dark // 4] * 2

with open("output.txt", mode="w") as f:
    f.write(output)
```

試しに私のアイコン(これ↓)を変換してみます。
![nico.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/60a477e9-190f-6436-e544-c709de670b2e.png)
結果は...

![スクリーンショット (148).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/293c74e7-5b21-6de2-ba5e-abe36b6d5b99.png)

こんな感じ。
意外とちゃんと変換できていてびっくりしました。

次に、ぱくたそ様から頂いたイギリス北部の自然風景のフリー画像を、300×200pxに変換したもので試してみます。
![elly20160701265118_TP_V.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/29db1c14-764d-84b7-cb64-352bfc8ed72a.jpeg)
結果は...

![スクリーンショット (146).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/8364f26e-4d95-5dc3-3975-c981ab414206.png)
うん...まあいい線いってるんじゃないですかね。

最後に、[This person does not exist](https://thispersondoesnotexist.com/)という、AIが顔写真を自動生成してくれるサイトで入手した、
![image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/70664f48-8e81-4d79-e974-436eb56da20a.jpeg)
この画像を250×250pxに変換して実行してみます。

結果は...

![スクリーンショット (147).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624097/b8892c8b-96f2-6f81-a006-33492396c2e1.png)
かなりいい感じですね！
これは良い...頑張った甲斐があった...

# おわりに
という訳で、たった12行のコードで実現できてしまいました。
今回初めてOpenCVに触れたのですが、こんなに便利だとは思いませんでした。
これと同じことを256文字のUnicodeでやってみるのも面白いかもしれません。

# 参考文献
* [Python, OpenCV, NumPyでカラー画像を白黒（グレースケール）に変換](https://note.nkmk.me/python-opencv-numpy-color-to-gray/)
* [Python, NumPyで画像処理（読み込み、演算、保存）](https://note.nkmk.me/python-numpy-image-processing/)
【Python】matplotlib.pyplot のメモリリークの対処法

以下の様に描画用のプロセスを別途作成・終了させればメモリリークを防げます。

```python
from multiprocessing import Pool
import matplotlib.pyplot as plt
import numpy as np

# プロット用のメソッド
# plt.clf() や plt.close() をしなくてもプロセス終了時に自動でメモリが解放される。
def plot(args):
    x, y = args
    plt.plot(x, y)

# プロットする値
x = np.arange(1e7)
y = np.arange(1e7)

# プロット用のプロセスを作成し、その中で描画処理を行う
p = Pool(1)
p.map(plot, [[x,y]])
p.close()
```

実際にメモリが解放されているかは以下のコードで確認できます。

```python
from multiprocessing import Pool
import matplotlib.pyplot as plt
import numpy as np

# プロット用のメソッド
# plt.clf()・plt.close() をしなくてもプロセス終了時に自動でメモリが解放される。
def plot(args):
    
    x, y = args
    plt.plot(x, y)
    
    # 検証用に以下をしても良い
    plt.tight_layout()
    plt.savefig('aa.jpeg')

# 10回プロットしてメモリ使用量が変わらないかを調べる
for i in range(10):
    
    # プロットする値
    x = np.arange(1e7)
    y = np.arange(1e7)
    
    # プロット用のプロセスを作成し、その中で描画処理を行う
    p = Pool(1)
    p.map(plot, [[x,y]])
    p.close()
    
    # メモリ使用量を表示
    import psutil
    mem = psutil.virtual_memory().free / 1e9
    print(i, f'memory used: {mem} [GB]')
```

ちなみに、例えば以下の様な場合にメモリリークが起こります。（参考：[plt.close() だけではメモリが解放されない場合がある - Qiita](https://qiita.com/Masahiro_T/items/bdd0482a8efd84cdd270)）

- ``plt.close()``しかしていない場合
- ``plt.clf()`` → ``plt.close()`` をしているが、``plt.tight_layout()``や``plt.savefig()``をしている場合
「ディープラーニングで音声分類」をやってみた


ディープラーニングで音声分類
https://qiita.com/cvusk/items/61cdbce80785eaf28349

こちらの記事のコードを実行してみました。
メモを載せています。

#環境
・Windows10
・jupyterではエラーが出たのでAnaconda navigatorからpython 3.7のコマンドプロンプトを開いて実行していきました。

#メモ

・Kerasとtensorflowのバージョンによってはエラーが出て、試行錯誤の結果以下のバージョンを採用

Keras                  2.0.7
tensorflow             1.15.3

・下記はどうやら不要（実行するとテストデータの数が合わなくなる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543160/d067de82-0cab-b257-4390-d9e97e9c36d0.png)



・下記でエラーが出てamsgrad=Trueを削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543160/520bb1b1-e52c-ed98-a5c5-62d378d56876.png)

#音声分類プログラムを実行した感想
epochを試しに5に設定して学習させたところ自分のPCでは１時間半かかりました。
パソコンはハイスペックなものを使用してますが、gpuで計算しないと厳しそうです。




（記事作成中）
Unity - URPで遠くのマテリアルが薄くなる時の解決方法

# 環境
Unity2019.3.12f1
URPテンプレート

# 問題
Gameビュー（Simulationビュー）およびSceneビューでカメラから離れたオブジェクトのマテリアルが薄くなる現象が発生していた。
![コメント 2020-06-08 023822.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205347/1ade6c5c-d5b7-d50e-3363-2f5e5e036b18.jpeg)
SRP（スクリプタブルレンダーパイプライン）を触り始めて間もないため、特にレンダリング周りはまだ理解できていない部分が多い。
環境設定はURPテンプレートで立ち上げてから一切触っていないため、これはSRPの何かしらの都合があっての仕様だとしたら「問題」という言い方はおかしいのかもしれない。
しかしながら今回は、描画されているオブジェクトのマテリアルは均一な濃度で描画したかったため、これを解決（というか変更）したかった。

# 解決策
1. Window＞Rendering＞Lighting Settingsを開く
1. SceneタブのOther Settings＞Fog＞Densityがデフォルトで0.05になっているためこれを0に変更する
![コメント 2020-06-08 023941.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205347/f46e61c0-0fda-4c48-9b64-aa34c36bbf77.jpeg)

# 解決に至った経緯
1. オブジェクトは映っているため描画距離が原因ではなさそう
1. MainCameraの設定項目を1つずつ全て変更して確認してみたが変化はない
1. 他に描画系の設定は無いかと思い、SceneビューのEffectトグル（![コメント 2020-06-08 025032.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205347/530e36ee-2070-60da-6fcd-550a79713d2e.jpeg)
）のFogのOn/Offを変更したらFogのせいと判明

![コメント 2020-06-08 023848.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205347/390608aa-5e2a-065b-3c9e-9875f8a1aaa2.jpeg)
↓FogをOnからOffに変更
![コメント 2020-06-08 024132.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205347/abc26f04-d410-fecf-f4c5-e7f7f61da649.jpeg)
PythonでJSONファイルを作成する方法

## はじめに
Pythonのjsonモジュールでは、JSONファイルを読み込んだり、JSON形式のオブジェクトを書き込むことはできるが、JSONファイルを作成することはできない。JSONファイル作成を、必要に迫られ実装したので、メモとして残しておく。

公式ドキュメントより
https://docs.python.org/ja/3/library/json.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489653/6d11c838-e4a5-bd6c-c70f-e07f62173eba.png)

## 実装方針
- 書き込みたいJSONファイルが空なら [ を挿入する
- JSON形式のオブジェクトを挿入する
- 末尾に ] を挿入する
- 次に挿入するとき、末尾が ] なら , に置き換える

## 実装例
以下の3ファイルは同階層にあるものとする


```python:json_make.py
import json
from pathlib import Path

def json_make(path: Path, obj: dict) -> None:
    ls = None
    with open(path, 'r+') as f:
        ls = f.readlines()
        if ls == []:
            ls.append('[\n')
        if ls[-1] == ']':
            ls[-1] = ','
        ls.insert(len(ls), f'{json.dumps(obj, indent=4 ,ensure_ascii=False)}')
        ls.insert(len(ls), '\n]')

    with open(path, 'w') as f:
        f.writelines(ls)
```

```python:main.py
from json_make import json_make
from pathlib import Path

def main():
    path = Path(__file__).parent/'tmp.json'
    dict_obj = {'key1':'value1', 'key2':'value2', 'key3':['value3', 'value4']}
    json_make(path, dict_obj)


if __name__ == '__main__':
    main()
```

json.dumps(indent = 0) の場合

```python:tmp.json
[
{"key1": "value1", "key2": "value2", "key3": ["value3", "value4"]}
,{"key1": "value1", "key2": "value2", "key3": ["value3", "value4"]}
,{"key1": "value1", "key2": "value2", "key3": ["value3", "value4"]}
,{"key1": "value1", "key2": "value2", "key3": ["value3", "value4"]}
]
```

json.dumps(indent = 4) の場合

```json:tmp.json
[
{
    "key1": "value1",
    "key2": "value2",
    "key3": [
        "value3",
        "value4"
    ]
}
,{
    "key1": "value1",
    "key2": "value2",
    "key3": [
        "value3",
        "value4"
    ]
}
,{
    "key1": "value1",
    "key2": "value2",
    "key3": [
        "value3",
        "value4"
    ]
}
,{
    "key1": "value1",
    "key2": "value2",
    "key3": [
        "value3",
        "value4"
    ]
}
]
```
## 参照
[公式ドキュメント](https://docs.python.org/ja/3/library/json.html)


## 終わりに
もっと良い書き方があれば教えてください