OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScriptによるセキュリティ攻撃

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/3f06f408-5a88-4cc0-9566-cac9c18bd7ac.png)
1:攻撃の概要
 JavaScriptを埋め込まれてしまうような攻撃を許すWebアプリケーションは、この攻撃に対する脆弱性があると言えます。そして、悪意のあるプログラムを脆弱性のあるWebアプリケーション上で実行させるような、JavaScriptを利用した攻撃方法をXSSと言います。

①XSS（Cross Site Scripting）エックスエスエス（クロスサイトスクリプティング）
　XSSとは、攻撃者が脆弱性のあるWebアプリケーション上に、悪意のあるJavaScriptのプログラム（スクリプト）を埋め込み、そのサイトの利用者を攻撃する手法です。

　「スクリプトを埋め込む」とは、ユーザーがブラウザ上で表示するHTML中に、JavaScriptのプログラムを埋め込むことを言います。
　悪意のあるスクリプトをWebアプリケーションを表示したときに実行させることをゴールとした攻撃がXSSです。「クロスサイトスクリプティング」のうち、スクリプトを埋め込んで実行させることが「スクリプティング」に該当します。

　実際はユーザーの個人情報などを、悪意のある人のサーバーなどへ送付するスクリプトが埋め込まれることが多いです。

２：XSSの種類
　「反射型XSSクロスサイトスクリプティング」
　ユーザーが悪意のあるURLをクリックすると、脆弱性のあるWebアプリケーション上でスクリプトが実行されるようにする手法です。

それぞれのステップについて説明します。

①ユーザーにURLをクリックさせる
攻撃者が、ユーザーに悪意のあるURL（脆弱性のあるWebアプリケーションへ遷移するURLに細工をしたもの）をクリックさせます。ユーザーにクリックさせる方法としては、メールで送付したり、掲示板などに書き込んだりすることがあります。

②ユーザーがクリックすると脆弱性のあるWebアプリケーション上でスクリプトが動く
上記の悪意のあるURLには、脆弱性のあるWebアプリケーション上で発火するスクリプトが仕込まれています。そして、ユーザーが脆弱性のあるWebアプリケーションのページを開くと、そのスクリプトが発火します。

③スクリプトが発火すると、攻撃者のサーバーへ個人情報が送られる
直前のステップで発火したスクリプトは、個人情報を抜き取るようなものでした。クリックしたユーザーの個人情報が攻撃者のサーバーへ記録されてしまいました。

この様に、URLをクリックしてレスポンスがあると、即座にスクリプトが実行されることから、「反射型」と呼ばれます。

また、上図のように別のサイト（またはメールなど）から、脆弱性のあるWebアプリケーションへ遷移したあとにスクリプトが実行されます。これが「クロスサイトスクリプティング」の「クロスサイト（Webサイト間をまたぐ）」を意味します。

「格納型XSSクロスサイトスクリプティング」
　脆弱性のあるWebアプリケーションの投稿などに、悪意のあるスクリプトを埋め込み、ユーザーがそのWebアプリケーションを訪れたときにスクリプトが発火するようにする攻撃手法です。

それぞれのステップについて説明します。

①攻撃者が、脆弱性のあるWebアプリケーションにスクリプト付きの投稿をする
フォームからコンテンツを投稿する際に、スクリプトを埋め込んで投稿をします。

②ユーザーが、その投稿のあるページを訪れるとスクリプトが発火する
スクリプトが埋め込まれた投稿のページを開くと、そのスクリプトが発火します。または、画像にマウスを合わせるとスクリプトが発火するような仕掛けになっていることもあります。

③スクリプトが発火すると、攻撃者のサーバーへ個人情報が送られる
直前のステップで発火したスクリプトは、個人情報を抜き取るようなものでした。ユーザーの個人情報が攻撃者のサーバーへ記録されてしまいました。

　このように、脆弱性のあるWebアプリケーションにスクリプトを格納し、ユーザーが訪れたタイミングで発火するようになっていることから「格納型」と呼ばれます。
SpringBoot でファイルダウンロード

SpringBootにて、ファイルをダウンロードするユーティリティメソッドを作ったのでメモとして残します。
引数は、ダウンロード対象のファイルパス、出力ファイル名、HttpServletResponseです。
Controllerの引数でHttpServletResponseを読み込むことで、これを利用することができます。

---

```Java
	/**
	 * ファイルダウンロード
	 * 
	 * @param originFilePath ダウンロードファイルパス
	 * @param outputFileName 出力ファイル名
	 * @param response       HttpServletResponse
	 */
	public static void downloadFile(String originFilePath, String outputFileName, HttpServletResponse response) {
		String CONTENT_DISPOSITION_FORMAT = "attachment; filename=\"%s\"; filename*=UTF-8''%s";
		outputFileName = String.format(CONTENT_DISPOSITION_FORMAT, outputFileName,
				UriUtils.encode(outputFileName, StandardCharsets.UTF_8.name()));
		try (OutputStream os = response.getOutputStream();) {
			Path filePath = Path.of(originFilePath);
			byte[] fb = Files.readAllBytes(filePath);
			response.setContentType("application/octet-stream");
			response.setHeader(HttpHeaders.CONTENT_DISPOSITION, outputFileName);
			response.setContentLength(fb.length);
			os.write(fb);
			os.flush();
			Files.delete(filePath);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
```
JacksonでCSV書込み

CSVファイル作成のユーティリティメソッドを作ったのでメモとして残します。
引数には出力クラス、ファイルパス、追記フラグ、クォートフラグ（ダブルクォーテーションのありなし）、改行コードを用意しました。

---

```Java
	/**
	 * CSVファイル書込み
	 * 
	 * @param <T>           CSV出力クラス
	 * @param filePath      ファイルパス
	 * @param csvList       CSV出力リスト
	 * @param appendFlg     追記フラグ
	 * @param quoteFlg      クォートフラグ
	 * @param lineSeparator 改行コード
	 */
	@SuppressWarnings("unchecked")
	public static <T> void writeCsv(String filePath, List<T> csvList, Boolean appendFlg, Boolean quoteFlg,
			String lineSeparator) {
		Class<T> clazz = (Class<T>) csvList.get(0).getClass();
		CsvMapper csvMapper = new CsvMapper();
		CsvSchema csvSchema = null;
        if (appendFlg) {
             csvSchema = csvMapper.schemaFor(clazz).withLineSeparator(lineSeparator);
        } else {
             csvSchema = csvMapper.schemaFor(clazz).withHeader().withLineSeparator(lineSeparator);
        }        
		csvMapper.configure(CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS, quoteFlg);
		try {
			// アップロードファイルをバイト値に変換
			byte[] bytes = csvMapper.writer(csvSchema).writeValueAsString(csvList)
					.getBytes("MS932");
			FileOutputStream stream = new FileOutputStream(filePath, appendFlg);
			// ファイルに書き込み
			stream.write(bytes);
			// ファイルクローズ
			stream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
```
【Python】*argsとか**kwargsとかって何？

# はじめに

Kivyの[公式文書](https://kivy.org/doc/stable/api-kivy.uix.boxlayout.html)を眺めていたときに、超基本的メソッドである`add_widget`に書かれている`*args`や`**kwargs`の意味が分からなかったので、調べたことをまとめました。
（Kivyが分からない方でも大丈夫です！今回は全く使いません）


# 目次
- 環境のバージョン
- Pythonでの`*args`と`**kwargs`
- 参考文献


# 環境のバージョン
- macOS Ventura 13.4.1
- Python 3.11.2


# Pythonでの`*args`と`**kwargs`
## `*args`について
### ① 基礎の形

実際に簡単な例を紹介します。

```python:example.py
def cal_sum(*args):
    return sum(args)

def cal_sum_type(*args):
    return type(args)

sum_a = cal_sum(1, 2, 3, 4, 5)
sum_b = cal_sum(10, 20, 30, 40)
type_a = cal_sum_type(1, 2, 3, 4, 5)

print('a =', sum_a)
print('b =', sum_b)
print('a is', type_a)
```

結果
```
a = 15
b = 100
a is <class 'tuple'>
```

これを見るに、どうやら関数に代入した値を、丸ごとタプルとして扱えるようです。
ちなみに、関数内では`*args`ではなく`args`を使います。

---
### ②他の変数と一緒に使う
では、他にも代入したいものがあった場合はどうでしょう。
```python:example.py
def fruit_div(fruit, number, *args):
    print('----------')
    print('*args =', args)
    print(number, '個の', fruit, 'を', sum(args), '個に分けたよ')

fruit_div('りんご', 1, 2, 3, 4, 5)
fruit_div('ぶどう', 10, 20, 30, 40)
fruit_div('もも', 1)
```

結果
```
----------
*args = (2, 3, 4, 5)
1 個の りんご を 14 個に分けたよ
----------
*args = (20, 30, 40)
10 個の ぶどう を 90 個に分けたよ
----------
*args = ()
1 個の もも を 0 個に分けたよ
```

このように、最初に`fruit`、`number`に必要な値は代入され、残りの右側の部分は丸ごと`*args`に代入されます。
`*args`がない場合でもエラーは出ず、空のタプルが代入されるようです。(正直0個には分けないで欲しかったんですけどね...)

ちなみに、`*args`は一番後ろに書いた方が良さそうです。

<details><summary><strong>一番後ろじゃないとこうなります。</strong></summary>

```python:example.py
# numberと*argsを逆にしただけ
def fruit_div(fruit, *args, number):
    print('----------')
    print('*args =', args)
    print(number, '個の', fruit, 'を', sum(args), '個に分けたよ')

fruit_div('りんご', 1, 2, 3, 4, 5)
```

結果
```
TypeError: fruit_div() missing 1 required keyword-only argument: 'number'
```

「`number`がないぞ！」って怒られちゃいました。後ろの引数全てを`*args`に代入してしまったようです。エラーが起きない方法もありますが、ここでは解説しません。

</details>


## `**kwargs`について

基本は`*args`と一緒ですが、`**kwargs`は代入したものが辞書型になります。

```python:example.py
def dic_age_dog(**kwargs):
    print('----------')
    print('*kwargs =', kwargs)
    print(type(kwargs))

def dic_age(kind, **kwargs):
    print('----------')
    print('kind =', kind)
    print('*kwargs =', kwargs)

dic_age_dog(pochi=1, hana=2, kuro=3, buchi=4)
dic_age('animal', hamu=1, tori=2, neko=3, inu=4)
```

結果
```
----------
*kwargs = {'pochi': 1, 'hana': 2, 'kuro': 3, 'buchi': 4}
<class 'dict'>
----------
kind = animal
*kwargs = {'hamu': 1, 'tori': 2, 'neko': 3, 'inu': 4}
```

`*args`のときと同様、残りの右側の部分は丸ごと`**kwargs`に代入されます。



# 参考文献

[Pythonの可変長引数（*args, **kwargs）の使い方 - note.nkmk.me](https://note.nkmk.me/python-args-kwargs-usage/)
Ruby 配列 ブロックについて 2

# はじめに
- Rubyの配列やブロックの復習用(2日目)
- 学習したことの備忘録
- 「[Ruby 配列 ブロックについて](https://qiita.com/takayuki91/items/8842c3ac481528097251)」の続き

# 学習内容
##### 配列(Arrayクラス）
- 要素の選択や追加
- 集合

# 参考にした教材
- [プロを目指す人のためのRuby入門]( https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERuby%E5%85%A5%E9%96%80-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E6%8A%80%E6%B3%95%E3%81%BE%E3%81%A7-Software-Design-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4774193976)
- [Ruby リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/doc/index.html)

# 配列(Arrayクラス）
```rb
a = [1, 2, 3, 4, 5]
```

<details><summary>変数aの配列の2つ目の要素から2つ分の要素を取り出したいとき</summary>

`配列[位置, 取得する長さ]` 
```rb:例
a = [1, 2, 3, 4, 5]

puts a[1, 2] => 2, 3
```
</details>

<details><summary>変数aの配列の1つ目、3つ目の要素を選択して取り出したいとき</summary>

`values_atメソッド` 取得したい要素の添字を複数指定
```rb:例
a = [1, 2, 3, 4, 5]

puts a.values_at(0, 2) => 1, 3
```
</details>

<details><summary>変数aの配列の最後の要素を取り出したいとき（メソッドなし）</summary>

```rb:例
a = [1, 2, 3, 4, 5]

puts a[-1] => 5
```
</details>

<details><summary>変数aの配列の最後の要素を取り出したいとき（メソッドあり）</summary>

`lastメソッド` 配列の最後の要素を取得
```rb:例
a = [1, 2, 3, 4, 5]

puts a.last => 5
```
</details>

<details><summary>変数aの配列の最後の要素から3つを取り出したいとき</summary>

`lastメソッド` 配列の最後の要素を取得
```rb:例
a = [1, 2, 3, 4, 5]

puts a.last(3) => 3, 4, 5
```
</details>

```rb
b = []
```
<details><summary>変数bに1,10,100を追加したいとき</summary>

`pushメソッド` 配列に要素を追加
```rb:例
b = []

puts b.push(1, 10, 100) => 1, 10, 100
```
</details>

```rb
array = [1]
other = [2, 3]
```
<details><summary>変数arrayと変数otherの配列を連結したいとき（破壊的）</summary>

`concatメソッド` 「concat(other)」で配列otherを自身の末尾に破壊的に連結
```rb:例
array = [1]
other = [2, 3]

puts array.concat(other) => 1, 2, 3
```
</details>

<details><summary>変数arrayと変数otherの配列を連結したいとき（破壊的でない）</summary>

```rb:例
array = [1]
other = [2, 3]

linking = array + other
puts linking　 => 1, 2, 3

# 参考
puts array => 1
puts other => 2, 3
```
</details>

```rb
a = ["カレー", "ラーメン", "寿司"]
b = ["ステーキ", "寿司", "パエリア"]
```

<details><summary>変数aと変数bの和集合</summary>

```rb:例
a = ["カレー", "ラーメン", "寿司"]
b = ["ステーキ", "寿司", "パエリア"]

puts a | b => カレー, ラーメン, 寿司, ステーキ, パエリア
```
</details>

<details><summary>変数aと変数bの差集合（aからbを取り除く）</summary>

```rb:例
a = ["カレー", "ラーメン", "寿司"]
b = ["ステーキ", "寿司", "パエリア"]

puts a - b => カレー, ラーメン
```
</details>

<details><summary>変数aと変数bの積集合</summary>

```rb:例
a = ["カレー", "ラーメン", "寿司"]
b = ["ステーキ", "寿司", "パエリア"]

puts a & b => 寿司
```
</details>

### 本格的に集合演算をする場合
配列よりもSetクラスを使う方が望ましいとのこと
```rb
require "set"
a = Set["カレー", "ラーメン", "寿司"]
b = Set["ステーキ", "寿司", "パエリア"]

puts a | b => #<Set: {"カレー", "ラーメン", "寿司", "ステーキ", "パエリア"}>
puts a - b => #<Set: {"カレー", "ラーメン"}>
puts a & b => #<Set: {"寿司"}
```

# まとめ
- 苦手な配列が少しわかってきた気がする
- 次回はブロックについてまとめたい

⚠️学習4ヶ月目の初学者による投稿です。
⚠️間違いがあるかもしれません。ご容赦ください。
⚠️ご指導、ご教授いただけると幸いです。
【Python】エラー「_csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)」と対処法

# 概要
PythonでCSVを読むコードを実装していたら以下のエラーになりました。
本記事では原因と解決方法を記載します。

```
_csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)
```

# 原因
発生する原因は、`csv`モジュールの`reader`オブジェクトに対して、バイト列を返してしまっているため。
文字列を返す必要があります。以下、どちらでも上述のエラーになります。

```py
csvfile = request.FILES['file']
reader = csv.DictReader(csvfile)
for row in reader:
```

```py
csvfile = request.FILES['file']
decoded_file = csvfile.read()  # バイト列として読み込んでいる
reader = csv.reader(decoded_file)
for row in reader:
```

ちなみに、`open()`関数で`'rb'`というモードを指定している場合もファイルがバイナリモードで開かれているので、同じくエラーが発生します。`csv.reader`は文字列を期待しているからですね。


# 解決方法
エラーメッセージの通り、ファイルがテキストモードで開かれていないのが原因なので、`csv.reader`に渡す前にテキストモードで開けば解決します。以下のように変更するとエラーがなくなりました。


```py
csvfile = request.FILES['file']
decoded_file = csvfile.read().decode('utf-8-sig').splitlines()
reader = csv.reader(decoded_file)
for row in reader:
```

上記では、`.decode('utf-8-sig')`を使用してバイト列をUTF-8エンコーディングでデコードし、テキストに変換します。

`decode('utf-8-sig')`については、BOM除去という点で一つ詰まった点があります。
BOM除去については以下の記事で記載していますので参考ください。

[【Python】CSVを読み込むと文字列の中に\ufeffが入ってしまう場合の原因と解決方法](https://qiita.com/Ryo-0131/items/7d6b1c772b32c3bbe15e)

## 補足：`request.FILES['file']`とは
Djangoでは、HTTPリクエストに添付されたファイルを処理するために、`request.FILES`という属性を提供しています。

`request.FILES`は、ユーザーがフォームからファイルをアップロードした場合や、APIリクエストの一部としてファイルを送信した場合など、リクエストに含まれるファイルデータを取り扱うための特別なデータ構造です。

`'file'`部分は、アップロードされたファイルのフィールド名を指定します。
例えば、`hogehoge.csv`をアップロードした場合、`request.FILES['file']`をデバッグすれば`hogehoge.csv`と出力されます。また、データの型は`<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>`という`InMemoryUploadedFile`クラスになります。ファイルのデータをメモリ内に一時的に保存し、後続の処理で利用することができます。


詳細はDjangoドキュメントからどうぞ。
[ファイルのアップロード — Django 4.0.6 ドキュメント](https://man.plustar.jp/django/topics/http/file-uploads.html)
pre-commit + commitizen + commitlint で快適なコミットを実現する

# コミットのイメージ

![usage_example.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1666407/c6b41bfc-8d2c-1bc3-110b-6f6fb19108ce.gif)

- コミット前に静的解析やフォーマッター、セキュリティチェックが自動で走る
- コミットメッセージを対話的に作成できる(もし所定の形式に沿わない場合、エラーとして弾く)

→ あまり意識しなくとも、品質を高めつつ、コミットメッセージを統一できる
→ ただし、あくまでローカルでのチェックになるので、リポジトリ側でのチェックは別で必要

# サンプルリポジトリ

https://github.com/SF-28/git_hooks_sample/tree/for_qiita

# 利用ツールについて

## [pre-commit](https://pre-commit.com/)

- `.pre-commit-config.yaml`で各種hooksを一元管理できる
- 静的解析やフォーマッタ、セキュリティ検査などをコミット前に自動実行

## [commitizen](https://github.com/commitizen/cz-cli) + [cz-customizable](https://github.com/leoforfree/cz-customizable#steps)

- コミットメッセージを対話的に作成できる
- `.cz_config.js` で設定することで、テンプレートは変更可能

## [commitlint](https://commitlint.js.org/#/) + [commitlint-config-gitmoji](https://github.com/arvinxx/gitmoji-commit-workflow/tree/master/packages/commitlint-config)

- `commitlint.config.js`でコミットメッセージのフォーマットを指定
- 上記フォーマットに当てはまらなければ、エラーとしてコミットを止めてくれる
- 絵文字を使いたかったので[gitmoji](https://gitmoji.dev/)を選択

# 環境構築

## pre-commit

### インストール

以下を参考に、`pre-commit`コマンドが使えるようにする

https://pre-commit.com/#install

- `asdf`が使える場合は、そちらでも可
- `pip`が使えない場合は、Pythonのインストールからやってみること

### 設定

- 以下を参考にhooksを設定

https://pre-commit.com/#plugins

- [Supported hooks](https://pre-commit.com/hooks.html) が参考になる
  - 各hooksの設定はそれぞれの紹介ページを参照


## Node.js

### インストール

以下から Node.js をインストールし、`npm`コマンドが使えるようにする

https://nodejs.org/ja/download

`yarn`を使いたい場合は入れておく

```sh
npm install -g yarn
```

## commitizen、cz-customizable

### インストール

```sh
npm install --save-dev commitizen cz-customizable

or

yarn add -D commitizen cz-customizable
```

### 設定

対話形式で組み立てるメッセージのテンプレートを設定する

- package.json で coonfig設定

```json:package.json
...
  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    },
    "cz-customizable": {
      "config": "./.cz_config.js"
    }
  },
...
```

- `.cz_config.js`を作成して編集する
    - [公式サンプル](https://github.com/leoforfree/cz-customizable/blob/master/cz-config-EXAMPLE.js)
    - [絵文字対応のサンプル](https://github.com/SF-28/git_hooks_sample/blob/main/.cz_config.js)

## commit-lint, commitlint-config-gitmoji

### インストール

```sh
npm install --save-dev @commitlint/cli commitlint-config-gitmoji

or

yarn add -D @commitlint/cli commitlint-config-gitmoji
```

### 設定

- `commitlint.config.js`を作成して設定
    - [絵文字対応のサンプル](https://github.com/SF-28/git_hooks_sample/blob/main/commitlint.config.js)

## commitlint を git_hooksに追加

- `commit-msg`ファイルを作成

```text:./git_hooks/commit-msg
#!/bin/sh
npx --no-install commitlint --edit "$1"
```

- package.json で scripts設定
    - リポジトリをクローンしたとき、個別設定が不要なように`prepare`で定義
    - ついでにコミットのためのコマンドも設定

```json:package.json
...
  "scripts": {
    "prepare": "bash -c \"cp ./git_hooks/commit-msg ./.git/hooks/\"",
    "commit": "pre-commit run && npx cz"
  },
...
```

```json:Windowsの場合
・・・
    "prepare": "cmd /c \"COPY .\\git_hooks\\commit-msg .\\.git\\hooks\\\"",
・・・
```

- git_hooksに追加

```sh
npm install

or

yarn install
```

# いざコミット

pre-commit → commitizen の順に実施したいため、コマンドでコミットする
(pre-commitが後になると、エラーが出た場合に折角コミットメッセージ組み立てたのにやり直し、となってしまうため)

```sh
npm run commit

or

yarn commit
```
nkf,iconv

```
[linuxstudy@localhost ~]$ nkf -g file.txt   //文字コード確認
UTF-8
[linuxstudy@localhost ~]$ iconv -f UTF-8 -t SHIFT_JIS file.txt > filec.txt        //文字コード変換
[linuxstudy@localhost ~]$ nkf -g filec.txt 
Shift_JIS
```
スクラム開発を10人で回したときのチームワークの問題点と改善方法

# はじめに
こんにちは！

仕事でスクラムマスターをやっているサラリーマンです

　

#### 今回は、スクラム開発のメンバーの人数が増えた時の問題点と改善方法について述べてみます！

　
我々のチームでは

#### 開発メンバー10人！

でスクラム開発を回してます！

（PO1名、SM兼開発1名、開発9名）
　
　

チーム開発・スクラム開発の人数をスケールアップしたい！
と考えている方々には、参考になる情報があるかもしれません

　


# チーム開発の人数について
チーム開発 やってますか？

「チームで開発してるよ！」って方は何人で開発を進めていますか？

　

「総勢100人です！」
というのはナシです🙅‍♂️



毎日顔を合わせてコミュニケーション取ってる人数とします

朝のデイリーミーティングに参加している人数でもいいかもしれません

　

2人・・・非常にコンパクトですね。最小構成人数。

3人・・・コンパクト。

4人・・・まだまだコンパクト。

5人・・・だんだんと人が増えてきて『チーム』って感じです。

6人・・・割合としては一番多いかも。

7人・・・大所帯になってきた感じです。

8人・・・多いかな。全員が各メンバーのやっている内容を把握するのは難しい。

9人・・・多い。

10人以上・・・多すぎる。

　

皆様の人数に対する感触はいかがでしょうか

　

我々の開発チームは、人数に変動はありますが、

最近は、1チーム10人で動いていました

　

プロジェクト発足当初は、3人の開発者で動き出しました

そこから紆余曲折あって、プロジェクトのスケールも大きくなり


### 現在、200社程度の企業が利用するサービスを10人の開発者で回しています

　

# 人数が増えるとどういう問題点が出てくるのか？
問題点として、コミュニケーションが難しくなります
　

新しく入ってきたメンバーは、わからないことを聞く際に

「誰に聞けばいいんだろう...」

「あの人いつも忙しそうだから声かけたらマズイかな...」

「詰まってるけど明日の朝会で聞けばいいか...」

「朝会だけど人が多すぎて聞きづらい...」

### こういうような状況に陥りがち😇

　

一方、上級エンジニアや長らくチームに在籍しているメンバーは、

「（自分はがんばっているが、チーム全体の生産性が上がらない...）」

「（人数増加に対してチーム全体の生産性は増えているのか...？）」

「（あいつがやってるタスクの進捗状況が気になる...）」

「（朝会でちょっとツッコミだすと時間がどんどん伸びてしまう...）」

「（『手が空いたのでタスクを振ってくれ』と言われてばかりで困る...）」

「（わからないことがあったら気軽に聞いてほしいんだけど、若手が遠慮して聞いてこない...）」

「（こちらから察して聞き出すのもなかなか大変...）」

### こういった悩みが出てきます🤔

　

加入時期や年齢、経験値でメンバー間に多少の違いが出てくることで

頼られがちなメンバーとそうでないメンバーが出てくるのは自然なことです

　

期待したいチームの動きとしては、

ペアプログラミングがいつも何箇所かで行われていたり、

情報が一箇所に集約されていて適切に管理されている

という整った状態が理想ですが...

　

### なかなかそうもいかない🤦‍♂️

　

また、スプリントイベントでも、

・朝会が伸びがち。30分で終わらないこともある

・スプリント振り返りでも深いところまで話せない

・スプリント計画で1,2人が喋ってばかりで他のメンバーが喋らない

　
### 人数が増えても生産性は上がってるのか・・・？🤔

　

これじゃなんのために人員を増やしたのかわかりませんね

　

人数が増えてきても

#### 「チームの一体感」

#### 「チームワーク」

#### 「エンゲージメント向上」

を大事にしていきたいですよね！

　

そして、

#### 「チームの生産性の向上」

を目指していきたいですね！

　


# 改善方法

改善方法として、

### 3人、3人、4人のサブチームを作りました！

　

結局、2人、3人、4人 このあたりが最も密にコミュニケーションできるという結論に至りました


　
　

サブチームとしての活動としては、

全体の朝会のあとにサブチームごとの

#### 『サブ朝会』

をやるだけです

　

・朝会、スプリント計画、スプリントレビュー、スプリント振り返りなどなど
　すべてのイベントは10人全員でやります

　

全てをサブチームで分けて代表者だけで各イベントを行う「スクラムofスクラム」というやり方もありますが、

これでは代表者だけに情報が集中してしまい
各メンバーがチーム全体の情報にアクセスできないことがあります

　

あと、スプリント振り返りでも、

全体でふせんとか使って振り返り内容を発表していっていましたが、

3人くらいの小グループに分かれて話したほうが話しやすいですね

　

TeamsとかZoomで、ブレークアウトルームという機能があると思うので、

それを使うとよいです

　

# 効果

#### サブ朝会

をやるようになった効果としては、

・全体朝会の時間が半減した

10人全体の朝会では詳細な相談ができない or 詳細な相談をしているとあっという間に時間が経ち他の人の時間を奪ってしまっている罪悪感が生まれる

のに対して、

「サブ朝会で相談すればいいや」

という安心感があることで全体で共有する内容のみに集中し、全体の朝会が15分程度でサクッと終わるようになった

・サブ朝会で詳細な相談　→ そのままペアプロへの流れがスムーズ

その場で画面を共有しながら相談し、モブプロ、ペアプロに移行していきます

　

### まさにスクラムを組んで進んでいるような感覚・・・！！

　

スクラム組んで動くには、3±1人くらいがちょうどいい

　

チームとしては、10人程度居てもいいが

3±1人のサブチームを作って動くようにすると

### 自然とコミュニケーションが活発になる

という話でした

　

おわり

少しでも参考になった！という方は👍をポチッと押して行ってくれるとうれしいです
プログラミング勉強会256times「特訓CSS メディアクエリー編」に参加しました


## 特訓CSS メディアクエリー編に参加しました。

初めてゼロからWebサイトを作る経験として、とても楽しかったです。
こちらが４日目に作成した、<a href="https://colcmia.github.io/cafe/">自由制作 こだわりカフェの紹介ページを作ろうのサイト</a>です。

### 工夫したところ


ビューポートの幅が 600px 未満のときは SNS アイコンを非表示にし、ロゴ画像を左側、三本線のアイコンを右側に配置。

ビューポートの幅が 600px 以上、800px 未満のときは三本線のアイコンを非表示にし、SNS アイコンのみを右側に配置。

ビューポートの幅が 800px 以上のときは三本線のアイコンを非表示にし、SNS アイコンに加え、「Twitter」「Instagram」「LINE」のテキストも表示。

ヘッダー下とフッター上にぼかしを入れました。

ビューポートの幅が 600px 以上、でヘッダーアイコン画像を入れ替えしました。

ビューポートの幅が 600px 未満のときは カフェの特徴の画像と文章を縦並びにしました。
ビューポートの幅が 600px 以上の時は、カフェの特徴の画像と文章横並びにしました。

ヒーローエリアの画像と地図の画像は、画面サイズと共に大きさが変わるようにしました。
su


su  linuxstudy
bashrc, /etc/bashrc, /etc/profile.d/*

su - linuxstudy 
HOMEなどの初期化が走る   
/etc/profile, /etc/profile.d/*, bash_profile, bashrc, /etc/bashrc

```
[linuxstudy@localhost ~]$ su linuxstudy
Password: 
this is bashrc
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/linuxstudy/.local/bin:/home/linuxstudy/bin
LANG=en_US.UTF-8
this is /etc/bashrc
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/linuxstudy/.local/bin:/home/linuxstudy/bin
lang.sh
LANG=en_US.UTF-8
LANG=en_US.UTF-8
LANG=en_US.UTF-8
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/linuxstudy/.local/bin:/home/linuxstudy/bin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/linuxstudy/.local/bin:/home/linuxstudy/bin
```
```
[linuxstudy@localhost ~]$ su - linuxstudy
Password: 
Last login: Fri Jul 14 17:30:55 JST 2023 on pts/2
this is /etc/profile
/usr/local/bin:/bin:/usr/bin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
lang.sh
LANG=
LANG=en_US.UTF-8
LANG=en_US.UTF-8
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
this is bash_profile
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
this is bashrc
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
LANG=en_US.UTF-8
this is /etc/bashrc
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/linuxstudy/.local/bin:/home/linuxstudy/bin
```
direnvでディレクトリごとに環境変数を切り替える

タイトル通りでdirenvを使うとディレクトリごとに環境変数を定義することができて便利だと感じたのでメモ。[サイバーエージェントのMLOps資料](https://github.com/nsakki55/aws-mlops-handson)で知ったのをきっかけに使い始めました。

例えば、aws cliを使用する際に--profileオプションで認証情報を指定することができるが、つけ忘れる可能性があるし面倒なのでもっと楽にしたい時などに使ってます。

本記事の実行環境：Ubuntu 22.04.2 LTS（WSL 2）

# 使ってみる
```.envrc```を作成し環境変数を記述します。例えば、/work/sample_direnv/に以下の```.envrc```を作成します。=と文字間はスペースを入れずに詰めてください。
```.envrc
export HOGE=hoge
export FUGA=111
```
ちなみに```export```コマンドは環境変数を設定するときに使用するコマンドです。
```
direnv: error /home/user/work/sample_direnv/.envrc is blocked. Run `direnv allow` to approve its content
```
```.envrc```を書き換えた場合、そのままだとこのようなエラーが発生するはずです。```direnv allow```コマンドで```.envrc```の内容を承認する必要があります。

読み込んだ環境変数は```.envrc```が置かれているディレクトリ以下で使用できます。
```bash
/work/sample_direnv$ echo ${HOGE}
hoge
```
例えば、ここから一つ上のworkディレクトリに移動すると、```direnv: unloading```と表示され、環境変数が使用できなくなると通知されます。

aws cli向けにdirenvを使用する場合、前述の流れでAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION等必要な情報を記述すれば良いです。



# 補足
```.envrc```をリポジトリにコミットしてしまうと認証情報が洩れるので注意してください。
例えば、```.gitignore```ファイルに```.envrc```を記述する等して回避します。

# 参考
- [Linuxでdirenvを使う](https://qiita.com/kompiro/items/5fc46089247a56243a62)
Vercel無料コンテナでHexo軽量ブログを一クリックでデプロイ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2997148/a6bbc79a-f586-66cd-17fc-19ea71f5ddd6.png)

インストールガイド アカウントの準備 まず、Github アカウントを登録してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2997148/e1c926a2-e0f1-7cf8-fb8d-c5099804e15a.png)


次に、Vercel のウェブサイトに移動し、Github アカウントを使ってアカウントを登録します。これにより、Vercel であなたの Github プロジェクトが確認できるようになります。
# Vercel
https://vercel.com/
# Github
https://github.com/


# Hexoプロジェクトの作成 Hexoプロジェクトの直接リンクの作成：

https://vercel.com/new

# 配備

これで、Hexoプロジェクトを作成するページに移動します。



まさかのGit ScopeはあなたのGithubアカウントで、権利のREPOSITORY NAMEはあなたのアカウント下のHexoブログリポジトリの名前です。ここにあなたのブログのソースファイルが保存され、名前は自由に選択できます。

プロジェクトの継続性はプライベートに保持し、他の人があなたのHexoリポジトリの機密情報を見ることができません。これにより著作権とプライバシーを効果的に保持できます。



成功すると、あなたにサブドメインが付与されます。このサブドメインはあなたのものであり、取り消されることはありません。デバッグ時に一時的に使用することを推奨します。

デプロイが完了すると、それはあなたが最初に入力したリポジトリにバインドされます。リポジトリに変更があると、それは自動的に同期デプロイされます。全過程は約5分でデプロイを完了できます。

あなたは今、そのサブドメインをクリックすることで、あなたのHexoブログを確認することができます。
Prettier3がリリースされて日本語と英語の間に半角スペースが入る問題が解消された

2023-07-05に[Prettier3がリリースされた](https://prettier.io/blog/2023/07/05/3.0.0.html)❗

これにより、Breaking Changeとして、
日本語と英語の間に半角スペースが入る問題が解消された。

Prettier2では↓のようなMarkdownをフォーマットすると、

```md
これはMarkdownです。
```

↓のように、勝手に半角スペースが入っていた...ﾅﾝｼﾞｬｿﾘｬ❗

```md
これは Markdown です。
```

この奇妙すぎる動作がPrettier3では改善された。
実際に `npm install prettier@latest` して、Prettier 3.0.0で試してみたら、
確かに半角スペースが入らなくなっていた❗素晴らしい❗
(なぜかVSCodeの再起動が必要だったが。)

この改善は[こちらの記事](https://qiita.com/tats-u/items/bcbfe2bb4e71bf0a2b87)にあるように@tats-u氏の奮闘によるもの。
Prettierの[Issue](https://github.com/prettier/prettier/issues/6385)を見に行くと、なが〜い奮闘の記録が見れるのでぜひ見に行って欲しい。
氏に感謝。
Git のエラー "object file is empty" や "loose object is corrupt" の直し方

# エラー内容
Git 操作をしている間に Raspberry Pi がフリーズしてしまい、再起動後にリポジトリの状態を確認しようとしたら以下のようなエラーが発生しました。

```shell:shell
git status
```

```
error: object file .git/objects/fb/38f089a711a4dfcd7843114d25158dded221ff is empty
error: object file .git/objects/fb/38f089a711a4dfcd7843114d25158dded221ff is empty
fatal: loose object fb38f089a711a4dfcd7843114d25158dded221ff (stored in .git/objects/fb/38f089a711a4dfcd7843114d25158dded221ff) is corrupt
```

エラーが発生したリポジトリのリモートリポジトリを別の場所で clone して、`.git` ディレクトリの中身を丸ごと差し替えるという方法もありますが、今回はリモートリポジトリを作成していない場合も想定してリモートリポジトリを使わずに上記のエラーを修正する方法について紹介しようと思います。



# リポジトリのルートディレクトリに移動
ここから先の作業ではリポジトリのルートディレクトリにいると仮定します。そうでない場合はまず最初に移動してください。

```shell:Shell
cd /path/to/repo
```



# 空のファイルを削除
エラーメッセージを見ると Git の情報を管理する一部のファイルが空になっており、データが破損していると書かれています。そのため、まずは該当するファイルを見つけます。

```shell:Shell
find .git -type f -empty
```

```
.git/FETCH_HEAD
.git/objects/dc/3f1dc308cf66273606e6ff0f3f308676eb0caa
.git/objects/d3/8b76bbf4b80f372e2d19cd738bec8ccafbfc32
.git/objects/fb/38f089a711a4dfcd7843114d25158dded221ff
.git/objects/d4/720586ff6baf19a14ae8ccc883d54d8a3d6e4c
```

`git status` では `.git/objects/fb/38f089a711a4dfcd7843114d25158dded221ff` しか表示されませんでしたが、実際にはそれ以外にもいくつか空もしくは破損しているファイルが存在します。

これらのファイルの中にあった情報は何らかの原因で消えてしまったためファイルごと削除します。

```shell:Shell
find .git -type f -empty -delete
```



# `HEAD` の向き先を変更
破損したファイルを削除したところでもう一度 Git の状態を見てみます。

```shell:Shell
git status
```

```
fatal: bad object HEAD
error: option `merged' must point to a commit
```

エラーメッセージが変わりました。今度は `HEAD` の向き先がおかしいと書かれています。先ほど削除した `.git/FETCH_HEAD` が今まで `HEAD` になっていたようですが、これを削除したために向き先がおかしくなってしまったということです。

そこで、現存する最新の履歴を見てみます。

```shell:Shell
tail -n 2 .git/logs/refs/heads/main
```

メインブランチ名が `master` の場合は `.git/logs/refs/heads/master` に変えて実行してください。

```
4f04774918baa04669a12bec9d8a64b3c65a95b4 b51206040e9446f1acc8b6da1ecd1101f013e6e1 noraworld <mail@noraworld.com> 1686930840 +0900	commit: Add new conf: Netflix Allow
```

これが現存する最新の履歴のようなので、`HEAD` がここを指すように変更します。

```shell:Shell
git update-ref HEAD b51206040e9446f1acc8b6da1ecd1101f013e6e1
```

`b51206040e9446f1acc8b6da1ecd1101f013e6e1` の部分は `tail -n 2 .git/logs/refs/heads/main` で表示された 2 つのコミットハッシュのうちの 2 つめのものを指定します。



# 最終確認
最後にもう一度ステータスを確認してみます。

```shell:Shell
git status
```

```
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
```

エラーが解消されもとに戻ったことが確認できました。



# 参考サイト
[Gitのfatal: loose object *** is corruptを解決する](https://higelog.brassworks.jp/3910)
【SQL】INNER JOIN, OUTER JOINメモ

# 参考テーブル

**authors**
| id | name |
|:-:|:-:|
|  1 |  夏目 |
|  2 |  太宰 |
|  3 |  三島 |

**books**
| id |author_id| title |
|:-:|:-:|:-:|
|  1 |1|  吾輩は猫である |
|  2 |1|  坊ちゃん |
|  3 |1|  こころ |
|  4 |2|  走れメロス |
|  5 |4|  容疑者Xの献身 |

# INNER JOIN
- ON~ で一致しないレコードを省く。
- LEFTもRIGHTもいらない

```
SELECT authors.id, name, title FROM authors
INNER JOIN books ON authors.id = books.owner_id;
```
| author.id |name| title |
|:-:|:-:|:-:|
|  1 |  夏目 |  吾輩は猫である |
|  1 |  夏目 |  坊ちゃん |
|  1 |  夏目 |  こころ |
|  2 |  太宰 |  走れメロス |

# OUTER JOIN
- ON~ で一致しないレコードは、片方だけ残し、もう片方はNULLにする。
- LEFT→ LEFTのほうを残し、RIGHTはNULLにする
- RIGHT→ RIGHTのほうを残し、LEFTはNULLにする
- FULL→ 両方とも残す
- OUTERは省略してもOK

### LEFT
```
SELECT authors.id, name, title FROM authors
LEFT OUTER JOIN books ON authors.id = books.owner_id;
```
| author.id |name| title |
|:-:|:-:|:-:|
|  1 |  夏目 |  吾輩は猫である |
|  1 |  夏目 |  坊ちゃん |
|  1 |  夏目 |  こころ |
|  2 |  太宰 |  走れメロス |
|  3 |  三島 |  NULL |

### RIGHT
```
SELECT authors.id, name, title FROM authors
RIGHT OUTER JOIN books ON authors.id = books.owner_id;
```
| author.id |name| title |
|:-:|:-:|:-:|
|  1 |  夏目 |  吾輩は猫である |
|  1 |  夏目 |  坊ちゃん |
|  1 |  夏目 |  こころ |
|  2 |  太宰 |  走れメロス |
|NULL|  NULL |  容疑者Xの献身 |
そのSQLどういう分離モードで動いてますか(Db2)

# 事の発端
割と時間のかかる(数分)CSV出力処理をしている最中、画面からの更新処理でロックタイムアウトエラーが発生した。

あれ?なんで?SELECTなのに?

ロックタイムアウトが発生するということはSELECTによりロックが発生しているということ。
SELECTと更新が同時に発生したときの挙動に関わってくるから**分離レベル**に関することを調べる必要がある。

分離レベルの説明やその設定方法(JDBCのカスタムプロパティやJava Connection setTransactionIsolation () method)の説明は色々なページに記載されているが、現在実行中のSQLがなんの分離モードで動いているか調べる方法はあまりない。

**このSQLはどの分離モードで動いているのかしりたい**でもやり方がよくわからない。そういう人向けのヒントを記載する。

# db2pdコマンドで確認できる
確認するコマンドはdb2pd -tcbstats -db hoedb -dynamic、実行するとダラダラ表示される中にDynamic SQL StatementsとDynamic SQL Environmentsという項目がある。

インスタンスオーナーでdbへ接続し、db2 "db2 flush package cache"してから業務処理を実行するとリストアップされるものが減り見やすい(もちろん本番環境でflashしてはダメだよ!)。

```:db2pd -tcbstats -db hoedb -dynamicの抜粋
Dynamic SQL Statements:
Address            AnchID StmtUID    NumEnv     NumVar     NumRef     NumExe     Text
0x00007F24025CFD00 0      1          0          0          1          1          SELECT * FROM SYSCAT.SEQUENCES WHERE SEQSCHEMA = ? AND SEQTYPE <> 'A' ORDER BY SEQNAME WITH UR
0x00007F240242D4C0 15     1          0          0          1          1          SELECT * FROM SYSCAT.ROUTINES WHERE ROUTINESCHEMA = ? AND ROUTINETYPE= 'P' AND 
0x00007F24028DECE0 88     1          0          0          29         29         SELECT *  FROM SYSCAT.INDEXES WHERE INDSCHEMA = ?   AND INDNAME = ? WITH UR
0x00007F2402D8E160 448    1          1          1          3          3          SELECT めちゃ長SQLだよ

Dynamic SQL Environments:
Address            TenantID   AnchID StmtUID    EnvID      Iso QOpt Blk
0x00007F24028450C0 0          22     27         2          CS  5    B
0x00007F24028CD660 0          448    1          3          RS  5    B
0x00007F240286FAA0 0          809    27         1          UR  5    B
0x00007F24028B5220 0          959    28         1          CS  5    B
0x00007F24028DE380 0          1014   27         1          CS  5    B

```
**このdb2pd結果から分離レベルを読み取ることができる。**

1. Dynamic SQL Statementsの方でロックしていると思われるSQLを探す。
2. そのSQLのAnchID項目、例では448を探す。
3. 探したAnchIDをDynamic SQL Environmentsの方で探す
4. Isoの項目に表示されているRSが分離レベルを示す

このSQLは分離レベルRS(Repeatable Read)で動いていると判断できる。
また業務処理の都合インデックスのないSELECTを実行している。
その結果テーブルロックを行っていて横から更新処理しようとしてもロック待ちとなり、更新処理はロックタイムアウトエラーとなっていた。

**つまり原因は分離モードRSだから。**

原因判明したので対策を打つことができる。
業務要件を考えて分離モードをCSにしたりURにしたりすればよい。

例えばSQLにwith CSを付けてdb2pdを再取得すればIsoがCSに変化していることがわかるはず(更新のブロックも発生しないことがテストでわかるはず)。

実装の方法はSQLにwith CSやwith URをつける、JDBCのカスタムプロパティやJava Connection setTransactionIsolation () method等、その影響範囲を考えて実装すればよい。
OCRAの医療辞書をATOKで使う（特にMacの場合）

## ATOK 使っていますか？

現在、日本語変換ソフトをわざわざ購入する人は少なく、OSに付属の「Microsoft IME」を使ったり、「日本語入力プログラム」（いまはことえりって言わないんですね）を使ったり、「Google日本語入力」を使っている人が多いと思います。しかし、まだまだATOKを使っている人も少なくないと思います。

ATOKでは医療辞書は別売りで結構な値段がします。しかし生ATOKでは、かなり一般的な医学用語でも変換候補に出なかったりします。

一方、Google日本語入力やそのオープンソース版のMozcでは、以下のOCRAの医療辞書を無料で導入することができます。

https://www.orca.med.or.jp/receipt/use/medic.html

OCRAとは、日本医師会が提供しているレセプト用のソフトです。レセプトとは診療報酬明細書で、一種の会計ソフトということになります、これは通常Ubuntu上で動作します。つまり業務上、Ubuntuで正確に医学用語を変換する必要性から、無料でOCRA医療辞書が提供されているのです。ありがたいですね。

ATOKでもこの辞書を使うことはできないでしょうか？　結論からいうと可能です。

## やり方

1. [OCRA Project](https://www.orca.med.or.jp/receipt/use/medic.html)のサイトからMozc医療辞書をダウンロードします。
1. MOZCの辞書ファイルをATOK用に変換して「単語ファイル」を作成します。
    1. ファイルの先頭に「!!ATOK_TANGO_TEXT_HEADER_1」を追加します。
    1. 必要に応じてファイルエンコーディングを変更します。
    1. 多分これだけでも大丈夫ですが、最新のATOKのマニュアルを参照してこれだけで大丈夫か確認してください。必要に応じてテキストエディアの置換機能などを使ってファイルを整形してください。
1. ATOK辞書ユーティリティを開きます。
1. OCRA医療辞書を新たに作成します。
1. メニューバーの［ツール-ファイルから登録・削除］を選択し、［単語一括処理］シートを選択します。
1. 単語が正しく辞書に読み込めていることを確認します。
1. 読み込んだ辞書を有効にします。

## 注意点

ATOKのマニュアルを呼んで、必要に応じてテキストエディアを利用してファイルを置換すれば単語ファイルを簡単に作成できます。しかし、はまりどころがいくつかあります。

エンコーディングに注意してください。公式マニュアルにはエンコーディングに関する指定はなく、設定もありませんでした。そのため、どんなエンコーディングでも大丈夫そうに思ってしまいますが、macOSでは、MacOSというエンコーディングしか受け付けてくれませんでした。（UTF-8はダメでした）今どきこれはないだろう……と思いましたが、最新のATOKで実際にそうだったので仕方ありません。

OCRA医療辞書のライセンスはGPL-2です。日本語入力の辞書として使いたい人には問題ないライセンスだと思いますが、自作ソフトを作成中で、OCRA医療辞書を組み込みたいという方は（そんな方がこの記事を読むことはあるだろうか？）の場合はご注意ください。

すべての単語が登録できるわけではありません。読みにアルファベットが入っている単語があり、そういったものはうまく登録できないようです。

辞書に単語を登録しても、推測変換では候補が出てこないようです。これははっきりとした理由はわかりませんが、設定で改善できるかもしれません。

以上で、この記事は終わりです。
locale, localectl

```
[linuxstudy@localhost ~]$ localectl status
   System Locale: LANG=en_US.UTF-8       //  /etc/locale.confを読み出し
       VC Keymap: us
      X11 Layout: us
[linuxstudy@localhost ~]$ locale
LANG=ja_JP.UTF-8                         //  localectl設定地と異なる。なぜ。
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC=ja_JP.UTF-8
LC_TIME=ja_JP.UTF-8
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY=ja_JP.UTF-8
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER=ja_JP.UTF-8
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT=ja_JP.UTF-8
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=
```
```/etc/locale.conf
LANG="en_US.UTF-8"
```
ログイン処理の中で、/etc/locale.confを読み出す
```/etc/profile.d/lang.sh
# /etc/profile.d/lang.sh - set i18n stuff
echo "lang.sh"
echo "LANG=${LANG}"
sourced=0

if [ -n "$LANG" ]; then
    saved_lang="$LANG"
    [ -f "$HOME/.i18n" ] && . "$HOME/.i18n" && sourced=1
    LANG="$saved_lang"
    unset saved_lang
else
    for langfile in /etc/locale.conf "$HOME/.i18n" ; do
        [ -f $langfile ] && . $langfile && sourced=1
    done
fi
```
どうやら、/etc/profileなどのログイン処理以前にすでにLANG設定されている、
/etc/locale.confの設定がスキップされているみたい。
contextを使わないでデバイスサイズを取得したい

# デバイスサイズを取得する方法
備忘録
他にいい方法があったらコメント欄で教えてください
## context使用
```Dart
Size size = MediaQuery.of(context).size;
double width = size.width;
double height = size.height;
```
## contextを使わない方法
contextを使わないでデバイスサイズを取得する場合`WidgetsBinding.instance.platformDispatcher.views.first.physicalSize`を用いるのですが、取得できるのは物理ピクセルでのサイズになります。
contextを用いる方法の`MediaQuery.of(context).size`で取得できるサイズは論理ピクセルです。
そのため、contextを用いずに論理ピクセルを取得したい場合は`WidgetsBinding.instance.platformDispatcher.views.first.devicePixelRatio`で割ってあげる必要があります
```Dart
double pixelRatio = WidgetsBinding.instance.platformDispatcher.views.first.devicePixelRatio;

// 物理ピクセル
Size physicalSize = WidgetsBinding.instance.platformDispatcher.views.first.physicalSize;
double physicalSizeWidth = size.width;
double physicalSizeHeight = size.height;

// 論理ピクセル
Size logicalSize = WidgetsBinding.instance.platformDispatcher.views.first.physicalSize / pixelRatio;
double logicalSizeWidth = size.width;
double logicalSizeHeight = size.height;
```
enex2notionを利用したEvernoteからNotionへの移行

EvernoteからNotionへの移行には、Notion自身のインポート機能ではなく、[enex2notion](https://github.com/vzhd1701/enex2notion)を使うのがお勧めです。
私の場合、Notion自身のインポート機能だと多くのノートが移行に失敗してしまいましたが、enex2notionだと成功しました。

enex2notionの使い方は難しくありませんが、Tipsをまとめておきます。

## Token ##

enex2notionによるデータのアップロードにはtoken_v2という名前のNotionのCookieの値が必要になります。

enex2notion作者による[Find Your Notion Token](https://vzhd1701.notion.site/Find-Your-Notion-Token-5f57951434c1414d84ac72f88226eede)というノートに手順が書かれているのですが、内容が古いのかここに書かれているChromeの手順では取得できません。そのため、私はFirefoxで取得しました。

## 移行時間 ###

ノートの内容に依存しますが、ノートの移行には非常に時間がかかります。私の場合、1つのノートに5分以上かかるものもありました。

そのため、私は自分のPCでenex2notionを実行するのではなく、[Oracle Cloud Infrastructure (OCI)](https://www.oracle.com/jp/cloud/)上にVMを作成し、VM上でenex2notionを実行しました。OCIは[Always Free](https://www.oracle.com/jp/cloud/free/)という無料で利用出るサービスがあるのでそれを利用しました。enex2notionはArm上でも動くので、私はArm Ampere A1 Computeを使いました。
ガバナンス(ポリシー)を利用した、UiPath Studio Windows - レガシの非推奨メッセージの非表示設定

# はじめに
UiPath Studio（ver 22.10）で、Windows - レガシで作成されたワークフローを開くと、ワークフローの画面上部にWindows - レガシの非推奨メッセージが表示されるようになりました。この非推奨メッセージをガバナンスを利用し非表示設定にする方法を紹介します。

# 前提条件
本手順は、クラウド環境のご利用を前提に記載しています。

ご利用環境：　クラウド/オンプレミス共通
UiPath Studioバージョン： 22.10.5以降

# Studio（ユーザ毎)の設定方法
ガバナンスファイルを利用した方法を解説します。
[参考情報：ガバナンス設定(UiPath公式サイト)](https://docs.uipath.com/ja/studio/standalone/2022.10/user-guide/governance#generate-the-governance-file)

## 設定手順　
1. Studio起動＞ヘルプ＞ガバナンスファイルを生成＞クラシックポリシーを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361279/72395acb-efdd-a69e-db4d-e1f5456f541a.png)

2．ダウンロードした、「uipath.policies.config」をテキストエディタで開き、編集する。
　※編集箇所、"DisplayLegacyFrameworkDeprecation"true → falseへ変更

        },
        "EnforceReleaseNotes": false,
        "DisplayLegacyFrameworkDeprecation": false,
        "AnalyzeOnPublishParam": {
          "AllowEdit": true,
          "Value": true
        },

3.　編集した「uipath.policies.config」を指定フォルダへ配置する。
    指定フォルダ　C:\Users"ユーザ"\AppData\Roaming\UiPath\
4.　ガバナンス(ポリシー)を反映するため、Studioを再起動する。
5.　Studio起動＞ヘルプに画面遷移し、企業ポリシーガバナンスが適用されていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361279/53a98948-1276-6bac-d281-8475d5e0af88.png)


# Orchestratorを用いたガバナンス設定方法
Orchestratorを利用し、複数ユーザへの適用する方法を解説します。
[参考情報：ガバナンス設定(UiPath公式サイト)
](https://docs.uipath.com/ja/studio/standalone/2022.10/user-guide/governance#using-an-orchestrator-asset)

## 設定手順
注意：本設定は、フォルダ名・アセット名が重要になります。
　　　手順以外の命名では設定できない可能性がありますので注意してください。

1. Orchestrator で [テナント] > [フォルダー] を選択し、uipath.settings.config という名前の新しいフォルダーを追加します。
※既存フォルダのサブフォルダとして作成しても動作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361279/f265decb-8428-d24a-a245-dcf6bc673af3.png)
2. ガバナンス(ポリシー)を適用したいユーザーを作成したフォルダー：uipath.settings.configに追加します。
※ユーザーには、アセットの読み取り権限が必要になります
3. uipath.settings.config フォルダーで新しいアセットを作成し、次のように設定します。
    * アセット名 - uipath.studio.governancepolicy
    * 種類 - テキスト
    * グローバル値 - このオプションを選択し、uipath.policies.config ファイルの内容全体をテキスト ボックスに貼り付けます。
　※"DisplayLegacyFrameworkDeprecation"true → false
　※ローカルPCで作成したuipath.policies.config ファイルの内容そのままで動作します（貼り付けるための形式変更など不要）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361279/a2862f20-73f3-99cc-a5e9-05ddbda81b4e.png)

4. ガバナンス(ポリシー)を反映するため、Studioを再起動する。
5. Studio起動＞ヘルプに画面遷移し、企業ポリシーにガバナンスが適用されていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361279/73542136-8faa-abe8-607c-a35b207734df.png)
gitコミットにはタイムスタンプのほかタイムゾーンも記録されている

gitのコミットにはタイムスタンプだけでなくコミットした環境のタイムゾーンも記録されている、という発見です。

gitコミットにはタイムスタンプだけが保存されており、タイムゾーンの表示は見ている人の環境に合わせて表示されているんだと思い込んでいました。しかしそうではなく、タイムゾーンもコミットごとにちゃんと保存されていました。なので、オープンソースのリポジトリのログを見ればいろんなタイムゾーンに開発者が散らばっている様子がわかります。

以下のの記事を読んで、タイムゾーンも保存されてるのか？？？って疑問から調べてしまったのが今回の記事のきっかけです。

https://qiita.com/vallack5296/items/846a6013bcc8c81c4392


# 確認した内容

ローカルにclone済みの適当なgitリポジトリを見ます。`.git` というディレクトリにGitログや過去のファイルがすべて保存されており、コミットの情報も含まれています。gitリポジトリの内容は `.git` がすべてです。

まず以下のファイルを見ます。

```plain
$ cat .git/refs/heads/main
```

最新のmainブランチのコミットのハッシュ値が書いてあります。40文字のSHA-1ハッシュ値です。このファイルがなくても `.git/refs/heads/` の中の別名のファイルでもよいです。

ハッシュ値が例えば `ca218c30e4ed29eb778f45c75faa2043708b143e` だった場合、以下のファイルの存在を確認します。ハッシュ値の最初の2文字をディレクトリ名にして、残り38文字をファイル名にします。

```plain
$ ls .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e
```

`git gc`を実行した直後だったり、 `git clone` したばかりの場合は、このファイルがない場合があります。かわりに `.git/object/pack/` の中に圧縮されています。この中を見るのは面倒なので、その場合は別のリポジトリを見るなり、もしくはダミーで適当なコミットをしてみて、再チャレンジしてください。

`.git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e` はzlibで圧縮されています。Rubyのワンライナーであれば次のようにして展開できます。

```plain
$ cat .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e | ruby -e "require 'zlib'; puts Zlib::Inflate.inflate(STDIN.read)"
```

Perlのワンライナーであれば次の通りです。

```plain
$ cat .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e | perl -e 'use Compress::Raw::Zlib; undef $/;new Compress::Raw::Zlib::Inflate()->inflate(<>,$o);print $o'
```

Pythonのワンライナーであれば次の通りです。

```plain
$ cat .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e | python -c "import zlib,sys;print(zlib.decompress(sys.stdin.buffer.read()).decode('utf8'))"
```

どの言語を使っても次のように表示されます。

```plain
commit 274tree c15e322196a5f6a9cd34ff42709848e649e156c6
parent 491c797feb18eff93d25fe19cb2a83bb399ec9d8
author suzuki-navi <...> 1689242567 +0900
committer suzuki-navi <...> 1689242567 +0900

dummy commit

これはダミーのコミット
```

コミットの情報がテキストで表示されます。 `.git` に所定のフォーマットのテキスト形式でコミット情報が保存されているのです。

最初の `commit 274` は説明省略しますがコミット情報を `.git/objects` に保存するためのヘッダみたいなもので、そのあとの `tree ...` から後ろがコミット情報の本体です。 `...` と書いた個所は本当はメールアドレスが載っています。

この中にタイムゾーンが `+0900` というふうにテキストで記載されていることがわかります。ヨーロッパやアメリカなどタイムゾーンの異なる環境からこのリポジトリをcloneしてもこのコミットに関しては `+0900` と表示されるはずです。へぇー。


# 補足 その1

今回の記事では `.git/objects` の中を直接見ましたが、以下のように `git cat-file` コマンドでも見ることができます。 `git` コマンドが出力をいい具合に整形しているという疑念を払拭するために、生データを直接見ることにしました。

```plain
$ git cat-file -p ca218c30e4ed29eb778f45c75faa2043708b143e
tree c15e322196a5f6a9cd34ff42709848e649e156c6
parent 491c797feb18eff93d25fe19cb2a83bb399ec9d8
author suzuki-navi <...> 1689242567 +0900
committer suzuki-navi <...> 1689242567 +0900

dummy commit

これはダミーのコミット
```


# 補足 その2

今回の記事の内容は、以下のドキュメントにだいたい書いてあります。コミット情報にある `tree` とか `parent` とかもだいたい説明されています。

https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88

以上。
ログアウト実行でNo route matches [GET] "/logout"エラー 解決方法

# 実施環境
ruby "3.1.4"
gem "rails", "~> 7.0.3", ">= 7.0.3.1"
gem "sorcery", "~> 0.16.3"
Gemfileより

# エラー内容

ログアウト機能追加の課題実施中、
ログアウトボタンを押すとNo route matches [GET] "/logout"エラーが発生。


### エラー画像
![スクリーンショット 2023-07-14 10.59.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488699/f160bd95-6b19-75f4-f465-d101a319a8dc.png)

### エラーログ
```
Started GET "/logout" for 172.20.0.1 at 2023-07-14 10:58:08 +0900
Cannot render console from 172.20.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1
ActionController::RoutingError (No route matches [GET] "/logout"):
```

routs.rbでもちゃんとDELETEで指定しているし、html.erbでもmethod:deleteなのに、
getになってしまった。


### 現状のコード
```routs.rb
Rails.application.routes.draw do

  get '/login', to: 'user_sessions#new'
  post '/login', to: 'user_sessions#create'
  delete '/logout', to: 'user_sessions#destroy'
end
```
```_header.html.erb
<%= link_to 'ログアウト', logout_path, class: 'dropdown-item', method: :delete } %>
```

```user_sessions_controller.rb
  def destroy
    logout
    redirect_to root_path
  end
```

# 解決
[伊藤さんのQiita](https://qiita.com/jnchito/items/5c41a7031404c313da1f#destroy%E3%81%AE%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%AB-status-see_other-%E3%82%92%E4%BB%98%E3%81%91%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B)に解決策がありました。

1:turboを使っている場合、link_toメソッドのmethod:オプションの書き方が変わった
2:destroyアクションのレスポンスには必ず status: :see_other を付ける必要がある


Rails 7.0でTurboはデフォルト導入されるそうでリンクでdata-turbo-method属性を使うことで、GET以外のHTTPメソッドを指定できるとのこと。

上記を踏まえて、ソースコードを修正したところ、ログアウト実行がうまくいきました。

### 修正したコード
```_header.html.erb
<%= link_to 'ログアウト', logout_path, class: 'dropdown-item', data: { turbo_method: :delete } %>
```

```user_sessions_controller.rb
  def destroy
    logout
    rredirect_to root_path, status: :see_other
  end
```

# 参考記事
https://qiita.com/jnchito/items/5c41a7031404c313da1f#destroy%E3%81%AE%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%AB-status-see_other-%E3%82%92%E4%BB%98%E3%81%91%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B
firebase deploy --only functions時のError: functions predeploy error:


# はじめに

firebase deploy --only functionsしたらエラーError: functions predeploy error:になってしまい、出来なかったが解決した。（というか諦めた。）


# 環境の情報
OS
macOS Big Sur 11.3

# 注意
最新の状態を確認して下さい。

# 参考さまはこちら
https://qiita.com/pontarou194/items/55b53700082a59a148fb

# 最終更新日
2023年7月12日

# 状況

```
% firebase deploy --only functions
```

すると
バキッとエラーになってしまう。

```
=== Deploying to 'myproject'...

i  deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint

> lint
> eslint .


Oops! Something went wrong! :(

ESLint: 8.44.0

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/いろんなeslint-plugin.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.


Error: functions predeploy error: Command terminated with non-zero exit code 2
```

プラグインとか、依存関係など調べてチクチク入れたり直したけど、直らず。


# 結論

```firebase.json
"predeploy": [
        "npm --prefix \"$RESOURCE_DIR\" run lint"
      ]
```

下

Firebaseのデプロイ時には、ESLintを無効して使わない。
"predeploy"の値を空の文字列に変える。
これにより、firebase deploy --only functionsを実行する際にESLintのステップがスキップされる。


```firebase.json
"predeploy": [
        ""
      ]
```

# 注意
デプロイ時にLint処理を無効にすることは、エラーやコード品質の問題がデプロイ前に検出されなくなってしまう。
コードの品質を保証し、問題を事前に検出するためには有効にしたほうが良かったり。
ViewBuilderを理解するためresultBuilderを独自実装

```playground.swift
@resultBuilder
public struct AdderBuilder {
    //supports DSL in block
    public static func buildBlock(_ components: Int...) -> Int {
        components.reduce(0, +)
    }
    
    //supports "if" statement without "else"
    public static func buildOptional(_ component: Int?) -> Int{
        return component ?? 0
    }
    
    //supports "if else" statement
    public static func buildEither(first component: Int) -> Int {
        return component
    }
    public static func buildEither(second component : Int) -> Int{
        return component
    }
    
    //supports "for in" statement
    public static func buildArray(_ components: [Int]) -> Int{
        return components.reduce(0, +)
    }

}

func blockAdder(@AdderBuilder block:()->Int)->Int{
    return block()
}

        
let sum = blockAdder{//buildBlock()
    0
    1
    if 0<1 {//buildOptional()
        2
    }
    
    if 0<1{//buildEither(first:)
        3
    }else{//buildEither(first:)
        4
    }
    
    for _ in 0...2 {//buildArray
        5
    }
}

```

https://speakerdeck.com/chocoyama/20fen-dewakaru-su-xi-resultbuilder-iosdc-2022?slide=83

https://qiita.com/toya108/items/ef62a45f7278a1b019a9

https://software.small-desk.com/development/2021/08/04/swift-to-understand-result-builder/
[VB.NET]GitHub上で自動ビルドするワークフローを作った

GitHub Actionsを使って、VB.NETのプロジェクトをmasterにpushしたときに自動ビルドして、成果物をダウンロード可能な状態にする仕組みを考えた。

ネット上に情報はいろいろと点在しているが、そのままだと情報が古かったりしてうまく動かなかったので、2023/07時点で実行可能なスクリプトを含めてメモを残す。

1. GitHubのリポジトリを作成
1. コードをPushする
1. GitHub Actionsでこちらを有効化 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267148/5a5664de-300a-bcea-b10d-d648f587e66d.png)
1. msbuild.ymlを編集 
```yaml:msbuild.yaml 
name: MSBuild
on:
  push:
    branches:
      - master
      - msbuild-test
jobs:
  build:
    name: MSBuild
    runs-on: windows-latest
    env:
      ACTIONS_ALLOW_UNSECURE_COMMANDS: true #セキュリティ的にアレなので自己責任
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 1
  
    - name: Setup MSBuild.exe
      uses: microsoft/setup-msbuild@v1.1
      
    - name: MSBuild
      run: dotnet build your_project_name.sln -p:OutDir="out/"
      shell: cmd
        
    - name: Upload artifact
      uses: actions/upload-artifact@v3
      with:
        name: build-result
        path: ./out/ #出力先は適宜変更。ルートディレクトリからの相対パスなので注意。フォルダ名変えたらOutDirも変更すること。
```

これでビルドに問題なければ、Actionsのビルドのページに成果物が上がってるはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267148/f09485a2-2e59-1658-d443-fc6052843b9a.png)
Go言語の並行処理: ゴルーチンとチャネルについて

この記事では、Go言語の並行処理について記載します。
Go言語は、複数のタスクを同時に実行するための強力な機能を持っています。
その実現には、ゴルーチン（Goroutines）とチャネル（Channels）という2つの主要な概念がキーとなります。

## ゴルーチンについて

ゴルーチンは、軽量なスレッドのようなもので、Goランタイムによって管理されます。ゴルーチンは非常に少ないメモリ（数KB）を使用し、必要に応じて成長・縮小します。これにより、数千から数百万のゴルーチンを同時に実行することが可能となります。

新しいゴルーチンは、`go`キーワードと関数呼び出しを組み合わせることで作成されます。

```go
go doSomething()
```

上記のコードは、新しいゴルーチンを作成し、その中で`doSomething`関数を非同期に実行します。

## チャネルについて

チャネルは、ゴルーチン間での通信と同期を可能にするデータ構造です。一つのゴルーチンはチャネルにデータを送信し、別のゴルーチンはそのチャネルからデータを受信することができます。

チャネルは、`make`関数とチャネル型を使用して作成されます。

```go
ch := make(chan int)
```

上記のコードは、整数を送受信するための新しいチャネルを作成します。

チャネルにデータを送信するには、送信演算子`<-`を使用します。

```go
ch <- 10
```

上記のコードは、チャネル`ch`に整数`10`を送信します。

チャネルからデータを受信するには、同じ送信演算子を使用しますが、この場合は左辺に変数を置きます。

```go
x := <-ch
```

上記のコードは、チャネル`ch`からデータを受信し、それを変数`x`に代入します。

## ゴルーチンとチャネルの組み合わせ

ゴルーチンとチャネルは、一緒に使うことで最も強力になります。ゴルーチンは計算の並列化を可能にし、チャネルはその並列計算の結果を合成するための安全な方法を提供します。

以下に、ゴルーチンとチャネルを使用して、2つの関数を並列に実行し、その結果を合成する例を示します。

```go
func main() {
    ch := make(chan int)

    go func() {
        ch <- doSomething()
    }()

    go func() {
        ch <- doSomethingElse()
    }()

    result1 := <-ch
    result2 := <-ch

    fmt.Println("Combined result:", result1 + result2)
}
```

上記のコードは、2つのゴルーチンを作成し、それぞれで異なる関数を実行します。各関数の結果はチャネルに送信され、メインゴルーチンではそれらの結果を受信し、合成します。