OmniAICreator/Qiita-1.07M huggingface dataset:
VBScriptでどうしてもプログレスバーを使いたい

作業の進捗状況を表示するプログレスバーです。
サンプルでは、5% = 1マスずつ増えていきます。

``` VBScript
Option Explicit

' オブジェクトの生成
Dim objWsh : Set objWsh = Wscript.CreateObject("Wscript.shell")

' 当スクリプトの名前を取得
Dim strScriptName   : strScriptName = WScript.ScriptName

' 当スクリプトの引数が空でも動作するようにON ERROR RESUME NEXTを使う
ON ERROR RESUME NEXT

Dim strArg1 : strArg1 = Wscript.Arguments(0)
' 引数が"ESC"であればESCを叩きつける
If strArg1 = "ESC" Then
    WScript.Sleep 100
    objWsh.SendKeys "{" & strArg1 & "}"
    Wscript.Quit
End If

ON ERROR GOTO 0

' 引数がなければ以下に進む

Dim i
For i = 1 To 20
    ' 当スクリプトを"ESC"を引数にして実行し直す
    objWsh.Run (Wscript.ScriptFullName & " ESC")

    ' 次に進捗状況を表すメッセージを表示する
    Wscript.Echo "進捗状況 " & i*5 & "%" & vbCr & String(i, "■") & String(20-i, "□")

    ' ESCが叩きつけられるので進捗状況が次々進む（ように見える）
Next
```
【Python】difflibモジュールのSequenceMatcherを使って類似度計算を行う


# 概要
`difflib`モジュールの`SequenceMatcher`クラスというツールを使って、類似度計算を行いました。
このクラスは、テキスト処理に関連する多くの処理を行うことができます。

# サンプルコード
以下のサンプルコードは、2つの文字列の類似度を計算し、特定の比率を超える場合に `"重複発見!"`というメッセージを表示するものです。

```python
from difflib import SequenceMatcher

phrase1 = "あいうえおかきくけこ"
phrase2 = "あいうえお"

def similar(a, b):
    match_ratio = SequenceMatcher(None, a, b).ratio()
    print(match_ratio)
    return match_ratio

def check_for_duplicate(ratio):
    if similar(phrase1, phrase2) > ratio:
        print("重複発見!")

ratio = 0.6
check_for_duplicate(ratio)

## 出力結果 ##
# 0.6666666666666666
# 重複発見!
```

最初ちょっと「？」となったことがあります。
上記のひらがなのように10文字中5文字が同じであれば、同じ文字は50%なので、`ratio`が`0.6`の場合は`重複発見!`が表示されないのかなと思いました。しかし、実際の公式は以下の公式ドキュメントに記載してあります。

[6.3. difflib --- 差分の計算を助ける — Python 3.5.10 ドキュメント](https://docs.python.org/ja/3.5/library/difflib.html)

> T が2つのシーケンスの要素数の総計だと仮定し、M をマッチした数とすると、この値は 2.0*M / T であらわされます。もしシーケンスがまったく同じ場合、値は 1.0 となり、まったく異なる場合には 0.0 となります。

上記の例で言うと、Mは`5`であり、Tは`15`になります。つまり、以下の計算が行われていたのです。

```
2 * 5 / 15 = 0.6666666666666666...
```

言われてみればそれはそうか、と思いました...。
探索

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/dfef3705-df0a-b32d-e465-4d7d55ca7ab2.png)
１：ハッシュ法
　ハッシュ法は、データの格納場所を計算によって求め、短時間で目的のデータを探し出す方法です。ハッシュ法を利用するためには、事前にデータをハッシュ表に登録しておく必要があります。　
　データの格納場所を求める計算式をハッシュ関数と言います。データのキー値（社員番号、口座番号、伝票番号など）をハッシュ関数に入力し、ハッシュ値を得ます。そして、ハッシュ値をアドレス（あるいは要素番号）として扱い、該当箇所にデータを格納します。基本情報技術者試験では、ハッシュ関数として、
　キー値％N：キーチをNで割った余り
が使われることが多いです。なお、％は余剰（割った余り）を表す記号です。ハッシュ関数として余剰を使うときには、先頭要素の要素番号が０から始まる配列を用意すると便利です。

２：ハッシュ法における衝突
　異なったキーチに対して、同じハッシュ値が計算されることを衝突（コリジョン）と言います。例えば、ハッシュ関数を
　ハッシュ値＝キー値％１１
としましょう。このハッシュ関数を使って、データをハッシュ表に格納します。　はじめに、キー値３のデータをハッシュ表に格納しましょう。この時のハッシュ値は３ですから、ハッシュ表の[3]の場所に格納します。次に、キー値１４のデータをハッシュ表に格納します。この時のハッシュ値も三となります。ハッシュ表の[3]にはすでにデータが格納されていますから、ここに格納することはできません。このように、ハッシュ値が衝突するとデータを格納できなくなります。
　この場合、後から格納しようとしたキー値１４のデータをシノニムと呼びます。シノニムは、本来の場所とは違う場所に格納せざるをえません。シノニムを格納するを格納する代表的な方法には、オープンアドレス方とチェーン法があります。
　オープンアドレス法は、本来の場所から下方向へ見ていって、空いていた場所に格納する場所という方法です。
　チェーン法は、同じハッシュ値のデータをリストで管理するという方法です。
0 だけ末尾になるように並べ替える

`3, 4, 0, 1, 2` のような数列を、 `1, 2, 3, 4, 0` のように 0 だけ末尾に来るように並べ替えます。この簡単そうに見えて意外と簡単ではないかもしれない問題について解いてみます。

## 0 を大きな数字に置き換える

並べ替えのキーが 0 の場合だけ `Number.MAX_SAFE_INTEGER` などの大きい数に置き換えることでソートします。以下は JavaScript (lodash) の例です。

```javascript
import _ from 'lodash';

const foo = [
  { id: 1, order: 300 },
  { id: 2, order: 0 },
  { id: 3, order: 200 },
];

const sorted = _.orderBy(
  foo,
  [
    // order が 0 の場合だけ、巨大な数字に置き換える
    (item) => item.order === 0 ? Number.MAX_SAFE_INTEGER : item.order,
    'id',
  ]
);

console.log(sorted);
```

大きい数としては、C# であれば `Int32.MaxValue`、C++ であれば `INT_MAX` などが使用できます。使用する型に合わせて適切な値を使用してください。型で許容される最大値が元の配列に含まれていて、より大きいサイズの整数型がない場合、この方法は使用できません。

## 値が 0 かどうかで最初にソートする

値が 0 かどうかを示す boolean 値をソートキーに含めることで並べ替えを行います。SQL の場合は `ORDER BY <column> IS NULL` 構文を参考にしてソートします。今回は NULL ではなく 0 なので、`ORDER BY <column> = 0` とします。当然インデックスは効かないので、`LIMIT` などを併用する場合は、次の3つ目の方法も検討してください。

https://qiita.com/tanaka-qtaro/items/9bbb3a9b088f0d5deb14

```sql
SELECT column_0 as id, column_1 as ord
FROM (VALUES
  ROW(1, 300),
  ROW(2, 0),
  ROW(3, 200)
) AS A
ORDER BY ord = 0, ord, id;
```

## 値が 0 の配列とそれ以外に分ける

ソート値が 0 の要素と 0 以外の要素に分けることで並び替えを行います。要するにバケツソートです。

以下は Python の例です。

```py
arr = [
  { 'id': 1, 'order': 300 },
  { 'id': 2, 'order': 0 },
  { 'id': 3, 'order': 200 },
];

sorted_arr = sorted(arr, key=lambda x:[x['order'], x['id']])

is_zero = []
is_not_zero = []

for item in sorted_arr:
  if item['order'] == 0:
    is_zero.append(item)
  else:
    is_not_zero.append(item)

result = [*is_not_zero, *is_zero]
print(result)
```

SQL の場合、この方法であればインデックスを使用することができるため、サブクエリにも適切に LIMIT を設定すれば計算量を抑えることができます。以下の記事が参考になります。

https://ngyuki.hatenablog.com/entry/2014/07/16/194621

> 次のように is null と is not null を無理やり２回に分けた方が速いことがあります。
>
> (select * from t where val is null order by id asc limit 20)
> union all
> (select * from t where val is not null order by val asc, id asc limit 20)
> order by val is null asc, val asc, id asc limit 20;

## 追記：ユーザー定義の比較関数を使用する (コメントより)

（コメントで提案して頂いた方法がありましたので追記しました。）

言語によっては比較関数を与えることでソートを実行できる場合もあります。

> 返値は、 2 つの要素の相対順序を示す符号を持つ数値である必要があります。 a が b より小さい場合は負の値、a が b より大きい場合は正の値、等しい場合は 0 とします。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#comparefn

```javascript
const foo = [
  { id: 1, order: 300 },
  { id: 2, order: 0 },
  { id: 3, order: 200 },
];

const sorted = foo.toSorted(
  (a, b) => (a.order === 0) - (b.order === 0) || a.order - b.order || a.id - b.id
);

console.log(sorted);
```

【余談】なお、このコードで使われている `.toSorted()` は ES2023 で導入された比較的新しいメソッドだそうですが、(mozilla.org に掲載されている) モダンなブラウザでは全て実装されているようです。非破壊的に実行する必要がなければ `.sort()` でも構いません。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted

https://qiita.com/tixyu10/items/3b99419432d8d809f12e
文系出身IT初心者必見!!これだけで作業効率upショートカットキー3選


## alt＋Tab
1つ前に開いていた画面に戻りたいけど色々開いていてどれか分からない。
そんな時はalt＋Tab
alt＋Tabは「現在開いているものを一覧表示する」ショートカットキーとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/ab8ba7e0-9675-f688-5f01-0609c0e3163b.png)
その状態で何も押さないと1つ前の画面に移動、Tabを押すと一覧表示された画面から1つずつ戻るように選択出来ます。
コレで今何を開いているのかわかるし、好きな画面に戻ることができますね。


## Windows＋D
色々な画面を開いていてデスクトップに戻りたいのに戻るのに時間がかかる。
そんな時はWindows＋Dで解決
Windows＋Dは「現在開いているものを全て最小化し、デスクトップに移行する」ショートカットキーとなります。
下の画像のようにたくさん開いていても、Windows＋Dで自身のデスクトップに移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/bac61240-d78f-8509-b954-559de1566299.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/f4d8a500-728e-cf03-d145-ded62c4a4418.png)
コレで最小化のボタンを何度もクリックする必要がなくなりますね。

## Windows＋R
URLをいちいちChromeやEdgeで開いて検索するの面倒くさくないですか。
そんな時はWindows＋R
Windows＋Rは「ファイル名を指定して実行」を呼び出すショートカットキーとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/8e5b0bf3-4ea2-08fb-9b31-0df7631aec4d.png)
Windows＋Rを入力すると左下に上記画像が出現します。
URLで検索するのはもちろん、ファイルパスなどにも対応しているので、お仕事では必須級のショートカットキーです。

また、Windows＋Rのファイルパス応用編として素早く自分の開きたいものを開くことができます。
その方法は以下になります。

１．フォルダを作る
今回はCドライブ直下に『01』というフォルダを作成しています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/62859bc4-5896-771b-65af-2d0fa5013c56.png)

２．『01』フォルダ内に開きたいものを入れる
今回はメモ帳を入れています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/82c73658-c823-ceee-7459-bb3c885b4673.png)

３．メモ帳の名前を短く変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/17a33365-14c6-d171-5cee-219a797ef172.png)

４．Windows＋Rで検索する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329733/dc9ac4ed-a5ab-f3d8-b035-2ab97c7fddf6.png)
OKをクリックするとメモ帳が開きます。
もちろんメモ帳の他にも上記方法で様々なものを簡単に開くことができます。


以上、作業効率upショートカットキー3選でした。
ショートカットキーは他にも便利なものが多いのでぜひ皆さんも調べてみてください。
最後までご覧いただきありがとうございました。
Geopyで緯度経度からその都道府県を取得する方法(備忘録)

# 目的
緯度経度を入力に、都道府県を出力とする関数を作ること

# 方法
二つのメソッドを使う。
1. Geopyのreverseという緯度経度を入力に都道府県コードを出力するメソッド
2. pycountryのsubdivisions.getというISO 3166-2:JP都道府県コードから都道府県名を出力するメソッド

以上2点を組み合わせて
インプット：緯度経度
アウトプット：都道府県名
の関数を作成する。

# 準備
geopyとpycountryをインストールしましょう。
```pip install geopy```
```pip install pycountry```
動いた環境のpythonのバージョンは3.8.8でした。

# コード
*user_agent* は書き換えてご利用ください。
```{python}
from geopy.geocoders import Nominatim
import pycountry

geolocator = Nominatim(user_agent = "something")

# 緯度経度から都道府県コードを取得
def get_prefecture_code_from_lat_lon(latitude, longitude, geolocator):
    location = geolocator.reverse((latitude,longitude),language = "jp")
    if location and location.raw.get("address"):
        return location.raw["address"].get("ISO3166-2-lvl4")
    return None

# 都道府県コードから都道府県名を取得
def get_subdivision_name(iso_code):
    subdivision = pycountry.subdivisions.get(code=iso_code)
    if subdivision:
        return subdivision.name
    return None

latitude = 35.6895  # 例：東京
longitude = 139.6917

prefecture_code = get_prefecture_code_from_lat_lon(latitude, longitude, geolocator)
print(f"都道府県コード = {prefecture_code}") 
prefecture = get_subdivision_name(prefecture_code)
print(f"都道府県：{prefecture}") 
```

# 注意点
### geopyのライブラリからの都道府県情報はISO 3166-2:JP コードで取得している。
```
latitude = 35.6895  # 例：東京
longitude = 139.6917
location = geolocator.reverse((latitude,longitude),language = "jp")
print(location.raw)
```
とすると、*display_name* に東京都と書かれており、都道府県情報が入っていることがわかる。
```
print(location.raw["display_name"])
```
とすると、カンマ区切りで住所の情報が入っている。ここから都道府県情報を取得することもできなくはないが、ちょっと面倒くさく感じ、ISO 3166-2:JPコードを用いることを検討した。
Reactで無限スクロールを実現する

## はじめに
表題通り、Reactで無限スクロールを実現するための仕様です。
そもそも取得件数が多い場合、ページネーションを行います。次にページ遷移する場合、次のページを押して表示する方法が一般的です。無限スクロールはページを押すのでなく、下にスクロールすると次のページ内容を取得する。これが取得の限界までできることから無限スクロールと呼ばれています。(infinitescrollとも呼ばれているようです。)
![スクリーンショット 2023-10-25 21.04.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/cc44fa9f-4508-3d01-0a23-f543d22aa30d.png)

## Reactで実装
![スクリーンショット 2023-10-25 21.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/fb0fc254-e230-04ab-770f-fea65529d6bb.png)

```App.tsx
import React, { useState, useEffect } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import { getJsonPlaceholder } from "./api"

const style = {
  border: "1px solid green",
  padding: 8,
  overflow: "hidden"
};

function App() {
  const [items, setItems] = useState<any[]>([]);
  const [hasMore, setHasMore] = useState(true);
  const [page, setPage] = useState(1);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    try {
      const newItems = await getJsonPlaceholder(page)
      console.log('page',page)
      setItems(prevItems => [...prevItems, ...newItems]);
      if (newItems.length < 5) {
        setHasMore(false);
      }
      setPage(prevPage => prevPage + 1);
    } catch (error) {
      console.error("Error fetching data: ", error);
      setHasMore(false);
    }
  };

  const fetchMoreData = () => {
    fetchData();
  };

  return (
    <div>
      <h1>JSONPlaceholder Infinite Scroll Example</h1>
      <hr />
      <InfiniteScroll
        dataLength={items.length}
        next={fetchMoreData}
        hasMore={hasMore}
        loader={<h4>Loading...</h4>}
      >
        {items.map((item, index) => (
          <div style={style} key={item.id}>
            <h3>{item.title}</h3>
            <p>{item.body}</p>
          </div>
        ))}
      </InfiniteScroll>
    </div>
  );
}

export default App;

```

```ts:api.ts
import axios from "axios"

export const getJsonPlaceholder = async (page:number) => {
    const response = await axios.get(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=5`);
    return response.data;
}
```
超解像部門トップのモデルHATの使い方

# ベンチマークトップのモデルを使う

![スクリーンショット 2023-10-25 11.57.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/ba38e535-a843-31b1-fe35-5bb7e9e7463e.png)


https://github.com/XPixelGroup/HAT

### インストール

```shell
git clone https://github.com/XPixelGroup/HAT.git
cd HAT
pip install -r requirements.txt
python setup.py develop
```

### 事前トレーニング済みモデルのダウンロード

```shell
pip install --upgrade gdown
gdown https://drive.google.com/u/0/uc?id=1Ma12vCWT27P9M99-s2RXnynKN-OQsBrv
```

リポジトリで提供されている事前トレーニング済みモデルはGoogle Driveにあります。

https://drive.google.com/drive/folders/1HpmReFfoUqUbnAOQ7rvOeNU3uf_m69w0

### 構成ファイルの書き換え

以下は、自分で用意した画像で実行する場合の手順です。

options/testにある該当モデルの構成ファイルの

```
path:
  pretrain_network_g: ./experiments/pretrained_models/Real_HAT_GAN_SRx4.pth
```

を先ほどダウンロードした事前トレーニング済みモデルファイルのパスに書き換えます。

datasetの項目を

```
datasets:
  test_1:  # the 1st test dataset
    name: custom
    type: SingleImageDataset
    dataroot_lq: input_dir
    io_backend:
      type: disk
```

に書き換え、datarootに自分が超解像したい画像を入れたディレクトリのパスを指定します。

valの項目を以下のみにします。

```
val:
  save_img: true
  suffix: ~  # add suffix to saved images, if None, use exp name
```



### 実行

上記で書き換えた構成ファイルを指定してテストを実行します。

```shell
python hat/test.py -opt options/test/HAT_GAN_Real_SRx4.yml
```

結果はresultsディレクトリに保存されます。

低解像度644*799
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/c7f84f79-822c-9119-d6f5-e03d7fbf1b13.jpeg width=600>

高解像度2576*3196
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/0f911178-9303-679a-d2c5-cfc816899b33.png width=600>

背景がくっきりしましたね。

CUDAのout of memoryが出た場合は、構成ファイルに以下を追加します。
インプット画像を小さく分割して実行します。

```
tile: # use the tile mode for limited GPU memory when testing.
  tile_size: 512 # the higher, the more utilized GPU memory and the less performance change against the full image. must be an integer multiple of the window size.
  tile_pad: 32 # overlapping between adjacency patches.must be an integer multiple of the window size.
```

🐣
****
フリーランスエンジニアです。
AIについて色々記事を書いていますのでよかったらプロフィールを見てみてください。

もし以下のようなご要望をお持ちでしたらお気軽にご相談ください。
AIサービスを開発したい、ビジネスにAIを組み込んで効率化したい、AIを使ったスマホアプリを開発したい、
ARを使ったアプリケーションを作りたい、スマホアプリを作りたいけどどこに相談したらいいかわからない…

いずれも中間コストを省いたリーズナブルな価格でお請けできます。

お仕事のご相談はこちらまで
rockyshikoku@gmail.com

機械学習やAR技術を使ったアプリケーションを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
【プラクティス紹介】1分でさらっと分かる「オープンスペーステクノロジー」

![OST.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3526800/231df0c5-1cda-1791-6451-30fe5eda479a.jpeg)

## プラクティス名（別名）
オープンスペーステクノロジー　（OST）

## プラクティスの目的・狙い
* 参加者が主体的に話し合うことができるオープンな場をつくる
* 立場や興味が異なる多様な参加者が自由に対話することで創造性やアクションを引き出す

## どんな時に使うか
* 現状課題や問題意識を持ち寄り、対話する中で解決の糸口を見つける
* ステークホルダーが集まってプロダクトの方向性を模索する
* 普段あまり接点がない人たちと交流し、新しいアイデアを創出するための場づくり

## 実施手順
1. **オープニング**：ファシリテーターが場の趣旨とルール（４原則＆移動原則）を説明する
1. **マーケットプレイス**：参加者から話したいテーマを募り、どのテーマを、どの場所で、何時から話すのかを決め、壁に貼りだす
1. **セッション**：テーマの提案者（コーラー）がそのセッションを運営する。参加者は自分の興味があるセッションに自由に参加する。
1. **ハーベスト**：各セッションの対話の結果をまとめ、全員に共有する

::: note info 
開催場所は参加者全員が集合できる広めの部屋が必要。そこから部屋の四隅（または別の小部屋）に分かれて、各セッションが行われる。自由に休憩/雑談ができる空きスペースもあった方がよい。
:::

### ４つの原則
* ここにやってきた人は、誰もが適任者である
* 何が起ころうと、それが起こるべき唯一のことである
* いつ始まろうと、始まった時が適切な時である
* いつ終わろうと、終わった時が終わりの時である

### 移動性の原則（別名：二本足の法則）
* 参加者は自分で参加するセッションを選ぶ（どれにも参加しない、もアリ）
* 話されている内容に、興味がない/貢献できない、と感じたら自由に移動してよい

|  | 「移動性の原則」を説明する際に使われるメタファ |
|:-:|:--|
| 蜂  | セッションを次から次へ移動する人。隣のセッションでこんな話が出ていたという貴重な情報をもらたしてくれる。（＝他花受粉の役割を担う）  |
| 蝶  |  セッションに参加せずに休憩/雑談している人。休憩中にぼんやり考えていたことや、何気ない雑談から新たなテーマが生まれることもある。|
| キリン  | 隣のセッション内容が気になっている人。（ナシではないが、気になるようだったら移動してしまった方がよいかもしれない） |

## アレンジ例
* マーケットプレイスで、全ての時間枠を埋めずにあえて余白を残しておく

## アンチパターン
* ファシリテーターが過度に仕切りすぎて、参加者の自主性が失われる
* 冒頭のルール説明が不十分で、「蜂」や「蝶」を不快に感じる人が出てしまう

## 参考情報

体験記（2018年エンタープライズアジャイルの集い）

https://www.ogis-ri.co.jp/otc/hiroba/Report/EnterpriseAgileGathering2018/ost.html

書籍

https://eijipress.co.jp/products/2252

## こぼれ話（私的コメント）
「４つの原則」について少し補足しておきます。
「誰もが適任者」とは、組織上の役職や知識/経験の有無に関係なく、そのセッションに情熱をもって参加している人こそがそのテーマを話す最適者だ、という考え方です。逆に言えば興味を失ったなら「移動性の原則」に従って離脱することが求められている、ともとれます。
セッションによっては当初思ってもみなかった方向に話が進むかもしれませんが、それはたまたまその場ではそうなっただけ、とは考えず「起こるべき」必然だった、と考えます。同じように、「いつ始まって」「いつ終わるか」も、自然の成り行きが全てです。ただし「いつ終わるか」に関しては時間枠を設けておかないと会の運営自体が成り立たないので、制限はあります。
これらの原則は、OSTの考案者であるハリソン・オーウェン氏の気づき「国際会議の場で最も有意義だったのは参加者が自由に対話できるコーヒーブレイクの時間だった」に由来するものです。

　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
ERBFormatter/Beautify 設定

## はじめに
html.erbファイルを保存するときに自動でフォーマットされるようにします。
フォーマッターにはERBFormatter/Beautifyを使います。
https://github.com/aliariff/vscode-erb-beautify

## 環境
`rails 6.1.7`
`ruby 3.0.6`

## extensions.json
フォーマッターの設定は.vscode直下に`settings.json`と`extensions.json`を作成して行います。
今回使うExtensionをjsonに設定しましょう。

```json:.vscode/extensions.json
{
  "recommendations": [
    "aliariff.vscode-erb-beautify"
  ]
}

```

## htmlbeautifier
ERBFormatter/Beautifyは内部的にhtmlbeautifierを使っているのでPCにインストールします。

```terminal
gem install htmlbeautifier
```

あとで設定する時にhtmlbeautifierの実行パスが必要になるので調べておきます。

```terminal
rbenv which htmlbeautifier
```

## settings.json
後はsettings.jsonに設定を記載します。

```json:.vscode/settings.json
{
  "files.associations": {
    "*.html.erb": "erb"
  },
  "[erb]": {
    "editor.defaultFormatter": "aliariff.vscode-erb-beautify",
    "editor.formatOnSave": true
  },
  "vscode-erb-beautify.executePath": "path_to_htmlbeautifier",
  "vscode-erb-beautify.customEnvVar": {
    "LC_ALL": "en_US.UTF-8"
  }
}
```


## 参考リンク
https://qiita.com/pokeneko/items/c80be1af2edb7698f248
https://www.y-i.jp/entry/auto-format-erb-vscode
機械学習で一度40個以上のモデルをトレーニングできるライブラリ：lazypredict

先週github上で「lazypredict」という面白いライブラリを見つけました。
これを使うと、データがすべてのモデル上でのトレーニング結果を表示することができます。

Colab上で「カリフォルニア住宅価格データ」を使って価格予測の回帰トレーニング試してみました
![10-26-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/c1451103-66fe-fb09-4eca-7a0ee13c82c5.png)


モデルのトレーニング結果は以下となります。一部だけのスクリーンショットですが、全部では約40個のモデルの結果が表示されます。
![10-26-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/47a47334-b237-1706-bea0-f8999d5c1b82.png)

回帰問題なのでデフォルトの評価指標はR-SquaredとRMSEですね。分類問題にすると混同行列になります。
また、"custom_metric"というパラメーター使えばカスタマイズ評価指標の結果も出せるようになります。
あとは処理時間（TimeTaken）も見れます。

複数モデルのために、ハイパーパラメーターチューニングはできないですが、データマイニングのケースではハイパーパラメーターチューニングもそれほど重要ではないため、確認用としては特に問題ないと思います。
もちろんモデルに関しては、比較せずLightGBMにしても良いのですが、資料作成の時に「こういう比較結果ありますよ」みたいな感じで活用できるではないかと思います。


興味ある方試してみてください。
github: https://github.com/shankarpandala/lazypredict
[AzureBlobStorage / python] ファイルをアップロードしたいだけなのに

# 1. 概要

## 前提

- `python` で開発作業をしている
- アップロード先は、 Azure の **blob storage service**
- 今回は csv をアップロードした
- html など、他のファイルでも同様の方法でアップロードできるよ


## 発生した課題

Azure の `BlobStorageService` に python コードでファイルをアップロードしたかったのだけど、以下の記事の通りにしたところ、

https://stackoverflow.com/questions/50014827/write-python-dataframe-as-csv-into-azure-blob

下記エラー (など、他1件) が発生した。

```python:databricks
from azure.storage.blob import BlockBlobService

# 出力
ImportError: cannot import name 'BlockBlobService' from 'azure.storage.blob' (/local_disk0/.ephemeral_nfs/envs/pythonEnv-0958e968-c466-4814-af6c-068d76bb71bb/lib/python3.10/site-packages/azure/storage/blob/__init__.py)
```

# 2. 環境

|項目|version など|
|:--|:--|
|実行環境|Azure Databricks|
|python|3.10|
|azure-storage-blob|12.18.3|


# 3. 調査経過

## BlockBlobService について

stackoverflow の以下の記事によると `BlockBlobService` は古いバージョンにあったクラスらしい。 (`2.1.0`?)

https://stackoverflow.com/a/62561949/8674852

自分が使っているバージョンを確認してみたところ、

```python:databricks
%pip list | grep azure-storage-blob

# 出力
azure-storage-blob       12.18.3
```

上記の通り、バージョンに差がありすぎて、古いバージョンの `azure-storage-blob` をインストールする気にはなれなかった。

そこで、新しいバージョンでも使えるクラス (`BlobServiceClient`) で処理を書くことにした。


## BlobServiceClient について

「概要」欄に貼った stackoverflow の記事では、 `create_blob_from_text` が使用されていたが、これまた古いメソッドであり、現在は使用できず、以下のようなエラーが発生した。

```python
AttributeError: 'BlobServiceClient' object has no attribute 'create_blob_from_text'
```

## BlobServiceClient.get_container_client メソッド 

Azure公式の以下の記事より、 `BlobServiceClient.get_container_client` というメソッドを使えば BlobStorageService へとファイルをアップロードできることがわかった。

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-upload-python#upload-a-block-blob-from-a-local-file-path

# 4. ソースコード

結果的にはこれで行けた。

```python:databricks
# module install と restart
%pip install -q azure-storage-blob

dbutils.library.restartPython()
```

```python:databricks
from azure.storage.blob import BlobServiceClient
import pandas as pd


# Create dummy data
data = [
    [1, 2, 3],
    [4, 5, 6],
    [8, 7, 9]
]
df = pd.DataFrame(data, columns=["col1", "col2", "col3"])
output = df.to_csv(index_label="idx", encoding = "utf-8")
print(output)


# Define Auth information, and so on ...
ACCOUNT_NAME: str = "<your account name>"
ACCOUNT_KEY: str = "<your account key>"
CONTAINER_NAME: str = "<your container name>"


# Initialize classes to interact with blob storage
connect_str = (
    'DefaultEndpointsProtocol=https;AccountName=' + ACCOUNT_NAME
    + ';AccountKey=' + ACCOUNT_KEY 
    + ';EndpointSuffix=core.windows.net'
)
blob_service_client = BlobServiceClient.from_connection_string(connect_str)
container_client = blob_service_client.get_container_client(container=CONTAINER_NAME)


# Upload 
blob_client = container_client.upload_blob(
    name="sample_output.csv", data=output, overwrite=True
)
```


# 5. ひとこと

公式サイトはやはり大事。

でも、1発目で公式サイトを見るとげんなりさせられることが多いので、最初は初心者向けの (Qiita とかの) 記事を見て、少しずつ理解を深めるのがスムーズかな。
社内SE、ラズパイ4を買う。パート7（CO2測定　リベンジ編）

・前回

https://qiita.com/ra_risu/items/888c2f37a22f4db090ac

CO2センサー使ったら火事になるかと思うぐらい熱くなって焦げ臭いにおいがした。

・今回

購入したお店に「これ初期不良じゃね？」って問い合わせたら「ちゃんとした環境で使ってそれなら着払いで返送してちょ」って来たので返送したら一営業日で「確かにこっちの不手際だわ、すぐ代替品送るからごめんち」って帰ってきた。
すぐ届いた代替品を使って前回の記事の通りにセッティングしたら数分で設定が終わり、これまでの苦労は何だったのかと思った。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565403/df30f0b3-0805-2ae1-074a-17f5f3ff29f1.png)

あとはこれを使ってライン通知を行うプログラムを書くだけ
とりあえず5分ごとに測定しようと思う。一日に1440回も通知出したらライン側にBOT判定食らいそうだし。

完成したものがこちらになります。

    def LinePrint(msg):

    import mh_z19
    CO2_conce = mh_z19.read_all()["co2"]

    if (CO2_conce > 1000):
        message = "二酸化炭素濃度が" + CO2_conce + "です。換気してください。"
        import requests
        token='(トークン)'
        headers = {'Authorization': 'Bearer %s'%token, }        
        files = {'message': (None, message),}
        r = requests.post('https://notify-api.line.me/api/notify', headers=headers, files=files)

    LinePrint('')

動作確認して終わり！
次は温度・湿度のセンサーが金曜日に届くはずなのでそれを設定する。
Acquia Cloud PlatformでDrupalのAutomated Cronを無効にする

1. 対象のDrupalサイトの管理画面で、Automated Cronモジュールをアンインストールする。
1. Acquia Cloud Platformの管理画面にログインする。対象のアプリケーション、対象の環境ページに遷移して、左メニューから「Scheduled Jobs」に移動する。
1. 「Add Job」をクリックする。
1. 「Job name」に「Drupal Cron」と入力して、「Command」に`/usr/local/bin/cron-wrapper.sh ***.dev https://***dev.prod.acquia-sites.com`を入力する。最後にジョブを実行する頻度を指定して「Submit」をクリックする。


https://docs.acquia.com/cloud-platform/manage/cron/
React コンポーネントとpropsを改めて理解

## はじめに
reactってなんか便利な気がしているんだけど
いまいち理解できてない。。。

改めてドキュメントを読んでみて
腹落ちするか試してみた記録です

## コンポーネント　=　1つの機能をまとめた塊
コンポーネントって言っても大きく2つあるらしい

``関数コンポーネント``
```React:
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
```
propsというオブジェクトを引数として受け取りReact要素を返している
→<font color=red>立派なReactコンポーネント<font/>


``クラスコンポーネント``
```React:
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
```

Reactの視点から、上記2つは等価


## コンポーネントを使っていざ、表示！
Reactではこういう宣言ができる
```React:
const element = <div />;
```
さらに、ユーザー定義のコンポーネントも表せる
```React:
const element = <Welcome name="Sara" />;
```
この時、下記のコードでは　__"Hello, Sara"__　を表示できる
```React:Welcome関数コンポーネント
function Welcome(props) {
   return <h1>Hello, {props.name}</h1>;
 }
    //関数コンポーネントWelcomeを定義する

const root = ReactDOM.createRoot(document.getElementById('root'));
    //idがrootと設定されたDOM要素を指定し、Reactのrootを作成

const element = <Welcome name="Sara" />;
    //Welcome関数コンポーネントを実行し、props.nameに”Sara"を入れる

root.render(element);
    //elementを表示させる
```

## コンポーネントpropsを使えばコードが整理される
下記は1つのコメントを返す、ソーシャルメディアサイトのコードの一例です。
```React:Comment関数コンポーネント
function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}
```
なんだかごちゃごちゃしていて見にくいですね。
コンポーネントの修正にもかなり苦労しそうです。

<font color =red>コンポーネントとpropsを駆使すると。。。
```React:Comment関数コンポーネント(修正後)
function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} /> 　　　　　　　　　　←　コンポーネントを使ってる
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}
```
 
__UserInfo__ という関数コンポーネントにまとめたことで、
こんなにもスッキリ😊しました。

また中で使われているコンポーネントは下記のようになっています。

```React:UserInfo関数コンポーネント
function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}
```
``※UserInfoはCommentの内側でレンダーされているということを知っている必要はない。
``
``なのでpropsは props.user　でOK。Comment内と同じく、authorでなくてよい。``

__User Info__ の中の __Avatar__ コンポーネントはこうなります。

```React:Avater関数コンポーネント
function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}
```


1つのファイルに書き切るのではなく、機能毎に分けることで、
コードの可読性と保守性があがります！

## さいごに
コンポーネントの考え方を理解するのは少々苦戦しますが、
__プロジェクトの全体像→徐々に深層に入っていく__ 
というコードの読み方ができるようになるのでとても重要なようです。

ただし。。。書くには訓練が必要。
またコンポーネントで分けすぎるのと
逆に読みにくくなってしまう((深すぎたり広がりすぎる))ので
__<font color=red>やりすぎ注意！<font/>__ のようです。


まだ関数コンポーネントで分けるときと、クラスコンポーネントで分ける時
何が違うのかはふわっとしているので、
次回それについてもう少し調べてみようと思います。
VSCodeVimのおすすめ設定

VisualStudioCodeではVimのキーバインドで開発ができるように以下のプラグインが提供されています。

・VSCodeVim
https://marketplace.visualstudio.com/items?itemName=vscodevim.vim

こちらのプラグインは、VSCodeのユーザ設定から様々なカスタマイズを行うことができます。
本記事はその中でおすすめな設定を紹介します。

## 前提知識：ユーザ設定の開き方

VSCode上でF1キーを押下し、
setting.jsonと入力すると、Jsonファイル上でユーザ設定を編集することができます。

## おすすめ設定一覧

* OS側とのクリップボードの共有

```
"vim.useSystemClipboard": true
```

デフォルト設定では、OS側とプラグインのクリップボードはそれぞれ独立しており、
OS側でコピーしたコード等をpキーで貼り付けることができません。
また、逆にyキーでコピーした文字列をOS側で扱うこともできません。
上記の設定を入れることで、クリップボードが共有され、お互いにコピー&ペーストが可能となります。

* ショートカットキーのカスタマイズ

```
"vim.handleKeys": {
        //以下はVimのショートカットを利用
        "<C-d>": true,  //下方向へのカーソル移動 ※上方向へのカーソル移動(Ctrl+u)はデフォルト設定でも動作
        //以下はVimではなく、Windows側のショートカット
        "<C-c>": false, //コピー
        "<C-v>": false, //貼り付け ※VisualBlockモードはCtrl＋Qで行う
        "<C-x>": false, //切り取り
        "<C-f>": false, //検索
        "<C-a>": false, //全選択
        "<C-p>": false  //ファイル検索
}
```

VimのコマンドではCtrl+キーを押下することで、様々な操作を行うことができます。(Ctrl+Aでインクリメント等)
VSCodeVimではほとんどのコマンドをサポートしており、一部を除いてOS側のショートカットよりもVim側のコマンドが優先されます。
しかし、Ctrl+V等、OS側のショートカットを優先して使いたい場合もあると思います。
そのような場合に、上記のオプションで設定を無効化することでOS側のショートカットが優先されます。

* jjでノーマルモードに戻る

```
"vim.insertModeKeyBindings": [
    {
        "before": [
            "j",
            "j"
        ],
        "after": [
            "<Esc>"
        ]
    }
]
```

上記のオプションを適用することで、
Escキー以外にも、jjと入力することでインサートモードからノーマルモードに戻ることができます。
指をホームポジションから動かさずにノーマルモードへ切替できるため便利です。

* 選択状態で貼り付け時、クリップボードの内容が書き換わらないようにする

```
"vim.visualModeKeyBindingsNonRecursive": [
    {
        "before": [
            "p",
        ],
        "after": [
            "\"",
            "_",
            "d",
            "P",
        ]
    }
]
```

ビジュアルモード等で文字列を選択した際に、pコマンドで貼り付けを行った場合、
クリップボード上の文字列が最初に選択していた文字列へ書き換わってしまいます。
そこで、上記のオプションを適用することで、クリップボードの書き換わりを防ぐことができます。

※
仕組みとしましては、ビジュアルモード中(選択状態中)にpキーを押すことで「\"\_dp」が実行されるようにしています。
まず、「\"\_」で消去用のレジスタ(\_)が選択されます。
その後dコマンドで文字列の削除が行われ、レジスタ(\_)には削除された文字列が送られます。
(ただしレジスタ(\_)は消去用の特殊なレジスタのため、文字列の保管は行われません。)
この時、文字列が削除されると同時に選択状態が解除されるため、最後のpコマンドを実行してもクリップボードの内容が書き換わらない仕組みとなっています。
新言語「Mojo🔥」に触れてみた

# この記事の読者
* 新しい技術に触れてみたい方
* Mojoに興味のある方

# きっかけ
先日、Qiitaのトレンドを見ていると以下のような記事を発見しましたので、試さずにはいられないと思い、試してみました１

https://qiita.com/mohki7/items/c511274aeb7fe23d3737#python%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%86-python-integration


# 実際に試してみた🔥

## インストール
Mojoのホームページに則ってインストールを行いました。
なお、Mojoのインストールにはどうやらユーザー認証が必要だそうで…。
下記リンクを貼っているページからダウンロードを行ってみてください:)

https://www.modular.com/mojo

## Visual Studio Code の拡張機能をインストール
下記のリンクよりダウンロードいただくか、「Mojo」で検索してみてください！ 

https://marketplace.visualstudio.com/items?itemName=modular-mojotools.vscode-mojo

## 実行🔥！
拡張子は```.mojo```もしくは```.🔥```だそうです。拡張子に絵文字があるのはなんだか新鮮ですね。ちなみに、**実行する内容は```main()```内に記述する必要があります。**

~~~mojo:test01.mojo
fn main():
    print("Hello World!")
~~~
~~~:実行結果
Hello World!
~~~
ちなみに、Pythonのコードも実行できるそうです！

https://docs.modular.com/mojo/programming-manual.html#python-integration

ということで、試してみたら本当に実行できました！

~~~mojo:test02.mojo
def main():
    from python import Python
    let np = Python.import_module("numpy")
    array = np.array([1, 2, 3])
    print(array)
~~~

~~~:実行結果
[1 2 3]
~~~

ということで、これで実際何ができるかなと思って試しで半径から体積を計算できるプログラム作ってみました！

~~~mojo:test03.mojo
def main():
    from python import Python
    let py = Python.import_module("builtins")
    let np = Python.import_module('numpy')
    user_inp = py.input("Enter the rudius of ball: ")
    let radius = py.float(user_inp)
    let volume = radius * radius * 4 * np.pi / 3
    print("Volume is ", volume)
~~~

（てかほとんどPythonで書いてもーてるから意味なくね…？）

## ビルド
ビルドは、```mojo build ファイル名```です。とっても簡単ですね！
```bash:
mojo build test03.mojo
```
すると、実行ファイルが出来上がりますので、実行してみましょう！

```bash:
./test03
```

すると、こんなエラーが、、、
```
Mojo/Python interoperability error: Unable to locate a suitable libpython, please set `MOJO_PYTHON_LIBRARY`
zsh: segmentation fault  ./test03
```

エラーが出てるので直そうと思って調べてみると、どうやらMojoがPythonのバージョンをバイナリに埋め込んでないことが原因だそうです:(

https://docs.modular.com/mojo/roadmap.html

ということで、GitHubのIssue通りにこのバグを直していきたいと思います。

## バグ修正

https://github.com/modularml/mojo/issues/551

### 1.Pythonライブラリのパスの取得
~~~bash:
python3 -c 'import sysconfig; print(sysconfig.get_config_var("LIBDIR"))'
~~~

~~~:実行結果
/opt/homebrew/opt/python@3.11/Frameworks/Python.framework/Versions/3.11/lib
~~~

### 2.共有ライブラリファイルの取得
~~~bash:
ls $(python3 -c 'import sysconfig; print(sysconfig.get_config_var("LIBDIR"))') | grep libpython
~~~

~~~:実行結果
libpython3.11.dylib
~~~
ここで、GitHubのIssueには'''.so'''ファイルを検索するように書いてありますが、実際検索して出てきたファイルの拡張子は```.dylib```です。が、この違いはどうやら問題がないようです。

### 3.環境変数を設定
ちなみに、
~~~:.~/zshrc
export MOJO_PYTHON_LIBRARY="/opt/homebrew/opt/python@3.11/Frameworks/Python.framework/Versions/3.11/lib/libpython3.11.dylib"
~~~

さあ、もう一回ファイルを実行してみると、

```bash:
./test03
```

```:実行結果
Enter the rudius of ball: 2
Volume is  16.755160819145562
```
今度はうまくいきましたね！！やった！

# 感想
* まだまだ完成までの道のりは遠いけど、確かにDjangoしか触ったことのないレベルの僕でも違いがわかるぐらいなので、完成した時の使い道がかなり広そう！
* 絵文字の拡張子はやっぱあたらs（ry
* Pythonを勉強せなあかんなあって思いました。（もっとはよ気づけ）

# 最後に
InstagramやThreadsで何気ない日常やについて投稿してますので、ぜひフォローの方よろしくお願いします:)

https://www.instagram.com/_0_terarin_0_/

https://www.threads.net/@_0_terarin_0_/
構造体と関数のレシーバの関係性

## 今回のゴール

構造体と関数のレシーバの関係性をコードで書いてみて理解する

## 実装

最終的なコードです。

```main.go
package main

import (
	"fmt"
)

type User struct {
	Name string
}

type Task struct {
	TaskName string
}

func (u *User) changePointerName(name string) {
	u.Name = name
}

func (t *Task) changePointerTaskName(name string) {
	t.TaskName = name
}

func main() {
	user1 := &User{
		Name: "アリス",
	}

	task1 := &Task{
		TaskName: "勉強する",
	}

	fmt.Println(user1.Name)
	user1.changePointerName("たくま")
	fmt.Println(user1.Name)

	fmt.Println(task1.TaskName)
	task1.changePointerTaskName("仮眠をとる")
	fmt.Println(task1.TaskName)
}

// アリス
// たくま
// 勉強する
// 仮眠をとる
```

- `changePointerName`メソッドは`User`構造体に対して定義しています。また、`changePointerTaskName`メソッドは`task`構造体に対して定義しています。
- `user1`と`task1`は構造体の実態を定義しています。
- `user1`と`task1`で実態を定義したもののみ、メソッドを処理するようになっている。

## 参考記事
https://qiita.com/Yuuki557/items/e9f5bdfbbfe92973a05e
FFmpegでMP3の音声データをMP4の動画にする

# はじめに
FFmpegというフリーウェアを使って動画を作る方法です。動画といっても静止画に音声をつけるだけです。

# FFmpegの環境設定
Windowsで行います。

1. FFmpegのダウンロード
https://ffmpeg.org/download.html

1. ダウンロードしたzipファイルを解凍します。
```C:\Users\talomina\Downloads```に解凍したとします。
# 素材データをそろえる
用意するもの。
* 画像データ(PNG) ```gazou.png```とします。
* 音声データ(MP3) ```onsei.mp3```とします。

これらのファイルを```c:\Users\talomina\Documents```に置くものとします。

# 動画を作成する
1. Powershellから実行します。

```bat:
C:\Users\talomina\Downloads\ffmpeg-master-latest-win64-gpl-shared\ffmpeg-master-latest-win64-gpl-shared\bin\ffmpeg.exe `
-loop 1 -r 30000/1001 `
-i C:\Users\talomina\Documents\gazou.png `
-i C:\Users\talomina\Documents\onsei.mp3 `
-pix_fmt yuv420p -shortest douga.mp4
```

# おわりに
パスの設定等はしなくてもフルパスで```ffmpeg.exe```を実行することができました。

# 参考文献
https://qiita.com/economist/items/bb325e8d23e0b3521c65
【RPA導入】DX_エントリーロードマップ～体験者は語る～

## はじめに

この記事は、DX化推進に取り組まれる際に
事前に検討すべき項目を経験談とともに記載した記事になります。

DX推進のお役に立てて頂けると幸いです。

業務効率化やDXに取り組む際には、事前に以下の点に対応できるような施策を準備しておくことをお勧めします。

1. ロボット化（ツール化）の前提で業務フローのシンプル化（改善）が必須
1. シンプル化のためには、属人化の排除は必須。業務をすべて可視化しておく
1. 可視化した業務でトリガーが似ている業務のフローを集約し、シンプル化を実施
1. 業務を集約・改善したうえで、複数人での業務対応を実行する
1. 担当の複数人の知見が固まると同時に、ロボット化（ツール化）を検討する
1. ロボット化で空いた時間になにをすべきか認識を合わせておくために、ミッションの設定を工夫する

上記は、以下の経験に基づく提案となりますのでご参考にされてください。

## DXを始める

DX（デジタルトランスフォーメーション）を導入する！と専門の部署も立ち上がりました。
まず、初めにRPAロボットを導入してルーチン業務をロボットに任せてみようとなります。

**✅ TODO**

- 部門ごとに部門内担当者を選定します。
- 自部門のロボット半年で3件作成の目標を設定し、研修実施します。

そしていよいよ、自部門の業務のロボット化に着手していきます。

## RPAロボットを作ってみる

### ＜１＞対象の業務の選定に入ります。

**✅ TODO**

①全体ヒアリング実施　②優先順位設定　③除外対象判定　
④対象確定　⑤結論と反省　

#### ①全体ヒアリング実施
担当者が `自部門のメンバーにロボット化したい業務ってありますか？` とヒアリング実施

出てきた業務は200件強…
何かが違うのでは？という思いを抱きながら、選定開始。

みていくと、年1回の業務から毎日5分の業務まですべてがロボット化希望にあげられている。

#### ②優先順位設定

優先順位は、年次ベースで通算時間が一番かかっている業務から対応を検討していく。

必然的に毎日行う定型業務が上位に挙がってきます。
例：頻度：毎営業日、工数：2H

上から優先順位をつけて、業務フローを確認していきます。

#### ③除外対象判定
提案してくださったメンバーと話をしながら、現在の業務フローで、できることできないことを確認していきます。

そうすると、`前半をロボットで実施、中間を目検で確認する、後半をロボットで実施` のようなフロ―が出来上がったり

ある部分は、`現実としてどうしても人じゃないとできないというステップ` あるいは、`希望として、必ず目視で確認したいというステップ` が途中で入り込んでいたりします。

そういう理由もあり、対象の業務がどんどん除外され、数が小さくなっていきます。

#### ④対象確定

そして、やっとロボットに任せる業務が決まります。
DB内にあるデータを使って、データとデータを突合して、NGな一覧とOKな一覧を吐き出すというチェック業務のみロボット化の対象となりました。

当時、データ突合のスキルがない一部担当者は、目検で対応し長時間残業をしていた為、毎営業日2Hの短縮ができるため、残業は少し少なくなるはずと信じて、RPAロボットでの対応に踏み切りました。


#### ⑤結論と反省

対象がチェック業務のみという結果になった要因ですが、ロボット化の前に業務フローの標準化シンプル化の検討が必要だったのです。

しかし、業務フローをシンプル化するには、担当者のコンクリフト調整や業務手順の見直しなど課題は山積みです。
期限までには到底間に合わないため、シンプル化はスコープから外すという非常にもったいない結果となってしまいました。

### ＜２＞あれ？RPAが停滞しているぞ

結論からですが、ロボットを導入した結果、残業は減りませんでした。

要因ですが、具体的に空いた時間に何をするべきかのすり合わせが不足していたためにロボット化で空いた時間に、メンバー自身で他の業務をどんどん入れていく状況が生まれてしまいました。

### ＜３＞そうだ！業務改善だ

固定した定型業務を変更するには、かなりのパワーが必要になります。
いろんな思いが交錯しています。

担当しているメンバーの思い入れも強い
そもそもの可能性として、
担当者自身は、業務フローを変えたいなんて思っていない可能性もある


色々な思いがある中で、
ロボットを使おうとも、ACCESSやAIを使おうとも
ツールを利用しても、結局、決定（判断）できるのは人であり、
もっと正確に書くと、
会社が決定（判断）しなければならないことに何も変わりはないという認識を
メンバー全員でそろえることが重要かと思います。


## 参考文献

DX戦略とロードマップの立て方 – DXを実現して目指すべき姿とは？  
https://ict-miraiz.com/how-to-create-a-dx-strategy-and-roadmap/
JQueryを学習時に学んだ備忘録


# 文法
ネットで調べたサンプルコードに改造を加えたコードを記載します。

## 属性と要素を指定して内容を取得
### サンプルコード
```index.html
    <ul class="pref_list">
        <li data-id="1">北海道</li>
        <li data-id="2">青森県</li>
        <li data-id="3">岩手県</li>
        <li data-id="4">宮城県</li>
        <li data-id="5">秋田県</li>
        <li data-id="6">山形県</li>
        <li data-id="7">福島県</li> 
    </ul>
```
```main.js
$(function(){
    $('.pref_list [data-id]').click(function(){
        if($(this).data('id')){
            var id = $(this).data('id');
            //クリックした都道府県を標準出力する
            console.log($('[data-id="' + id + '"]').text());
        }
    });
});
```

## プログレスバーと進捗率を表示する
### サンプルコード
```index.html
    <div class="box">
        <div>進捗率：</div>
        <div class="progress-bar">
            <span class="meter-num">0</span>%
        </div>
    </div>
    <input type="button" class="animation_exe" value="アニメーションを実行する">
```

```main.js
$(function(){
    //100%になるまでの時間（ミリ秒）
    var total_time = 10000

    //パーセントの表示 //setIntervalでカウントアップさせる
    //$('.meter-num')内の数字からmetarNumまでカウントする
    function numCount() {
        var num = 0;
        var speed = total_time / 100; //1%あたりの進捗の速さ
        var count = setInterval(function() {
        $('.meter-num').text(num);
        num++;
        if (num > 100) {
            clearInterval(count);
        }
        }, speed);
    }

    //ボタンクリックされたら
    $('.animation_exe').click(function(){
        //1秒かけて青いバーの横幅を300pxに変更
        $('.progress-bar').animate({
            //プログレスバーの横幅
            width:  '500px'
        }, {
            duration: total_time,
            complete: function(){
                //完了したら緑色に変更する
                $('.progress-bar').css('background-color', 'green');
            }
        });
        //ボタンがクリックされた時に進捗率のカウント処理を発火させる
        numCount();
    });
});
```
```main.css
.progress-bar{
    background-color: red; 
    width: 0px; 
    height: 50px; 
    color: white; 
    text-align: center;
    padding: 25px 0px 0px;
}
.meter-num{
    font-weight: bold;
}
```


# トラブルシューティング
## Access Control-Allow-Origin
Ajax通信でURLを指定しGETした際に発生したエラー。
以下のいずれかで解決できる。
1. Chromeでセキュリティの変更
1. 「Access Control-Allow-Origin」という拡張機能を追加し一時的にセキュリティを無効にする

## テキストボックスを無効から有効に変更する
### サンプルコード
```index.html
    <input type="text" name="test_input" disabled>
    <input type="button" class="test_btn" value="disabledを削除する">

    <script>
    $(function(){
        $('.test_btn').click(function(){
            //$('[name="test_input"]').removeProp('disabled'); //こちらも試したが無効のままだった
            $('[name="test_input"]').prop('disabled', false);
        });
    });
    </script>
```

# 参考
### [キノコログ](https://kinocolog.com/jquery/)
サンプルコードベースで関数を勉強することができる。
MySQLのLEFT JOIN（INNER JOIN, RIGHT JOIN, LEFT OUTER JOIN）が何者か調べてみたのでメモのすけ

どうもこんにちは。

今回は業務内でMySQLを使用して、`LEFT JOIN`というコードが何者かわからず勉強したのでメモします。

# LEFT JOINって何？

そもそも、`JOIN`がSQLでいうと「結合」という意味らしいです。

要するに、二つのテーブルを結合するということですかね。

`LEFT JOIN`のコードを作成すると以下のようになります。

```SQL
SELECT *
FROM table1
LEFT JOIN table2 ON table1.id = table2.id;
```

何をやっているかわからないので例を出します。以下の二つのテーブルが存在します。

＜table1＞
| id | name |
| --- | --- |
| 1	| Alice |
| 2	| Bob |
| 3	| Carol |

＜table2＞
| id | score |
| --- | --- |
| 1	| 95 |
| 3	| 88 |
| 4	| 79 |

この二つのテーブルに対して、`LEFT JOIN`のコードを当てます。

そうすると、以下のようになります。

| id | name | score |
| --- | --- | --- |
| 1	| Alice | 95 |
| 2	| Bob | null |
| 3	| Carol | 88 |

作成した`LEFT JOIN`のコードは、table1がメインのコードになっています。
なので、table1のIDと同じIDのデータをtable2から探して、一致したデータをくっつけます。

# RIGHT JOINは？

`RIGHT JOIN`のコードを作成すると以下のようになります。

```SQL
SELECT *
FROM table1
RIGHT JOIN table2 ON table1.id = table2.id;
```

先ほど用意した二つのテーブルに対して、`RIGHT JOIN`のコードを当てます。

そうすると、以下のようになります。

| id | name | score |
| --- | --- | --- |
| 1	| Alice | 95 |
| 3	| Carol | 88 |
| 4	| null | 79 |

作成した`RIGHT JOIN`のコードは、table2がメインのコードになります。
なので、table2のIDと同じIDのデータをtable1から探して、一致したデータをくっつけます。

`LEFT JOIN`の動作と違うのは**メインとするテーブルが異なる点**になようです！

# INNER JOINは？

`INNER JOIN`のコードを作成すると以下のようになります。

```SQL
SELECT *
FROM table1
INNER JOIN table2 ON table1.id = table2.id;
```

先ほど用意した二つのテーブルに対して、`INNER JOIN`のコードを当てます。

そうすると、以下のようになります。

| id | name | score |
| --- | --- | --- |
| 1	| Alice | 95 |
| 3	| Carol | 88 |

`INNER JOIN`には、メインのテーブルとかはなさそうですね。
両方のテーブルを比較して、比較対象のカラムが一致したもののみ結合するという感じです。もっと言うと`NULL`は受け付けないよと言う感じですね。

# 似たようなLEFT OUTER JOINって何者？

これは似てるのではなく、**同じ**らしいです。

なんやねん。

# まとめ

個人的に使用するなら、NULLを受け付ける時には`LEFT JOIN`で、NULLを受け付けないなら`INNER JOIN`かなと言う印象です！
はじめて読む486　第7章 割り込み

## 7. 割り込み

## 7.1 割り込み

- 割り込み機能により、タイミングを予測できない周辺装置の制御処理を行うことができる
- 割り込みの処理の流れは以下の通り
    1. 割り込みの発生
        - 何らかのきっかけ（割り込み要因）を検出してプログラムの実行を中断する（割り込みが発生）
    2. 割り込み処理ルーチンの呼び出し
    3. 割り込み処理ルーチンの実行
        - 処理内容は、割り込み要因の種類によって異なる
    4. 割り込み処理の終了
- 割り込みの種類
    
    
    | 割り込みの種類 |  | 発生源 |
    | --- | --- | --- |
    | ハードウェア割り込み |  | 周辺機器からの信号によって発生する |
    | 例外割り込み | トラップ | INT、INTO命令の実行によって発生する（ソフトウェア割り込み） |
    |  | フォールト | 保護機能、MMUのチェックによって発生する |
    |  | アボート | 処理を続けられないエラーが起きた場合に発生する |

## 7.2 ハードウェア割り込み

- ハードウェア割り込みは、486の割り込み入力端子に信号が送られてくることによって発生する割り込み
- 割り込みコントローラが複数の割り込み要因から送られてくる割り込み要求信号を調停して優先度の高いものを1つ選んで486に伝える役割を持っている
- 割り込みコントローラは、486が割り込みを受け付けた後、割り込み要因に対応する割り込み番号をデータバスを通じて486に送る
    - 割り込み番号は00HからFFHの256種類
- 486内部のフラグレジスタの第9ビットは割り込み許可フラグと呼ばれ、ハードウェア割り込みの受け付けをコントロールする役割がある
    - 割り込み許可フラグを変更する処理はアセンブリ言語で記述する
    - CLI（Clear Interrupt Flag）命令は割り込み許可フラグを0にリセットする
    - STI（Set Interrupt Enable Flag）命令は割り込み許可フラグを1にセットする
    - 割り込み禁止状態のときに信号が送られると、割り込み許可状態になった途端に割り込みが発生する

## 7.3 例外割り込み

- トラップ
    - ソフトウェア割り込みとも呼ばれる
    - マシン語命令のINT、INTO命令が割り込み要因となって発生する
    - MS-DOSでは、アプリケーションソフトウェアがオペレーティングシステムやBIOSを呼び出す方法として使われている
- フォールト
    - マシン語命令を実行しているときに検出された例外状態が割り込み要因となって発生する割り込み
    - 保護機能に関するフォールトは多くがプログラムの実行を継続するのが困難なため、元のプログラムに戻らず強制終了させる
    - メモリ管理に関するフォールトの場合は、適切にメモリを配置しなおせばフォールトの原因になったマシン語命令を実行できるようになる場合があり、その場合は元のプログラムに戻って命令を再実行する
    
    |  割り込み番号 | フォールトの原因 |
    | --- | --- |
    | 00H | 除算エラー |
    | 01H | デバッカ割り込み |
    | 05H | 配列境界違反 |
    | 06H | 無効命令 |
    | 07H | コプロセッサ無効 |
    | 0AH | 無効TSS |
    | 0BH | セグメント不在 |
    | 0CH | スタック例外 |
    | 0DH | 一般保護例外 |
    | 0EH | ページフォールト |
    | 10H | コプロセッサエラー |
    | 11H | アラインメントチェック |
- アボート
    - マシン語命令を実行しているときに検出された例外状態が割り込み要因となって発生する割り込み
    - フォールトよりも致命的なエラー
        - 例えば、フォールトが発生し、対応する割り込み処理ルーチンが無効なセグメントにあったりした場合
    
    |  割り込み番号 | アボートの原因 |
    | --- | --- |
    | 08H | ダブルフォールト |
    | 09H | コプロセッサセグメントオーバーラン |
- ハードウェア割り込みやトラップに対応する割り込み番号は、20H以上の番号の中から選ぶ

## 7.4 割り込み処理

- リアルモードでの割り込み処理
    - 割り込み番号と割り込み処理ルーチンの対応を割り込みベクタテーブルによって設定する
    - 割り込みベクタテーブルは、割り込み処理ルーチンのアドレスを割り込み番号の順に並べておくようになっている
    - 割り込みが発生すると、486はフラグ、CS、IPレジスタの値をこの順でスタックにPUSHし、割り込みベクタをロードし割り込み処理ルーチンを実行する
    - 割り込み処理ルーチンの末尾ではIRET命令を実行し、スタックからIP、CS、フラグレジスタの値をPOPする
- プロテクトモードでの割り込み処理
    - 割り込みディスクリプタテーブル（IDT）を使用し、割り込みが発生すると、割り込み番号に対応する位置にあるゲートが呼び出される
    - 割り込みディスクリプタに格納するゲートは、割り込みゲート、トラップゲート、タスクゲートがある
        - 割り込み、トラップゲートはコールゲートと同じ構造をしている
        - 割り込みゲートは割り込み許可フラグが割り込み禁止状態になる
            - ハードウェア割り込みに対応するゲートは、一般に割り込みゲートを使用する
        - トラップゲートでは割り込み許可フラグは割り込み前の状態と同じ
- IDTR
    - 割り込みディスクリプタを指し示すために使われるレジスタ
    - IDTRに値を設定するには、LIDT命令を使う

## 7.5 ハードウェア割り込みを確認する

- GPE（General Protection Exception）
    - 保護機能に違反した命令の実行時には、割り込み番号0DHの一般保護例外（GPE）が発生する
    - 一般保護例外では、他の割り込みと違い、フラグレジスタ、CSレジスタ、IPレジスタに加えて、エラーコードがスタックにPUSHされた状態で割り込み処理ルーチンが呼び出される
    - エラーコードはIDT、TI（エラーコードがGDTを参照しているか、LDTを参照しているか）、セレクタ値からなり、例外の原因を表している
- シャットダウン
    - 割り込みの設定が適切に行われていないときに割り込みが発生したり、割り込みゲートの設定が誤っていて対応する割り込み処理ルーチンに制御を移せなくなってしまったときには、486はシャットダウン状態に入る
    - シャットダウン状態になると、486は外部にシャットダウン信号を出力し、シャットダウン検出回路がこれを検出し、リセット回路を働かせる（システム全体を再起動）
未経験エンジニア読め　「飛ぶぞ…」

　　　　　　・要件定義

- プログラムを作れるようになるには課題設定とタスクバラシが骨格
- 作る必要がないものは作らない
- 最初に課題定義しておかないと意味のないものを作ってしまいがち！

- **具体化**

　　　①課題を設定する

　　　②要件に落とし込む

　　　③要件をタスクにバラシ、実行する順番を決める

　　　④１つずつやっていく

- **課題定義**

　　　→先ずは背景・目的を決める

　　　→次に達成状況(ゴール)を決める

　　　→最後にやらないことを決める

- **要件定義**

　　　→システムを作るうえでの必要な条件を定義して、システムに落とし込みたい

　　　→今回は、業務要件・機能要件のみ行う

　　　→また、非機能要件・運用保守要件は定義しない

　　　　・業務要件

　　　　　　　登場人物ごとに業務(行動)の流れを落とし込むこと

　　　　　　　業務要件を行わないと、利用者の行動に沿ったものにならず非常に使いずらくなる

　　　　　　　具体的な行動を想像してみて、それを１つずつ図にしていく

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/688f319d-48b4-442e-8a22-be4ffb6e5465/fa043a40-bef1-4d3a-8a31-a8319793b428/Untitled.png)

[https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=4#4d6a624323844d1baf9cca550bfbe917](https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=21)　　　

- 機能要件

　　　・ページ遷移図(サイトの全体の構成が明確になる)

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/688f319d-48b4-442e-8a22-be4ffb6e5465/fca69f9a-6298-406d-9953-c03f454a38e9/Untitled.png)

　　　　[https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=4#4718f13913da488ba5755516ba9eb7b3](https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=21)

　　　　

　　　　・WF(デザインを当てずにページの構成要素をまとめたもの)

　　　→WF，機能(そのページでできること)，データを３つ１セットでまとめる!!

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/688f319d-48b4-442e-8a22-be4ffb6e5465/22d00fc8-edee-4c9f-8095-ac463b6fc220/Untitled.png)

　

[https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=4#11affe02a8a04a89b2ab70fec78e6bc9](https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=21)　

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/688f319d-48b4-442e-8a22-be4ffb6e5465/fba896db-7212-44ea-8e3e-97c726473f73/Untitled.png)

[https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=4#cf49682243854ccbb101ef198b2e64d7](https://www.notion.so/89a2932aa442401794e7c5b18f045d95?pvs=21)

出典：独学エンジニア
Flutter、Dart言語の基礎を学習する際に参考にしたサイト

# はじめに
Flutterを二週間ほど学習した中で参考にしたサイト、動画や本などをまとめてみます。

## Flutter超入門【2022年6月】
こちらはFlutterエンジニアに特化したコミュニティの「FLutter大学」を運営されているKboyさんが、AndroidSturdioを使用してFlutterのセットアップから、簡単なWidgetを表示するまでの基礎的な内容を学習できます。
丁寧に解説されているので、入門として非常にわかりやすくて良いと感じました。
https://www.youtube.com/playlist?list=PLuLRJz1UnJzHX1dDN-jnaa7gQ3Av7eEmJ

本で学習したい方はこちらの本がおすすめです。
上記でご紹介した動画を本にまとめたものになります。

https://zenn.dev/kboy/books/ca6a9c93fd23f3


##　Dartの教科書 by Flutter大学
こちらも「FLutter大学」が初買いしている本になります。
Flutterで使用する基本文法をFlutte初心者でもわかりやすいように丁寧に書かれています。
https://zenn.dev/flutteruniv/books/dart-textbook

## The Complete Flutter Development Bootcamp with Dart
こちらは、オンライン学習プラットフォーム「udemy」でFlutterの基礎から応用までを学べるコースです。
講師のAngelaYuさんは世界的に有名なインストラクターで、この講座はGoogle Flutterチームと共同で作成されたようです。
Dart言語の基礎、Widgetの基礎、Firebaseの使い方まで幅広く学習できます。
英語の動画になりますが日本語字幕も付けれますので、英語が分からないという方でも問題なく進められるかと思います。
https://www.udemy.com/course/flutter-bootcamp-with-dart/

## Flutter documentation
最後にご紹介するのはFlutterの公式ドキュメントになります。
分かりやすいサイトはたくさんありますが、やはり一番詳しく信頼性が高い情報が載っているのは公式ドキュメントですので、早いうちから公式ドキュメントを見ることに慣れておくのがおすすめです。
全て英語で書かれていますが翻訳すれば問題なく進められるかと思います。
https://docs.flutter.dev/

# まとめ　
今回はFlutterの基礎を学習するのに参考になったものを簡単にまとめてみました。
Flutterを学習してみた感想としては、学びやすい環境が整っていてとても楽に進められました。
Flutterにはホットリロード、ホットリスタート機能が優秀なためコードを修正した後すぐにシミュレーターで確認出来るのはすばらいいなと感じました。
Xcodeだとビルドするのに時間かかる場合があるので。。。
最後までご覧いただきありがとうございました！
【Vitest】日時を固定してテストする方法【new Date()】

## はじめに

日時によって結果が変わる処理をテストをする場合、`new Date()`はテストの実行日時となりますが、Vitestではモックして日時を固定することができます。

`vi.useFakeTimers()`で日時のモックを有効化して、`vi.setSystemTime()`で日時を指定すると、テスト処理の`new Date`が指定した日時となります。

## コード

```typescript
import { afterEach, beforeEach, expect, test, vi } from 'vitest'

// カフェが営業中かどうか調べる関数
const checkOpenCafe = () => {
  const date = new Date()

  const hours = date.getHours()

  // 8時〜18時なら営業中、それ以外は営業時間外
  return 8 < hours && hours < 18
}

beforeEach(() => {
  // 日時のモックを有効化
  vi.useFakeTimers()
})

afterEach(() => {
  // 実際の日時に戻す
  vi.useRealTimers()
})

test('現在時刻が9時の場合を検証', () => {
  vi.setSystemTime(new Date('2023/01/01 09:00:00'))

  const isOpenCafe = checkOpenCafe()

  expect(isOpenCafe).toBe(true)
})

test('現在時刻が23時の場合を検証', () => {
  vi.setSystemTime(new Date('2023/01/01 23:00:00'))

  const isOpenCafe = checkOpenCafe()

  expect(isOpenCafe).toBe(false)
})
```

`vi.useRealTimers()`で実際の日時に戻さないと、次のテストに影響が出るため注意が必要です。

## まとめ

Vitestで日時を固定してテストする方法をご紹介しました。`vi.setSystemTime()`で簡単に日時をモックできるので便利だなと思いました。

## 最後に

### GoQSystemでは一緒に働いてくれる仲間を募集中です！

ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=122d5eb4cafd903cdeb9
ABC325（A~C問題）をPythonで解く

## 初めに

この記事はABC325のA,B,C問題をPythonを使って解いてみた記録となります。

### コンテストへのリンク

https://atcoder.jp/contests/abc325



## Problem A Takahashi san
[Problem A](https://atcoder.jp/contests/abc325/tasks/abc325_a)

### 考察

苗字と名前がもらえるので苗字にsanをくっつけて出しました。

### コード

```python
S, T = map(str, input().split())
print(S, "san")
```

## B問題 World Meeting
[Problem B](https://atcoder.jp/contests/abc325/tasks/abc325_b)

### 考察

`collections`の`defaultdict`に0時から23時（標準時）までのキーを持ち、参加可能な人数を足していくイメージでコードを書きました。

### コード

営業開始時間から9時間後までの全てのキーに参加可能人数を足します。日付を跨いでしまうとカウントできないので`mod`で余りを取りました。

```python 
from collections import defaultdict

N = int(input())
w = list()
for _ in range(n):
    w1, w2 = map(int, input().split())
    w.append([w1, w2])

d = defaultdict(int)

for i in range(N):
    for j in range(9):
        d[(w[i][1] + j) % 24] += w[i][0]

print(max(d.values()))


```




## C問題 Sensors
[Problem C](https://atcoder.jp/contests/abc325/tasks/abc325_c)

### 解法

問題文を読んだときには（木の個数を数えればいいのか…？）と思いましたが、方法が思いつかずかなり苦戦しました。入力時から木を作れればと思ったのですが、ピンと来なかったので最終的には幅優先探索で解きました。

### コード

手順としては、
1. 全てのマス目に対して順番に
2. まだチェックしていない（木に加えられていない）`#`の時は
3. 木の数を1つ増やし、キューを作ってそのマスを追加
4. そのマスの周囲8マスを探索
5. まだチェックしていない（木に加えられていない）`#`の時は
6. キューに追加して続行　\
で書いています。

```python
from collections import deque 

H, W = map(int, input().split())
S = []
for _ in range(H):
    s = input()
    S.append(s)

cnt = 0

Seen = [[False] * W for _ in range(H)]

for row in range(H):
    for col in range(W):
        if S[row][col] == "#" and not Seen[row][col]:
            cnt += 1
            d = deque()
            d.append((row, col))
            while d:
                i, j = d.popleft()
                for dr in [-1, 0, 1]:
                    for dc in [-1, 0, 1]:
                        if dr == dc == 0:
                            continue 
                        else:
                            if (0 <= i+ dr < H and
                                0 <= j + dc < W and
                                S[i+dr][j+dc] == "#" and
                                not Seen[i+dr][j+dc]):
                                d.append((i+dr, j+dc))
                                Seen[i+dr][j+dc] = True

print(cnt)
```