OmniAICreator/Qiita-1.07M huggingface dataset:
脱Excel Elastic Stack（docker-compose）でcsvログを分析・可視化 - multilineの中の"年/月/日,時:分:秒"をgrokフィルタでパースし、日本時間として扱う

## はじめに
どうも！生産技術部で製品の検査工程を担当しているエンジニアです。[脱Excel Elastic Stack（docker-compose）でcsvログを分析・可視化 - Elastic Stackとは](https://qiita.com/TomoyukiSugiyama/items/619ab258ba230dfcf0a0)の続きになります。

## 対象読者
この記事では、Elastic Stackをそもそも知らない方、これから試そうと思っている方を対象としています。

## この記事の内容
* このように年/月/日の順で並んでスラッシュ区切りの日付は、標準のgrokフィルタでパースすることはできません。カスタマイズしたフィルタを用意し、パースできるようにします。
* Kibanaでグラフ化すると、logstashでパースしたデータのTimezoneが標準でjpではないため、時刻がずれて表示されてしまう問題を解決します。

```csvs
Date,2020/10/30,12:20:50
```


GitLabに設定ファイル一式を置いておきましたので参考にしてください。
リポジトリはこちら -> [elastic-stack](https://gitlab.com/iyama_yuki/elastic-stack/-/tree/master/)

## カスタムパターンを用意
まず、標準で用意されているgrok-patternsはこのようになっています。DATEを使うと年月日の順番が合いません。また、TIMESTAMP_ISO8601は年月日がハイフン区切りとなっています。公式サイトのカスタムパターンについての説明は[こちら](https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html#_custom_patterns)です。

```yml
# Months: January, Feb, 3, 03, 12, December
MONTHNUM (?:0?[1-9]|1[0-2])
MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])

# Years?
YEAR (?>\d\d){1,2}

# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it)
DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR}
DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}
TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
DATE %{DATE_US}|%{DATE_EU}
```

年月日の順で並べたDATE_JPを用意し、TIMESTAMP_JPに標準のTIMEとカンマ区切りで組み合わせます。

```yml:logstash/extra_patterns/date_jp
DATE_JP %{YEAR}[/-]%{MONTHNUM}[/-]%{MONTHDAY}
TIMESTAMP_JP %{DATE_JP}[,]%{TIME}
```


## カスタムパターンを使う
作成したdate_jpファイルを`/opt/logstash/extra_patterns`に割り当てます。

```yml:docker-compose.yml
  logstash01:
    build: ./logstash
    container_name: logstash01
    links:
      - es01:elasticsearch
    volumes:
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
      - ./logstash/config/jvm.options:/usr/share/logstash/config/jvm.options
      - ./logstash/config/log4j2.properties:/usr/share/logstash/config/log4j2.properties
      - ./logstash/config/pipelines.yml:/usr/share/logstash/config/pipelines.yml
      - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
      - ./logstash/extra_patterns/date_jp:/opt/logstash/extra_patterns
    networks:
      - esnet
```

patterns_dirにextra_patternsを設定する。
カスタムパターンのTIMESTAMP_JPを利用し、read_timestampフィールドを作成します。

```yml:logstash.conf
filter {
  grok {
    patterns_dir => ["/opt/logstash/extra_patterns"]
    match => { "message" => "%{TIMESTAMP_JP:read_timestamp}" }
  }
}
```

## タイムゾーンをAsia/Tokyoに設定
logstashは、デフォルトが文字列型であるため、read_timestampも文字列型となります。タイムスタンプとして認識されないため、dateフィルタを用いて、date型に変換します。dateフィルタのtimezoneをAsia/Tokyoに設定し、targetを@timestampに割り当てます。

```yml:logstash.conf
filter {
  grok {
    patterns_dir => ["/opt/logstash/extra_patterns"]
    match => { "message" => "%{TIMESTAMP_JP:read_timestamp}" }
  }
  date {
    match => ["read_timestamp", "yyyy/MM/dd,HH:mm:ss"]
    timezone => "Asia/Tokyo"
    target => "@timestamp"
  }
}
```

## 最後に
カスタムパターンを使った日付のパースとtimezoneの設定について説明しました。
今後は、csvファイルの扱い方などについて紹介したいと思います。
gcc で explicit specialization in non-namespace scope エラー

クラス内でテンプレート特殊化を定義すると発生します(C++11 想定)

```
class MyClass {

  template <class T>
  static bool SetValue(const std::vector<T>& v, BaseHandler& handler)  {
    if (!handler.StartArray()) {
      return false;
    }

    for (size_t i = 0; i < v.size(); i++) {
      if (!SetValue(v[i], handler)) {
        return false;
      }
    }

    return handler.EndArray(v.size());
  }

  // Error!
  template<>
  bool SetValue(const std::vector<float>& v, BaseHandler &handler) {
    ...
  }
}
```

clang, MSVC では発生しないですが, 仕様としては gcc のほうが正しいようです.

http://www.cplusplus.com/forum/general/58906/#msg318049

## 解決方法

クラスの外(e.g. .cpp)で特殊化のコードを記述すれば解決します.
OwlgardenRPA - 遊んでみる3

# 遊んでみる その3

1. 登録用のデータテ－ブルを構築
2. データテーブルを再構築（列フィルタリング）
3. CSV出力
4. デモサイトの登録ページへ移動
5. データテーブルの内容を使って一件登録

## 共通変数定義
| 変数名 | データ型 | 備考 |
|:-:|:-:|:-:|
| data_default | テーブル型 | 初期構築用 | 
| data_temp | テーブル型 | 列フィルタリング用 | 
| data_input | テーブル型 | 登録データの登録用 | 

## シナリオの流れ

### 1. 登録用のデータテ－ブルを構築

- 変数パネルから以下のように定義（変数：data_default）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340394/eb4b360a-d15d-7d39-545d-f363abf44d1e.png)

- COM名：テーブル項目値置き換え
    - 変数パネルではテーブル項目しか初期設定できないため、無理やり初期値設定。
    - 但し、このCOMでは1行ずつしか追加できない模様（しかも2行目の追加方法は不明）
    - また、置き換え後の結果を同じテーブル型変数に上書きすることはできない。

| プロパティ名 | 設定値 |
|:-:|:-:|
| 対象テーブル | data_temp |
| 置き換え後テーブル | data_input |
| 項目値置き換え設定 | （※以下参照） |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340394/a990169b-f7bb-16e6-4898-a701406dd74f.png)


### 2. データテーブルを再構築

- COM名：テーブル型変数再構築
    - 一件データ追加後のデータテーブルから、日付列を取り除く。
    - また、再構築後の結果を同じテーブル型変数に上書きすることはできない。

| プロパティ名 | 設定値 |
|:-:|:-:|
| 対象テーブル | data_default |
| 再構築テーブル | data_temp |
| 再構築設定 | （※以下参照） |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340394/5b247f04-03bc-6ddc-7aa4-8409acef681d.png)

### 3. CSV出力

- COM名：CSV出力
    - ファイルがない場合は新規作成可能
    - テーブル項目（ヘッダ）出力可能
    - 上書きまたは追記の選択可能

| プロパティ名 | 設定値 |
|:-:|:-:|
| 対象テーブル | data_input |
| CSVファイルパス | （任意のパスを設定） |

### 4. デモサイトの登録ページへ移動

- COM名：アプリケーション実行
    - U○Pathのデモサイトを使わせてもらおう…

| プロパティ名 | 設定値 |
|:-:|:-:|
| 実行パス | （chromeの実行パスを設定） |
| 実行引数 | "--new-window https://www.expense-demo.com/" |

- COM名：クリック
    - 経費登録ボタンを押下

- COM名：クリック
    - 明細登録ボタンを押下

### 5. データテーブルの内容を使って一件登録

- COM名：文字貼り付け

| プロパティ名 | 設定値 |
|:-:|:-:|
| 入力文字 | data_input.rows(1).column("タイトル") |

- COM名：リストボックス選択

| プロパティ名 | 設定値 |
|:-:|:-:|
| 入力文字 | data_input.rows(1).column("種別") |

- COM名：文字貼り付け

| プロパティ名 | 設定値 |
|:-:|:-:|
| 入力文字 | data_input.rows(1).column("金額") |

- COM名：文字貼り付け

| プロパティ名 | 設定値 |
|:-:|:-:|
| 入力文字 | data_input.rows(1).column("備考") |

- COM名：クリック
    - 登録ボタンを押下

- COM名：クリック
    - 戻るボタンを押下

![pic_06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340394/822e05ec-309c-d03a-ef47-acb959ef3208.jpeg)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340394/a83231da-28b5-50cb-90d9-1ade838ee0d8.png)

## テーブル型変数

- シナリオ内でテーブル型変数を作成し、そのデータを登録に使うといった処理は普通ありえないと思うので、変数パネルから初期値が設定できないというもやもやは仕方がない。ただ、できればデータを地産地消して試してみたかったので、テーブル型変数に関してできることがやや限られているのはちょっと残念。テーブル型変数関係は初学者には難しいので、UIにはかなりこだわって作られている印象がある。その反面、できることが限定されてしまったという感じであるか。
- また、テーブル型変数に限ったことではないが、プロパティ値に設定ミスが発生した際、ミスが解消されるまで他の項目へ移動できなくなるのは地味に使いづらい（涙）

![pic_07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340394/327a35ea-0c1b-1670-63e7-b6348eed14b2.jpeg)
Rails 直打ち禁止の方法 （URL入力で他人の編集画面へ遷移させない）

#　直打ち禁止ってなんだ
プログラミング歴が７ヶ月と、まだまだ右も左もわかりません。
課題をこなしてく中で、「*投稿者のみ*が編集や削除ができるように設定してください。」という条件がありました。
これを、 **直打ち禁止**というそうです（URLに**直接** https:///XXX/edit と**打ち込む**ことで他人の投稿を編集できちゃから、、、直打ち？）。

![スクリーンショット 2020-10-31 18.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664818/fbd6abe3-ee14-356b-698a-8e0227086e9a.png)


なるほどなぁ...と想いながら月日が経って、ポートフォリオを作成する時期になり、完成後に直打ちできちゃうことが判明。
うっかり忘れてしまっていたので、備忘録として直打ち禁止の方法を記録します。

ログインしていない状態だと、*「投稿者のみ」*という判断ができないので、ログイン機能がないアプリやホームページはどうやるんだろうか。それは今後、調べて学んでいきます。
（ちなみに、それで直接予約サイトへ飛べちゃうので困ってる会社さんがいました...。）

とにかく、直打ち禁止をするのは簡単にもかかわらず、うっかり忘れてしまって結構大変なことになるので、忘れちゃいけない機能です！

#直打ち禁止のコード

まず、application_controllerに、before_actionメゾットを追加します。

```ruby:application_controller.rb
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
```

次に、直打ち禁止させたいcontrollerページを開きます。
（例えば、Postという名前の投稿ページだったら、post_controller.rb）

```ruby:post_controller.rb
class PostsController < ApplicationController
    before_action :authenticate_user!
    before_action :correct_post,only: [:edit,:XXX]
```

ちなみに、before_action :authenticate_user!　は、ログインしているユーザーのみ使えるようにする！という意味です。

before_action :correct_post,only: [:edit,:XX]を追加します。
:XXは他にも、直打ちしたくないアクションを追加します。

また、同じpost_controller.rbの下（privateより上）に下記のコードを追加します。

```ruby:post_controller.rb
def correct_post
        @post = Post.find(params[:id])
    unless @post.user.id == current_user.id
      redirect_to posts_path
    end
end
```

redirect_to posts_path　は、投稿者以外が直打ちした場合、飛ばすリンク先を記載してください。
以上で、直打ち禁止ができると思います！

ちなみに、correct_postと似ているのでcurrent_postというのがあります。
そのおかげで、私は頭の中がごちゃごちゃになってしまい、直打ち禁止のコード書いてるのになんで禁止されないんだ！と数分頭を抱えちゃってました。

こちらも合わせて気をつけたい点です。
デフォルト値付きの引数 Railsチュートリアルのfull_titleメソッドを例に

##対象者
・以下のRailsチュートリアル4章で出てくるfull_titleメソッドの引数(page_title = '')に違和感がある方 ・デフォルト値付き引数について理解していない方
full_title(page_title = '')
・Railsチュートリアル、チェリー本で学習している方

## 記事の目的
Railsチュートリアル4章のfull_titleヘルパーメソッドの引数(page_title = '')の部分について理解する。

初学者で勉強のアウトプットもかねてます。間違いがあれば、ご指摘下さい。

##Railsチュートリアル4章で出てくるfull_titleの引数である(page_title = '')とは？

【リスト 4.2: full_titleヘルパーを定義する】

```app/helpers/application_helper.rb
module ApplicationHelper
  # ページごとの完全なタイトルを返します。
  def full_title(page_title = '')
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      page_title + " | " + base_title
    end
  end
end
```
以下のRailsチュートリアルの説明にあるように、タイトルがなければ空欄にならないように・タイトルがあればページにより異なるタイトルに変更できるようにする為に、full_titleメソッドを定義しています。

>このとき、もしタイトルをまったく与えていなければ、タイトルが空欄になってしまいます。これを防ぐには、すべてのページで使う基本タイトルを定め、特定のページでは異なるタイトルに変更できるようなオプションを与えるのが常套手段です。

こちらで出てくるメソッドの引数である(page_title = '')の部分に私は、「なんだこれ？」と違和感を感じましが、一度流したチェリー本の[2.11.1のデフォルト値付きの引数]の部分を見たら、理解できました。

##デフォルト値付きの引数とは？（チェリー本より引用）
デフォルト値付きのメソッドの構造は以下の通り。

```
def メソッド（引数 = デフォルト値1, 引数2 = デフォルト値2）
# 必要な処理
end
```
以下はチェリー本のデフォルト値付きメソッド例文です。

```
 def greeting(country = 'Japan')
  if country == 'Japan'
    'こんにちは'
　else
    'hello'
  end
 end

#メソッドの呼出の結果
 greeting #=> "こんにちは"
 greeting（'us'） #=> "hello"
```
上の例だと、デフォルト値は(country = 'Japan')の部分ですね。
チェリー本の解説によると、デフォルト値付きの引数は、メソッドの引数を柔軟に変える方法の1つとして紹介されています。
通常メソッドを呼び出す際に引数の過不足があるとエラーになるが、上のようにデフォルト値を設定するとgreetingと引数なしで呼び出した場合でもエラーにならず、"こんにちは"と表示されるのです。

なるほど！！まとめます。

##上の例でまとめると、、、

「空であれば、｜なしで"Ruby on Rails Tutorial Sample App"と表示させたい」
「引数付きで呼び出されたら、引数 + " | " + "Ruby on Rails Tutorial Sample App"と表示させたい」
という目的に対して、

メソッドの引数を柔軟に変えられるデフォルト値付き引数である(page_title = '')
を使って、引数あり・なしで表示を変えている、と言えますね。
buttonタグでdivタグ全体をボタンにし、フォームでPOSTしたい！

こんにちは、JeffTechです。

# この記事で実現できること
buttonタグを親要素のdivタグ全体に広げて、ボタン(リンク)を作成し、フォームでPOSTできるようにします。
aタグで紹介している記事は多数あったのですが、buttonタグで紹介している記事が見当たらなかったので、書いていきます！

# 開発環境
OS：macOS Catalina
テキストエディタ：VSCode
ブラウザ：Chrome
使用言語：HTML, CSS

# 実装
## HTML

```html:index.html
<form action="送信先" method="POST" name="form_post">
  <div class="linkbox">
    <p>タイトル</p>
    <p>これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文これは本文</p>
    <input name="user_id" type="hidden" value="ここに送りたい値を記述">
    <button type="submit"></button>
  </div>
</form>
```
これで親要素のdivタグの中に、buttonタグを配置して準備は完了しました。
formタグ→divタグ→buttonタグの順番でコーディングしてください。

## CSS
```css:style.css
.linkbox {
    position: relative;

    /* ここはボタン位置がわかりやすいように設定しています */
    background-color: aqua;
    height: 200px;
    width: 500px;
}
.linkbox button {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;

    /* buttonのスタイル削除 */
    background-color: transparent;
    border: none;
    cursor: pointer;
    outline: none;
    padding: 0;
    appearance: none;
}
```

まずはポジションを使用して、buttonタグを浮き上がらせて、buttonタグのスタイルをすべて削除することで、スケスケのbuttonタグが出来上がるというイメージです。

# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
GASでカレンダーのイベント作成者一覧（重複なし）を出力する。

googleカレンダーを用いて、備品や会議室の予約表を使っています。
トラブルなどでしばらくそれらが利用できない場合、"使えなくなってしまったので代替手段を取ってちょんまげ"メールを出すことがありますね。
カレンダーを利用している全員に出しても良いのですが、予約している（イベント登録している）人だけに伝えると、スマートかなと思いました。

＊と記事を書いてて、利用できないことを周知する意味もあるので、全員にメール出した方が良さそう。そうなると記事の価値がパアなので続けますワニ🐊

#ソースコード
```
const CALENDAR_ID = '＊＊＊＊＊＊＊＊＊＊＊＊'; //カレンダーID

function getCalendarEventCreatorList() {
  const calendar = CalendarApp.getCalendarById(CALENDAR_ID); // 検索元カレンダー
  const startDate = new Date('2020/10/01 00:00:00'); // 検索開始日
  const endDate = new Date('2020/11/01 00:00:00'); // 検索終了日

  let creatorName; // イベント作成者
  let creatorList = []; // イベント作成者一覧

  // 開始日から終了日のイベントを取得
  const events = calendar.getEvents(startDate, endDate);
  
  // イベント数分繰り返す
  for(const event of events){

    // 作成者の取得
    creatorName = event.getCreators()[0];
  
    // 今までのイベント作成者一覧に登録されていなければ、
    if(creatorList.indexOf(creatorName) === -1){
      
      // イベント作成者一覧に登録する
      creatorList.push(creatorName);
    }

  }
 
 // イベント作成者一覧の出力
 console.log(creatorList);
}
```

#注意点
・カレンダーのイベント作成者を取得するので、イベント内容は見ていません。
　例えば、スマホ端末管理カレンダーでNo.10のiPhone利用者だけを抽出というのは、もうひと手間必要になります。

#参考にさせて頂いたURL
https://tonari-it.com/gas-calendar-getevents/
https://teratail.com/questions/134118
https://qiita.com/takeharu/items/d75f96f81ff83680013f
https://www.wakuwakubank.com/posts/485-javascript-include-array-string/
サーバーリソースモニタリング用のコマンド


# はじめに

最近はサーバーリソースを監視するためのツールが色々あります。しかし、たまにコマンドでも確認したいことがあるため備忘的にアウトプット。

# dstat

`dstat`とは簡単に説明するとCPU負荷をコアごと、IO負荷をディスクごと、ネットワーク転送量をインターフェイスごとに表示できるコマンド。 topやiostat,netstatを使って監視しているリソースがコマンド1つで監視できます。
引用：https://qiita.com/ryuichi1208/items/387fa1cba44690c3db9b

```bash:dstat.sh
# ---------
# シェルにしておく方が何かと扱いやすいのシェルを作成
# ---------
# ログ出力先のディレクトリを作成
mkdir /home/log/dstat/

# シェルの内容
echo '#!/bin/sh' > /home/takiguchi-yu/dstat.sh
echo "dstat -T --cpu --disk -D sda10 --load --mem --net --swap -g --output /home/log/dstat/dstat-\`hostname -s\`-\`date +%Y-%m-%d-%H\`.csv 1 3599" >> /home/takiguchi-yu/dstat.sh

# 実行権限付与
chmod 755 /home/takiguchi-yu/dstat.sh
```

```bash:crontab
crontab -e

# dstat log
0 * * * * /home/takiguchi-yu/dstat.sh > /dev/null
```

出力結果
![スクリーンショット 2020-10-31 17.43.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59081/eecec1fe-6fa7-1467-7311-fb970f9a912d.png)

# jstat

`jstat`ツールは、設置されている HotSpot Java 仮想マシン (JVM) のパフォーマンス統計データを表示します。ターゲット JVM は、仮想マシン識別子、つまり下記の vmid オプションによって識別されます。
引用：https://docs.oracle.com/javase/jp/1.5.0/tooldocs/share/jstat.html

```bash:jstat.sh
# ---------
# シェルにしておく方が何かと扱いやすいのシェルを作成
# ---------
# ログ出力先のディレクトリを作成
mkdir /home/log/jstat/

# シェルの内容
echo '#!/bin/sh' > /home/takiguchi-yu/jstat.sh
echo "/usr/java/jdk/bin/jstat -gcutil | awk 'NR>1 {print strftime("%Y/%m/%d %H:%M:%S"),$0} {system(":")}' | sed -r 's/  +/,/g' >> /home/log/jstat/jstat_\`hostname -s\`-\`date +%Y-%m-%d-%H\`.log" >> /home/takiguchi-yu/jstat.sh

# 実行権限を付与
chmod 755 /home/takiguchi-yu/jstat.sh
```

```bash:crontab
crontab -e

# jstat log
* * * * * for i in `seq 0 5 59`;do (sleep ${i}; /home/takiguchi-yu/jstat.sh) & done;
```

# tcpdump

`tcpdump`とはネットワーク通信の生のデータをキャプチャし、その結果を出力してくれるキャプチャツールです。
引用：https://qiita.com/tossh/items/4cd33693965ef231bd2a

```bash:tcpdump.sh
# ---------
# シェルにしておく方が何かと扱いやすいのシェルを作成
# ---------
# ログ出力先のディレクトリを作成
mkdir /home/log/tcpdump/

# シェルの内容(ポート番号はサンプルなので適宜変更)
echo '#!/bin/sh' > /home/takiguchi-yu/tcpdump.sh
echo "tcpdump -i eth0 -s 0 -w /home/log/tcpdump/tcpdump-`hostname -s`-%Y-%m-%d-%H.pcap -G 3600 -Z root -z gzip \( tcp port 9160\) or \( tcp port 7000 \)" >> /home/takiguchi-yu/tcpdump.sh

# 実行権限付与
chmod 755 /home/takiguchi-yu/tcpdump.sh
```

```bash
# 実行
sh /home/takiguchi-yu/tcpdump.sh
```

tcpdumpは[wireshark](https://www.wireshark.org/)を使えば中身を可視化できます。
MacであればHomebrewでインストール可能です。
Liquidで配列を作る、要素を追加する

配列を作るには```split```というフィルターを使うしかない。

```liquid
{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}
{% for member in beatles %}
  {{ member }}
{% endfor %}
```

```
John
Paul
George
Ringo
```

そして、要素を追加するには、文字列として結合してから、最後に```split: ","```する。
Rubyの```push```的なものはない。

```liquid
{% assign words = "" %}
{% assign words = words | append: "John" | append: "," | append: "Paul" |append: "," | append: "George" | append: ","| append: "Ringo" %}
{% assign array = words | split: "," %}

{% for member in array %}
  {{ member }}
{% endfor %}
→上と同じ出力結果
```

煩雑ですが、しょうがないですね。

ちなみに、
要素を追加するかfor文を回して配列の元になる文字列を結合していく時、条件によって文字列を足すか足さないかすると、```,```が最後に残ってしまって、正しく配列が生成できなかったりします。
そういった時は、```,```を文字列の最初に含めて足していって、最後に```remove_first: ","```するといいです。

```liquid
{% assign words = "" %}
{% for word in someArray%}
  {% if forloop.index0 == 0 or forloop.index0 == 2 or forloop.index0 == 4 %} {% comment %}この条件文稚拙ですが例としてとりあえず{% endcomment %}
    {% assign words = words | append: "," | append: "word" %}
  {% endif %}
{% endfor %}
{% assign words = words | remove_first: "," %}
{% assign array = words | split: "," %}
```

```forloop.index0``` は、for文の中で、何回目の繰り返しなのかを返します(0から始まる。```index1``` で1から始まる)


##参考
split
https://shopify.github.io/liquid/filters/split/
append
https://shopify.github.io/liquid/filters/append/
remove_first
https://shopify.github.io/liquid/filters/remove_first/
forloop
https://shopify.dev/docs/themes/liquid/reference/objects/for-loops
​経験ゼロから始めるIoT - 勉強会に参加した

## 開催日程
* 2020年10月29日（木曜日）

## 場所
* オンライン

## 主催
* SORACOM株式会社

## 申し込み
* https://www.hello.soracom.jp/20201029?id=cp

## 費用
* 無料


## セッション - IoT 事例からひも解く「SORACOMが選ばれた理由」
### 概要
* IoT契約回線数は200万回線を超え、さまざまな業界の15,000を超えるお客様がSORACOMをご活用いただい。お客様の事例やシステム構成を元に、IoTプラットフォームSORACOMのサービス概要と採用理由、よくあるIoTの困りごとの解決策をお届ける


### 可視化
* 事例
    * ソーラーカーのバッティリー状況をリアルタイムで収集、可視化
    * 海老の養殖池の水温を遠隔モニタリング
* ソラコムサービス
    * Harvest: データ収集、保存、可視化
    * Lagoon: ダッシュボード作成、共有

### データアップロード/双方向通信
* 事例
    * 天然水を必要なタイミングにお届け、自動再注文を実現するIoTウォーターサーバー
    * 海外のエレベーター遠隔監視
        * エレベーターの状況を遠隔で把握、故障発生時の早期把握と対応
* ソラコムサービス
    * Beam: データ転送支援
    * Funnel: クラウドアダプター
    * Funk: クラウドファンクション

### リモートメンテナンス
* 事例
    * POSレジのバックアップ回線をモバイル回線に切り替え
        * 全ての店舗のPOSレジのバックアップ回線をIP-VPNからSORACOMのモバイル回線に
    * クックパッドの受け取り冷蔵庫、ラベルプリンターの遠隔操作と監視を実現
* ソラコムサービス
    * Canal: プライベート接続(AWSのVPCと接続)
    * Door: VPN接続(プライベートクラウドと接続)
    * Direct: 専用線接続

### B2C製品のユースケース
* 事例
    * 74の言語で双方向のコミューニケーションを実現、クラウド型通訳機
    * 日本へ旅行者向けのSIM： SORACOM AirでAPI運営を自動化
* ソラコムサービス
    * Air


### まとめ
* ソラコムサービスより、どうなことを実現できることがわかった
* ソラコムサービスの便利性
Power Automateで月末に予定表から実績時間を工数を出してExcelに貼付　サラリーマンSE故、工数報告は大事

#できたもの



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/161a9a7b-db94-8403-d80d-50fb01b16b35.png)
変な時間に働いてるな。と思ったら、タイムゾーンがUTCでした。
<FONT COLOR=red> **でも、測りたい工数を計算出来ているからよし！**</FONT>

#何故やったのか
わたくし、サラリーマンSEでして、毎月何の作業にどれだけ時間を使ったか報告する必要があります。
Excelを毎日__分類とか作業内容とか記入してってやるのが面倒__（見なければいけないツールをなるべくしぼりたい。）なので、
予定表は絶対開くからそこに書いておけばいいや。と思って今回のことを思い立ちました。

たぶんいいツールあるんだろうなーと思いながら、
使ってよいツールが限られている状態のため、今使ってよくて簡単に仕組みも作れるもので工数計算するやつ。

#ソースじゃないけど、フロー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/f97cd624-f642-7db6-2e83-043ab5ae0b2d.png)
Outlookからイベントを抽出→
今月分だけという条件を付ける→
Excelに追加したいことを行追加。

#ここに気をつけろ！
１．予定はイベントという言葉で扱われている。
　　データどこにあるねん。って思いました。イベントというところにあります。
　　https://qiita.com/Sugizo50073508/items/a4b68ce735dbd4de9ad6

２．OutputのExcelのシート内にテーブルを作っておかないといけない。
　　データを取り出せたはよいが、貼り付け先見当たらずエラーになります。
　　https://qiita.com/Sugizo50073508/items/34984b7c8f4e4712b4cb

３．PowerAutemateは大体UTC
　JSTに変えたかったら関数をかまさないといけない。(convertFromUtc)

４．工数の桁数というか単位
　開始と終了の引き算をするために、
　数値に戻す→引き算する→hourに戻す
　ということをやった。
　数値に戻すのに、ticksという関数をつかう。
　「いつからの時間やねん」みたいな「ある日時からの時間」をマイクロ秒で表している。
　引き算し後もマイクロ秒になる。
　Hourに戻すのに3600×1000万で割る前に、型をfloatにしないと、小数点以下が消えます。。。

#データ（予定表）を作るときに意識しておくこと
１．アウトプットでExcelにおとした時に、どう分類と作業内容を分解しておくか決めておく。
　　分類・内容などの区切り文字を決めておくと後の作業で扱いやすい。
　　ただ、他の人が入れてきた予定は自分が
　　MTGが多い人は大変ですね。他の人から入ってくることが多いでしょうし。
　　幸い私は自分で予定入れられます。

２．予定表で重複した時間なるべくなくす
　　並行して作業してたりするとなかなかつける時間が難しいですよね。
　　__計測したいモノがわかればよし！__
　　足したら1か月分超えてるよ。とかなるかもしれないですけどね！

#後で作ろうと思うもの
１．分類を抽出した項目

２．分類別のピボットテーブル

#環境
PowerAutomate O365
Excel O365
【初心者】Javaの基礎的な”配列”の記述

#javaの配列の書き方


Java初心者です。学んだことを記述していきます。


##1.配列 　
一個ずつ丁寧に配列を作った場合

```java

 String[] memo = new String[5];    //5個分の配列をmemo変数に代入

 memo[0] = "だいこん" ;
 memo[1] = "にんじん" ;
 memo[2] = "さば" ;
 memo[3] = "レモン" ;
 memo[4] = "からし" ;


 String fruits = memo[3] ;     //memo[3]の配列をfruitsに代入　　
 System.out.println( fruits );


（コンソール実行結果）

    レモン

```


#####上記の省略した書き方
```java
 String[] memo = {"だいこん","にんじん","さば","レモン","からし"};

 String fruits = memo[0] ;     
 System.out.println( fruits )
```



##2.二次元配列の記述
```java
 String[][] animal = {

      {"ワシ","タカ"},
      {"チンチラ","ハムスター"},
      {"インコ","ハト"},
      {"ダックスフンド","チワワ"}

 };


 System.out.println(animal[0][0]);   //　ワシ

 System.out.println(animal[0][1]);   //　タカ

 System.out.println(animal[1][0]);   //　チンチラ

 System.out.println(animal[1][1]);   //　ハムスター

 System.out.println(animal[2][0]);   //　インコ

 System.out.println(animal[2][1]);   //　ハト

 System.out.println(animal[3][0]);   //　ダックスフンド

 System.out.println(animal[3][1]);   //　チワワ

```

##Eclipseでコマンドライン引数の利用 手順

対象のファイルから　「実行」　→　「実行の構成」
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678283/ff3d2c3c-0402-4b00-5cdb-8a802e963b90.png)


対象のファイルを検索　→　選択
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678283/797af42d-7e1c-d4e0-1a10-9b4fb22df88d.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678283/7506eac8-d486-22e2-2c56-aafe811cd767.png)





「引数」を選択して「args」に配列情報を入力（複数の場合、スペースを置く）
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678283/6f0705ea-f67c-240c-3f46-ab48be7dba99.png)



　※argsは強制的にString型の配列のため注意　（整数などの場合はキャストする必要があります。）
```
int 変数 = Integer.parseInt(args[0])
```

```java

 class args {
      public static void main (String[] args) {
	
		String input1 = args[0] ;  //iOS入っている
		String input2 = args[1] ;  //Android入っている                    
		String input3 = args[2] ;  //windows入っている          
		String input4 = args[3] ;  //Macが入っている

		System.out.println( input1 );
		
		System.out.println( input2 );
		
		System.out.println( input3 );
		
		System.out.println( input4 );
		
      }
 }
```
メタタグ再入門 〜OGPを設定してみよう！〜

# はじめに
メタタグの設定って考えたことありますか？
コンテンツの見た目や動きに意識が行ってしまって、メタタグは初期設定のままとかあると思います！

今回はそんなメタタグに焦点をあてて、解説しました！

動画で確認したい方はこちらをどうぞ！
[【YouTube動画】 改めて勉強する HTMLのMetaタグの世界。](https://youtu.be/gIlR7x6jMlg)
[![改めて勉強する HTMLのMetaタグの世界。](https://img.youtube.com/vi/gIlR7x6jMlg/0.jpg)](https://www.youtube.com/watch?v=gIlR7x6jMlg)

# 必須項目
有無を言わさず設定をした方が良い項目を紹介します！
メタタグ以外も含まれています。

## デフォルトの言語
まず、メタタグではないですが... 言語の設定はしましょう！

```html
<html lang='ja'>
```

## titleタグ
検索結果で表示される部分なので、設定しておきましょう！

```html
<title>Yassun</title>
```

## keywords
検索でヒットするかどうか変わってくるので、設定しておきましょう!

```html
<meta name='keywords' content='Yassun, YouTube'>
```

## description
検索した時にタイトルの下に表示される項目です。
サイトの説明を書きます！

```html
<meta name='description' content='ほげほげー'>
```

## charset
charsetは文字化けしないように、utf-8を設定しておきましょう！

```html
<meta charset='utf-8'>
```

## viewport
デバイスの大きさが変化しても、正しく表示されるようにviewportを設定しておきましょう！
CSSのメディアクエリと組み合わせると、より柔軟に表示を変えることができます。

```html
<meta name='viewport' content='width=device-width, initialscale=1'>
```


# OGP
OGPはリンクを貼った時にタイトル、画像、概要を表示するための規格です！
↓こんな感じです。
![スクリーンショット 2020-10-31 13.01.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/1e2c688f-34a2-3419-a8d2-9b731bfdc435.png)

Twitterや他のサイトでも同じように表示してもらうためには、リンク元のサイトでOGPを設定する必要があります。
ちなみにQiitaでは以下のように設定されています (検証ツールで見れます)。
![スクリーンショット 2020-10-31 15.57.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/b9d73b15-8761-e903-9f59-aa0334f0e4c7.png)


## 自分のサイトでの設定方法
メタタグを追加するだけなので、簡単です！

例えば以下のように設定します。
コンテンツタイプはウェブサイトならwebsite, 記事なら articleなどと設定します。
Qiitaはarticleを設定してますね。

```html
<meta property='og:type' content='<コンテンツタイプ>'>
<meta property='og:title' content='<タイトル>'>
<meta property='og:description' content='<概要>'>
<meta property='og:url' content='<サイトURL>'>
<meta property='og:image' content='<画像URL>'>
<meta property='og:title' content='<タイトル>'>
```

ただ、twitterで表示するときは特殊で、別途以下のように設定する必要があります。
cardの表示形式はcard_image, summary, playerなどがあります。
Qiitaはsummary_large_imageを使ってますね。

```html
<meta name='twitter:card' content='<cardの表示形式>'>
<meta name='twitter:site' content='<twitterのアカウント名>'>
```

## OGP Checker
実際の設定後の確認はOGP Checkerを使います。
Facebookの場合は以下
https://developers.facebook.com/tools/debug/

Twitterの場合は以下で確認できます。
https://cards-dev.twitter.com/validator

# 必須ではないけど、他にもメタタグあるよ！
その他にも電話番号を自動認識するためのメタタグ

```html
<meta name='format-detection' content='telephone=no'>
```

アンドロイドで見た時にテーマカラーを指定できるメタタグ

```html
<meta name='theme-color' content='#FFFFFF'>
```

などがあります。
動画では、もう少し例を出しているので、気になった方は動画も確認していただけると嬉しいです！
[【YouTube動画】 改めて勉強する HTMLのMetaタグの世界。](https://youtu.be/gIlR7x6jMlg)

# まとめ
今回は無視しがちなメタタグについて紹介しました！
ぜひ、Bodyタグ内だけでなく、メタタグのことも気にかけていただけると嬉しいです！
[メモ]JSONで、文字列内のダブルクオーテーションと配列内の""は違う(そりゃそうか)

不完全な記事です。

JSONで、
文字列内のダブルクオーテーションと配列内の""は違う(JSONに限らずか)
だから、文字列に"を含めて配列の中で展開しても、配列として正常に認識されない。

だめ

```liquid:~.liquid
<script type="application/json" id="mobile-menu-data">
{
  {% for link in navMobile.links %}
    {% assign sublink_strs = "" %}
    {% for sublink in link.links %}
　　 {% unless sublink.type == 'collection_link' and sublink.object.products.size <  1 %}
      {% assign str = "," | append: '"' | append: forloop_1.index0 | append: "--" | append: forloop.index0 | append: '"' %}
      {% comment %}そもそもこれもだめ{% endcomment %}
      {% comment %}{% assign str = "," | append: forloop_1.index0 | append: "--" | append: forloop.index0 %}{% endcomment %}
      {% assign sublink_strs = sublink_strs | append: str %}
      {% endunless %}
    {% endfor %}
    {% assign sublink_strs = sublink_strs | remove_first: "," %}
    {% assign sublink_ary = sublink_strs | split: "," %}
    {% comment %}下記sublink_arysがちゃんと展開できていない{% endcomment %}
    "links": {{ sublink_ary }}  {% comment %}←これはだめ。正しく展開されない{% endcomment %}
  {% endfor %}
}
</script>
```

OK

```liquid:~.liquid
<script type="application/json" id="mobile-menu-data">
{
  {% for link in navMobile.links %}
    {% assign sublink_strs = "" %}
    {% for sublink in link.links %}
      {% unless sublink.type == 'collection_link' and sublink.object.products.size <  1 %}
      {% assign str = "," | append: forloop_1.index0 | append: "--" | append: forloop.index0 %}
      {% assign sublink_strs = sublink_strs | append: str %}
      {% endunless %}
    {% endfor %}
    {% assign sublink_strs = sublink_strs | remove_first: "," %}
    {% assign sublink_ary = sublink_strs | split: "," %}
    "links":[
      {% for sublink_str in sublink_ary %}
        "{{sublink_str}}"{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ]
    {% comment %}こんな感じで配列リテラルの中にダブルクオーテーションを直接記述したらOK{% endcomment %}
  {% endfor %}
}
</script>
```
[]の中で、直接ダブルクオーテーションを書かないとだめ。
まあ、「文字列内のダブルクオーテーションと配列内の""は違う」というのは当然か。
でも、
{% comment %}{% assign str = "," | append: forloop_1.index0 | append: "--" | append: forloop.index0 %}{% endcomment %}
を元に配列作って、
"links": {{ sublink_ary }}
はなんで配列として正しく認識されないんだ？

{{}}の理解が悪いのかな。

参考:
[テンプレート言語Liquid](https://clipkit.co/docs/ja/admin/liquid/)

ちなみに、

```
{% unless sublink.type == 'collection_link' and sublink.object.products.size <  1 %}
{% endunless %}
```

は、リンクがコレクションのリンク、かつ、コレクションの中に商品が存在する時のみ、コードを実行することで、中身のないコレクションのリンクを表示しないようにするためのものです。

参考:
[Debut Theme - Hide Empty Collections from Main Menu](https://community.shopify.com/c/Shopify-Design/Debut-Theme-Hide-Empty-Collections-from-Main-Menu/td-p/519003)
thisをつけないとundefinedが出てしまう件(javascript)

苗字と名前をconsoleで出力するクラス(設計図)を定義して
それをインスタンス化(製造)した場合下記のコードだとundefinedが出る

```javascript
const Member = function (firstName,lastName) {
  firstName = firstName;
  lastName = lastName;
};
const women = new Member('天王寺','璃奈');
console.log(women.firstName +' ' + women.lastName);
```

------------------
![スクリーンショット 2020-10-31 14.21.24（3）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/2c17ef82-c837-3d55-1c64-b5b9fb3ca32a.png)
-------------------





これにthisを付与すると名前を出力してくれる。
これが俗にいうthis.変数を指定する事でインスタンス(製造)のプロパティ(クラスの要素)を設定できるという事。

```javascript
const Member = function (firstName,lastName) {  
　this.firstName = firstName;
  this.lastName = lastName;
};
const women = new Member('天王寺','璃奈');
console.log(women.firstName +' ' + women.lastName);
```

-------------------
![スクリーンショット 2020-10-31 14.22.48（3）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/6104f914-af58-6d37-f8ba-c7ead2aff60e.png)
-------------------
【Rails】新規プロジェクトを立ち上げる

#はじめに
新規プロジェクトを立ち上げる時にバージョン指定等を行います。
全ての始まりなので丁寧に記録を残しておきます。

####目次
1.新規プロジェクトの立ち上げ
2.データベースを作成
3.GitHubと連携


#1. 新規プロジェクトの立ち上げ

tabiという名称のアプリケーションを作成します。

```ターミナル.
% cd ~/projects
% rails _6.0.0_ new [ユーザ名] -d mysql

#......読み込みをしばらく待って。
successfully が表示されれば成功。
```
「Commnd」 + 「o」で新しくできた[ユーザ名]アプリに移動します。


#2. データベースを作成
データベースを作成する前に、database.ymlに記載されているencodingの設定を変更します。

```config/database.yml
efault: &default
  adapter: mysql2
   #encoding: utf8mb4 ←これをutf8に編集
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
```

続いて、データベースを作成します。

```ターミナル
% rails db:create
```


Createdが表示されば成功です。

```ターミナル
Created database '[ユーザ名]_development'
Created database '[ユーザ名]_test'
```
作成されました。
これでアプリケーションのベースが完成しました。

#3. GitHubと連携

最後にGitHubを使っているので連携します。
デスクトップからcommitをして完了です。

#最後に
私はプログラミング初学者ですが、同じ様に悩んでる方々の助けになればと思い、記事を投稿しております。
今回は個人開発に当たって、最初の作業の記録を兼ねて投稿させていただきました。
それでは、また次回お会いしましょう〜
配列の中身を確認する方法

配列の中身は、関数を使うことによってブラウザに表示できます。
関数は`var_dump`,`print_r`,`var_export`の3種類があります。
それぞれの違いは下記の通りです。

###1.var_dump($変数名);
・変数の中身の値と型を表示。
・数値型→int(数値) 文字型→string(バイト数)

```
<?php
 $data = ["tori", "sakana", "niwatori"];
 var_dump($data);
?>
↓
array(3) {
 [0]=>
 string(4) "tori"
 [1]=>
 string(6) "sakana"
 [2]=>
 string(8) "niwatori"
}
```

###2. print_r($変数名);
・変数の中身の値のみ表示。

```
<?php
 $data = ["tori", "sakana", "niwatori"];
 print_r($data);
?>
↓
Array
(
 [0] => tori
 [1] => sakana
 [2] => niwatori
)
```

###3. var_export($変数名);
・変数の中身の値をPHPのソースコードで表示。

```
<?php
 $data = ["tori", "sakana", "niwatori"];
 var_export($data);
?>
↓

array (
 0 => 'tori',
 1 => 'sakana',
 2 => 'niwatori',
)
```

参考元はこちら(https://techacademy.jp/magazine/22756)
SQLで行える3つの命令

### はじめに
SQLの知識を定着させるために備忘録としてまとめております

### SQLで行える３つの命令

全体を抑えておくと理解を進めるのに有効なので、きっちり抑える

|  SQLの種類  |  内容  |
| ---- | ---- |
|  DDL(Data Definition Language)  |  テーブル作成・削除、データのアクセスできるユーザーの定義を行うための言語  |
|  DML(Data Manipulation Language)  |  テーブルのデータを変更、削除、追加、問い合わせをするための言語  |
|  DCL(Data Control Language)  |  データベースに対するアクセス制御やトランザクションの制御を行う言語  |

#### データを定義する（DDL）

DDLの主な一例

| 命令 | 説明 |
| --- | --- |
| CREATE | 新しいデータベースやテーブルなどを作成する |
| ALTER | すでにあるデータベースやテーブルなどの定義を変更する |
| DROP | すでにあるデータベースやテーブルなどを削除する |
| TRUNCATE | テーブルやデータを全て削除する |

#### データを操作する(DML)

DMLの主な一例

| 命令 | 説明 |
| --- | --- |
| SELECT | データを検索する |
| INSERT | 新しいレコードを挿入する |
| UPDATE | 既存のデータを更新する |
| DELETE | すでにあるデータを削除する |

一番よく使うSQLがこのDMLである

#### データを制御する(DCL)

DCLの主な一例

| 命令 | 説明 |
| --- | --- |
| GRANT | データベースに対するアクセス権限を与える |
| REVOKE | データベースに対するアクセス権限を削除する |
| COMMIT | 更新を確定する |
| ROLLBACK | 更新を取り消す |
GitHub にプッシュした時に .org ファイルに書いたシェルスクリプトをファイル出力して自動コミットさせる

表題まま。

覚えた Tips や備忘録のような一言メモ（ツイートみたいなやつ）を Org Mode で書いて、プライベートリポジトリで管理していたりするリポジトリがあります。

.org ファイルに自分用のコマンドをシェルスクリプトで書いてある部分があって、シェルスクリプトの内容を書き換えたら手動でファイル出力して、リポジトリに追加したりしていました。

.org ファイルの中のシェルスクリプトの書き換えで満足してしまって、ファイル出力するのを忘れることがありそうだし、単に面倒くさいということもあって、これを自動化してみた試みについての話です。

# README.org

`README.org` というファイルにいくつか自分用のシェルコマンドを書いてあります。

一言メモは投稿日時と投稿内容だけが保存されているようなもので、勤務中に org-capture して蓄積した一言メモを、退勤時に一回だけコミットして、GitHub にプッシュしておき、後でスマホから見たり編集したりできるように [^1] しているだけなので、いちいちコミットメッセージとかつけるようなものではありません。
なので、退勤時に一発コマンドを叩けば、適当なコミットメッセージで今ある差分すべてをコミットしてプッシュしてくれるようなシェルスクリプトが `README.org` に記述されています。

以下のような感じです。

```org
* GitHub に同期するコマンド

  日常的には以下のスクリプトで commit & push する。

  #+begin_src shell :tangle bin/upload :tangle-mode (identity #o755) :shebang #!/bin/bash
    cd $(dirname $(realpath $0))
    git commit -am "autocommit: $(TZ=Asia/Tokyo date -Iseconds)"
    git push
  #+end_src
```

上記をタングルする（`org-babel-tangle` でファイル出力するの意）と、Org Babel のヘッダに記載されているとおり、パーミッション 755 で `bin/upload` というファイルが生成されます。

# GitHub Actions

上記以外にも `README.org` にはファイル出力したいコード片がいくつかあります。コード片を書き換えた時にファイル出力を忘れることを防止したい、そもそも楽したいということで、下記の GitHub Actions で自動化したという話です。

コード片の変更によって出力されるファイル内容が変われば、それが差分となって GitHub アクションが勝手に出力されたファイルをリポジトリに追加してくれるようになります。

```yaml
name: tangle

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Set up Emacs
        uses: purcell/setup-emacs@v3.0
        with:
          version: 27.1
      - name: Tangle
        run: emacs -Q --batch --eval "(progn (require 'ob-tangle) (with-current-buffer (find-file-noselect \"./README.org\") (org-babel-tangle)))"
      - name: Git Auto Commit
        uses: stefanzweifel/git-auto-commit-action@v4.7.2
        with:
          commit_message: "[自動コミット] GitHub Actions がタングルした"
```

すでに世に出回っているアクションの組み合わせで事足りました。

Emacs をセットアップしてくれる [Set up Emacs](https://github.com/marketplace/actions/set-up-emacs) アクションを使ったのと、一連のステップでリポジトリに生じた差分を自動コミットしたりできる [Git Auto Commit](https://github.com/marketplace/actions/git-auto-commit) アクションを使わせてもらいました。

自分で書かなきゃいけなかった箇所は実質、Emacs を使って `README.org` に記載されているコード片をタングルする所だけですが、これも公式ドキュメントの [Batch Execution](https://orgmode.org/manual/Batch-Execution.html) という項目にやり方が載っていました。

ということでたいした苦労もせずに自動化できてしまい、先人の皆様ありがとうございます :bow: という気持ちです。

現場からは以上です。Happy Org Babel !!

[^1]: Termux に GitHub の Git リポジトリをクローンして、Orgzly のローカルリポジトリに割り当ています。
ポインタ、メモリを擬人化

ポインタ、メモリについて初心者の自分なりに解釈したことをまとめてみました。

##ポインタ
まず「ポインタとは」と調べた時、下記のように説明しているサイトがあった。

>ポインタとは、何かの位置を指し示すための仕組みや道具などのこと。プログラミングでは、変数や関数などが置かれたメインメモリ上の番地などを格納する特殊な変数のことをポインタという。

正直、初心者の自分では何を行っているのかほとんど理解できなかった。
要するに、なりすましができる変数のこと。
例えば、東京都世田谷区OO-OOに両親男1人の3人家族が住んでいたとする。
値を変数に代入するのはこの家族の構成をコピーするようなもの。
つまり、大阪府大阪市OO-OOに両親男1人という家族構成の家族が住んでいるという設定になる。
新しい変数（大阪の家族）に変更を加えた時、大阪府大阪市OO-OOに女の子が一人増えたというような変更になる。
ポインタ変数の場合、アドレスを代入するので、新しい変数には東京都世田谷区OO-OOを代入し、そこには両親男1人の3人家族が住んでいるということがわかるというような仕組みになる。
ポインタ変数とただの変数の代入は同じように見えて異なる。
下記のようなコードに置き換えてみる。

```main.c
int a = 3;
int b = 0;
int *p = NULL; //整数型のポインタ変数
p = &a; //これはポインタ変数pが変数aになりすますということ、値ではなくアドレスを代入している
b = a;
```
~~この場合、pとbの値は一緒だが、アドレスが異なる。~~
この場合、*pとbの値は一緒だが、アドレスが異なる。
つまり、家族構成は同じだが、pは東京、bは大阪ですよ、ということになる。

##メモリ
メモリというのは作業台のようなもの。
例えば、図書館に行って勉強する場合を想像する。
小さな机だと、様々な参考書を置くスペースがないので一回一回本棚に直して取りに行くというような作業をしなければいけなくなり、効率が悪い。
しかし、大きな勉強机があった場合、参考書を空いているスペースに置いていけば探しに行く時間も直しに行く時間も省くことができる。
この例をPCに置き換えると、机→メモリ、勉強→処理、というように置き換えられる。
メモリが大きければ、効率の良い処理を行うことができる。
ただし、机の上に参考書を置きすぎると勉強をするスペースがなくなってしまい、参考書の上で勉強するというようなことになってしまう。
PCも同じでメモリには制限があり、制限を超えてしまうと、一気に処理効率が低下してしまう。

<メモ>
IT用語を説明する際、横文字も多く知らない単語ばかりで、説明の説明を調べていかなければいけないことがよくあると思う。
わかりやすく説明をするときは擬人化した方が良い。



###参照サイト
[Udemy 1週間で身につくC/C++言語](https://www.udemy.com/course/cc-lubmn/)
[ポインタとは](http://e-words.jp/w/%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF.html)
replace()メソッドの使い方（Javaシルバー）

# replaceメソッド

**文字列を置換する**

replaceメソッドは対象の文字列から第１引数で指定した文字列を検索し、マッチした文字列を第２引数で指定した文字列で置換する。そして、置換後の文字列を戻り値として返す。文字列の置換は先頭から始まり、文字列の最後まで行われる。

簡単に言うと**第一引数で指定した文字列を第二引数で指定した文字列に置換**する。

Stringクラスのメソッド  
java.lang.String.replace()


## 使い方

```java
対象の文字列.replace(置換される文字列, 置換文字列)
```

例

```java
	public static void main(String[] args) {

		  // 対象の文字列
		  String strBefore = "Hello world!";

		  // 置換される文字列"Hello" を 置換文字列"Goodbye"に置換
		  String strAfter = strBefore.replace("Hello", "Goodbye");

		  System.out.println(strAfter);
		}
```
実行結果

```
Goodbye world!
```


## 置換する箇所が複数ある場合
置換する箇所が複数ある場合は、該当箇所が全て置換される。

```java
	public static void main(String[] args) {

		  // // 対象の文字列
		  String strBefore = "aabbaacc aab ";

		  // "aa"→"DDD"に置換
		  String strAfter = strBefore.replace("aa", "DDD");

		  System.out.println(strAfter);

		}
```

実行結果

```
DDDbbDDDcc DDDb 
```

## 文字列の置換は先頭から順番に始まる

以下の例では先頭のAAAとその次のAAAがBに置換される。
そのためAABBやABBAにはならない。

```java
	public static void main(String[] args) {

		  // 置換前文字列 Aが8個
		  String strBefore = "AAAAAAAA";

		  // "AAA"→"B" に置換
		  String strAfter = strBefore.replace("AAA", "B");

		  System.out.println(strAfter);

		}
```
実行結果

```java

BBAA

```


## 引数について

replaceメソッドはオーバーロードされており、**char型**の引数を２つ受け取るものと、**CharSequence型**の引数を２つ受け取るものがある。char型とCharSequence型が混在する引数を受け取るオーバーロードは存在しないことに注意する。
シバン（shebang）にスクリプトを実行しないコマンドを指定してみる実験

シェルスクリプトを書く時、おまじないのように先頭行を **`#!/bin/bash`** などとしていた。（ `#!` はシバンなどと呼ばれる）

色々なスクリプトを見ていたら、シェルを宣言しているわけではなく**自身のスクリプトを実行するコマンドを書けばいい**らしいとわかった。

* [awk](https://ja.wikipedia.org/wiki/AWK) → `#!/usr/bin/awk -f`
* [expect](https://core.tcl-lang.org/expect/) → `#!/usr/bin/expect -f`
* perl → `#!/usr/bin/perl`
	* PATHに従う場合 → `#!/usr/bin/env perl` （[参考](http://www.gnu.org/software/coreutils/env)）

だったら**スクリプトを実行しないコマンドを書いてもそれに応じた動作をするのでは**、と思って試してみた。実用性は無いと思う。

## 実験
単独で実行するときは権限が必要なので、事前に `chmod u+x script-*` などとパーミッションを適切に設定しておくこと。

### echo
簡単で無害そうなコマンドから試す。 `echo` は引数を表示するコマンド。

```bash:script-echo
#!/bin/echo
echo "Hello, world!"
```

```shell-session
$ bash script-echo  # 普通にシェルスクリプトとして実行 → 普通の結果
Hello, world!

$ ./script-echo
./script-echo

$ ./script-echo arg1 arg2
./script-echo arg1 arg2
```

どうやら `/bin/echo ./script-echo arg1 arg2` と実行した感じになるらしい。**引数にファイル名が来ても問題ないコマンド**なら大丈夫そう。

### cat
引数にファイル名をとるコマンドの代表、 `cat` もやってみる。

```bash:script-cat
#!/bin/cat
echo "Hello, world!"
```

```shell-session
$ ./script-cat 
#!/bin/cat
echo "Hello, world!"
```

書いたスクリプトは実行されず、自身のファイルの中身が表示された。

### false
`false` は何もせず失敗するコマンド（引数や入力も無視する[^help]）。なのでシバンに書いておくと、**直接実行するのを禁止**することになる。

シェルの組み込みコマンドになっていたり、OSによってパスが違っていたりする。ファイルは `whereis false` とすれば探せる。

```bash:script-false
#!/bin/false
echo "Hello, world!"
```

```shell-session
$ ./script-false

$ echo $?  # コマンドの終了ステータスを確認
1
```

[^help]: `--help` などのオプションを受け付ける実装もある。例：[GNU Coreutils](http://www.gnu.org/software/coreutils/false)

### rm
**自爆**。ファイルが消滅する。

何も表示されないのは面白くないので `-i` を付けておく。

```bash:script-rm
#!/bin/rm -i
echo "Goodbye, world!"
```

```shell-session
$ ./script-rm
/bin/rm: remove regular file './script-rm'? y

$ ls -l script-rm
ls: cannot access 'script-rm': No such file or directory
```

## 追加の実験
上で試したコマンドはファイルの内容に依らないものだった。そのため内容は大して意味のないものになってしまった。

ファイルの内容に意味があり、シバンを加えても邪魔にならないものを考えたところ、**「 `#` をコメント扱いするアプリのファイル」**なら良いはずと思った。そのようなものは各種スクリプトだけでなく一部の設定ファイルも当てはまる。

というわけで**実行可能な設定ファイル**を作れるか簡単に試してみる。

### sshd
SSHサーバーは起動時に `-f` オプションで設定ファイルを指定できる。なお、設定項目は以下を参考にした。 

* `/etc/ssh/sshd_config`
* [sshd_configの設定項目の理解を目指す | Unskilled?](https://unskilled.site/sshd_configの設定項目の理解を目指す/)

```ssh:sshd-custom
#!/usr/sbin/sshd -f
# ↑これが今回の実験テーマ

# わかりやすく、通常と異なるポートを指定
Port 2222

# 安全のためループバックインターフェースのみ使用
ListenAddress 127.0.0.1

# 実験目的ということでパスワード認証
PasswordAuthentication yes
PermitEmptyPasswords yes
PubkeyAuthentication no  # "Too many authentication failures" 対策
```

あとはこのファイルを実行してみるだけ。するときちんとSSHサーバーが起動する。

```shell-session
$ chmod +x sshd-custom
$ sudo ./sshd-custom  # サーバー起動（サーバー鍵を読む都合上root権限が必要）

$ ssh -p 2222 localhost  # ポートを指定して接続
＜パスワードを入力する＞
＜ログインできたら適当に遊ぶ＞

$ sudo pkill sshd-custom  # サーバー停止
```
MacでAviraを使う際にスキャン対象外のパスを設定する方法

## 概要
Macでアンチウィルスソフトを入れている方で`Avira`を使っている人は一定数いると思います。少し古い記事になりますが、[Mac用のセキュリティソフトは一体どれが最も優れているのか？](https://gigazine.net/news/20160726-security-suites-mac-os-x/)にある通り、無料から利用できるソフトウェアとしてはAvastやAVGとともに候補に上がるソフトウェアになると思います。
今回は、MacでAviraを使う際に特定のパスをスキャン対象外とする方法を紹介します。

## 方法
Aviraのアプリケーションを開いて設定画面からパス設定できるのかと思いきや、2020年11月時点でMacでは画面では設定できないようです。ちなみに、[Avira Antivirusの例外設定のやり方](https://neoblog.itniti.net/avira-antivirus-exception/)の記事を見ると、Windowsでは画面から設定できるようです。
では、Macではどうすれば良いかというと、[またまたワクチンソフトをAviraに戻しました](https://another.rocomotion.net/14403119914678.html)の記事にある通り、confファイルに`ExcludePath`を追加し、PCを再起動することでスキャン対象外のパスを設定できます。

## confファイルについて
2020年11月現在の仕様だと`/Library/Application Support/Avira/Scanner/config`にconfファイルが配置されています。ファイル構成は下記のキャプチャーの通り。
![スクリーンショット 2020-10-30 10.52.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/7b558386-e96d-759f-bc5a-0d6196b5b481.png)
confファイルの役割ですが、[Avira/CentOSへのインストール](https://vok.paburica.com/index.php?Avira%2FCentOS%E3%81%B8%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)によると`avguard.conf`がリアルタイムスキャン設定ファイルで、`avscan.conf`が手動スキャン設定ファイルとなるそうです。
Firefox で Yahooリアルタイム検索の URL を更新する

### 最初に

先日 Yahoo リアルタイム検索 の URL が **ドメインそのものが変更されたようです。**

|旧URL|新URL|
|:-:|:-:|
|http://realtime.search.yahoo.co.jp/|https://search.yahoo.co.jp/realtime

Firefox の「検索エンジン」で使っていたのですが、利用できなくなってしまいました。

新しい URL に書き換えようとした所、
通常の手順では URL を更新できなかったのでやり方をまとめてみました。



### 編集できるアドオンを入れる

まずは検索エンジンを編集できるアドオンを追加します。

 [mozlz4-edit](https://addons.mozilla.org/ja/firefox/addon/mozlz4-edit/)

追加したら Windows ユーザーの方は `Win + R` キーを押下し下記を実行します。

```
▶Windows版
%APPDATA%\Mozilla\Firefox\Profiles

▶Mac版
~/Library/Application Support/Firefox/Profiles/
``` 
※以降、Windows 版で実施しています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/5339138e-e19e-8d76-4229-c0b99759c506.png)

そうするとエクスプローラーでプロファイル一覧が表示されるので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/8febe3e5-b5c0-3389-675c-30a02d6e0fd9.png)

プロファイルのディレクトリに移動して、
タイトルバーからリンクを `Ctrl + C` でコピーしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/681fc56d-1b7d-5ca5-d8c3-e51a1d372dad.png)

準備ができたので、次のステップで実際に編集していきます。

### 検索エンジンの URL を書き換える

先程追加したアドオン *mozlz4-edit* を開くと、下記のような画面がでます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/ddda40e0-f65b-acb8-fc5b-4efc423ab2c7.png) 
一番左上にある  ***Open File*** をクリックするとウィンドウが表示されるので、
**先程コピーしたディレクトリを貼り付け移動します。**

プロファイルディレクトリに移動した後は **search.json.mozlz4** というファイルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/38047764-0dda-5fa5-ee37-c7b13c8353cd.png)

そうすると編集モードになるので **Yahoo検索（リアルタイム）** を探しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/c11b1cd8-4699-627c-45f2-26f859c37ad0.png)

該当する項目が見つかったので２項目を編集します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/c5f5c198-4184-7552-d508-a996a81801a2.png)

▶下記の通りに差し替える

```
■１つ目
"__searchForm": "https://search.yahoo.co.jp/realtime/search",

■２つ目
"resultDomain": "search.yahoo.co.jp",
"template": "https://search.yahoo.co.jp/realtime/search"
```

編集が終わったら上のメニューから **Save as mozlz4** をクリックして、
ダウンロードディレクトリに保存します。

### 最後に

Firefox を終了しダウンロードにある **search.json.mozlz4** をプロファイルのディレクトリに
上書きコピーすれば完了です！

あとは Firefox を再起動し「Yahoo リアルタイム」で検索すれば今まで通り利用できます。
PowerAutomateでExcelに値を突っ込むときのメモ

#やろうとしていること
予定表から取得したイベントをExcelの行にうめていく。


#つまった
PowerAutomateでOutlookの予定表からイベントを取ったはよいが、
Excelのツッコミ位置を指定できない！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/a3339d48-471a-cdd7-20a9-022180ea2563.png)
↑のテーブルを指定できなくて止まった。

どうやらExcel側で先にテーブルとして箱を作っておく必要があるみたい。
ある範囲を指定して、ホーム→下の画像でテーブル保存可能。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/a07c46a5-1bdb-844b-8e95-e035017906aa.png)


[助けていただいたサイト](https://blog-tips.sekenkodqx.jp/2020/07/17/power-automate-action-add-a-row-into-a-table-excel-online-business/)
STM32G031J6M6のUSARTシリアル通信書き込み

2020/10/31現在　STM32G031のシリアル書き込みは、STM32CubeProgrammerのみ

X何らかの方法で「OB」の「User Configuration」の「nBOOT_SEL」をUnchecked
x書き終わったらbootを開放

SWCLK(boot) - 3.3V
PA11(PA9)(TX) -> USBシリアル(RX)
PA12(PA10)(RX) <- USBシリアル(TX)

OB - nBOOT_SEL - Unchehecked
OB - NRST_MODE - 1

1.書き込み装置を「ST-LINK」から「UART」に変更
2.USARTシリアル通信をUSBに接続
3.Portを再読み込み
4.この場合COM7を選択　各自違う
5.Connectボタンを押して接続する
6.Open Fileタブをチェックしファイル選択ボックスを開く
7.firmware.binを選択する　各自違う
8.Downloadボタンをクリックして書き込みを行う
9.終了

忙しい人よう
https://github.com/caa45040/blinky_G031_PA11
firmware.bin を書き込むとブリンクします。

![sel_tx_9600_g031_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/bda299f5-1113-3c9f-1ea9-091a20d4eb9b.jpeg)

![sel_tx_9600_g031_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e280fe16-e0ab-615b-5ac1-7b9b71587147.jpeg)

![sel_tx_9600_g031_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/922f5923-7df5-d8ca-ee03-004f7fad6bfa.jpeg)

![sel_wite_031_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/c6bd9379-415e-1052-1331-90701d2ff6c3.jpeg)

![sel_wite_031_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1c37531e-5f31-0d93-4168-b00666da1b16.jpeg)

![sel_wite_031_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5747c030-d163-10f9-baef-987270e6060c.jpeg)
PowerAutomateではOutlookカレンダーの予定もイベントとして扱われる！メモ

#やろうとしていること
Outlookに登録されている予定をExcelに月次で勝手に追加する。
工数の集計を分類別にしたい。
Power automateを使用

#つまった
カレンダーの取得したのに中身がない。。。
⇒カレンダーではなくて、イベントを取得するべきだった。
　カレンダーだと、誰の予定表です。という情報しかこなかった。
　普通の自分で入れた予定もイベントに入るのね。
　入れるときは予定とイベントで言葉ちゃうやん。

<img alt="outlookの名前" width="200px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/cf7893a3-16d4-2407-2c92-86bfbdc9ec10.png">
すべての要素に対しtransformを並列で適用し順番を維持した戻り値の配列を返すメソッド

### 概要
タイトル

```swift
import Foundation

private let parallelQueue = DispatchQueue(label: "Sequence#parallelMapQueue", attributes: .concurrent)
extension Sequence {
  
  // parallelMap
  // すべての要素に対しtransformを並列で適用し順番を維持した戻り値の配列を返す
  //
  func parallelMap<T>(_ transform: @escaping (Element) throws -> T) rethrows -> [T] {
  
    let group = DispatchGroup()
    let semaphore = DispatchSemaphore(value: 1)
    
    var result: [(Int, Result<T, Error>)] = []
    
    zip(0..., self)
      .forEach { i, v in
        
        parallelQueue.async(group: group) {
          
          let r = Result { try transform(v) }
          
          semaphore.wait()
          defer { semaphore.signal() }
          
          result.append((i, r))
        }
    }
    
    group.wait()
    
    return try result
            .sorted { $0.0 < $1.0 }
            .map { try $0.1.get() }
  }
}

```

### 実行例

```swift

print(
  (0...10)
    .parallelMap { i -> Int in
       let t = UInt32([0, 2, 3, 5].randomElement()!)
       sleep(t)
       print(i, t)
       return i + 1
  }
)

// 出力例
//
// 0 0
// 4 0
// 10 0
// 1 2
// 2 2
// 3 2
// 5 2
// 7 2
// 6 3
// 9 3
// 8 5
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
```

ばらばら（並列）に実行されていることと戻り値の順番が維持されていることがわかる。


### 追加（2021/03/30）

効率の良い`Collection`バージョン。

```swift
import Foundation

private let parallelQueue = DispatchQueue(label: "Sequence#parallelMapQueue", attributes: .concurrent)
extension Collection {

  // parallelMap
  // すべての要素に対しtransformを並列で適用し順番を維持した戻り値の配列を返す
  //
  func parallelMap<T>(_ transform: @escaping (Element) throws -> T) rethrows -> [T] {
    
    if isEmpty {
      return []
    }

    let group = DispatchGroup()
    let semaphore = DispatchSemaphore(value: 1)

    var result = [Result<T, Error>]()
    result.reserveCapacity(count)

    zip(0..., self)
      .forEach { i, v in

        parallelQueue.async(group: group) {

          let r = Result  { try transform(v) }

          semaphore.wait()
          defer { semaphore.signal() }

          result[i] = r
        }
    }

    group.wait()

    return try result.map { try $0.get() }
  }
}

```
スクレイピング：Webサイトをローカルに保存

#スクレイピング：Webサイトをローカルに保存

備忘録。バックアップ目的のみ。
太陽電磁波？太陽磁気嵐？のような世界的電源停止に備えて。microCMSにはバックアップ機能がないため実施。


###コード

```python
import os
from urllib.request import *

# 記事カテゴリー毎のURL
#base_url = "https://benzoinfojapan.org/patients-article/"
#base_url = "https://benzoinfojapan.org/doctors-article/"
base_url = "https://benzoinfojapan.org/medias-article/"

# 保存先ファイル名接頭詞
#prefix = "patients-article"
#prefix = "doctors-article"
prefix = "medias-article"

num = 1

# 各カテゴリ記事上限値をwhile num <= Xに設定. 以下2020年10月現在値.
# patientsの場合10
# patientsの場合26
# patientsの場合13
# 　　　　　　↓↓
while num <= 13:
    print("ダウンロード開始")
 
    # HTMLファイル 保存先のディレクトリ
    save_dir = os.path.dirname(os.path.abspath(__file__)) + "/html/"
    # 存在しなければディレクトリ作成
    if not os.path.exists(save_dir): 
        os.mkdir(save_dir)

    url=base_url + str(num)

    # 保存先ファイルのパス
    num_str = str(num)
    save_file = save_dir + prefix + num_str + ".html"

    urlretrieve(url, save_file)

    # doctors-articleの記事が22番目抜けてるので必要な処理^^;
    if num != 11:
        num += 1
    else:
        num += 2
```
※ エラー処理なし


###使い方

3つの各カテゴリーごとにパラメーターを変更して上記のコードを3回実行する。

変更箇所は以下のみっつ。

- base_url
- prefix
- while num <= xx:　← xxの数値を現在総記事数に。




###結果
ページ毎にHTMLファイルとしてローカルドライブに保存される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307441/cc285832-d4fe-ceb4-5227-349a2b3c603e.png)



以上。