OmniAICreator/Qiita-1.07M huggingface dataset:
【NestJS】Docker ComposeでDBとAdminerを起動してアプリケーションと接続する

#はじめに
Docker ComposeでDB(MySQLとPostgreSQL)とAdminer(DB管理ツール)を起動して、NestJSアプリケーションと接続してみました。
本記事はその手順のメモです。

#実装
実装は大きく分けてコンテナの起動とNestJSアプリケーションの接続の2つです。

##コンテナの起動
MySQL, PostgreSQL, AdminerのDockerイメージは公式のものを使用します。

https://hub.docker.com/_/adminer

これらをDocker Composeで一発で起動できるように、`docker-compose.yml`を以下のように記述します。

```yml:docker-compose.yml
version: "3.8"

services:
  mysql:
    image: mysql:8.0.23
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    ports:
      - 3306:3306

  postgres:
    image: postgres:13.1
    restart: always
    environment:
      POSTGRES_PASSWORD: example
    ports:
      - 5432:5432

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
```

`docker-compose up`を実行し、`localhost::8080`にアクセスするとAdminerが開きます。
![スクリーンショット 2021-11-23 10.53.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/1a9957c2-f90f-25e3-4fe3-3c8b49c4ecb7.png)

以下の情報を入力するとMySQLとPostgreSQLにログインすることができます。

```
データベース種類：MySQL (PostgreSQL)
サーバ：mysql (postgres)
ユーザ名：root (postgres)
パスワード：example
```

MySQLとPostgresQLでデータベース`nest-events`を作成します。
![スクリーンショット 2021-11-22 21.09.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/28c7479d-41e6-14a8-c547-8df173ff1f6b.png)

##NestJSアプリケーションの接続
MySQLとの接続についてのみ記述します。

アプリケーションからDBを操作するにあたり、ORMとしてTypeORMを使用します。
そのため、まずは以下のパッケージをインストールします。

```
npm install @nestjs/typeorm typeorm mysql
```
次に、`app.module.ts`内でTypeOrmの設定を行います。
`database`に前項で作成した`nest-events`、`entities`に`Event`を記述することで、DBとEntityの紐付け(マッピング)を行います。

```ts:app.module.ts
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: '127.0.0.1',
      port: 3306,
      username: 'root',
      password: 'example',
      database: 'nest-events',
      entities: [Event],
      synchronize: true
    }),
  ],
  controllers: [AppController, EventsController],
  providers: [AppService],
})
```
Entityである`Event`は以下のように記述します。
各カラムにデコレータを付加することで、属性を指定しています。
`@PrimaryGeneratedColumn()`を付加すると、MySQLでいう`AUTO_INCREMENT`なカラムとなります。

```ts:event.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Event {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  description: string;

  @Column()
  when: Date;

  @Column()
  address: string;
}
```

`app.module.ts`で`synchronize: true`を指定していたため、`npm run start:dev`でアプリケーションを起動すると、以下のように自動的にテーブルが作られます。

![スクリーンショット 2021-11-22 21.34.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/df28a23e-e16b-cb7c-a15d-360874418547.png)

#参考資料

https://www.udemy.com/share/104jqs3@C044Ya6zVNsYZRIqUPsHWdt1NGhznGxZ-i6hlVs3dnpU_LpGRXZTEfN_rKvB31Uu/
ruby on rails tutorial３章を始めたら出てきたThere was insufficient space〜 というエラーの解決方法

やっと3章に突入して意気揚々と進めていくと、

```ruby:qiita.rb

There was an error while trying to write to
`/tmp/xxxxxxxxxxxxxxxxxxxx/versions`. There was
insufficient space remaining on the device.

```

がこんにちは。


どうやら何かの容量がないということらしい。

そうこうしているうちに、awsのターミナルにコードを入力できなくなる。
![スクリーンショット 2021-11-23 10.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2144713/a365d842-4b6f-973f-26eb-5265ba55315b.png)
![スクリーンショット 2021-11-23 10.30.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2144713/7f0518ec-6c1f-0c2e-4cb0-097a6fa6be27.png)

ちょwどうするんこれ

#ま、やる事は2択！消すか、増やすかでしょ。

と言うことで調べてみるとこれらの記事が参考になりそうだったので読み進めました。が、解決できませんでした。


https://qiita.com/zuck3r/items/d783bfacb5868b31c44e

https://qiita.com/yonabe710/items/2001a7d48384231d5e01

https://qiita.com/shizuma/items/64545f2e2037011647ae

https://stackoverflow.com/questions/6151695/ec2-instance-on-amazon-and-i-am-greeted-with-no-space-left-on-the-disk


#解決方法はいつもシンプル

壁にぶち当たるとモチベーションにデバフかかって睡魔召喚し始めますよね私だけですかw

https://railstutorial.jp/help#volume-up-aws-ebs


 AWS Cloud9 の__容量不足__を解決する

__第3章に入ったら `hello_app`, `toy_app` は削除しよう__

書いてあるやん！

~~hello_app、toy_appを delete してターミナルを再起動して解決しました。~~

…解決したと思っていました。[続く…](https://qiita.com/kotetsu09/items/41ac819633b13a27524a)
疑似セレクタ・疑似要素の活用

擬似クラスを利用すると、マウスホバー状態時など、HTMLのみでは表現できない状態のスタイルを設定できます。
擬似要素はHTML上に直接指定できない要素にスタイルをあてたり、存在しない追加のコンテンツを挿入したりできます。

サンプルのNEWSは、マウスオーバーやドラッグで選択した時のスタイル設定、
2つめ以降の要素にのみマージンを設定したり、CSSだけでNEWの表記を追加しています。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="GRvarpK" data-user="satonaka" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/satonaka/pen/GRvarpK">
  Untitled</a> by Ryuta Satonaka (<a href="https://codepen.io/satonaka">@satonaka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
DBDシリアルコード取得BOT

## 内容

discord botを使用してDBD(Dead By Daylight)のシリアルコードを[神ゲー攻略](https://kamigame.jp/dbd/index.html)から取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604560/31041169-b557-3b37-3096-657e8bf19712.png)

## 使い方


[成果物のbot追加リンク](https://discord.com/oauth2/authorize?client_id=903811636064825415&permissions=0&scope=bot%20applications.commands)

サーバにBOTを招待して放置するだけ
※　現在停止中

## 機能

サーバに招待されるとシリアルコードを送信
3hおきにサイト確認
シリアルコードを取得し、送信

## 開発環境

windows: 10

EXE
Visual Studio Code: 1.62.3　エディタ
Node.js: 16.13.0

パッケージ
discord.js: 13.3.1　discordBotのベース
log4js: 6.3.0　ログ出力
node-cron: 3.0.0　定期実行
puppeteer: 11.0.0　データ取得
sqlite3: 5.0.2　データを保存

## ファイルツリー

appディレクトリ下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604560/76c720f8-4412-ca0f-567f-d8d3cae1f8c0.png)

appディレクトリ直下にnode_modulesもあるがツリーが見づらいため写してない

## パッケージインストール

appディレクトリで下記コマンド実行
> npm install puppeteer sqlite3 log4js node-cron discord.js

## ソース
https://github.com/wowwwwwwwwwww/dbd-serial-code-acquisition-bot

## 参考サイト

js スクレイピング
https://qiita.com/ledsun/items/0965a60f9bdff04f2fa0

pupptter高速化
https://qiita.com/markey/items/ebf2b48626b6ac61ee89

puppetter 引数
https://qiita.com/horikeso/items/f87d3e703828aa13e2ff

id無しエレメント取得
https://gray-code.com/javascript/get-child-element-and-paranet-element-and-previous-element-and-next-element-of-specific-html-element/

非同期処理
https://qiita.com/kerupani129/items/cf4048a7d4e3aad75881

sqlite
https://qiita.com/zaburo/items/a155cbc02832b501a8dd

ログファイル出力
https://webbibouroku.com/Blog/Article/log4js

node 定期実行
https://qiita.com/n0bisuke/items/66abf6ca1c12f495aa04
DockerコンテナをマルチCPUアーキテクチャ対応でビルドする方法

# 準備

dockerのbuildxを使ってビルドします。まずはビルダを作成して起動します。

```bash
docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx inspect --bootstrap
```

# ビルド・push

ビルドしてpushします。`--platform`にはビルドしたいプラットフォームを指定します。ここではarm64とamd64を指定しています。

```bash
docker buildx build \
  --platform linux/arm64,linux/amd64 \
  -t {ご所望のDockerHubレジストリ(user_name/registry_name)} \
  --push .
```
2020年やったこと振り返り | 受託開発企業に転職


# はじめに

未経験で入社し約9ヶ月が経ちました。感染拡大前にギリギリのタイミングで転職できたことがまず非常に幸運だったと思っています。（受託開発の会社）


完全に新しい環境で、新しいことをたくさん経験しました。触れることが出来た業務・技術やその所感をまとめます。


# 試験仕様書の作成

入社後すぐから1ヶ月半 ~ 2ヶ月ほど行いました。要件の理解や、どういった観点でソフトウェアの開発が行われるのかを概覧することができました。

うまく書けないことも多く実力不足を思い知りました。ミスの原因は大きく以下の３つです。

- 設計書／仕様書を読み込めていない
- ドキュメント作成の規約、ルールを確認していない
- そもそもの前提知識が足りていない

中でも「前提知識の不足」はその場で対処不可能であり深刻なので、職場で耳にした知らない用語や概念はすぐにメモしておいて通勤時間に調べるなどしていました。

# AWS認定 クラウドプラクティショナー取得

前提知識の不足を解消するためにAWS認定を取得しました。ネットワークや基本的なIT常識を身につけるとともに、職場で使用されているAWS関連知識もカバーするためです。

入社後しばらくは他のエンジニアの方が何を言っているのか分からない状況が続いていたので、なんとかしたいという思いが強かったです。


# React Native

React Nativeは「オワコン」と言われたり、一方では「はじまった」と言われたり、評価が別れているように思います。基本的にはReact Nativeに限らず技術選定は適材適所だと思っていて、Reactの知識でモバイルアプリ開発ができて、要件を満たすならそれに越したことはないと考えています。

多くのnpmパッケージの恩恵を受けることもできて、さらにReact Nativeで培った知見をWebアプリの開発にも生かすことができます。また、ネイティブモジュールをSwiftで書いたりなど、少しずつですがネイティブアプリ側の知識も付きました。

戦えるフィールドが増えることは経験の少ないエンジニアにとっての武器になると思っています。知識の深さではベテランエンジニアには敵いませんので、横に展開しながら優秀な人のやり方にたくさん触れられたらいいなと思っています。


# Vue.js

Vue.js（バージョン３以前）は感覚としてはあまりハマりませんでした。なんかHTMLを書いてそこに付け足していく感じ？に慣れないというか。おそらく勉強が足りないのだと思います…


# AtCoder

入社してすぐは週末にAtCoderもやっていました。C問題まではギリ解けますがそれ以降は無理でした。

ちなみに言語はNode.js。

数学やアルゴリズムの理解が必要な分野はすごく苦手意識があることがわかりました。それ以外の分野で自分が活躍できる場所、案件や業務を取っていく必要があると感じました。


# Redux / Redux Saga

慣れてしまえばどうということはないのですが、大量のボイラープレートと学習コストが必要になるため、チーム全体として品質を保つのが非常に難しかったです。

外部APIとの通信（いわゆるサーバーステート）が絡む部分は、後述する「SWR」あるいは「React Query」を今後積極的に使用してReduxコードを減らしたいです。

しかしながら、Reduxはその概念というか設計思想の部分に価値があると思っていて、実装詳細をうまく隠蔽しておいて、値の変更をコントロールする知見は他でも役に立っています。「スタイルガイド」のページとか、思想が出てるので読むの楽しいです。

https://redux.js.org/style-guide/style-guide



# SWR

控えめに言って最高で、TypeScriptとの相性も良いのですごく気に入りました。

「APIからフェッチするデータのSingle Sourse of Truthはサーバーにあるでしょ」ということで、そもそもステートとして管理しない方が諸々の都合が良いというのは、言われてみれば確かにそうなんだけど今まで主流でなかったのが不思議です。


# Recoil

まだExperimentalなパッケージですが使用感が非常に良いです。

Reduxでいう「アクション」の概念がないので、値の変更をコントロールするためにうまくカスタムフックにして必要がありそうです。

なんと言っても学習コストが小さいので、小さいプロジェクトであれば積極的に使って行きたいと思わせてくれます。


# Svelte

出始めの頃に少し触ったきりでしたが、どんどん進化が進んでいるらしいので来年ぜひ取り組みたいです。TypeScriptとの相性も良いらしい。

Reactできるならそれで良いじゃんって思うこともあるのですが、やっぱり色々触っておきたいのと、後から出たものは基本的に現状の課題を解決するものであるはずなので、Reactの課題を知る意味でも使っておきたいと考えています。


# Rust

現状JavaScriptしか知らないのでもう１言語くらいやりたい。できれば低レベル言語を学びたいと思い独習していますが難しくて10回くらい挫折しています。ちなみに「Rocket.rs」でAPIサーバ作ったりしていました。

言語としての人気が高いので、ぜひそこに付いていけるようになりたいと思っています。


# TailwindCSS

最高。ただし慣れれば。


# AWS関連

以下を使用。

    AWS AppSync
    AWS Amplify
    AWS DynamoDB
    AWS Cogunito
    AWS Pinpoint
    AWS Lambda

# アニメーション/3D表現など

以下を使用。計算苦手です。

    TweenMax
    Three.js
    シェーダー
    React Konva

# その他 のこと

以下を使用。

    Gatsby.js
    Jest
    Testing Library
    Express
    StyledComponent
    TailwindCSS
    Rocket.rs
    Docker
    Firebase
    GraphQL
    Flutter
    Swift
    WASM
    MikroORM
    インターンシップのメンター
React-NativeでContextにユーザオブジェクトを保持する

# 記事の目的
- ログイン中のユーザ情報をContext上に保持し再利用できるようにする
- 必要な最小限の作業を5Stepで整理する

# 前提と課題
- ReactNativeでContextを利用する
- アプリはクラスでコンポーネント(画面)を作っている -> フックを直接呼べない
- firebase周りはv9系で大きく書き方が異なるため、読替が必要

# 環境
- Firebaseはv８系
- Expo 4.13.0

# 手順
- 手順の概要
 1. AuthProviderを作成
 1. AuthProviderを設置
 1. AuthContextを読み込み、useAuthContextフックを用意する 
 1. フックから必要なstateを呼び出す。それをコンポーネントの引数に渡す 
 1. propに渡されたuserを利用する 

- コード例
 - プロジェクトのトップ階層にAuthContextを設置 1/5

```js:AuthContext.js
import React, { createContext, useState, useContext,useEffect } from 'react';
import * as firebase from 'firebase';
import 'firebase/firestore';
const AuthContext = createContext();

export function useAuthContext() {
  return useContext(AuthContext);
}

export function AuthProvider({ children }) {
  const [user, setUser] = useState('');

  const value = {
    user,
  };

  useEffect(() => {
    const unsubscribed = firebase.auth().onAuthStateChanged((user) => {
      setUser(user);
    });
    return () => {
      unsubscribed();
    };
  }, []);

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

```

- Appでコンテクストを効かせる範囲のコンポーネントをAuthProviderに組み込む 2/5

```js:App.js
import { AuthProvider } from './AuthContext'; // <-AuthProviderを読み込む

export default function App() {
  const Stack = createStackNavigator();

  return (
    <AuthProvider>　 <- ここと
      <NavigationContainer>
        <Stack.Navigator>
       　　　　 <Stack.Screen name="Hone" component={Home} />
　　　　　　　　　　　　　　　　　　　　その他任意のページ
        </Stack.Navigator>
      </NavigationContainer>
    </AuthProvider> <-　ここでかこう
  );
}

```

- Contextの情報（保持しているuser）を使用する

```js:home.js
// コンテキストからのユーザ取得 3/5
// AuthContextを読み込み、useAuthContextフックを用意する
import { useAuthContext } from '../AuthContext';
export default function(props) {
  // コンテキストからのユーザ取得 4/5
  // フックから必要なstateを呼び出す。それをコンポーネントの引数に渡す（user={user}）
  const { user } = useAuthContext();
  return <Home {...props} navigation={navigation} user={user} />;
}

class Home extends React.Component {
componentDidMount (){
    // コンテキストからのユーザ取得 5/5
    // propに渡されたuserを利用する
    console.log(this.props.user)
  }
}

```

- propにuserを移し替える作業は、クラスから直接フックを呼べないために行っっているクラスを利用していない場合は直接フックを利用すればいい


# 参考
> コンテクスト REACT公式
> https://ja.reactjs.org/docs/context.html

> 【完全版】ReactのFirebase Authentication(認証)を基礎からマスターする
> https://reffect.co.jp/react/react-firebase-auth#Cotext
【CSS】メディアクエリ(Media Queries)基礎

# メディアクエリを利用したRWD（レスポンシブ・ウェブ・デザイン）の実装

## モバイルファースト

小さなビューポートサイズをベースとして、大きなビューポート用のスタイルを上書きしていくスタイル。

- 上書きするスタイルが少なくなる傾向にある。
- flexboxやgridなど、包括する要素が必要になるDOM（HTMLタグ）などを予め想定する必要がある。

```css
/*  ベーススタイル  */
div {
  width: 100%;
}

/*  横幅が321px以上のときのスタイル  */
@media (min-width: 321px) {
  div {
    width: 100%;
  }
}

/*  横幅が769px以上のときのスタイル  */
@media (min-width: 769px) {
  div {
    width: 640px;  
  }
}

/*  横幅が769px以上かつ、992px以下のときのスタイル  */
@media (min-width: 769px) and (max-width: 992px) {
  div {
    width: 800px;
  }
}

/*  横幅が993px以上のときのスタイル  */
@media (min-width: 993px) {
  div {
    width: 1200px;
  }
}


```



## PCファースト

大きなビューポートサイズをベースに、小さなビューポート用のスタイルを上書きしていくスタイル。

- 上書きする項目が多くなる傾向にある。
- 複雑なPCレイアウトからシンプルなSPへシフトするため、レスポンス想定が比較的容易。

```css
/*  ベーススタイル  */
div {
  width: 1000px;
}

/*  横幅が992px以下のときのスタイル  */
@media (max-width: 992px) {
  div {
    width: 800px;
  }
}

/*  横幅が768px以下かつ、640px以上のときのスタイル  */
@media (max-width: 768px) and (min-width: 640px) {
  div {
    width: 700px;
  }
}

/*  横幅が320px以下のときのスタイル  */
@media (max-width: 320px) {
  div {
    width: 100%;
  }
}

```
HTML、CSS、JavaScriptのファイルをリンクさせる方法

#はじめに
Webサイトの開発をやっているとHTML、CSS、JavaScriptのファイルを主に扱うのですが、その3つのファイルをリンクさせて、HTMLに適用する方法を紹介したいと思います。

#環境
Mac OS Monterey
MacBook Pro M1

VS Code

#本編
主にHTMLのファイルにCSS、JavaScriptを適用させる感じです。

##HTMLとCSS
head上にこのように記載します。

```html
<link rel="stylesheet" href="ファイル名.css">
```


##HTMLとJavaScript
bodyタグの一番最後にこのように付け足します。

```html
<script type="text/javascript" src="ファイル名.js"></script>
```


__これで完了です。__
エンジニアの種類

#前提
私はエンジニアに転職をしようと勉強している者です。
そこで学んでいた時にどんなエンジニアになりたいのか考えていたのですが、調べれば調べるほど多岐に渡っていたので整理してみようと思い記事にしました。

こんなのもあるよ、その認識はちょっと違うかもなどありましたらご教授頂けますと幸いです。

#追記
２０２１年１１月２４日
@hisuie08　　さん　より

#フルスタックエンジニア
定義は非常に曖昧ですが主にWeb実装面で用いられる括りのため、Webで重要スキルである

・フロントエンド
・バックエンド
・データベース
・インフラ
のスキルを持つことが必要要件かなと思われます。
賛否ありそうですがSEOやセキュリティにまでは精通していなくとも最小限フルスタックを名のれる気がします(精通しているに越したことはありませんが)。

#データエンジニア/データ分析エンジニア
データベースエンジニアと名前が似ていますが全く別物です。アクセス数や利用者情報など煩雑なデータを整理・取捨選択して必要な情報を割り出すエンジニアです。やや専門的な気もしますが、近年はPythonやビッグデータ概念の普及で比重が増しているように思います。

#ハードウエアエンジニア
組み込みエンジニアが中身ならハードウエアエンジニアはガワを作る人達です。
こちらは回路、特に論理回路や集積回路に深い理解が必要な仕事です。
組み込みプログラムとハードウエアは依存関係が特に強い上ハードウエアの性能による制約も生じるため、組み込みとの綿密な連携が必要となります。どちらかがハードとソフトを兼務することも少なくないそうです。

#デザイナー
エンジニアと名前は付きませんが、私は「インターフェイスエンジニア」と呼んでも良いくらい他のエンジニアに劣らぬ重要なポジションだと思います。
訪問者の心を掴むランディングページ、利用者が直感的に利用できる操作画面などは彼らの仕事なしには実現不可能でしょう。

##------------------------------------------------------------------------------

#エンジニア
大辞林で調べると下記の内容でした。
`機械・電気・土木などの技術者。技師。`
もう少し詳しく書くと
`エンジニアリング(工学）の専門的な知識やスキルを持った人材`
かなと思います。

#システムエンジニア
コンピューターのシステム開発に関する業務を一貫して行うエンジニア。
この中から`フロントエンド`や`バックエンド`などに別れたり、発展して`PM`などになる認識です。

#フロントエンドエンジニア
Webサイトの閲覧や操作などのユーザーが直接見たり、触れたりする部分を開発するエンジニア

#マークアップエンジニア
主にHTMLによるマークアップを担当するエンジニア
フロントエンドとの違いはJavaScriptなどの言語を扱うか、マークアップ言語を扱うかの違い

#バックエンドエンジニア
Webサイトを利用するユーザーには見えない部分を担当
主にサーバー側のシステム要件定義、設計、開発するエンジニア
`アプリケーションエンジニア`・`データベースエンジニア`・`サーバーエンジニア`に分けていけるみたいです。

#アプリケーションエンジニア
恐らく多くの人がイメージするエンジニア像
システム開発の一連の作業を担当し、情報システムにおける設計、プログラムの開発、開発したシステムの動作テストなどを担うエンジニア

#組み込みエンジニア
家電製品・携帯電話・自動車など様々な機器の機能を正常に作動させるコンピュータシステムを開発するエンジニアです。
ハードウェアに関する知識、また力学など物理の知識も必要とされる。

#データベースエンジニア
データベースを構築・維持管理・運用をするエンジニア
SQLなどを扱う`ソフトウェアエンジニア`とストレージやサーバーなどを扱う`ハードウェアエンジニア`に分かれる

#プログラマー
システムエンジニアが製作した仕様書を元にプログラムを書いて実装していく人

#テストエンジニア
テストエンジニアとは、テストの計画から改善提案までの工程を請け負うエンジニア
テスト計画書やテストプログラムを与えられテストを実施していく人は`テスター`と呼ばれるそうです。
テスター(実施する人)とテストエンジニア（計画・仕様書から担当）の違いは担当範囲で分かれるようです。

#インフラエンジニア
ITインフラの設定や管理を行っているエンジニア
この中から`サーバーエンジニア`と`ネットワークエンジニア`に分かれるそうです。
ITインフラの監視やメンテナンスもインフラエンジニアが対応します。

#サーバーエンジニア
サーバーの選定や設計、構築、テストなど運用業務全般を行なうエンジニア。
クラウド化も進んでいるのでクラウドの知識も必要とされる

#ネットワークエンジニア
コンピューターやサーバーを接続し、データを送受信できる環境を作るエンジニア

#セキュリティエンジニア
個人情報の漏洩対策や企業の情報セキュリティなど情報セキュリティ専門のエンジニア
IT犯罪に対処するために知識や高い技術レベルが必要であり、様々な企業機密案件に触れることも多いため高い倫理観が求められる

#ミドルウェアエンジニア
`ミドルウェア`というのは、システムソフトウェアの一種
ミドルウェア単体では動作せず、アプリケーションを正常に動作させるために必要なソフトウェアの事です。
ミドルウェアは`〇〇Server`と付くものが多数あるのが特長だそうです、身近なものだど`MySQL`（DB管理サーバー）などもここに当てはまるらしいです。
これらを設計、実装、運用などを担当するエンジニア

#SEOエンジニア
検索エンジンを実験・研究し、SEO実行計画の策定や指示、実務をするエンジニア
SEO：検索をかけた際、自分のWebサイトがページの上位に表示されるように工夫するための技術
サーチエンジンのアルゴリズムに適応し、顧客ニーズに応える必要があります。

#セールスエンジニア
顧客が自分たちの商品を正しく活用できるように製品・機器の仕様等の技術的な説明し営業をサポートするエンジニア

#サポートエンジニア
企業などに導入した情報システムの顧客に、様々なサポートをして、IT製品の仕様や技術的な問題に関する問い合わせに対応するエンジニア

#フィールドエンジニア
顧客先に出向いて、コンピュータの設置や保守・点検、修理などを担うエンジニア

#まとめ
色々と調べていても整理されるどころか逆にこんがらがるぐらい種類がありますね・・・
自分の思うエンジニア像はありましたでしょうか？？
何をやりたいのか明確にできると企業ともミスマッチもリスクは格段に減ると思うので参考にして頂けますと幸いです。
クロスコンパイル環境の整理(for Raspberry Pi)

#1.この記事の内容

C言語のARM向けクロスコンパイル環境をDockerfileで整理しました．
クロスコンパイル環境一式は[GitHub](https://github.com/ryoma-jp/samples/tree/master/env/cross_compile)に公開しています．

ビルドしたプログラムの動作確認には，[Raspberry Pi 4B 8GB](https://jp.rs-online.com/web/p/raspberry-pi/1822098)を使用しました．
OSはRaspbianで，armv7l(32bit)とaarch64(64bit)の2種について紹介します．aarch64は公式サポートされていませんが，[
Raspberry Pi OS (64 bit) beta test version](https://forums.raspberrypi.com/viewtopic.php?f=117&t=275370)にテストバージョンへのリンクが掲載されています．

ビルドを行うマシンはWindows11上に構築したWSL2(Ubuntu 20.04)です．

#2.クロスコンパイル手順

本記事ではクロスコンパイル環境をDockerイメージとして構築します．
ベースとするイメージは，[ubuntu:22.04](https://hub.docker.com/_/ubuntu?tab=tags&page=1&name=22.04)として，クロスコンパイルとビルドしたファイルを転送する為に必要なパッケージをインストールします．

armv7l向けのコンパイルにはarm-linux-gnueabihf-gccを，aarch64向けのコンパイルにはaarch64-linux-gnu-gccを使用します．

クロスコンパイルの際の注意点としては，動的リンクする場合に，クロスコンパイル環境上のライブラリのバージョンと，動作させるボード(今回の場合はRaspberry Pi)にインストールしているライブラリのバージョンを合わせる必要があります．
今回は，-staticオプションをつけることで静的にリンクし，実行体に組込まれるように実装しました．

##2-1.armv7l

```
$ git clone https://github.com/ryoma-jp/samples.git
$ cd samples/env/cross_compile/docker_armv7l/
$ docker build -t env_xc_armv7l/ubuntu:22.04 .
$ ./docker_run.sh
# cd /work/sample_source
# make -f Makefile_for_xc_armv7l
# file sample_armv7l
sample_armv7l: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, 
BuildID[sha1]=5499e43859ab2244f2ec8179590b929c4767dd71, for GNU/Linux 3.2.0, not stripped
```

#2-2.aarch64

```
$ git clone https://github.com/ryoma-jp/samples.git
$ cd samples/env/cross_compile/docker_aarch64/
$ docker build -t env_xc_aarch64/ubuntu:22.04 .
$ ./docker_run.sh
# cd /work/sample_source
# make -f Makefile_for_xc_aarch64
# file sample_aarch64
sample_aarch64: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, 
BuildID[sha1]=b79de0a72f4ebc2a1ce8a1b5b27760427a5ee667, for GNU/Linux 3.7.0, not stripped
```

#3.ビルドしたプログラムの動作確認

##3-1.armv7l

32biit環境上では，64bitでビルドしたプログラムを動作させることはできません．

```
pi@raspberrypi:~/work/bin $ ./sample_armv7l
Cross Compile has been succeeded!!
pi@raspberrypi:~/work/bin $ ./sample_aarch64
-bash: ./sample_aarch64: バイナリファイルを実行できません: 実行形式エラー
```

##3-2.aarch64

64bit環境上では，32bitでビルドしたプログラムを動作させることが可能です．

```
pi@raspberrypi:~/work/bin $ ./sample_armv7l
Cross Compile has been succeeded!!
pi@raspberrypi:~/work/bin $ ./sample_aarch64
Cross Compile has been succeeded!!
```

#4.さいごに

仮想環境上でクロスコンパイル環境を構築しておくと，ホストPCの置き換えやN増し，クロスコンパイル環境間の競合などを気にしなくてよい為，メリットは多いと思います．
なお，Raspberry Piのセットアップは，[Raspberry Pi Imager](https://www.raspberrypi.com/software/)を使用してSDカードに書き込むだけですので，本記事では割愛しました．

#5.関連リンク

* [Raspberry Pi 4B 8GB](https://jp.rs-online.com/web/p/raspberry-pi/1822098)
* [Raspberry Pi OS (64 bit) beta test version](https://forums.raspberrypi.com/viewtopic.php?f=117&t=275370)
    * [raspios_arm64/images](https://downloads.raspberrypi.org/raspios_arm64/images/)
* [Raspberry Pi Imagerで64bit版Raspberry Pi OSイメージを書き込む](https://downloads.raspberrypi.org/raspios_arm64/images/)
mediawikiのupgradeのトラブル解決

#概要
 mediawikiを1.30->1.33に変えたときにデータが移行出来てない場合の解決方法

#状態
 前のバージョンでは、その1つ前のバージョンで登録されているユーザを登録していないのにもかかわらず動いていた。
 今回1.33にupgradeすると、そのデータが消失してしまう！あああ！どうすりゃいいんだ？

#結論
　そのユーザを追加して、再度maintenanceフォルダで「php update.php」を実行する。
　そうすると、よしなにテーブルを更新してくれて見えるようになった。
　ああ、ありがたい。

#蛇足
 1.33というのが今では公式ではないから、だめなのか？とか、1.35にあげたらエラーになったとか
 いろいろありましたが、とりあえずは1.33で動いて、phpも7.1->7.3に上げられました。
 めでたしめでたし。
Composer基礎的な知識

# Composer
忘備録です。
ほぼ、公式からの拝借です。

## composer.json
プロジェクトの依存関係が記述されており、他のメタデータも含まれている場合があります。通常、プロジェクト/ VCSリポジトリの最上位ディレクトリに配置する必要があります。(Packagistに上げなければ、最上位じゃなくても問題はない)

*require*
		* 探して依存関係を解決してダウンロード、インストールする
		* Composerはこの情報を使用して、 [repositories](https://getcomposer.org/doc/04-schema.md#repositories)  キーを使用して登録したパッケージ「リポジトリ」、またはデフォルトのパッケージリポジトリである [Packagist.org](https://packagist.org/) で [適切](https://packagist.org/) なファイルのセットを検索します。上記の例では、composer.jsonファイルに他のリポジトリが登録されていないため 、monolog/monologパッケージがPackagist.orgに登録されていると想定しています。

```php
{
    "require": {
		 //パッケージ名: バージョン
        "monolog/monolog": "2.0.*"
    }
}

```

#### パッケージ名
基本的にベンダー名/パッケージ名である。
パッケージ名が被っても、ベンダー名で差別化できる

## composer.lock
composer.lockには、インストールしたパッケージ情報が記載されてます。


## composer update
Composer.jsonにパッケージを追加した際には、composer updateを実行させます。追加したパッケージがインストールされcomposer.lockも更新されます。
バージョン指定が〜以上と曖昧な指定の場合はupdateするとメジャーアップデートも含まれる可能性がある為、安易にupdateしてはいけない。

Composerは次の2つのことを実行します。
composer.jsonファイルにリストされているすべての依存関係を解決し、すべてのパッケージとその正確なバージョンをファイルに書き込みcomposer.lock、プロジェクトをそれらの特定のバージョンにロックします。composer.lockプロジェクトで作業しているすべての人が同じバージョンの依存関係にロックされるように、ファイルをプロジェクトリポジトリにコミットする必要があります
暗黙的に [install](https://getcomposer.org/doc/03-cli.md#install-i) コマンドを実行します。これにより、依存関係のファイルがvendorプロジェクトのディレクトリにダウンロードされます。（vendor ディレクトリは、プロジェクト内のすべてのサードパーティコードの従来の場所です）

## composer install
composer installを実行するとcomposer.lockに基づいてパッケージをインストールします。初回はcomposer.lockがないので、composer.jsonに基づいてcomposer.lockが作成されたうえでパッケージがインストールされます。
composer.lock  vendor(ダウンロードしたライブラリ群)が作成される。

## vendorフォルダ
vendorフォルダにはインストールしたパッケージが格納されます。
vendorフォルダ配下にあるautoload.phpをプログラムで読み込むだけでライブラリを利用することができます。


## オートロード
Composerは、オートロード機能(自動でクラスファイルを読み込む機能)を提供しています。オートロード機能には、psr-4 classmap filesといった方法があります。

### PSR-4(名前空間)
psr-4では、「名前空間」と「composer.jsonの存在するディレクトリからの相対パス」の対応付けを行います。下記例では、Appから始まる名前空間のクラスへアクセスした際に、appディレクトリ配下から対応するクラスファイルを探してロードします。

```php
"autoload": {
    "psr-4": {
        "App\\": "app/"
    }
},
```

*autoloadセクションを編集した場合、下記コマンドを実行して変更を反映させる必要があります。*

```php
composer dump-autoload
```
Dynamics365の標準Pluginのソースを確認する方法

Dynamics 365はDataVerseの上で構築されています。MSも私たちと同じくPluginやJavascriptを開発しています。
標準のDocsに記載されていない仕様もよくあります、標準テーブルの裏のロジックを確認する方法を紹介します。
①XrmToolboxのAssembly RecoveryToolでMSのプラグインをエクスポートする（自分開発したPluginでもエクスポート可能）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/0936b74c-08f0-f3a4-1e35-6a090fd4443c.png)
②逆コンパイルツールILSpy,dnSpyなどで、Pluginアセンブリを逆コンパイルする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/a93a075d-ccb9-8b4d-f203-582160859bc2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/a08c68a1-3d7f-081e-d553-199926e3c7b2.png)
③対象テーブル名で検索することが可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/31ea8583-1def-6c2d-8217-985b230bffb8.png)
④該当するロジックを確認することが可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/af1c9649-1497-1977-cfe4-6b6be976dacd.png)
⑤ソースをエクスポートしてVisualStudioで開くことが可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/65d3ae45-2988-58b6-b2e2-ec8b338e526e.png)
Dynamics365サポート案件の取引先企業と取引先担当者の依存関係を無視

サポート案件を登録、更新する場合、顧客（取引先企業）と取引先担当者の項目の関連付けがチェックされています。顧客に属していない取引先担当者レコードを選択して保存する場合、以下のような
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/353b7ba0-dea9-c43c-7e47-f33abe5ca739.png)
「指定された取引先担当者は、顧客として選択された取引先企業に属していません。選択された取引先企業に属している取引先担当者を指定してから、やり直してください。」というエラーメッセージが表示されます。

このチェックをOFFにする設定を最近提供されました。
https://docs.microsoft.com/ja-jp/dynamics365/customer-service/remove-validation-contact

環境変数にmsdyn_IncidentShouldValidatePrimaryContactという変数を追加して、Valueを0に設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/f6a2a5db-9723-9838-6841-f6a1d6b31c48.png)

環境変数の関連資料は以下のURLを参考
https://docs.microsoft.com/ja-jp/powerapps/maker/data-platform/environmentvariables
使用するバージョンを明記してくれぇ (テンプレート付き)

# はじめに

どうも、最近リアルが忙しく、あまり開発できていない人です。

# 言いたい事

__**使うライブラリのバージョンを明記してくれ**__

使おうとしてたバージョンが参考記事と違うせいで、昨日だけで8時間は無駄にしている

バージョンが違う時だけ出てくるエラー構文もあるので、対応も難しい…

(追記)
後、OSの種類も書いといてもらえるとありがたい。


# テンプレート
唐突に
『バージョンを明記しろ』
と言われても、どうすればいいのかわからない人のためにテンプレートを用意した。

## windows用

> （空白）
> ```bash
> C:\> node -v
> v16.10.0
> 
> C:\> npm -v
> 8.0.0
> 
> C:\> vue -V
> @vue/cli 4.5.13
> ```
> （空白）

```bash
C:\> node -v
v16.10.0

C:\> npm -v
8.0.0

C:\> vue -V
@vue/cli 4.5.13
```

こんな感じで、Command Prompt・Power Shell等で使う環境のバージョンを確認し、それを記述するのが一番早く簡単だと思う。

## npm用

npmであれば、`package.json`をそのまま記事に置いてもいいかもしれない。

```markdown
(空白)
<details><summary>package.json<summary>
<div>
(空白)
\```json:package.json
{
  "name": "template",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "Zect",
  "private": true
  ...
}
\```
(空白)
</div></details>
```



<details><summary>package.json</summary><div>

```json:package.json
{
  "name": "template",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "Zect",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "node build/build.js"
  },
  "dependencies": {
    "firebase": "^9.2.0",
    "vue": "^2.5.2",
    "vue-nl2br": "^0.1.2",
    "vue-router": "^3.0.1"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^8.2.1",
    "babel-helper-vue-jsx-merge-props": "^2.0.3"
  }
}
```
</div></details>


## linux用
根本的なところはwindowsと同じ

ただ、linuxにはいろんな派生がある。
それぞれ、使えるアプリ・使えないアプリが存在する。

***必ず*** OSの情報も記述してもらいたい。

```markdown
（空白）
\```bash
$ cat /etc/os-release
NAME=”Amazon Linux AMI”
VERSION=”2017.09″
ID=”temp”
\```
（空白）
```

```bash
$ cat /etc/os-release
NAME=”Amazon Linux AMI”
VERSION=”2017.09″
ID=”amzn”
ID_LIKE=”rhel fedora”
VERSION_ID=”2017.09″
PRETTY_NAME=”Amazon Linux AMI 2017.09″
ANSI_COLOR=”0;33″
CPE_NAME=”cpe:/o:amazon:linux:2017.09:ga”
HOME_URL=”http://aws.amazon.com/amazon-linux-ami/”
```

## 質問フィード
さて、Qiitaの質問機能についても少し言わせてもらおう。

***タイトルの一番最初に使用言語を明記してくれ***

使用している言語を`[`と`]`で囲むだけ
これだけで、回答率上がる！

# さいごに
君の記事は、どんなに酷くても誰かが参考にする。
それを頭の隅に置いて記事を書いて欲しい。

最後にこの言葉で締めようと思う。

__***「使用するバージョンを明記してくれぇ」***__
macOSでsudoをTouch IDで許可するためのスクリプトをGistからワンライナーで動かす

# 概要

MacBook AirやMacBook Proで、Touch IDが搭載されたモデルにおいて、ターミナルでsudoコマンドを使うときにTouch IDで許可できるようにするためのスクリプトです。

Qiitaの他の記事でも、いくつかあることを見たのですが自分のケースに合わなかったことと、複数回実行するケースもありそう(複数のmac、アップデート後、など)なのでスクリプトにしました。

## 書いたものとできること

### 書いたもの

[Gist](https://gist.github.com/hrkt/1bbac50c84d99fdb07375d713587f864)に置いてあるものをこちらにもコピペしておきます。

```sh
#!/bin/sh
# A shell script to enable sudo by "Touch ID" on macOS
# tested on macOS 11.6 Big Sur
TARGET_FILE=/etc/pam.d/sudo 

# skip if it is not run on macOS
if [ 'Darwin' != `uname` ]; then
	echo "not on macOS platform. exit."
	exit 0
fi

# check target file
grep "auth       sufficient     pam_tid.so" $TARGET_FILE > /dev/null 

if [ $? -ne 1 ]; then
	echo "already has pam_tid.so line in ${TARGET_FILE}. do nothing."
	exit 0
fi

# edit file with sed command. 
# with -i option, sed creates backup file on the same directory.

sudo chmod +w ${TARGET_FILE}
sudo sed -i '.bak' -e '2 i\
auth       sufficient     pam_tid.so' ${TARGET_FILE}
if [ $? -ne 0 ]; then
	echo "an error occured. exit."
    exit 0
fi

sudo chmod -w ${TARGET_FILE}

echo "succeeds. see ${TARGET_FILE}."

cat ${TARGET_FILE}
```

### できること

- /etc/pam.d/sudo ファイルの2行目に、Touch IDで認証するため、「auth       sufficient     pam_tid.so」という行を追加します。

### 動作前提

/etc/pam.d/sudo ファイルが、以下のような構成になっていることを前提としています。

```
# sudo: auth account password session
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so
```

### 試した環境

macOS Big Sur で書きました。
(2021/11/25追記: macOS Monmtereyでも動作することを確認しました。)

```shell
uname -a
Darwin MacBook-Air.local 20.6.0 Darwin Kernel Version 20.6.0: Mon Aug 30 06:12:20 PDT 2021; root:xnu-7195.141.6~3/RELEASE_ARM64_T8101 arm64

```

## 動かし方

### 方法１：上記スクリプトを手元に保存して実行

1. 上記ファイルをご自身のmacOSで好みのファイル名をつけて保存します。
1. ファイルに実行権限をつけるか、"sh ファイル名" で実行します。

### 方法２：Gistからスクリプトをダウンロードして実行

1. まず、下記のワンライナーで指定されているGistファイルの内容を確かめ、実行してもよいか考える。
1. 実行して良いと判断した場合、下記のワンライナーを実行する。(sudoコマンドを内部で使っているので、パスワードなりで許可してあげる)

```sh
curl https://gist.githubusercontent.com/hrkt/1bbac50c84d99fdb07375d713587f864/raw/658ffd698a0d7552d160c9c5651757a96e874bc1/enable_sudo_by_touch_id.sh | sh 
```

## 追記

### 2021/11/25 

自分のMacをBig SurからMontereyにアップグレードで/etc/pam.d/sudoのからpam_tid.soの行がなくなっていたケースで、上記方法2.の実行でまたsudoにてTouch IDが使えるようになることを確認しました。



## 他の記事

検索して出てきた順にいくつか。~~~(を自分で書いちゃったあとに調べました)~~~

- [Touch ID搭載のMacでsudo実行時のパスワード入力をTouch ID化](https://qiita.com/y-vectorfield/items/3fc96150e63448a80c1b) ... 手動での手順が丁寧に示されています。
- [[Tips] MacのTouchIDでsudoコマンド認証を行う](https://qiita.com/kazuooooo/items/80678d890623f79dc599)
- [macOSの sudo で TouchID が使えるようにする（tmux内の利用も対応）](https://qiita.com/kawaz/items/0593163c1c5538a34f6f) ... スクリプトになっている例。tmuxを使われる方はこちらが参考になりそうです。
- [ターミナルでSudoのパスワード入力をTouchIDで実行する。]  (https://qiita.com/tukapai/items/d2daf0fbacb504365f6f)
おじいちゃん、もうRaspberry PiのISOファイルを焼くのにはオフィシャルツールがあるのよ。

# はじめに / 結論

ラズパイのセットアップを行うには、Raspbian等のISOイメージを何らかのサードパーティ製の専用ソフトを使ってmicroSDに書き込む必要がありました。**2020年3月までは**。

2020年3月に、**Raspberry Pi Imager** というISOを焼くソフトが公式に公開されて、そのあたりの手間が大幅に削減されました。使わない手はない。

ちなみに、ラズパイの標準的なOSって言ったら"Raspbian"だろ、と思っていましたが、これは2020年5月に**"Raspberry Pi OS"**という名称に変更されたようです。

おお、世は移り変わる……。

ラズパイに日常的に触れている方々には、何を今さら……的な情報かと思いますが、3年前くらいにラズパイから離れて久々に帰ってきた者としては革新的な情報だったので一記事としてまとめます。[去年のラズパイアドベントカレンダー](https://qiita.com/advent-calendar/2020/raspberry-pi
) にもなさそうだったし。


# Raspberry Pi Imager を使ってみよう

言うて解説するほどでもないし、巷に記事もたくさんあるけども、まあ一応。

公式サイトに行ったらインストーラが配布されています。Raspberry Pi OSを用いる場合は、**このソフトを使えばISOイメージはこのソフトが取ってきてくれるので、ISOイメージをユーザ自身がダウンロードする必要はありません**。

https://www.raspberrypi.com/software/

無事にインストールしてソフトを開くと、こんな感じの見た目です:

![rpimager02.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150194/676236a0-d8e5-1509-6f61-b1117d0b50ab.jpeg)

あとは使いたいOSを選んで、

![rpimager03.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150194/e12d928d-b6d8-0af7-5d2e-f626fc3c4144.jpeg)

書き込みたいmicroSDを指定すれば、

![rpimager04.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150194/65b04a79-5bdc-cb57-4d61-3fcd8d59c392.jpeg)

"WRITE"するだけです。すばらしい……。あとは煮るなり焼くなりです。


# 補遺1: ヘッドレスで（ラズパイをモニター・キーボード等に繋がないで）やる人のためのメモ:

少なし、手元のラズパイ3 モデルBで上手く行くことを確認した。使っているPCはWindows 10。

手順1. Raspberry Pi ImagerでRaspberry Pi OSを書き込んだmicroSDのルートは"boot"のはず。ここに、"ssh"というカラのファイルを作る。普通にエクスプローラから作っていい。

手順2. 同じく"boot"直下に、`wpa_supplicant.conf`というファイルを作り、以下を記載する。普通にテキストエディタでいい（文字コードはUTF-8にした。SJISとかだとダメかどうかは未確認）:

```
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
 ssid="Wi-FiのSSID"
 psk="Wi-Fiのパスワード"
}
```

手順3. microSDをラズパイに挿して起動する。ルータのDHCPが働いていたら、ラズパイのIPが分からなくても、`$ ssh pi@raspberrypi.local` でログイン可能。パスワードは`raspberry`。楽ちん。

<!-- マイメモ: アクセスポイント親機に直で繋ぐのは物理的に遠すぎて認識できないのかも知れない。中継器なら通る。1回セットアップしたのちまたやる場合は、windows側のuserディレクトリの.sshフォルダの鍵を削除してからでないとだめよ。 -->


# 補遺2: カメラモジュールで遊びたかったんだ

2018年にこういう記事をQiitaに書きました: 

https://qiita.com/yamasaki1ma/items/20fcb55f06d20e5ebb44

これの続きの構想がずっとあったから、そのためにラズパイを引っ張りだして来たのですが、本体側のカメラ接続部分がもうダメになっているのかも知れない。`$ sudo raspi-config` でカメラを有効化しても、`$ vcgencmd get_camera` の結果が`supported=0`で変わらぬ。ちくしょう……。

どうしようかなー。今年のアドベントカレンダーを眺めつつ、有効利用する方法を探そうと思います。
【Scala】AtCoder Beginner Contest 197の「C - ORXOR」をbit全探索を使わずに解く

## 概要
AtCoder Beginner Contest 197のC問題[C - ORXOR](https://atcoder.jp/contests/abc197/tasks/abc197_c)について、[解説](https://atcoder.jp/contests/abc197/editorial/997)を読むと、bit全探索を使うのが良いとあります。もちろん、こういった問題を見てぱっとbit全探索が思いつけば良いのですが、思いつかない場合もあると思います。（私は思いつきませんでした）
ということで、少し愚直めに実装した内容をメモ書きしたいと思います。実装言語はScalaです。

## 実装の方針
* まずは1区間しかない状態からスタートし、どの箇所で区切るかというのを全部試します。区切りの結果を二重のコレクションで保持します。
* 一重目のコレクションでOR演算の結果を取得して、そのOR演算の結果をXOR演算します。
* 一桁ずつ桁を動かしていき、区切った場合と区切らなかった場合で再起で関数呼び出しを行います。区切った場合はXOR演算で結果を取得します。

## 実装サンプル
提出結果は[こちら](https://atcoder.jp/contests/abc197/submissions/27451548)です。実装内容は以下にも記載します。

```scala
object Main extends App {
  val n = scala.io.StdIn.readInt();
  val aVector = scala.io.StdIn.readLine().split(" ").map(_.toLong).toVector
 
  // 適当な値で結果を初期化
  var result = 222222222222L
 
  // 与えられた区間のOR演算結果を取得
  def getOr(orVector: Vector[Long]): Long = {
    orVector.reduceLeft((z, n) => z | n)
  }
 
  // 二重のVectorに対してXOR演算結果を取得
  def judgeResult(targetVecVector: Vector[Vector[Long]]): Unit = {
    // 各区間毎にOR演算結果を取得の後にXOR演算
    val xor = targetVecVector.map(getOr).reduce((z, n) => z ^ n)
    // 取得した値がresultより小さかったら更新
    if (xor < result) {
      result = xor
    }
  }
  
  // 区切りを試す関数
  def splitAndJudge(targetVector: Vector[Vector[Long]], splitIndex: Int, count: Int): Unit = {
    if (count < n) {
      // そのままの状態で再起呼び出し
      splitAndJudge(targetVector, splitIndex + 1, count + 1)
      // 区間を分割
      // 最終区切り以外をそのまま取得
      var newTargetVector = targetVector.dropRight(1)
      // 最終区切りを分割
      val lastVector = targetVector.last
      val lastSplit = lastVector.splitAt(splitIndex)
      newTargetVector :+= lastSplit._1
      newTargetVector :+= lastSplit._2
      // 分割を行ったら結果取得
      judgeResult(newTargetVector)
      // 分割した状態で再起呼び出し
      splitAndJudge(newTargetVector, 1, count + 1)
    }
  }
  
  var vecVec = Vector.empty[Vector[Long]]
  // まずは1区間に全値がある状態でスタート
  vecVec :+= aVector
  // 1区間に全値がある状態でresult値を更新
  judgeResult(vecVec)
  // 区切りを試す
  splitAndJudge(vecVec, 1, 1)
  println(result)
 
}
```
【Git】typoを自動的に検出してコミットを防ぐ方法

「よし、完璧だ！」とコミットした後やPRで指摘されてtypoに気づき、`fix: typo`コミットするのはできるだけ避けたいです。
レビューする側にとってもtypoに意識を向けながらレビューをするのは負担になります。貴重な時間はもっと大事な確認と指摘に使いたいものです。

今回は、そんなtypoを自動的に検出してコミットを防ぐ方法を紹介します。
![悲しいfix: typoコミット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222499/c108636d-f5ed-9c1d-b853-647baea29b7f.png)
“悲しいfix: typoコミット”

# できるようになること
コミット時に変更ファイルのtypoを自動的に検出し、typoがあった場合はtypo箇所と修正のヒントを出力してコミットを防ぎます。typoがない場合はコミットは成功します。
![typo-check.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222499/a96bc1af-076f-7f5e-ac3d-811bf601579c.gif)


# 設定方法
## typoの検出
typoの検出にはRust製のtyposを採用しました。

https://github.com/crate-ci/typos

macの場合のインストール手順を記載します。

```shell:shell
# rustのインストール
brew install rust

# typosのインストール
cargo install typos-cli

# バージョンが出力されればOK
typos --version
```

※ GitHubからバイナリをダウンロードして利用する方法もあります。

## コミット時に自動的にtypoを検出する
[Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)を利用することで実現しています。

利用したいリポジトリの`.git/hooks/pre-commit`を編集してください。

```shell:.git/hooks/pre-commit
#!/bin/sh

# 変更差分をチェックしたい場合
# git diff --cached --diff-filter=AM | typos -
# 変更ファイルをチェックしたい場合
git diff --cached --name-only --diff-filter=AM | xargs typos

# typoがある場合にコミットを防ぐ
if [[ $? -ne 0 ]]; then
  exit 1
fi
```

`.git/hooks/pre-commit`に実行権限がない場合は権限を付与してください。

```shell:shell
# 実行権限の付与
chmod +x .git/hooks/pre-commit
```

# 動作方法
設定が終わったリポジトリでコミットすると自動的に動作します。

これでtypoを含んだコミットを自動的に防ぐことができ、`fix: typo`コミットすることはなくなります。

# 最後に
この記事を読んで「面白かった」「学びがあった」と思っていただけた方、よろしければ Twitter や facebook、はてなブックマークにてコメントをお願いします！
また [DeNA 公式 Twitter アカウント @DeNAxTech](https://twitter.com/DeNAxTech) では、 Blog記事だけでなく色々な勉強会での登壇資料も発信してます。ぜひフォローして下さい！
<a href="https://twitter.com/DeNAxTech?ref_src=twsrc%5Etfw" class="twitter-follow-button" data-size="large" data-lang="ja" data-show-count="false">Follow @DeNAxTech</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 2022/07/19 追記
この記事の拡張版として、typoをなくす理由と方法について、以下の記事を書きました。
「なぜtypo（スペルミス）がいけないのか？」「typoを仕組みでなくす3つの方法（実装、コミット、プルリクエスト）」について記載しています。

合わせてぜひご覧ください。

https://tech.youtrust.co.jp/entry/fix-typo

# 2023/06/21 追記
この記事の最終版として、以下の記事を書きました。

検知の仕組みをCSpellに変更しました。
エディタの拡張機能による開発時のチェック、Git HooksによるCommit時のチェック、GitHub ActionsによるPush時（PR上）のチェックの全てをCSpellで統一しているので、共通の設定が利用でき、同じ検知内容となります。
また、導入が楽になるようにしました。

合わせてぜひご覧ください。

https://zenn.dev/naro143/articles/215fa2ad250a57
google-cloud-bigquery の load_table_from_json で 400 Error

小一時間悩んだ

# 環境
- google-cloud-bigquery 2.30.1 (Python Client for Google BigQuery)
- Python 3.9.0

# 現象

下記のようなコードで、BigQuery に insert しようとしたところ

```foo.py
import json

from google.cloud import bigquery
from google.cloud.bigquery.job import LoadJob
from google.cloud.bigquery.table import Table

if __name__ == '__main__':


    a = '{"foo":"123","bar": "123"}'
    row = json.loads(a)

    project_id = 'foo_project'
    dataset_id = 'bar_dataset'
    table_id = 'test'

    client  = bigquery.Client(project = project_id)
    dataset  = client.dataset(dataset_id)
    table = dataset.table(table_id)

    table_result: Table = client.get_table(table)

    job_config = bigquery.LoadJobConfig()
    job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON
    job_config.schema = table_result.schema
    table_id_constructor = ".".join([project_id,dataset_id,table_id])

    job: LoadJob = client.load_table_from_json(json_rows=row, destination=table_id_constructor, job_config=job_config)

    print(job.result())
```

下記のようなエラーになる（そっけない...）

```
google.api_core.exceptions.BadRequest: 400 Error while reading data, error message: JSON table encountered too many errors, giving up. Rows: 1; errors: 1. Please look into the errors[] collection for more details.
```

# 原因

あれこれ見たりしたがエラーからはよくわからず、結果 <strong>load_table_from_json() の json_rows に渡すのは、list型（配列）じゃないとあかん</strong> ということがわかった。

というわけで以下のようにすることで insert できましたとさ。

（JSONLを期待してるだろうから、まぁ、そうなんだろうなという気もするが）

```foo2.py
import json
from typing import List

from google.cloud import bigquery
from google.cloud.bigquery.job import LoadJob
from google.cloud.bigquery.table import Table

if __name__ == '__main__':


    a = '{"foo":"123","bar": "123"}'
    row = json.loads(a)
    rows: List[dict] = []
    rows.append(row) # 変更点: list に append してあげる

    project_id = 'foo_project'
    dataset_id = 'bar_dataset'
    table_id = 'test'

    client  = bigquery.Client(project = project_id)
    dataset  = client.dataset(dataset_id)
    table = dataset.table(table_id)

    table_result: Table = client.get_table(table)

    job_config = bigquery.LoadJobConfig()
    job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON
    job_config.schema = table_result.schema
    table_id_constructor = ".".join([project_id,dataset_id,table_id])

    # 変更点:　row じゃなくて、 rows を渡す
    job: LoadJob = client.load_table_from_json(json_rows=rows, destination=table_id_constructor, job_config=job_config)

    print(job.result())
```
Dynamics365/PowerAppsモデル駆動アプリのPluginでの排他処理

数量増減、採番処理で数字の変化をより厳密的に管理、いわゆる排他制御を行う必要な場合のMSのサンプルを共有させていただきます。
FieldServiceの製品在庫の数量の増減は、在庫仕訳帳データの登録により管理しています。同時に複数在庫仕訳帳が登録される可能性があるため排他制御が必要になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/b18a1cd0-852e-237c-8937-82bda557683a.png)
実装上は主キーのみUpdateを実行することで行ロックをかけています。そのあとで再度数量を検索して計算を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/7c2f08d0-2bd5-5d06-6835-7f1d4fc8c731.png)
Dynamics365/DataVerseのカスタムPluginとWorkflowを起動させない（バイパス）設定

バッチ処理、データ移行やデータリカバリを行う際に、Plugin/Workflowのロジックを起動させたくない場合がよくあると思います。
以下のDocsの設定で実現可能です。
https://docs.microsoft.com/ja-jp/powerapps/developer/data-platform/bypass-custom-business-logic
ただし、非同期のPluginやWorkflowをバイパスすることができません。
csv/Excelでのデータインポート時も利用できません。
CGI とは

## 勉強前イメージ

よく聞くけどわからん・・・
web系？

## 調査

### CGI とは

Common Gateway Interface の略で、
webサーバがブラウザからの要求に応じてプログラムを実行する仕組みの一つで
動的なプログラムを起動させるために昔から用いられていた方法になります。
CGIを使用することで静的な情報だけでなく、プログラムの結果を提供することができます。

### 各アクセス方法

- htmlファイルへのアクセス

静的なファイルだとただ単にhtmlファイルを表示するだけの
webサーバになります。

![12021-11-22 # CGI とは - diagrams.net - Google Chrome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/fcc60fbd-fd87-52ca-cd09-53c5ba3926b2.png)

- CGIファイルへのアクセス

CGIファイルへのアクセスの際はwebサーバ側でCGIのプログラムを起動して結果をレスポンスとして送信します。
クライアント側はどちらもブラウザでアクセスすることは変わらず、サーバ側の中の挙動が違います。

![22021-11-22 # CGI とは - diagrams.net - Google Chrome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/89ea1ae7-2440-1a3b-678e-cf058e2ca306.png)

## 参考

- [CGI （Common Gateway Interface ）](https://www.infraexpert.com/study/tcpip16.5.html)
Dynamics365/PowerAppsモデル駆動アプリの取引先企業画面にニュースを表示

取引先企業画面に、関連するニュースを表示する要望があると思います。以下のニュースコントロールを利用して表示することが可能。
https://docs.microsoft.com/ja-jp/powerapps/maker/model-driven-apps/stay-current-with-news-control

手順は以下になります。
Bing New APIを取得する。
AzureでBing Searchを検索して、表示されるメニューから「Bing Search V7」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/66e8cb35-f02f-0386-8110-4e7d4481d96c.png)

動作検証する場合Free F1のプランで結構です。必要な情報を入力し、「作成」ボタンを押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/407d5ce5-9633-ed01-16af-b5ab38f2dfcb.png)
デプロイが完了すると以下のように表示されます。「リソースに移動」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/bde22f68-2f87-e88f-7b1c-dfcb3948156d.png)
画面左側の「キーとエンドポイント」を選択し、「キーの表示」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/6c474569-d8bd-8a9b-4a1c-ed6017d4c24d.png)
「キー１」の値を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/ee38ba9d-8000-2f22-6215-02003dd8a23c.png)
Docsの記述通りに、以下の二つの項目を作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/df12dfcd-8aef-fbf3-5b63-3a9c6c04fbb8.png)
メインフォーム画面に、「取引先企業名」項目を配置する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/b44c936c-0774-3f3d-7658-326ebfef1e80.png)
「取引先企業名」の「プロパティの変更」で、以下の設定を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/e49e15b8-8bca-6c1b-2c96-d4808257d421.png)
ラベルも「ニュース」に変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/eba47211-619b-94d4-0435-4a6b161a91a9.png)
先ほど追加した二つの項目を画面に非表示として配置する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/db802560-492c-06aa-c400-9cf69c11242c.png)
NewsapiとnewsURL設定の業務ルールを追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/567787f0-d7c4-3085-c6e9-82ffb2200b03.png)
フォームを保存して公開すれば、以下のような企業の関連ニュースを表示すること出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/7391bb4a-887d-9ef0-27d8-8989eb80e57e.png)
【Python】画像ファイルの解像度取得方法メモ

Python で画像ファイル (*.png など) から解像度 (WxH) の情報を抽出する方法として

* OpenCV (https://opencv.org/)
* Pillow (https://pillow.readthedocs.io/en/stable/)
* imagesize (https://github.com/shibukawa/imagesize_py)

の使い方，速度のメモ．
画像ファイルは[いらすとやの人工知能のキャラクター](https://www.irasutoya.com/2016/12/blog-post_290.html)を使用

バージョン情報：Python 3.7.3, OpenCV 4.5.4.60, Pillow 8.4.0, imagesize 1.3.0

# OpenCV 

## インストール

```
pip install opencv-python
```

## 使い方

```python
import cv2

filename = 'ai_character.png'
img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
height, width = img.shape[:2]
print(f'Height: {height}, Width: {width}')
# Height: 800, Width: 688
```

# Pillow

## インストール

```
pip install pillow
```

## 使い方

```python
from PIL import Image

filename = 'ai_character.png'
img = Image.open(filename)
width, height = img.size
print(f'Height: {height}, Width: {width}')
# Height: 800, Width: 688
```

# imagesize

## インストール

```
pip install imagesize
```

## 使い方

```python
import imagesize

filename = 'ai_character.png'
width, height = imagesize.get(filename)
print(f'Height: {height}, Width: {width}')
# Height: 800, Width: 688
```

# 手法の比較

1,000 回平均を記録 (MacBook Pro (13-inch, 2017, Two Thunderbolt 3 ports))

|OpenCV|Pillow|imagesize|
|--:|--:|--:|
|8.4E-3 [s]|1.3E-4[s]|3.6E-5 [s]|

OpenCV は `cv2.imread` で np.ndarray のデータを読み込む一方，Pillow ではデータに処理が施されるまでデータを読み込まない (https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.open)．
また，imagesize では画像ファイルのヘッダをパースするのみである．
よって，速度は OpenCV < Pillow < imagesize となっている．

# 参考文献
* [python - Get Image size WITHOUT loading image into memory - Stack Overflow](https://stackoverflow.com/questions/15800704/get-image-size-without-loading-image-into-memory)
* [opencv - getting the shape of an image file from python without loading the image - Stack Overflow](https://stackoverflow.com/questions/23763216/getting-the-shape-of-an-image-file-from-python-without-loading-the-image)
ESP32でDY-SV17FをUARTで使おう

MP3サウンドモジュールDY-SV17をESP32で使ってみましょう。
#DY-SV17Fとは
フラッシュ内蔵のMP3サウンドモジュールです。
類似製品としてSDカードタイプのDFPlayerや同種類製品としてJQ6500 などがあります。
![DSC_0856 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/c47187d2-5f1d-764a-eacd-1ca410e3bcb8.jpeg)
#DY-SV17の使い方
スイッチでスタンドアローンコントロールしたり、UARTでコントロールしたり出来ます。
まずは、USBでフラッシュメモリに音源を用意しましょう。
なお、ファイル名は00001.MP3～とするようです。
#UARTで使う
CON1,CON2をプルダウン
CON3をプルアップします。
この状態で、5Vの入力とUART接続することでArduinoからコントロールできます。
#ESP32で使う
ESP32では以下ライブラリを使ってコントロールしようとしましたが素直にUARTで使う事が出来ませんでした。
https://github.com/SnijderC/dyplayer
この為、TXのみでコントロールするプログラムを作ってみました。
初めにUARTの中身をUART tuning toolを使って見てみましょう。
DY-SV17F manual & Datasheet
http://attach01.oss-us-west-1.aliyuncs.com/IC/Datasheet/13441.rar
![スクリーンショット 2021-11-21 121116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/2c3330ed-584f-d9fe-0778-29beaedc7c29.png)
##UART通信の中身
DY-SV17FはUSBフラッシュ以外にSDカードなどを使えるICにが載っています。
まずは、フラッシュで動作するコマンドを送ります。
そのうえで、再生するトラックを指定します。
#回路構成
ESP32の15ピンをDY-SV17FのRXにつなぎ
CON1,CON2をプルダウン
CON3をプルアップ
電源は5Vを入力します。
#プログラム内容
UART tuning toolで送信するコマンドは以下です。
停止

    0xAA, 0x04, 0x00, 0xAE
１曲目（0xXX　の6個目が変化します）

    0xAA, 0x16, 0x03, 0x02, 0x00, 0x01, 0xC6
2曲目

    0xAA, 0x16, 0x03, 0x02, 0x00, 0x02, 0xC7
3曲目

    0xAA, 0x16, 0x03, 0x02, 0x00, 0x03, 0xC8
UARTのポートはRXがなく、TXだけとするので-1としました。

    DY_TX.begin(9600, SERIAL_8N1,-1, 15);

#プログラム

```
HardwareSerial  DY_TX (1); // RX, TX
byte SOUND_1_MUSIC[]  = {0xAA, 0x16, 0x03, 0x02, 0x00, 0x01, 0xC6};
byte SOUND_2_MUSIC[]  = {0xAA, 0x16, 0x03, 0x02, 0x00, 0x02, 0xC7};
byte SOUND_3_MUSIC[]  = {0xAA, 0x16, 0x03, 0x02, 0x00, 0x03, 0xC8};
byte SOUND_STOP[]  = {0xAA, 0x04, 0x00, 0xAE};

void setup() {
  DY_TX.begin(9600, SERIAL_8N1,-1, 15);
  Serial.begin(9600);
}
void loop() {
  Serial.println("TRACK 1");
  DY_TX.write(SOUND_1_MUSIC, sizeof(SOUND_1_MUSIC));
  delay(5000);
  Serial.println("TRACK Stop");
  DY_TX.write(SOUND_STOP, sizeof(SOUND_STOP));
  delay(2000);
  Serial.println("TRACK 2");
  DY_TX.write(SOUND_2_MUSIC, sizeof(SOUND_2_MUSIC));
  delay(5000);
  Serial.println("TRACK Stop");
  DY_TX.write(SOUND_STOP, sizeof(SOUND_STOP));
  delay(2000);
  Serial.println("TRACK 3");
  DY_TX.write(SOUND_3_MUSIC, sizeof(SOUND_3_MUSIC));
  delay(5000);
  Serial.println("TRACK Stop");
  DY_TX.write(SOUND_STOP, sizeof(SOUND_STOP));
  delay(2000);
}
```

以上でコントロールできます。
phpMyAdminで外部キーを設定する方法


・resultテーブルを作る
・カラム名、データ型、桁数を決める
・主キーを作る
・外部キーを作る(customerテーブルのIDを参照する)


```
CREATE TABLE
    result (
        ID INTEGER(11),
        customer_id INTEGER(255),
        checkdate DATE,
        weight TEXT,
        height TEXT,
        bloodpressure TEXT,
        created_at datetime  default current_timestamp,
        updated_at timestamp default current_timestamp on update current_timestamp,
        PRIMARY KEY (ID),
        FOREIGN KEY (customer_id)
        REFERENCES customer (ID)

    );

```

**ハマったところ**
・PRIMARY KEY (ID)の後には「,」が必要
・FOREIGN KEY (customer_id)の後には「,」はいらない

```
PRIMARY KEY (ID),
FOREIGN KEY (customer_id)
REFERENCES customer (ID)

```
【ラズパイ】HDD が I/O エラー出すときに疑いたいこと

自宅でRaspberry Pi 4B (4GB RAM) に2TB HDDをつなげて運用しているんですが、
頻繁に入力/出力エラー（I/Oエラー）が出たり、不安定になったりしてました。

# 原因

今回の原因は、電力不足でした。

バスパワーで接続していたので、動作が不安定になっていたのです

# 解決方法

急遽、セルフパワーのUSBハブを購入して対処しました。
https://www.elecom.co.jp/products/U3H-A408SBK.html
その後、表題のエラーは発生してません。

-----

ネットで I/O エラーの情報を漁っても電力不足にはなかなか触れられていなかったので、備忘録として残しておきます
maven-shade-pluginを使おうとしたら「Unsupported class file major version ○○」って言われてビルドできなくなった話

# コトの発端
`Java 16`で`Maven`使いながらコードを書いていて依存関係を追加する必要があることに気が付いた私は`pom.xml`を開いて`dependency`を書き加えていた。
その依存関係は`relocation`する事を前提としていたので、いつも通り`maven-shade-plugin`のバージョン`3.2.4`を使って`relocate`の処理を書いた。
暫くしてコードを書き終え、ビルドしてみるとなんとエラーが発生！コンソールには

```console
Unsupported class file major version 60
```

とかいうわけのわからないエラーが出ていた。

# 結局何が原因だったのさ

使用していた依存関係が`Java 16`を使用していて、かつ`maven-shade-plugin`のバージョン`3.2.4`を使っていたこと、そしてその状態で`relocation`をしようとしていたことが原因だと私の中で結論付けた。（そのままやんけ）

# 解決方法は？

①`pom.xml`の`java.version`を`16`にしておく

```xml
<properties>
    <java.version>16</java.version>
    ...
</properties>
```

②`maven-shade-plugin`の`snapshot`が使えるように`pluginRepository`を追加する

```xml
<pluginRepositories>
    <pluginRepository>
        <id>maven-snapshots</id>
        <url>https://repository.apache.org/content/repositories/snapshots/</url>
    </pluginRepository>
</pluginRepositories>
```

③`maven-shade-plugin`の`version`を`3.3.0-SNAPSHOT`にする

```xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.3.0-SNAPSHOT</version>
    ...
</plugin>
```

※もちろん`IntelliJ`側などのプロジェクトSDKは`Java 16`にしておくように

# めんどいね

うん。