OmniAICreator/Qiita-1.07M huggingface dataset:
30分で Tanzu Community Edition 環境 と Spring アプリケーションを作ってみる

## 前置き
この投稿は、[TUNA-JP (Tanzu User kNowledge Assembly Japan) のアドベントカレンダー](https://qiita.com/advent-calendar/2021/tuna-jp) のエントリーです٩(ˊᗜˋ*)و

## 本記事の作成の経緯

Kubernetes の環境を作るときというのは、待ち時間が発生するものですよね。Kubernetes クラスタを作成して完了するまでの間とか、みなさん何をされていますか？
お茶をするものいいと思いますが、短い時間でタイムトライアル的にアプリケーションをつくってみるのも楽しいかもしれないですよね。

というわけで、この記事では実際に [Tanzu Community Edition](https://tanzucommunityedition.io/) の環境を作る際の待ち時間にアプリケーションを作ってみました、という内容です。

### ホントのところ

自分が今日アドベントカレンダーを担当していることを、今日気づき慌てて環境を作りながらアプリケーションを作ってみたというドキュメンタリーなのでした。

### アプリケーション作成の制限時間

Tanzu Community Edition で Kubernetes クラスタ環境を作る場合、自分の場合ローカル環境では大体 25〜30分かかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127983/3fc04208-485a-b755-43bd-dbbe20085c6a.png)

その時間内でアプリケーションを作り切るというチャレンジなのでした。

## 実施した内容

https://youtu.be/bp3lWjZCX8k

<iframe width="560" height="315" src="https://www.youtube.com/embed/bp3lWjZCX8k" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## まとめ

30分あれば、簡単なものであればサンプルアプリケーションは作れますね。
むしろ今回は、文章でなく動画でまとめようとしてしまった事による時間消費の方が大きかったです 笑

アプリケーションの内容自体、Spring の解説などはしていないので別途あらためてどこかで紹介していこうと思います。

### P.S.
久しぶりに Qiita の世界に戻ってきました٩(ˊᗜˋ*)و
【MySQL】外部キー制約がつけられなくてハマった話

これまでPostgresSQLを使ってきたのですが、MySQLに切り替えたところ、今回の事象が発生しました。
ハマって調べる中でピッタリの答えが記載されているものが見つからなかったため、備忘録がてら記載します。

##前提
companiesテーブルとemployeesテーブルを作成。

SQL文

```
CREATE TABLE companies(
id serial NOT NULL,
name text NOT NULL,
deleted boolean NOT NULL default false
);

CREATE TABLE employees(
id serial NOT NULL,
name text NOT NULL,
email text NOT NULL,
password text NOT NULL,
is_administrator boolean NOT NULL default false,
deleted boolean NOT NULL default false,
companies_id int NOT NULL
);
```

##現象
employeesにcompany情報を持たせるために、companies_idというカラムを追加。
companies_id カラムに、companiesテーブルのidカラムとの外部キー制約をつけようとしたところ、
以下のようなエラーが出てハマりました。

```
ERROR 3780 (HY000): Referencing column 'companies_id' and referenced column 'id' in foreign key constraint 'user_employees_ibfk_1' are incompatible.
```


##解決法
####employeesテーブルのcompanies_idカラムの「型」を`BIGINT UNSIGNED`にする
（UNSIGNEDは「符号なし」という意味）

##詳細説明
companiesテーブルのidカラムの型を`serial` で指定していたのが原因でした。

型の設定について不透明だったのですが、
`serial`で指定すると、

 * BIGINT
 * UNSIGNED
 * AUTO_INCREMENT
 * (長さ20？)
 
 の3つ(4つ)が自動指定されるようです。

※あとからHeidiSQLにて確認した画像※
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1165334/09144aa4-b371-bb1e-23bf-3097af5c33ac.png)

なので、employeeテーブルのcompanies_idカラムの方を合わせてあげれば、無事に外部キー制約をつけることができます！

##まとめ
最後までご覧いただきありがとうございます。
もし訂正・加筆すべき箇所がありましたらコメントにてご教示いただけますと幸いです。
書籍「ユースケースで学ぶDataiku－マーケティング活⽤のためのWeb ログ分析－」告知

2022/2/09 追記
 こちらの書籍は、以下の総集編に統合しました。以下をご利用ください。
 プログラミングレスデータ分析のすすめ ユースケース編
　[https://play.google.com/store/books/details?id=841aEAAAQBAJ](https://play.google.com/store/books/details?id=841aEAAAQBAJ)

----


INTECアドベントカレンダー7日目は、なんと<b>クリスマスプレゼント</b>のお知らせです:xmas-tree:

2021/12/1付でGoogle Play Booksから発行した「[ユースケースで学ぶDataiku－マーケティング活⽤のためのWeb ログ分析－](https://play.google.com/store/books/details?id=EXlQEAAAQBAJ)」。
[Dataiku](https://www.dataiku.com/)を扱った書籍としては４冊目、ユースケースシリーズとしては三冊目になります。
こちらをなんと無料でダウンロードできてしまいます！！

基礎から一歩踏み込み、ユースケースをもとにしたDataikuの応用的な使い方について学ぶことができる１冊です。
これからの冬休み、ちょっと新しい事を学んでみたいという方に最適です。

|<img width="400" alt="cover.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106215/4df9f9b9-54d5-e70b-e95f-4c1f2b12acc5.png">|
|:--:|


#本の紹介
本書は、[Dataiku 社](https://www.dataiku.com/)が提供する分析ツールDataiku Data Science Studio（Dataiku）を使って、実際の現場でデータ分析を進める第⼀歩を踏み出すための⼊⾨書です。
本書ではマーケティング活⽤のためのWeb ログ分析というユースケースを通じて、Dataiku の実践的な使い⽅を学んでいきます。Google Analytics などで⽤いられているイベントトラッキングデータを顧客情報と紐づけることで商品を購⼊しそうな顧客セグメントを⾒つけていくといった流れを体験できます。この内容はDataiku Academy で提供されている「Use Case: Web Log Analysis」の内容を⽇本語化しまとめたものとなります。

初⼼者の⽅でもデータ分析のことを知っていただけるように、Python やR などの分析⾔語の知識がなくても、Dataiku のGUI を使ってデータ分析を体験できるようになっています。そのため、現場でのデータ分析をどのように進めていけばよいか知りたい⽅には、きっと役⽴てていただける内容となっていると思っております。本書を通じて、実際のビジネス現場でのデータ分析で活⽤いただれば幸いです。

また、本書は書籍「プログラミングレスデータ分析のすすめ」の知識を前提としていますので、先にそちらを読んでおくとより理解が深まります。

ちなみに、クリスマス以降もずっと無料で頒布しております。

#執筆者
[@ayoyo](https://qiita.com/ayoyo)が執筆しています。そう、私です。

#ダウンロード
以下からダウンロードできます。
https://play.google.com/store/books/details?id=EXlQEAAAQBAJ

既刊である書籍「プログラミングレスデータ分析」は以下からダウンロード可能です。こちらも無料です。
技術書典
https://techbookfest.org/product/5117838303952896

また、このユースケースシリーズは、以下からダウンロードできます。全部無料です。
 - 1作目　「ユースケースで学ぶDataiku－レンタカーの故障予測－」
https://play.google.com/store/books/details?id=Wf4vEAAAQBAJ
 - 2作目　「ユースケースで学ぶDataiku－自転車シェアリングサービスの利用パターン分析－」
https://play.google.com/store/books/details?id=gu9EEAAAQBAJ

ちなみに、来年にはこの３冊をまとめた総集編も出る予定ですので、お楽しみに！

以上
むかつく上級生からのメールをふざけた文に書き換えてやったぜ

ゼミに命かけるムカつく上級生からのメール文をでふざけた文に書き換えてイライラせずに読む方法を探しました。




![kakikae.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1462552/89d5e2af-77e0-f7f3-ca5b-4fdb9c28fdab.png)


#方法
GmailのHTML要素を取得し、書き換えて表示する。

まず、requestIdleCallback関数を使い優先度の低い処理でもメインで実行させ、すべての処理を同時に行っているように見せています。 そして、

```
document.body.innerHTML =document.body.innerHTML.replaceAll('')
```

その下に書き換える文字の関数をどんどん追加していきます。

さん→チャン

```
var k = 0 
document.body.innerHTML = document.body.innerHTML.replaceAll("さん", () => "チャン")
```

で実際のHTML要素をJavaScriptで取得し、書き換えています。

どうやらmanifestファイルを読み込むみたいなので、manifestフォルダを作成し、その中にmain.js, manifest.json,imagesフォルダを格納します。


github
https://github.com/ytnd0928/Text-milder
デバッグモードで長期間のエージェントログを取得する方法

2021年OpsRampアドベントカレンダー12月19日分の投稿です。

#概要
エージェント ログの調査はトラブル対応に有効な手段です。そのため、何らかの問題が発生した場合はデバッグモードで再現時のログを取得することが多いです。
意図的に問題が再現できる場合は特に困りませんが、そうではない場合、問題が再現するまで長期間ログを取り続けなければならないことがあります。
エージェントログは設定したサイズを超えると古いログは削除されるため、デバッグ モードで長期間のログを取得するにはサイズを大きくする必要があります。
この記事では、デバッグ モードの設定とエージェント ログのサイズと数を変更する方法を紹介します。

#デバッグ モードの設定
エージェント ログは、デフォルトの設定ではトラブルの調査に必要な情報が足りないことがあります。そのため、出力レベルをデバッグ モードに変更して詳細な情報を取得できるようにします。
デバッグ モードへの変更はデバイスの以下のフォルダに存在する configuration.properties ファイルを編集します。

- Windows の場合
  C:\Program Files (x86)\OpsRamp\Agent\conf\configuration.properties

- Linux の場合
  /opt/opsramp/agent/conf/configuration.properties

(1) [Log] セクションの [log_level] を debug に変更して、ファイルを保存します。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345504/03517d0a-869f-4cea-70e0-06d68d3c0491.png)
(2) エージェントを再起動します。

#エージェント ログの場所
エージェント ログは以下のディレクトリに存在します。

- Windows の場合
  C:\Program Files (x86)\OpsRamp\Agent\log\agent.log

- Linux の場合
  /var/log/opsramp/agent.log 

#エージェント ログのサイズと数を変更する方法
エージェント ログは、デフォルトではサイズが 2MB に達するとファイルをアーカイブします。現在のログ ファイルとアーカイブ ファイルは合計 3つまで保持します。ファイル数がこれを超える場合は最も古いアーカイブ ファイルが削除されます。
このエージェント ログのサイズと数を変更するにはデバイスの以下のフォルダに存在する configuration.properties ファイルを編集します。

- Windows の場合
  C:\Program Files (x86)\OpsRamp\Agent\conf\configuration.properties

- Linux の場合
  /opt/opsramp/agent/conf/configuration.properties

[Log] セクションの [log_file_count] で保持するファイル数を設定します。[log_file_size_mb] で 1ファイルのサイズを設定します。これらのログファイルの合計サイズは 100MB までです。編集後にエージェントの再起動は必要ありません。
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345504/98a43023-73ae-7890-a39a-11a3db5461f9.png)
G検定に合格するためにやったこと[勉強法]

# 前置き

- [G検定](https://www.jdla.org/certificate/general/)の2021#3に合格することができました。
- その時に2つの参考書とWebサイトを使いました。
- 参考書・Webサイトを使った勉強法をこの後書いていきたいと思います。


# 勉強法
## [深層学習教科書 ディープラーニング G検定(ジェネラリスト)公式テキスト 第2版](https://www.amazon.co.jp/%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92%E6%95%99%E7%A7%91%E6%9B%B8-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88/dp/4798165948)

- 公式テキストを3回ほど読み、G検定の概要を掴む。

## [最短突破 ディープラーニングG検定(ジェネラリスト) 問題集](https://www.amazon.co.jp/%E6%9C%80%E7%9F%AD%E7%AA%81%E7%A0%B4-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E5%95%8F%E9%A1%8C%E9%9B%86-%E5%85%89%E5%A4%AA%E9%83%8E/dp/429711609X/ref=pd_lpo_1?pd_rd_i=429711609X&psc=1)

- 2,3回ほど繰り返し解く。
- 分からない問題には付箋を貼り、本番前まで繰り返し問題を解く。
- Study-AIよりは本番の問題はあまり出なかった。
- しかし、機械学習についての知識は増えるため「G検定合格」と「機械学習の勉強」におススメの本。



## [G検定(AIの検定)模擬テスト - Study-AI](https://study-ai.com/generalist/)
- 正答率は9割超えるまで繰り返し解く。（最初は4割ほどしか取れていなかった…）
- 本番に近い問題が出たので、最後の仕上げにもオススメ。

# まとめ
- この3つを使って勉強することで、体感ですが7割取ることができました。
デモ動画の撮影からREADMEへの挿入まで【Github】

エンジニアに転職するべく　Railsの勉強を始め、ポートフォリオとしてRailsを用いたWebアプリを制作しました。
自分の制作したアプリの使い方を直感的にアピールするためにデモ動画をREADMEに挿入してみたので手順をまとめます。

# 1. QuickTimePlayerのインストール
自分のOSに合わせたバージョンをインストールします。

# 2. 撮影
まずQuickTimePlayerを選択→新規画面収録クリック
![スクリーンショット 2021-12-06 14.10.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293293/1958f146-2d6a-bf16-add1-ee1481426ed8.png)

その後出てくる画面で選択部分を収録を選択→収録をクリック
で見てほしい画面だけを切り取って撮影が始まります。

#3. ffmpegを使ってmovからgifへ変換
ffmpeg（エフエフエムペグ）とは動画と音声を変換するためのフリーソフトウェアです。
homebrewを使ってインストールします

```
brew install ffmpeg
```

```
ffmpeg -i [撮影した動画の名前(任意)].mov [撮影した動画の名前(任意)].gif
```

#4. gifをREADMEヘ投稿
GithubのWikiを使用する場合もあるみたいですがカンタンなので自分はissueの方を使用しました。
Githubのリポジトリを開いてissuesを選択→New issue
![スクリーンショット 2021-12-06 14.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293293/17b737e3-43bc-1220-65b8-f394f519e0bb.png)

目的のgifをAttach→gifに対応したパスが出てくるのでそれをコピー→Submit new issue
![スクリーンショット 2021-12-06 14.45.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293293/000aba02-235b-6dbc-bd06-8c40fb6cc7a7.png)



このパスをREADMEに記述すると目的のgifが挿入されます！

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293293/2ba70dbf-82b8-9596-9088-99779c829d88.gif)

# 5. その他

+ 撮影した動画はQuickTimePlayerでカンタンなことなら編集できます。例えば動画の開始地点を変更したかったら編集→トリムで動画の始めの方をカットすることができます。

+ ffmpegでは画像のサイズを変更したりgifの容量を小さくすることもできます。

# 参考
[FFmpegで動画をGIFに変換](https://qiita.com/wMETAw/items/fdb754022aec1da88e6e)
[GithubやQiitaに載せるgif形式の動画を作成する方法](https://qiita.com/syamaoka/items/4d4054cd75df00460925)
[Githubに画像をアップロードする小技](https://qiita.com/Sylba2050/items/c9b46d225c840a23d980)
Microsoft Build of OpenJDK　インストール画面キャプチャ

【JDK11の場合】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/00adafb0-8185-75e1-18c6-b86696da6e45.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/33884b40-f237-5e57-2807-087968b55dc2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/48fdf109-9cf5-83af-88a1-529691e478ff.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/e3790454-3462-ecf0-dbaf-f4f557f323fa.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/1fc1b7f7-b9d0-abaa-29e4-bee033524c8c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/2893d5d9-f9d3-f38e-6998-89e900f1bf9d.png)

【JDK17の場合】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/840c4773-cdcf-fbb4-c1fd-e9b049d1f757.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/16b00cf1-0970-27e6-b280-3900bb965415.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/0e8acba0-f19f-f9bd-74cb-1c0e7d58460a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/d0690716-f720-3945-6978-188ebf4559fb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/3fc8514e-dfa7-a4c0-489b-117fe5d4d95a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564542/3d1bb311-e911-f134-3759-d706d045ac9d.png)


以上
useStateってなんじゃらホイ


Next.jsでUseStateについて、いまいちピンと来ていないため、簡単にまとめておきます。


#useStateとは

・変数と関数がセットになったようなもの？
・値を保存することができる
・値が更新される度に、関数自身が呼び直される

#宣言の方法

①インポートして、②宣言する

①import {useState} from 'react';

②[変数名, 関数名] = useState('');


#使い方

例えば
export default function Test(){
}

という関数の中で

const [name, setName] = useState('');

というuseStateを宣言したとする。

nameに値が入っていて、
setName('セットしたい名前')
で値を更新できる。

useStateを更新するたびに、Test()が呼ばれる。


#無限ループに注意する

useStateの動きを確認していたところ

Next.jsでToo many re-renders. React limits the number of renders to prevent an infinite loop.というエラーが出ました。



```JavaScript
import * as React from 'react';
import {useState} from 'react';


export default function Test(){

    const [name, setName] = useState('');

    setName('Piro');

    return(
        <>
            <p>私の名前は{name}です</p>
        </>
    )
}
```

setName('Piro');
のところで、どうも無限ループに入ってしまっているようです。

setName()の前にログを仕込んでみると、
５０回ほど呼ばれたところで、エラーを出して処理を止めていました。

useStateを更新するとreturn()の中だけが更新されると勘違いしていましたが、
どうもTest()自体が呼び直されるようですね。

#対策：関数の中に入れる

対策として、ボタンを押すと呼ばれる関数の中に、useStateの処理を入れました。

```JavaScript
import * as React from 'react';
import {useState} from 'react';

export default function Test(){

    const [name, setName] = useState('Piro');   //初期値を設定

    console.log("Test()がCall");
    //setName('Piro');

    const changeName = () => {
        setName('竜騎士ガルザーグ');
    }

    return(
        <>
            <p>私の名前は{name}です</p>
            <button type="button" onClick = {changeName}>実は本名は</button>
        </>
    )
}

```

これで、ボタンを押した時だけchangeNameが呼ばれて、
setNameで更新するため、無限ループを防ぐことができます。

![スクリーンショット 2021-12-06 13.56.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1942691/9d1c03c1-1e76-83b7-116b-d61156a92e8b.png)

「実は本名は」のボタンを押すと・・・↓

![スクリーンショット 2021-12-06 13.57.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1942691/e696d518-a6d9-c7b5-f244-7249e844c698.png)

となります。
社外イベントに初めて登壇して思ったこと


マーガリンこと藤曲でございます。
この記事は[ベリサーブ Advent Calendar 2021のカレンダー | Advent Calendar 2021 - Qiita]((https://qiita.com/advent-calendar/2021/veriserve))の13日目です。
本稿ではタイトルの通り、「社外イベントに初めて登壇して思ったこと」について書きたいと思います。

# ◆ はじめに
私は2018年4月から社外の勉強会やイベントに参加するようになり、これまで50以上に参加をしてきました。
そこで得た知識や、通常業務で得た知識やノウハウを社内の勉強会や社内イベントで発表することはあれど、
あくまで社内の域から出ることはありませんでした。

そんな私が、初めて（弊社主催ですが）社外のイベントに登壇して思ったことについて本稿では書きたいと思います。

# ◆ 登壇した社外イベントについて

主催：株式会社ベリサーブ
場所：Zoom ウェビナー
日時：2021/11/17(水) 19:00 - 20:05
タイトル：**VeriServe Test Automation Talk No.1 ～テスト自動化LT～**
発表タイトル：**部門内の自動化ノウハウを全社に向けて発信しているお話**
[<img width = 500 src = "https://connpass-tokyo.s3.amazonaws.com/thumbs/da/98/da98d6b3006aee9307f460968e666d0f.png">](https://veriserve-event.connpass.com/event/224759/)



# ◆ 思ったこと
弊社主催とはいえ、弊社社員以外に向けて発信する機会が今までになかったため、それなりに緊張をしました。
緊張して口が乾きながら話した経験から、反省点などの思ったことについて書き出したいと思います。

## オンライン特有の緊張感がある
今回発表をしたイベントはZoomウェビナーを使ったオンラインイベントでした。
オンラインンなので、参加者の顔を見ない分そこまで緊張しないかなぁ～　っと発表本番10分前まで思っていました。
対面での発表は社内で何度か経験し、それなりの緊張感を知っていますが対面とは違った緊張感でした。

**オンライン会議では、参加している人の反応が見えない**

この反応が見えないが私にとっては非常に辛く、緊張する要因となりました。
私はただ資料に書いてあるだけを発表することはあまり好きではなく、ちょっとした小ボケや冗談を交え、場の空気を柔らかい状態で発表することを好みます。
それがオンラインだと出来ない。そう思うと同時に緊張感が出てきました。
ただ、人によって顔が見えないことで対面よりも緊張しない人もいるかと思いました。

## コミュニケーションが一方通行
**オンラインイベントでは、発表者から参加者へ一方通行となってしまう。**
参加している人の反応が見えないことで、リアルタイムでのコミュニケーションが難しいと感じました。
対面であれば、イマイチ伝わっていない所や共感を得られている場合は頷きが見られたりしますが、それがありません。
唯一のコミュニケーション手段がZoomウェビナーのQA機能のみとなり、それも質問に回答して終わってしまう。
オンライン発表をしてみて思ったのが、私は対面での発表の方が合っているのかなと思いました。
そういう人には、オンライン発表は"慣れ"が必要だなぁ～ととても思いました。

## イベント終了後の交流がない
コロナ禍以前の参加してきたイベントでは、イベント終了後に**懇親会（交流会）**があり、登壇者や参加者同士で交流が行えていました。
その懇親会（交流会）でコミュニケーションを取ることで、イベントでの質疑を行ったり、気付きを得る、人脈を築くことができました。
今その役目をTwitterなどのSNSで代替していますが、やはり対面でのやりとりに勝るものはないなぁと改めて感じました。

# ◆ おわりに
今回オンラインイベントで発表をしてみての感想を書きました。
コロナウイルスの影響で対面でのイベントが制限されているなか、オンラインイベントの得意・不得意なことをとても感じました。
正直、私自身が慣れていない・順応しきれていないこともあるのかなぁとも思っています

ここ最近感染者が減っていますが、コロナ禍以前のように戻ることはないと確信しています。
今回登壇することで、参加者側・運営側のことを知れたので、この経験を基に更に自己成長に繋げられたら強く思いました。

-以上
あれ？ポチッとマージできちゃった？ガバガバGithubガバナンス

こんにちは！アドベントカレンダー2本いっちゃう？と言われ営業さんもびっくりな「はい！もちろん書かせていただきます！」と元気よく返事をしてしたもののネタに困っていたガチムチですが、藁にもすがる思いで見つけたGithubネタを投稿します。

# とある日のこと
自分が所属しているチームで管理しているrepositoryにPRを作成しレビュー依頼を行いました。
そのときにPR画面に大きな違和感を感じました。

あれ？これ、マージできるぞ！

設定を確認するとブランチのプロテクションルールが私の財布のように空っぽでした。

# 1匹いるなら...
こういった問題は、1つあると全体的に疑わしくなってします。まるで1匹いると何匹もいる奴らのようです。
チームで管理しているレポジトリを足元良し!の要領で１つずつチェックしていくのは、屈強なメンタルと絶対に間違えない自負が必要となります。
もちろん私のような一流の窓際コピペエンジニアには、そんなものは持ち合わせてないので、なんとか自動化(コピペ)できないかと考えました。

最初は[PRのテンプレート](https://docs.github.com/ja/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository)をrepositoryに添えるような感覚で同じようなものがないかと血眼になって探しました(10分ぐらい)が見つかりませんでした。(もしかしたらあるかも)

アドベントカレンダーも差し迫った日曜に「ちょっと今日調べ物が、、、」と嫁に言うも「あ？」と言われ、休日のママリバティのために精根尽き果てるまで公園戦士にジョブチェンジさせられた私は、子供に「一人で滑り台滑ってきてよ」と謎のクエストを実行させられているときに[Github API](https://docs.github.com/ja/rest)使ってなんとかしようと決意しました。

ちなみに滑っている最中は誰も見てなくて、なんかただただ滑った人みたいになっていました。滑り台だけに。

# 結局どうなったか？
一流の窓際コピペエンジニアは翌営業日の朝までになんとかすればいいと知っています。だから窓際コピペエンジニアなのです。

とりあえず、間に合ったということで雑なシェルを載せてきます。
私が所属しているチームでは、Githubのチームに管理するrepositoryをすべて入れているので、Githubのチームから辿るようにしました。
また、もし設定が入っていないrepositoryは最低限の設定を追加するようにしました。

※[jq](https://stedolan.github.io/jq/)がインストールされてないと動きません。

```shell
#!/bin/bash

ORG="オーガニゼーション"
TEAMS="チーム"
BASIC="ユーザー名:パーソナルトークン"

# repositoryの一覧を取得する(アーカイブされたrepositoryは除く)
REPOSITORIES=(`curl -s -u $BASIC https://api.github.com/orgs/$ORG/teams/$TEAMS/repos | jq -r '.[] | select(.archived == false) | .name'`)

for REPOSITORY in "${REPOSITORIES[@]}"
do
  # defaultブランチ名を取得
  DEFAULT_BRANCH=`curl -s -u $BASIC https://api.github.com/repos/$ORG/$REPOSITORY | jq -r .default_branch`
  # プロテクションが行われているか？
  IS_PROTECTED=`curl -s -u $BASIC https://api.github.com/repos/$ORG/$REPOSITORY/branches/$DEFAULT_BRANCH | jq .protected`
  if "${IS_PROTECTED}"; then
    echo $REPOSITORY $DEFAULT_BRANCH is protected.
  else
    # プロテクションが行われていないときに、最低限のプロテクションをセットする
    echo $REPOSITORY $DEFAULT_BRANCH is not protected.
    curl -s -u $BASIC -X PUT https://api.github.com/repos/$ORG/$REPOSITORY/branches/$DEFAULT_BRANCH/protection -d '{"required_pull_request_reviews": {"dismiss_stale_reviews": true,"require_code_owner_reviews": false,"required_approving_review_count": 1}, "enforce_admins": false, "required_status_checks": null, "restrictions": null}'
    echo update $REPOSITORY $DEFAULT_BRANCH protects
  fi
done
```
最初設定が入っていないrepositoryの一覧を表示するだけにしたのですが、結局設定を入れるので、apiで行うようにしました。
本当はciとのインテグレーションがあったらうんぬんかんぬんしてもっと上質なプロテクションルールにしたかったのですが、~~めんどくさかった~~最低限の設定を入れるにとどめておきました。


# まとめ
Githubのapiをまともに触ったことなかったのですが、repositoryの情報やprotectionの設定をかなり詳細に取得できるので、もともとやりたかったprotectionの設定をtemplate化してrepositoryに添えると勝手に設定を反映させてくれたり、設定と違ったら(なんかallow_forcepushがonになっているｱﾙとか)教えてくれたりするものがあってもいいなーと思いました。

一年通してrepositoryの管轄部署が変わったりすることがあると思います。それ以外にも古からオーパーツのように存在するrepositoryを管理していたり、大量のrepositoryを管理しているチームなどがあったら、年の瀬の大掃除ということで、一度プロテクションルールをチェックしてみてはいかがでしょうか。
EntityFramework Core でDB構築をしようとして詰まった時の話（記録用）

作業をして詰まったのでその記録用に残します。

# 開発環境
- OS:Windows10
- ASP.NET
- DB:PostgreSQL

# 作業
まだASP.NETは不慣れなのですが、開発で使用するために環境構築を行っていました。

パッケージマネージャーコンソールでコマンドを実行すると下記のエラーが出てしまいました。


```
Update-Database
Build started...
Build succeeded.
No DbContext was found in assembly 'プロジェクト名'. Ensure that you're using the correct assembly and that the type is neither abstract nor generic.
```

調べたところどうやらDBContext を定義していないプロジェクトでマイグレーションコマンドを実行しようとすると起きる事象のようです。


##　対処


もう一度同じコマンド**'Update-Database'**を打ったところ（ダメ元）下記が返ってきました。

互換性がないので指定されたフレームワークをインストールしてみてね。とのことでしたので、リンクから.NET Core 2.0 Runtime (v2.0.9) をインストールしました。

```
Update-Database
Build started...
Build succeeded.

It was not possible to find any compatible framework version
The framework 'Microsoft.NETCore.App', version '2.0.0' was not found.
  - The following frameworks were found:
      3.1.21 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
      5.0.12 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

You can resolve the problem by installing the specified framework and/or SDK.

The specified framework can be found at:
  - https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&framework_version=2.0.0&arch=x64&rid=win10-x64
```

再度**'Update-Database'**コマンドを実行。
すると下記が返ってきました。


```
Your startup project 'Infrastructure' doesn't reference Microsoft.EntityFrameworkCore.Design. This
```

エラーの通り**Microsoft.EntityFrameworkCore.Design.**をインストールしました。

ソリューションエクスプローラー　→　プロジェクト名を右クリック→　NuGetパッケージの管理からインストール実行

```
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Model.Validation[10400]
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
```

やっと構築できました。

succeededと出ているのになぜDBに接続できないのだろう？と不思議だったのですが、成功していなかったんですね。



#参考サイト
- [EF Core でマイグレーションを実行する際に発生しうるエラーとその対処法](https://zenn.dev/kmd_htsh0226/articles/7b7e4ae780e620fc7eb2)
- [.NET Core で DBマイグレーションを試したら色々ハマった話](https://blog.ecbeing.tech/entry/2019/06/12/125411)
- [[C#]EntityFramework(dotnet ef)マイグレーションまとめ](https://codelikes.com/csharp-dotnet-ef-migrations/)
- [runtime-2.0.9　インストールリンク](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-2.0.9-windows-x64-installer)
なんでもガバにする２

https://qiita.com/o________o/items/d2919c74544c506023d6

これの続き

# 今回の課題
ゲイン調整するってのがあったのでやる

# 今回のアプローチ
pydubのドキュメント見たら波形を上げれる最大まで上げるマキシマイザーフルテンみたいな機能があったのでこれ使ってみる
https://github.com/jiaaro/pydub/blob/master/API.markdown#audiosegmentmax_dbfs

# 実装

```python:
import numpy as np
import librosa
import pydub
from pydub import AudioSegment

path = "motoneta.mp3"
kick =  "gabba-kick.wav" # ガバキック音源

# とりあえずまず元ネタ音源のBPM取る
y, sr = librosa.load(path)
tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)

# BPMから4分のタイムを計算する
tempo_one = 60 / (tempo*4) 


# 拡張子はうまいこと合わせて音源読み込み
base_sound = AudioSegment.from_file(path, format="mp3") 
kick_sound = AudioSegment.from_file(kick, format="wav") 


# 元ネタ曲とキックのゲインをフルテンにする
base_sound = base_sound.apply_gain(-base_sound.max_dBFS)
kick_sound = base_sound.apply_gain(-kick_sound.max_dBFS)

# 元ネタ曲の長さを取る
time = base_sound.duration_seconds

# ここがメイン処理！！！！！！！！！
#キック音源を元ネタ音源の上に載せる
start_time_ms = 0  
while(True):
        

        base_sound = base_sound.overlay(kick_sound, start_time_ms)
        start_time_ms =  start_time_ms + tempo_one * 1000

        # 適当に終わらせる
        if time * 1000 < start_time_ms:
            break
# 早くする
base_sound = base_sound.speedup(playback_speed=2.0, crossfade=0)

# 出力する
base_sound.export("gabba.mp3", format="mp3")

```

おしまい


# 聞いてみた
ゴミみたいだった

https://soundcloud.com/bjack_mijilme/python-gabba-2

キックの音圧めっちゃ下がっとる

# 今後の展開
もうちょい音圧上げたい
Jetpack ComposeのTextで表示されている文字列の行数を取得する

TextのonTextLayoutのラムダに入ってくる `TextLayoutResult` の `lineCount` を使用すると表示される文字列の行数を取得することが出来る

``` kotlin
Text(
    onTextLayout = { result ->
        Timber.d("onTextLayout=${result.lineCount}")
    }
)
```

なので、rememberの値と `lineCount` の値を使えば改行されるような文字列が入ってきたら非表示にするとかが出来る

``` kotlin
@Composable
fun Hoge(
  text: String,
) {
    var isMultiline by remember { mutableStateOf(false) }
    // 改行されたら非表示にする
    if (isMultiline.not()) {
        Text(
            text = text,
            onTextLayout = { result ->
              isMultiline = result.lineCount > 1
            }
        )
    }
}
```
<備忘録>Macでターミナルを使ってフォルダーを作る方法

# ターミナルを使って任意の場所にフォルダーを作成。



### 1. まずターミナルを開く  
 finder →　ユーティリティー　→　ターミナル

### 2.cdコマンドで任意の場所へ移動

     $ cd 任意の場所 


### 3.mkdirコマンドでフォルダーの作成

     $ mkdir フォルダー名
[Servicenow]HTMLフィールドの改行の小ネタ

ナレッジ投稿の際など、HTMLフィールドに触れる機会が多いと思います。
そこで、HTMLフィールドに関するちょっとした小ネタを書いていこうと思います。


#HTMLフィールドとは
ServiceNowをよく触っている方には説明は不要かと思いますが、
HTMLフィールドは、その名の通り、HTML形式で入力できるフィールドです。
例を挙げるとナレッジのArticleBodyとかですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/af10419b-f242-d7e4-93bb-bd88d61b195f.png)



##改行小ネタ
文章をこの中に普通に書いていくと、以下のようになるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/eadee06d-dd27-2843-6cda-73de5babb2c1.png)

行間が空いていますね。
これをHTMLソースで見てみると、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/687bb7b8-0598-7e33-439a-5fcf6254c00b.png)
御覧の通り、改行ごとに、pタグで囲まれてしまうのです。
入力の際に、左下にpと出ていますが、これが効いています。

これを変更するには、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/f6a27bf3-43ee-4931-1e23-92db3010f02f.png)
囲ったところを変更すれば、p⇒preに変わります。
しかし、ココを変更するとフォントも変わってしまうため、ちょっとめんどくさい。
そんな時は、Shift+Enterを使用することで、改行にbrが使用されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/c5efa8b6-3804-3f06-e09d-d098f4189759.png)
行間が狭くなりました。
これをHTMLソースで見てみると、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/ef62d33b-1976-651d-83cb-ffae733dfb62.png)
こんな感じになります。
最初から最後までがpタグで囲まれて、中にbrが埋め込まれるので、行間は広くなりません。
ちょっと行間を詰めたいときはいいと思います。
roslaunchからノードを実行する場合にノードに引数を与える

roslaunchからノードを実行する場合にノードに引数を与える方法です。

実行するノードに`--test`という引数を与える場合は以下のように記載します。

```
<node name="listener1" pkg="rospy_tutorials" type="listener.py" args="--test" respawn="true" />
```

また以下の様に,パッケージのパスを取得することも可能です。

```
<node name="bar1" pkg="foo_pkg" type="bar" args="$(find baz_pkg)/resources/map.pgm" />
```

※ メモ:今回の内容とは関係無いですが,ノードの取得を行いたい時は, output="screen"を入れます。

# さいごに

roslaunchからノードを実行するとroslaunchがプロセスを色々管理してくれるみたいで安心感があるので,うまく扱えるようにしたいです。

# 参考

詳しくは以下をご参照ください。

http://wiki.ros.org/roslaunch/XML/node
Pleasanterの一覧画面に取扱説明書のリンクを追加する

作製したテーブルの操作説明などの取扱説明書を利用者に提供したい場合に、Wikiなどテーブルとは別の場所に書いても中々読んでもらえないと思います。
簡単なスタイルとスクリプトで取扱説明書(PDFなど)のリンクをテーブルの一覧画面に追加する方法を共有します。
※動作確認環境
Pleasanter：1.2.20.0
ブラウザ：Chrome
## 前準備
1. 取扱説明書の対象テーブルとは別に取扱説明書を保存する専用のテーブルを作成して、添付ファイル項目を追加します。

![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/32563ff7-5c2b-c140-c227-82708a6f9c24.jpeg)
2. 添付ファイル項目に取扱説明書を保存して、ダウンロードURLをメモします。
 ![WS000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/4c05a5ad-279e-748b-a2f5-b63b7e382199.jpeg)
![WS000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/777d30fc-c8b7-f6c4-10d8-8d77cc093a3c.jpeg)

## テーブルの一覧画面に取扱説明書のリンクを追加する

今回は集計欄の下に取扱説明書のリンク追加します。
![WS000003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/56d18031-e58e-fcc7-7075-a318fb57d7b0.jpeg)
### スタイル
集計欄と見た目を合わせるために、「テーブルの管理」-「スタイル」タブを開いて以下のCSSを入力します。

```css
#ManualLink {
    width: 100%;
    float: left;
    margin: 0 0 5px 0;
    padding: 3px 5px 5px 5px;
    border: solid 1px #c0c0c0;
    border-radius: 5px;
}
```
出力先は「一覧」を選択します。
 ![WS000004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/fc6613b8-492d-4058-e174-cc305add8c5d.jpeg)

### スクリプト
ダウンロードURLへのリンクHTMLを追加するJavaScriptを追加します。
「テーブルの管理」-「スクリプト」タブを開いて以下のコードを入力します。
ダウンロードURLの例：（環境に合わせて変更してください）
「http\://localhost:8686/binaries/e935b498727d470eb8318c8566282a91/download」）

```js
$('#ViewModeContainer').before('<div id="ManualLink"><a href="http://localhost:8686/binaries/e935b498727d470eb8318c8566282a91/download" download="Pleasanter業務アプリ作成者マニュアル.pdf">取扱説明書をダウンロード</a></div>');
```
出力先は「一覧」を選択します。
![WS000005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/46e93d3e-c63a-2804-3b07-b88740963011.jpeg)

## 設定結果
下図のとおり「取扱説明書のリンク」と「テーブル一覧」が同一画面に表示されます。
![WS000007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1542618/c44e6635-8405-6ace-1a9d-a7f1911d308a.jpeg)

## さいごに
オンプレの国産WebDBを検討した中で拡張性が頭抜けて高い物がPleasanterと感じました。ちょと古臭いUIも学習コストが少なくて高評価です。
この例ではファイルのリンクでしたが、D3.jsのグラフなど色々な物を一覧画面に埋め込めると思います。
CORS エラーにハマったら MDN を見ると良いよ

[MDN]: https://developer.mozilla.org/ja/docs/Web

# はじめに

フロントエンド開発で、別リソースの情報を表示したいけどうまく表示されないことがよくあると思います。
そのときにブラウザコンソールに赤い文字で `Access to fetched to fetched has been blocked by CORS policy error` と出て「またか...」となったことは一度や二度ではないでしょう。

CORS についてよく分からなくても、使っているフレームワークとエラーメッセージの reason を組み合わせて検索すると解決策が見つかるため、よく分からないままで放置していませんか?
この記事では CORS エラーについてその原因と解消するための説明。が [MDN][] にまとまっているのでそれを紹介します。

# 小噺

当初は、そもそも CORS とはなんぞやと言う解説も載せようと思いましたが、先週別のカレンダーでもっと分かりやすい記事が掲載されていましたので、エラー周りのみを取り上げています。
(アドベントカレンダーってこういうことがあるから怖いよね)

# CORS とは

以下の記事がとても分かりやすかったので、参考として貼らせていただきます :pray:

https://qiita.com/ryosuketter/items/a60a2bc0220a5cbff17e

# 本題

CORS エラー時には以下のページの [CORS のエラーメッセージ](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS/Errors#cors_error_messages)の章から、該当するエラーのページが確認できます。

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS/Errors

(:point_up: の記事へ直接飛ばなくても [HTTP カテゴリー](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS/Errors/CORSAllowOriginNotMatchingOrigin)のページならどこでも、左の **Table of contents** の **CORS エラー** グループから探すことができます。

このページの利点は、

- ブラウザコンソールに出てくるエラーメッセージがそのまま書いてあるので探しやすい。
- CORS エラーについて網羅的 (なのかな?) に書かれている。
- 各ページには「何が悪いのか」「どうすれば解消するか」についてまとまっているので、何となくの理解で終わらない。

ので、エラーが出たときに google 先生に聞いて解消する前に、これらのページからより深い理解に繋げてみてはいかがでしょうか。

# [補足] エラーにならないケース

この記事では CORS エラーを起点に解消するサイトを紹介しましたが、エラーにならないがクライアントで扱うためにサーバからの許可が必要なケースがあります。
それは JavaScript からのレスポンスヘッダーへのアクセスです。

通常、クロスオリジンからのレスポンスヘッダーは一部を除いて JavaScript から読み取ることができません。
そのまま取得しようとしても `undefined` 扱いになります。
これを JavaScript でも扱うためには、レスポンスヘッダーに [Access-Control-Expose-Headers](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Expose-Headers) を加える必要があります。

例えば [Content-Disposition](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Disposition) ヘッダーからファイル名を取得したい場合は、以下のようなヘッダーをレスポンスに加える必要があります。
(複数ある場合は `,` で区切って指定可能です)

```
Access-Control-Expose-Headers: Content-Disposition
```

# まとめ

[MDN][] って良いよね :relaxed:
Goでいいね機能を実装してみた。

この記事は　Aizu Advent Calendar 2021　の５日目の記事です

夏休み中にgo言語でそんな感じのコードを書いていたので、自分の復習も込めて記事にしてみます。
全てのコードはこちら  
=> https://github.com/wt128/dbapiBygo/
## フレームワーク等  
gin/gorm/mysql

## ER図とモデル![ergo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1504436/1a630627-5787-9e75-6315-5368ee7b959a.png)
- いいねのモデル

```
type Like struct{
	ID		uint `json:"id"`
	PostID 	uint `json:"postid" gorm:"index:idx_name,unique"`
	UserID 	uint `json:"userid" gorm:"index:idx_name,unique"`
	User	User `gorm:"foreignKey:UserID; references:ID; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
	Post	Post `gorm:"foreignKey:PostID; references:ID; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
```
likeテーブルのpost_idとuser_idにはペアでユニーク制約をかけています。

- いいね数のためのモデル

```
type CntList struct {
	Pid		uint	`json:"pid" gorm:"postid;"`
	Cnt		int64	`json:"cnt" gorm:"cnt;"`
}
```

gormで取得した後、jsonとして返すために構造体が必要なため用意しました。
##コードと仕様
- `/like`     いいねの表示
- `/like/:id` 特定のユーザー(id)のいいね数
- `/create`   記事へのいいね
- `/destroy`  いいね取り消し

```go:/like
    var cnt []CntList	
	db := db.GetDB()
	sql := db.Model(&Like{}).Select("COUNT(id) as cnt","post_id as pid").Group("pid").Find(&cnt)
```
```go:/like/id
var cnt []CntList
	id := c.Params.ByName("id")
	db := db.GetDB()
	sql := db.Model(&Like{}).Where("user_id = ? ", id).Select("COUNT(id) as cnt","post_id as pid").Group("pid").Find(&cnt)
```  
```go:/create
    var com Like
	db := db.GetDB()
	//currrent_user
	if err := c.BindJSON(&com); err != nil{
		c.JSON(400,gin.H{"errorMessages":"エラーが発生しました."})
		return
	}
```
```go:/destroy
db := db.GetDB()
	
	if err := c.BindJSON(&com); err != nil{
		c.JSON(400,gin.H{"errorMessages":"エラーが発生しました."})
		return
	}
	err := db.Where("post_id = ? and user_id= ?",com.PostID,com.UserID).Delete(&com)
```

##参考
https://hit.hateblo.jp/entry/mysql/iine
ホワイトクリスマス

最終回はクックブックではないですが、今日雪が降ったら素敵だなということで、雪を降らせるプロジェクトを。

最後までこのアドベントカレンダーを見てくれて、ありがとうございました。
Happy White X'mas!

https://scratch.mit.edu/projects/528930506

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/528930506_480x320.png)
サクッとApacheのerrorlogをJSON化してBigQueryにLoadします

このエントリーは、GMOアドマーケティング [Advent Calendar 2021](https://qiita.com/advent-calendar/2021/gmo-am)【12/22】 の記事です。

##Overview
apacheのerrorlogを簡単にBig QueryにUploadする方法になります。

##Reference
[ErrorLogFormat](https://httpd.apache.org/docs/2.4/en/mod/core.html#errorlogformat)
errorlogのformat変更はapache2.4から対応しています

##Environment
apache2.4

##Sample Format
```
ErrorLogFormat "{\"message\":\"%M\",\"error_time\":\"%{cu}t\",\"loglevel\":\"%-m:%l\",\"serverip\":\"%A\",\"host\":\"%a\",\"referer\":\"%-{Referer}i\""}"
```

##Sample Log Export
```
{"message":"error message","error_time":"2021-12-25 12:11:05.763873","loglevel":"php7:notice","serverip":"192.168.1.121:80","host":"xx.xxx.xxx.xxx:40812","referer":"http://hogehoge.jp/","log_type":"apache_error"}
```


##Schema
```
[
  {
    "name": "error_time",
    "type": "TIMESTAMP",
    "mode": "REQUIRED"
  },
  {
    "description": "ログレベル",
    "name": "loglevel",
    "type": "STRING",
    "mode": "NULLABLE"
  },
  {
    "name": "serverip",
    "type": "STRING",
    "mode": "NULLABLE"
  },
  {
    "name": "host",
    "type": "STRING",
    "mode": "NULLABLE"
  },
  {
    "name": "message",
    "type": "STRING",
    "mode": "NULLABLE"
  },
  {
    "name": "referer",
    "type": "STRING",
    "mode": "NULLABLE"
  }
]
```

##Big Query Upload Shell
```sh
#!/bin/bash

/bin/echo "S: `date +'%Y-%m-%d %H:%M:%S'`"

v_year="2021"
v_month="12"
v_day="25"
v_ymd="${v_year}${v_month}${v_day}"

v_gcp_project="GCPPROJECT"
v_gcp_bq_dataset="file"
v_gcspath="gs://DATASET/file/2021/12/25"
v_table="error"

v_errorfilename=error_log.${v_ymd}
v_errorfilepath=/var/log/httpd/${v_errorfilename}

#Compression
if [ ! -f ${v_errorfilepath}.gz ]; then
  nice -n 19 grep -v "^{-" ${v_errorfilepath} > ${v_errorfilepath}_tmp && \
  nice -n 19 sed -i -e "s/'/\"/g" ${v_errorfilepath}_tmp && \
  nice -n 19 gzip --fast -c ${v_errorfilepath}_tmp > ${v_errorfilepath}.gz && \
  nice -n 19 rm -f ${v_errorfilepath}_tmp
fi

#GCS Copy
trickle -s -u 10000 gsutil cp ${v_errorfilepath}.gz ${v_gcspath}/

#Big Query Load
bq load \
--project_id=${v_gcp_project} \
--dataset_id=${v_gcp_bq_dataset} \
--ignore_unknown_values \
--max_bad_records=100 \
--schema=/path/schema/${v_table}.json \
--source_format=NEWLINE_DELIMITED_JSON \
${v_table}_${v_ymd} \
${v_gcspath}/${v_errorfilename}.gz

/bin/echo "E: `date +'%Y-%m-%d %H:%M:%S'`"
```

##Result
![スクリーンショット 2021-12-06 12.28.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72945/3ce94e75-f2d4-8fc5-12d3-82a49d3865ad.png)

##次回の[Advent Calendar 2021](https://qiita.com/advent-calendar/2021/gmo-am)
明日は、【@watashinohakumai】さんの【AWS SAPを取得したら視野が広がった話】についてのお話です。
お楽しみに。

クリスマスまで続くGMOアドマーケティング [Advent Calendar 2021](https://qiita.com/advent-calendar/2021/gmo-am)
ぜひ今後も投稿をウォッチしてください！
【Unity】Blenderで作ったアニメーションを適用させるとアバターが中腰になってしまう現象の解決法

解決方法：Animation ClipのInspectorから，RigのAnimation Typeを"Humanoid"に変更（デフォルトではGenericになっている）する．そのあとでアバターに適用させる．
![animationtype.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459660/c01bb6ba-20f7-7957-f5fe-7bc94546be93.png)
それだけのことなのですが，意外と見落としがちで時間を吸われてしまったので記事に残しておきます．

↓ BlenderからインポートしたAnimation ClipをそのままAnimatorウィンドウのDefault Stateに設定した場合．
![中腰.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459660/b5c9e63f-dc70-d2c4-2f8a-5c8954a50a4e.png)

↓ Animation TypeをHumanoidに変更後．ちゃんと動くようになりました（ほかのHumanoidアバターにも適用できる）．
![中腰解決.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459660/148b1858-409f-8bb4-c157-997768874a4e.png)

Animation TypeをHumanoidに変更すると，fbxの中に，人型のAvaterファイルができます（=この状態になればok）
![InkedAfterHumanoid_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459660/e0b1cec6-80ce-21cc-4884-5dcb71253d69.jpeg)

---
Blenderでキャラクターのアニメーションを作る方法は↓のサイトがわかりやすかったです．
[VRoidStudio（VRMファイル）キャラでアニメーションを作ろう！](https://yuyu-log.com/vrm-animation/)

UnityのKeyframing（録画みたいにアニメーション作れるやつ）はHumanoidアバターアニメーション作成には対応していないっぽい（="Keyframing rotation on humanoid rig is not supported!"などと怒られる）ので，オリジナルでアニメーションを作りたい場合は一度Blenderに持ち込む必要がある．
vscodeのsftp機能をより理解する


# vscodeでFTP経由でファイルをアップする方法ってどうやってる？

たとえばこんな。
- 現在開いているファイルを全部サーバーにアップロードしたい
- 前回のgit push以降のファイルを全部サーバーにアップロードしたい
- サーバーに上がっているファイルとローカルのファイルの差分をチェックしたい

CIツールを使えば解決するんちゃうん？っていうこともありますが、自動でdeployっていうのもよくわからない。
って人向けのおすすめ機能を紹介します。

#プラグインの追加方法
https://marketplace.visualstudio.com/items?itemName=liximomo.sftp

## 接続先サーバーの設定方法
1. ⌘ + pを押します
2. 「>sftp config」と入力します
3. .sftp/config.jsonが生成されます
4. 接続するサーバーの設定を記述します

```
{
    "name": "myproject", //任意の名前でOK
    "host": "localhost", //接続するサーバーのhost
    "protocol": "sftp", //ftp or sftp
    "port": 22, //サーバーのport
    "username": "username", //sftp接続時のusername
    "password": "password", //sftp接続時のpassword(config作成時には表示されていないので注意)
    "remotePath": "/", //サーバーのrootパス
    "uploadOnSave": false //ファイルを保存時に自動でサーバーにアップロードするか
}
```


# ファイル操作機能の使い方
1. ⌘ + pを押します
2. 「>sftp」と入力します
3. 使いたい機能を見つけます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293564/92ef9fa9-7c40-fa0d-0671-6929a5c516e4.png)

## アップロード関連

#### Upload Active File
現在開いているファイルを、サーバーにアップロードします。

#### Upload Active Folder
現在開いているフォルダの中身をサーバーにアップロードします。
test/index.htmlをvscodeで開いている場合は、testのフォルダにある中身をすべてアップロードします。

#### Upload Changed Files
修正を加えたファイルをサーバーにアップロードします。
たとえば、前回git push以降の修正をすべてアップロードする場合は一括でファイルをアップロードできます。
一番便利。
※git管理されてることが前提

## ダウンロード関連
#### Download Active File
現在開いているファイルを、サーバーからにダウンロードします。

#### Download Active Folder
現在開いているフォルダの中身をサーバーからダウンロードします。
test/index.htmlをvscodeで開いている場合は、testのフォルダにある中身をすべてダウンロードします。


## ファイルチェック関連
#### Diff Active File with Remote
現在開いているファイルとサーバーにあるファイルでDiff、差分をチェックします。
本当にこのファイル上がってんの？ってときに使ったりします。

#### Open SSH in Terminal
例えば、SFTPは使えないけど、SSH経由だと接続できる。っていう場合に。

## その他
#### Sync Both Directions
サーバーとローカルのフォルダ・ファイルを同期します。
使ったことない。

#### Sync Local -> Remote
ローカルのファイルをサーバーに同期します。
サーバーにしかないファイルを削除するわけではないので、「Upload Active Folder」と違いはない。

#### Sync Remote -> Local
サーバーにあるファイルをローカルに同期します。
ローカルにしかないファイルを削除するわけではないので、「Download Active Folder」と違いはない。
Qt Creator buttonでQStackedWidgetのページ切り替え

Qt CreatorでPushButtonからQStackedWidgetのページを切り替えるプログラムを作成する方法です。要点だけ忘れない様にメモ。

# 内容

要点は以下の２点です。
・uiでボタンを配置し,そのボタン右クリック > Go to slotを選択しイベントハンドラーを関数を作成
・イベントハンドラー関数内に,ページ1にする時は`ui->stackedWidget->setCurrentIndex(0);`ページ2にする時は`ui->stackedWidget->setCurrentIndex(1);`のように追加

# 参考
- PushButtonのイベントハンドラー作成方法

https://www.youtube.com/watch?v=-wkiHPZeFvA

- ボタンからQStackedWidgetのページ切り替え方法

https://stackoverflow.com/questions/62401829/stack-widget-pages-using-pushbutton-in-qt
初めてのファイルサーバ構築

##はじめてファイルサーバ構築へ挑戦・・・

###■環境
・OS：CentOS7
・端末：仮想（Virtualbox）:メモリ1024MB、アダプター１（NAT）、
アダプター２（ホストオンリー）で接続。システムのマザーボードにて起動順　　
序でネットワークの優先度を２番目に設定済。
・ユーザー権限：root.

###Sambaのインストール

自動起動の設定
※ネットワーク設定がホストオンリーだけの場合ネット上からインストールできないため、エラーがでるため注意。

```bash
$ yum－y install samba

$ chkconfig smb on
```

###Sambaユーザ追加（centOS側）

アクセス用ユーザを追加

※パスワードはcentOS側と別管理

```bash
$ usradd samba
$ passwd samba
$ mkdir /home/samba/smb
$ chown　samba:samba /home/samba/smb

$ pdbedit –a samba
```

共有ディレクトリを作成＆権限設定

※まずはコンソール上で、共有すべきディレクトリを作成。ダミーファイルも作っておく。

```bash
$ mkdir  /usr/local/work
$ testdayo > /usr/local/work/hoge
$ chmod –R 777 /usr/local/work
```

作成したファイルを共有する

```bash
$ vi  /etc/samba/smb.conf
```


※余計なオプション項目を残すとややこしくなるので、思い切って削除する。

---
・workgroup
ワークグループ名/ドメイン名を設定する。既存のネットワークに接続する場合は、どれと同じものを設定する。

・security
認証方法を設定

・path
共有の対象ディレクトリを指定

・read only
書き込み禁止にするかどうかのパラメータ。更新がある共有ではNoを設定する。

・browseable
「ネットワークコンピュータ」に表示するかどうかの設定。表示させたい場合は「Yes」とする。

---

※Vi
i で入力モード
Esc入力モードからコマンドモードにする
コマンドモードで:wq 保存して終了
コマンドモードで:q! 保存しないで終了

---
ファイルを保存したら、構文チェックを実施する。

```bash
$ testparm
```

###共有開始

設定を反映させるためSambaを再起動させる。

Sambaの起動

```bash
$ service smb restart
$ service nmb restart

$ systemctl start smb
$ systemctl start nmb
```
Sambaの動作確認
Sambaの自動起動を有効

```bash
$ systemctl is‐active smb.service
$ systemctl is‐active nmb.service

$ systemctl enable smb.service
$ systemctl enable nmb.service
```

###ファイヤーウォールの設定
ファイヤーウォールの起動
ファイヤーウォールの稼働状況確認

動作中　running
停止中　not running

```bash
$ systemctl start firewalled

$ firewall‐cmd ‐‐state
```
httpサービスをpublicゾーンに追加
Sambaサービスを追加

Samba_share_t ラベルなしでもホームディレクトリへのアクセス可能にする。

```bash
$ firewall‐cmd ‐zone=public ‐‐add‐service
$ firewall‐cmd ‐‐add‐service=samba

$ sudo setsebool ‐P samba_enable_home_dirs on
```

###Sambaの再起動
ファイヤーウォールの再起動

```bash
$ sudo systemctl restart smb nmb
$ firewall‐cmd　‐‐reload
```

###Iptable設定

※	137と138はUDP

右のように記入して保存する。
※E212:書込み用にファイルを開けませんと表示された場合、viの前にsudoをつけて記入する。

```shell
$ vi /etc/sysconfig/iptables

iptables ‐A INPUT ‐m state NEW‐m ucp -‐p tcp -‐dport 137 -‐j ACCEPT
iptables ‐A INPUT ‐m state NEW‐m ucp -‐p tcp -‐dport 138 ‐-j ACCEPT
iptables ‐A INPUT ‐m state NEW‐m tcp -‐p tcp -‐dport 139-‐j ACCEPT
iptables ‐A INPUT ‐m state NEW‐m tcp -‐p tcp -‐dport 445 ‐-j ACCEPT
```
###Sambaのクライアント機能を有効

①	コントロールパネル
②	プログラム
③	プログラムと機能
④	Windowsの機能の有効化または無効化
⑤	SMBにチェックを入れる

Windowsのエクスプローラーからホームディレクトリにアクセスする

アドレス欄に「\\仮想マシンのIPアドレス\」
認証ウィンドウが出てくるので、ユーザー名「samba」とパスワード(pdbeditコマンドで設定)を入力する。
ULIDを試してみる

# はじめに

突然ですが、Heroku connectを使って、SalesforceとHeroku Postgresと同期する際の話です。
特に、Heroku ---> Salesforce という方向の連携が発生する時の話です。

この場合、Heroku Connectの設定画面でユニークキーを指定することが推奨されています。
すなわち、連携するオブジェクト側で外部キーとして定義されているフィールドを指定する、という具合ですね。
[Herokuリファレンス / Mapping Configuration Options](https://devcenter.heroku.com/articles/mapping-configuration-options#unique-identifier)

![heroku_connect_unique_identifier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/76428332-834f-e26b-5099-f29f6242dc5a.png)

このとき、Salesforce側からもレコードを作成することがあるならば、トリガやフローなどでユニークなキーを発行する必要が出てきます。
SalesforceのオブジェクトIDを流用しても良いですが、ユニークなキーといえば[UUID](https://ja.wikipedia.org/wiki/UUID)を思い浮かべる人も多いと思います。

今回、UUID以外のユニークキーとして、ULIDというものもあるので、それを適用してみたいと思います。


## ULIDとは

ULIDは`Universally Unique Lexicographically Sortable Identifier`を略したもので、このリポジトリに仕様が記載されております。
[ulid/spec](https://github.com/ulid/spec)

また、リポジトリのREADMEを見ると、様々な言語で実装されているようです。
(実装されている言語の例)

* C#
* Go
* Haskell
* Java
* JavaScript
* Kotlin
* .NET
* PHP
* Python
* Ruby
* Scala
* (etc)

ULIDは、__タイムスタンプ部__と__ランダム部__の2つから構成されています。

* タイムスタンプ部
    * 48ビット整数
    * UNIX時間(ミリ秒)から生成
    * 西暦10889年まで使用可能 --> 我々が生きてる間は大丈夫そう
* ランダム部
    * 80ビット
    * 可能であれば、暗号論的乱数を使う

タイムスタンプと組み合わせることでソート可能となる、という具合です。また、1ミリ秒内に 2^80 以上作成しない限りは一意性を担保してくれることでしょう。Salesforceで試す限りは、そんなハードな状況はなかなかなさそうです。
ソート可能であるという点は、UUIDと違って使い勝手が良いかもしれません。


# Apexでも試してみる

## タイムスタンプ部の生成

要はUNIX時間(ミリ秒)を32進数に変換する、という感じです。
単純に、UNIX時間(ミリ秒)を起点にして以下の処理を10回繰り返します。

1. 受け取った数値を32で割って、余りの部分を以下の配列のインデックスとして指定して文字を決定する。文字はタイムスタンプ部の前方に追加する。
2. 商の部分を「1.」の処理に回す

```
0123456789ABCDEFGHJKMNPQRSTVWXYZ
```

※仕様上、紛らわしい文字 `I`,`L`,`O`,`U` を除くようになってます。

ちなみに、しばらくの間タイムスタンプ部は`0`から始まります。`1`から始まるようになるまで、1000年以上かかるので、気長に待つにも程があります。


## ランダム部の生成

※もう少し良いやり方がないかな、と検討中です...

こちらの記事を参考にしてみましたが、同じミリ秒内で生成した場合、後に生成したキーが正しい順番になるかどうかは運任せになりますね。何か良い方法がないものかな...とボンヤリと模索中です。
[How do I generate a random string](https://salesforce.stackexchange.com/a/43826)

要は、この文字を使って16文字のランダムな文字列を生成することを頑張りましょう。
Apexで実装する際には [Crypto.getRandomLong()](https://developer.salesforce.com/docs/atlas.ja-jp.232.0.apexcode.meta/apexcode/apex_classes_restful_crypto.htm#apex_System_Crypto_getRandomLong) を利用してみました。

```
0123456789ABCDEFGHJKMNPQRSTVWXYZ
```


# おわりに

実装してみた爪痕はここに残してみました。
[ulid.apex](https://github.com/takahiro-yonei/ulid.apex)

UUIDにしてもULIDにしても、Salesforceの標準機能として組み込んでくれたら良いのになぁと思いますが、こうして仕様を追いかけながら、自作してみるのも楽しいかもしれません。

そういえば本記事はSalesforce Advent Calendar 2021の6日目です。
いまさら聞けない、ググり方のコツ

この記事は [ハンズラボ AdventCalendar2021](https://qiita.com/advent-calendar/2021/handslab) 8日目の記事です。

## はじめに

ITエンジニアとして働いている以上、突然出てきた訳のわからないエラーに頭を抱えることからは逃げられません。幸いにして、我々の業界にはアウトプットの文化があるため先人の知恵はインターネット上に存在することが多いです。しかし、昨今のノイズ増加に伴いうまく情報を見つけられなかったり、最悪の場合は誤った情報を掴んでしまうこともあります。

そこで、それなりの期間をITエンジニアとして働いてきて、何となく身についた **ググり方のコツ** を記述してみようと思います。



## 新鮮な情報を入手する

ITの世界は進化が早く、3年前の常識が今の非常識になることも多々あります。また、3年前に執筆された記事時点と現在では、各ソフトウェアのバージョンも大きく変わっているため、そのままの手順で動くことは稀です。

そんな時には、Googleの `期間指定機能` を使います。

![スクリーンショット 2021-12-06 11.35.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501670/d788cf7e-acc7-778b-86fb-c6399eaa0974.png)

Google検索結果のツールから期間指定を行うことで、記事の最終更新日時を指定できます。これで新しめの情報だけをチェックできます。体感ですが、概ね1年以内に更新された記事であれば有用に使えることが多いです。


## エラーメッセージはよく見てコピペする

「何かよくわからんエラーが出た！！」とエラーメッセージを **全文コピペ** して検索しても、思うような結果が出ないことがあります。それは、検索文字列にノイズが含まれているからです。

例えば、Pythonで例外が発生しこんな感じのスタックトレースが出たとします。

```
Traceback (most recent call last):,
  File /var/task/src/handlers/load_data_handler.py, line 53, in main,
    logic.load(message),
  File /var/task/src/common/logic/load_data.py, line 168, in load,
    logger.info(json.dumps(output_result)),
  File /var/lang/lib/python3.7/json/__init__.py, line 231, in dumps,
    return _default_encoder.encode(obj),
  File /var/lang/lib/python3.7/json/encoder.py, line 199, in encode,
    chunks = self.iterencode(o, _one_shot=True),
  File /var/lang/lib/python3.7/json/encoder.py, line 257, in iterencode,
    return _iterencode(o, 0),
  File /var/lang/lib/python3.7/json/encoder.py, line 179, in default,
    raise TypeError(fObject of type {o.__class__.__name__} ,
TypeError: Object of type Decimal is not JSON serializable

``` 

ここでウワーッとなって全文コピペ検索を行っても何の成果も得られません。まずは冷静にエラーメッセージを読み解いてください。このメッセージ、最終行以外は例外が発生したコードの場所をトレースしているのみです。つまり **この環境固有の情報が表示されているだけ** なのです。**あなたの環境でしか発生しない情報なので、それでググっても何もわかりません。** 

このエラーメッセージで見るべきは例外の内容である最終行の `TypeError: Object of type Decimal is not JSON serializable` のみです。


## 完全一致検索をうまく使う

エラーメッセージの内容があまり一般的なものでない場合、稀に検索してもそれぞれの単語で検索されてしまいエラー解決方法に辿り着けない場合があります。これはGoogleがスペースを区切り文字としてOR検索を行っているためと思われます。スペースを含むメッセージを明示的に検索したい場合は、完全一致検索を行うと良いでしょう。

検索したい文字列の前後を `""` で囲むと、間のスペースも含めて完全一致対象を検索できます。

例： `"TypeError: Object of type Decimal is not JSON serializable"`


## 英語から逃げるな

ソフトウェア開発の本場はやはり英語圏のため、突っ込んだ情報は英語で記述されていることが多いです。拒否反応を起こさず、翻訳ツールなどを駆使して情報を入手しましょう。[StackOverflow](https://stackoverflow.com/)は有用な情報を得られることが多いです。

また、明示的に英語の情報を検索したい場合は、 検索したい対象の後ろに `not work`(動かない)を付けると日本語とはまた異なった悲鳴を確認することができます笑。



## 公式から逃げるな

人間楽をしたいものですので、公式の細かい内容をうまく要約してくれた記事だけを読んで素早く把握したい気持ちはわかりますが、最終的に頼りになるのはやはり公式です。公式ドキュメントや、GitHubリポジトリを参照して情報を探しましょう。また、ドキュメントの内容やGitHub issueの内容は検索エンジンに乗ってこないことが多いので、サイト内部の検索機能を活用しましょう。

どうしても解決できなければ、新たなissueとして質問しても良いでしょう。その場合はissue作成ローカルルールの確認をお忘れなく。


## 検索エンジンを変える

私は基本的に[Google](https://www.google.com/?hl=ja)を利用していますが、他の検索エンジンの方が良い結果が出るとの情報も聞き及んでいます。[Bing](https://www.bing.com/)や[DuckDuckGo](https://duckduckgo.com/)を試してみてもいいかもしれません。



## 終わりに
これらのググり方のコツを意識することで、今までより有用な情報を入手しやすくなるかと思います。
ですが、いずれの情報も過信は禁物です。本番プロダクトに乗せる技術については、**必ず自らの環境で動作確認を行ってください。**

以上
Gitで任意のコミットメッセージを含むコミットのファイル一覧をマージして表示する。

# 結論

以下のコマンドを実行。

```bash
git log --grep=コミットメッセージ --name-only | sort | uniq
```

# 考えのもと

コミットメッセージからログを絞り込む

```bash
git log --grep=検索文字列
```

特定のコミットのファイル一覧を取得(今回不使用だった)

```bash
git show commit_id --name-only
```


重複行の削除

```bash
sort filelist.txt | uniq
```
Linux入門 2-3 関数、ローカル変数、グローバル変数

[](参照ソース)
[Linux Professional Institute公式HP]:https://www.lpi.org/ja/our-certifications/lpic-1-overview
[Udemy]:https://udemy.benesse.co.jp/career/workstyle/lpic-interview-company.html
[Udemyの動画講座]:https://www.udemy.com/course/linuxlpic/?utm_source=bene-content-marketing&utm_campaign=normal&utm_content=story&utm_term=career&utm_medium=udemyads
[Linux入門 2-2]:https://qiita.com/hoglet/items/4210fe95f8dfb7067b74
[Linux入門 2-4]:https://qiita.com/hoglet/items/152c3c9c711911e6d9c8

# はじめに
Linux初学者である自分向け用の記事です。[Udemyの動画講座]を参考にしました。
僕の勉強法は`動画を見る`→`実際に動かしてみる`→`問題演習`という流れです。

前回まで：[Linux入門 2-2]

***
#### 2. シェルスクリプト(問題、テスト、演習、発展問題)
##### 2-8. 関数

```
ファイルの中身
[test@ advance]$ cat ad1.sh 
#!/bin/bash
function hello(){
  echo 'hello world'
  echo $1
}
hello 'Who am I?'
```
```
実行結果
[test@ advance]$ ./ad1.sh 
hello world
Who am I?
```
##### 2-9. ローカル変数、グローバル変数
###### ローカル変数

```
ファイルの名前
[test@ advance]$ cat ad1.sh 
#!/bin/bash
function set_name(){
 local name=$1
 echo local: $name
}
echo $1
name='Taro'
echo before: $name
set_name 'Mike'
echo after: $name
```
```
実行結果
[test@ advance]$ ./ad1.sh hanako
hanako
before: Taro
local: Mike
after: Taro
```

###### グローバル変数

```
ファイルの中身
[test@ advance]$ cat ad1.sh 
#!/bin/bash
function set_name(){
  name=$1
}
echo $1
name='Taro'
echo before: $name
set_name 'Mike'
echo after: $name
```
```
実行結果
[test@ advance]$ ./ad1.sh hanako
hanako
before: Taro
after: Mike
```
*To Be Continued...*
[Linux入門 2-4]
***
点字メーカープログラムの動画レビュー Part 1 - Rubyプログラミング問題にチャレンジ！ －改訂版・チェリー本発売記念－

## この記事は何？
Qiita Advent Calendar 2021「Rubyプログラミング問題にチャレンジ！ －改訂版・チェリー本発売記念－」で投稿してもらったコードを出題者である僕、伊藤淳一が動画でコードレビューしてみました。

https://qiita.com/advent-calendar/2021/ruby-challenge

### アドベントカレンダー参加者のみなさんへ

ネタバレになってしまうので、自分の投稿が完了するまでこちらの記事（動画）は見ないようにお願いします〜 :pray: 

### レビュー対象の記事はこちら！

今回レビューさせてもらったのは以下の1日目から5日目の記事です。投稿してくれたみなさん、どうもありがとうございました！

@cielavenir さん

https://qiita.com/cielavenir/items/441631f6796af95fe0ea

@nodai2h_ITC さん

https://qiita.com/nodai2h_ITC/items/8217d525b308f9bd5a12

@morimorihoge さん

https://techracho.bpsinc.jp/morimorihoge/2021_12_03/114105

@Shun_Tagami さん

https://qiita.com/Shun_Tagami/items/34248e1c4bc4a8eb1905

@suzuki-mar さん

https://qiita.com/suzuki-mar/items/e1f25fca4d9f9b378027

## 動画でコードレビューしています

今回のコードレビューは動画で実施してみました。だいたい1投稿あたり5分ぐらいでさーっとコメントしています。
（あまりしっかりレビューできなくてすいません🙇🏻‍♂️）

動画はこちらです 👇

https://youtu.be/yh7eIL4jKA0

「それは好みの問題や！」みたいなコメントもあるかもしれませんが、何か参考になれば幸いです。

## まとめ

こんな調子でまたこの後の投稿についでもレビューしていきたいと思います。みなさん、どうぞよろしくお願いします〜！

### PR：改訂版・チェリー本が発売されました！🍒

「プロを目指す人のためのRuby入門 改訂2版（通称チェリー本）」が2021年12月2日に発売されました。この点字メーカープログラムを作る際にも役立つ知識が満載です。第1版を持っている方も持っていない方も、一度書店で手に取ってもらえると嬉しいです〜🍒

https://gihyo.jp/book/2021/978-4-297-12437-3

改訂版の見どころについては以下のブログにまとめていますので、こちらもあわせてどうぞ 💁‍♂️

https://blog.jnito.com/entry/2021/12/02/072804