OmniAICreator/Qiita-1.07M huggingface dataset:
未経験エンジニア、就職活動を終えて

# 本記事の趣旨
IT業界未経験で転職活動した時の経験をシェアするために書きます。これからIT業界に入られる方や転職活動で困っている方のための参考になれば幸いです。

# 自己紹介
はじめに参考までに当人の転職経緯等について紹介します。それぞれバックボーンが違うので、参考になること・ならないことがあるかと思います。何かの気づきのきっかけになれば幸いです。

2020年、経済学部を卒業（偏差値50くらいの大学）
⇨卒業後すぐ、金融機関に就職
⇨2０２２年3月、金融機関を退職（2年間勤務）
⇨退職して1ヶ月後の5月頭、プログラミング教室（テックキャンプ）受講開始。
⇨7月中旬、スクール終了。転職活動開始。
⇨およそ1ヶ月の転職活動で内定先3社獲得
⇨15社ほど応募して、転職活動に満足し、就活終了。
⇨10月入社予定。

# 転職活動の仕方について
## 利用サイト
WantdlyとPaizaをメインで利用。これらのサイトを利用した理由は
・あまり大きな会社に入るつもりはなかったこと
・古い考え方の企業が嫌だったこと
です。
その他に、テックキャンプからの紹介案件も積極的に応募しました。
福利厚生のしっかりした企業は業歴の長い安定した企業に行きたいのであれば、Greenやリクルートなどを使うのが良いのかもしれません。また、利用するサイトが多いと、管理や転職活動のための作業が大変になってくるので、利用サイト数は絞ることをおすすめします。

## エントリーシート
何人かに添削してもらうことをお勧めします。私は２回添削してもらいました。
１回目はリクルートの転職エージェントに前職での成果や自己PRについてブラッシュアップしてもらいました。
２回目はよりIT業界向けのエントリーシートにするために、テックキャンプの方添削してもらいました。
プロの力を借りることでより見栄えの良いエントリーシートになります。私の場合、yahoo以外の全ての応募した企業で書類選考の通過をすることができました。

## 面接
必要なのは場数だと思います。
場数が必要な理由を、テックキャンプのキャリアアドバイザーの面接の練習をした時のお話を通して説明します。

ーーー
私はキャリアアドバイザーとは普段からよく話す間柄でした。自身のキャリアの方向性について一緒に考えていただき、IT業界について度々教えてもらい、気兼ねなく話せる仲です。ある日、面接練習をすることになりました。私にとって面接練習は、転職活動スタートするにあたって最後の確認みたいなものだと思っており、全く緊張していませんでした。しかし、面接がいざ始まると徐々に緊張し、深い質問をされると考えるのに必死になり、いつの間にか脇汗をびっしょりかいていました。加えて、回答の仕方も徐々に回りくどい言い方になり、簡潔さもなくなり、自分のリズムが崩れているのを自覚しているのにも関わらず、最後まで自信を軌道修正できずに面接練習が終わってしまいました。面接練習が終了後、キャリアアドバイザーからは「普段の話し方で全然良かったんですよ。なぜか皆さん面接練習となると緊張しちゃんですよね」と言われました。
ーーー

結構話したことがある人とでも、面接するとなると緊張します。緊張すると、普段通りのパフォーマンスを発揮できないことが多いです。つまり、面接の敵は緊張になります。緊張を解くには場数を踏み、慣れることが１番です。加えて、場数を踏むと自分の回答がブラッシュアップされていきます。自分の中で切り返しのパターンができると、急に難しい質問が来た場合でも冷静に対処することができるようになります。

他、緊張をほぐす際に効いた事
・面接時、自分から「緊張しています」と言う
・事前準備をしっかりする（⇨想定外の質問がきて、狼狽えたことがあるのでなんとも言えないかも）
・事前にしっかり寝る

## 面接を受ける順番
第１志望の企業を１番最初に受けるのはお勧めしません。理由は上記の面接で書いた通り、面接に慣れていないからです。
自身の志望企業を上中下に分けるとすると、まず面接に慣れるまでは下の企業で練習することをお勧めします。
次は自身がいつまでに就職したいのかによりますが、
・時間に制約がないのなら、面接に慣れた段階で上の企業⇨上の企業が全滅したら、また上の企業を探してトライを繰り返す。
・時間に制約があるのなら、上と中の企業を混ぜながら面接を進め、滑り止め企業を確保しながら上を目指す。
という方法がいいかもしれません。

# 就活時に苦労した点
### 中小企業の場合、調べても情報が全く見当たらない、または情報が古すぎる。
⇨逆質問で要点を聞くようにしていました。逆質問が多いと、採用側から見て、「今回の応募者、弊社にすごく興味がある」と思われるメリットがあります。一方で拙い質問をすると、評価が下がったりもするので要注意。
### どうしても面接で緊張する
⇨場数を踏んで慣れるのが手っ取り早いです。
### 行きたい企業からお祈りメール
⇨正直、めちゃくちゃ辛いです。飯が食えなくなります。ここから立ち直るのは不可能に思えますが、人間生きてればなんとかなります。私の場合、本命企業に落ちて、転職活動を初めからやり直すことにし、新しく真の本命企業に出会いそこに入社することが決定し、救われました。止まない雨はないと言うやつです。とりあえず、少しでもいいから無理にでも飯を食い、散歩し、眠り、友達に相談し、サウナに行き、次への活力を蓄えることをお勧めします。
### 転職活動をするのが不安
⇨とりあえず、面接練習なり、志望度合いの低い企業で面接体験をすることをお勧めします。失敗してもいい場所で、失敗するのは傷が浅く済見ます。そして、むしろ次どうすれば良いか考えるきっかけにもなり、転職活動に対して前向きになり得ます。

# 似た立場の人にアドバイスするなら
今までの話をまとめると
・面接は緊張するから、場数を踏むこと
・転職サイトは絞ること
・エントリーシートはプロの添削を利用すること

・加えて、企業に応募しすぎないこともお勧めします。
応募数が多くなるとスケジュールや体力管理が難しくなり、自身の体力キャパシティーをオーバーするからです。
転職スタート1週間目は5社に応募。
⇨様子を見て、書類選考通過率が悪ければ（良ければ）、翌週以降は応募数を増やす（減らす）。このように行動し、自身の転職市場における価値を見極めていくことが重要です。

・最後に、応募先企業に落ちて、落ち込むことがあるかもしれません。しかし、その原因は運の要素が大きいです。例えば、
ーーー
・たまたま、あなたより少しだけ評価の高い応募者がいた
・採用人数が１人だけ足りなかった
・他の候補者が面接の時だけ、たまたま実力以上の力を発揮した
・あなたは面接の時体調が悪く、普段の実力以下の力しか出せなかった
・その面接官とは相性が悪かった
・本来入社できたはずの企業が、自身が転職活動をしている間、採用をしていなかった。
　　　・
　　　・
　　　・
ーーー
あげればキリがないですが、現代の面接は運（ご縁）の要素がとても大きいです。改善点を見つけ、次に活かすことは大切なことですが、決して自分を責めないように。

何か聞きたいことがあればTwitterにDMください。@harukipow225
RcloneでmacOSとGoogle Driveのファイルを同期してみた

## Rcloneとは

[Rclone](https://rclone.org/) とは40を超えるクラウドストレージをコマンドラインから操作出来るツールです。
Go製のOSSでソースコードも公開されています。

[rclone/rclone: "rsync for cloud storage" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Yandex Files](https://github.com/rclone/rclone)

## サポートしているクラウドストレージ

サポートしているクラウドストレージの一例です。
メジャーどころは概ね抑えていそうです。

- Amazon S3
- Google Drive
- Google Cloud Storage
- Microsoft OneDrive
- …

[Supported providers](https://rclone.org/#providers)

## ローカルのmacOSとGoogle Driveを連携してみる

## 環境

macOS 11.6.2

今回はmacOSですが、rcloneさえ導入できればLinux等の別のOSでも利用出来ます。

### Rcloneのインストール

```bash
$ curl https://rclone.org/install.sh | sudo bash
$ rclone version
rclone v1.59.1
...
```

[https://rclone.org/downloads/#script-download-and-install](https://rclone.org/downloads/#script-download-and-install)

### クライアントIDの取得

**1 Google Drive APIの有効化**

- [Google Cloud Platformの管理画面](https://console.developers.google.com/)にアクセスする
- サイドバーの「APIとサービス」→「有効なAPIとサービス」→「ライブラリ」と遷移する
- APIの検索ボックスに`Google Drive API`と入力する
- Google Drive APIを有効化する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/0c51b3a0-2760-8a71-9518-91cbc39eb781.png)

**2 OAuth同意画面の設定**

- アプリ名を`rclone`にする
- ユーザーサポートメールとデベロッパーの連絡先情報に任意のメールアドレスを記入する

**3 OAuth2.0クライアントIDの作成**

- サイドバーの「認証情報」をクリックする
- 「+認証情報を作成」→「OAuthクライアントID」をクリックする
- client_idとclient_secretを控えておく

### Rcloneの初期設定

rcloneの初期設定を行うには`rclone config`コマンドを利用する。
対話型で設定をしていく中で`client_id`と`client_secret`は上記で控えたものを利用する。

詳細は[ドキュメント](https://rclone.org/drive/)を参考にしてください。

## コマンド

### Google Driveのファイル一覧を表示する

```bash
$ rclone ls remote:path

# 例
$ rclone ls google_drive:rclone_test
-1 テストドキュメント.docx
```

[rclone ls](https://rclone.org/commands/rclone_ls/)

### ローカルのファイルをGoogle Driveにコピーする

```bash
$ rclone copy source:path dest:path

# 例
$ rclone copy test.txt google_drive:rclone_test
```

ディレクトリ指定で複数ファイルのコピーも可能。

```bash
$ ls
test.txt   test2.txt  test3.txt

# test.txt, test2.txt, test3.txtがGoogle Driveにコピーされる
$ rclone copy ./ google_drive:rclone_test
```

同じファイルは重複してコピーしないようになっている。（サイズと変更時間またはMD5SUMで検証している。）

ローカルのファイルに適当な修正を加えたあとに再コピーを行うとGoogle Drive側のファイルも更新される。

```bash
$ vim test.txt
$ rclone copy test.txt google_drive:rclone_test
```

バージョン管理も行われていた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/88f88087-2ef5-60c0-5703-c3f6715f19d9.png)

[rclone copy](https://rclone.org/commands/rclone_copy/)

### Google Driveのファイルをローカルに同期する

```bash
$ rclone sync source:path dest:path

# 例
$ ls
test.txt   test2.txt  test3.txt
$ rclone sync ./ google_drive:rclone_test
```

source（ローカル）の状態に合わせてリモート（Google Drive）のファイルが同期される。

**実行前**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/8d75a8e6-49f8-e0c7-a1b7-1ae01e7d57bd.png)


**実行後**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/6cd5d18c-1364-efff-8136-0ec3568a4053.png)


[rclone sync](https://rclone.org/commands/rclone_sync/)

## 最後に

今回はGoogle Driveのマイドライブを対象に同期を行いましたが、共有ドライブに対しても実行可能です。

検証が出来たらまた記事をまとめてみようと思います。

以上です。
CircleCIの設定ファイルメモ


GitHub Actionsがリポジトリに変更がないと60日ほどで止まってしまう問題で引っかかってしまったので代替策を検討しています。


最近使ってるCircleCIでは無料でもそういった制限はなさそうなので`.circleci/config.yml`をメモっておきます。


```yml
# This config is equivalent to both the '.circleci/extended/orb-free.yml' and the base '.circleci/config.yml'
version: 2.1

# Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.
# See: https://circleci.com/docs/2.0/orb-intro/
orbs:
  node: circleci/node@5.0.2

jobs:
  start: # 普通のテスト
    docker:
      - image: node:18
    steps:
      - checkout
      - run: yarn install
      - run: yarn start

# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
  normal_workflow:
    triggers:
      - schedule:
          # Every day, 0421Z.
          cron: "35 * * * *"
          filters:
            branches:
              only:
                - main
    jobs:
      - start

  # sample: # This is the name of the workflow, feel free to change it to better match your workflow.
  #   # Inside the workflow, you define the jobs you want to run.
  #   jobs:
  #     - node/test:
  #         # This is the node version to use for the `cimg/node` tag
  #         # Relevant tags can be found on the CircleCI Developer Hub
  #         # https://circleci.com/developer/images/image/cimg/node
  #         version: '16.10'
  #         # If you are using yarn, change the line below from "npm" to "yarn"
  #         pkg-manager: npm

```

これで毎時35分に実行されます。
Vue.jsのCDNを利用して、PHPを使わずにファイルのコンポーネント化してみた。

複数ページにまたがるサイトの場合、
ヘッダーやフッターなどのコンポーネント化（同じパーツを共通化）したいなーと思うときがあります。

そのときに、PHPだと`include("ファイル名")`でファイルを別に出来ますが、
PHPが使えない方法だと、ちょっと面倒です。

今回は、PHPが使えない場合、Javascriptだけでコンポーネント化する方法があります。

# jQueryのajaxを使う方法

ajaxはAPI取得などの外部ファイルの読み込みに使うイメージが強いと思いますが、実は同じサーバー内のHTMLファイルを読み込むことも可能です。
javascriptとして
```javascript:index.html
function header(){
    $.ajax({
        url: "header.html",
        cache: false,
        success: function(html){
            document.write(html);
        }
    });
}
```
を記載し、HTML部分には
```html:index.html
<script>header();</script>
```
を記載すると、共通化できるそうです。
ただ、設置の階層によってパスが変わることはないので、
CSSなどを相対パスにしている場合は別途調整が必要そうです。

## 参考
https://qiita.com/hiroyukiwk/items/f2a74ba1406de9fad6f6

# 個人的にはVue.jsを使う方法がおすすめ！
ヘッダーとフッターのみでしたらjQueryのやり方でも支障ありませんが、
いっぱいあると管理が大変になりますよね。
その時におすすめなのが、Vue.jsを使う方法です！

Vue.jsでコンポーネントを扱うにはVue CLIを使う方法が一般的ですが、
設定したりする負担を考えると、気軽に作りにくくなりますよね...
その時に使うのが「http-vue-loader」です。

## CDNを読み込ませる
まずは、VueのCDNとhttp-vue-loaderのCDNを設置します。
```HTML:index.html
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <script src="https://unpkg.com/http-vue-loader"></script>
```

## Javascriptを設定する
CDNを設置したら、Javascriptを書きます。
```javascript:index.html
    new Vue({
        el: '#app',
        components: {
            'component-name': httpVueLoader('component.vue'),
        },
    })
```
`'component-name'`→ コンポーネントを設置するのに指定するタグ名
`httpVueLoader('component.vue')`→`component.vue`を読み込む
といった意味になります。

複数設置する場合は、
```javascript
    components: {
        'component-name': httpVueLoader('component.vue'),
        'component-name2': httpVueLoader('component2.vue')
    },
```
といった感じで、カンマでつなげて設定します。

## HTMLを設定する
先程書いたVueに従って書いていきます。
IDにappを指定し、指定したコンポーネント名(component-name)をタグとして設置します。
```html:index.html
<main id="app">
    <component-name></component-name>
    ...
</main>
```

コンポーネント化として別にしたファイルは、`<template>`というタグを作成し、その中でパーツを作成します。
ちなみに、`<template>`タグの直下に複数設置は出来ないようなので、1つに囲うか別コンポーネントにする必要がありそうです。
```html:component.vue
<template>
   <タグ>
        ...
   </タグ>
</template>
```

# jQueryと一緒に使いたい場合
jQueryのプラグインなどを使いたいときもあるかと思います。
Vue.jsはjQueryと一緒に使えますが、記載する場所がとても大事です。

Vueには[ライフサイクル](https://qiita.com/ksh-fthr/items/2a9f173c706ef6939f93)という概念がありまして、実行したいタイミングにより、書く場所が変わってきます。

https://qiita.com/ksh-fthr/items/2a9f173c706ef6939f93

例えば、

> Vue.jsでHTMLを一通り作成 → jQueryで動きを指定する

という流れで利用したい場合、Vue.jsの下に記載しても動いてくれません。
その場合は`updated:function(){...}`の中に記載することで動いてくれます。

```javascript
new Vue({
    el: '#app',
    components: {
        'component-name': httpVueLoader('component.vue'),
    },
    updated: function() {
        $('#abc').addClass('.efg');
    }
})
```

慣れるまでは大変ですが、逆に慣れてしまえばどのタイミングにどのようなスクリプトが動くのかが分かりやすいので、jQuery単体よりも見やすいと思います
【Tableau Data Saber挑戦記】しくじり先生！俺みたいになるな　～コミュニティ活動での失敗談～

（この記事を書いたのは8月のはじめです。）

この記事を書いている今、来週に最終試験を控えた中でそれを受けられるかどうかの瀬戸際に私は立たされている…

技術試練をクリアし、コミュニティ活動も達成した（正確にはその”つもり”でいただけだった…）

それにもかかわず、、、

今回はそうなってしまった経緯などについて自身の経験も多分に踏まえてお伝えできたらと思っています。

# 事の発端
技術試練やコミュニティ活動も終え、最終試験対策を行う段階に入った7月下旬。90日間の期間で、あと10日ほど残っている状況になりました。なのでそれまでに最終試験に合格する必要があります。

社内のData Saber2期生は20人ほどが参加し、多いため、いくつかのグループに分かれて週1でディスカッションしたりしているのですが、そのなかでの出来事。

メンバーのひとりと最終試験対策の課題やコミュニティ活動の進捗について話していて、自分の行なった活動について聞かれたのですが…

自分「ブログ記事投稿や情報共有で対応しました」

メンバー「そうなんですね。師匠にはもう見てもらっているのですか？」

自分「…ん？　え？見てもらっていないですが許可が必要なものなのですか？」

メンバー「そうみたいですよ」

自分「えっ…？」


# コミュニティ活動で実施したこと
自分がそれまでに実施したコミュニティ活動は以下です。
【パブリック】
ブログ記事投稿：3回で10pt
conpassでユーザー会開催：2回で20pt
【組織内】
情報共有：6回で20pt
トータルで50pt以上達成

とりあえず実施したあと、フォームに内容を入力してそれで終わりだと思っていました。

# まさかの結果に…
取り急ぎ過去行なった活動の証跡（URL）とかスクショとかを集めて師匠に提示しました。
が、「conpassでユーザー会開催」がNGとなりました。
そのため、ここに来て急遽この記事を書いたりドタバタしているという経緯になります…

# 原因
## コミュニティ活動の要件を正しく理解できていなかった
「conpassでユーザー会開催」の要件ですが、
”Tableauユーザー会として認知されている”というところが満たせていなかったようです。
自分の場合は普通に個人的にconpassで公開して集まった人ともくもく会する、みたいな感じだったのでそれでNGとなりました。
これがちゃんと理解できていればそもそも何も問題にならなかった…

ちゃんと師匠がコミュニティで流している情報をちゃんとキャッチアップして理解していればよかっただけのこと。ちゃんと活動していれば自分のようなことにはならないと思います。（なのでこれは特殊な例だとは思います。他の方でそういうことにはなっていないです。）



# これから始める方へ伝えたいこと
実際にどうすればよかったのかということを記載しておきます。これからはじめようとする方のご参考になれば嬉しいです。

## はじめに師匠に相談すべし
これが一番だと思います。
このプログラムは素晴らしいと思うものの、コミュニティ活動の要件やらルールやら若干複雑です。そのため序盤に師匠に相談し、決めて、実行までしてしまったたほうが後々最終試験に時間を当てられるので非常に良いかと思います。（自分も序盤で片付けるという意味ではそうだったのですが…）
また、さらにいえば、エントリーする前から自分にはどの活動ができそうかをある程度見通しを立ててから参加するかどうかを決めたほうが良いと思います。


## できれば最初からExplorer以上のライセンスで分析できる環境があることが望ましい
これもエントリー前に制約をなくしておくということで重要だと思います。viewerライセンスでは先述の通り、社内のデータを使えませんのでそうするとコミュニティ活動で実施できる項目に制約が生じてしまいます。特に「分析案件実施」は30ptとポイントも高く一発で組織内ポイントをクリアできるすごいやつなのでこれはかなりでかいことだと思います。
反対にブログや情報共有は3回実施して10ptだったり、イベント開催も他の挑戦者と共同で行うと人数で割る形になるのでポイントが薄まってしまったりというのはあります。
ですので先の話とかぶりますが、制約を踏まえて最初の段階で何ができそうかを考えておくことが望ましいでしょう。

## 時間的制約もできるだけなくそう
これも非常に重要です。
実際に仕事が繁忙期で忙しさを理由に脱落する挑戦者もいました。正式に脱落を表明していなくても実質的にこれはもう無理だろうな…というメンバーも少なくとも5名以上はいました。課題をクリアできていても、期間的に今瀬戸際の人もそれ以上に多く居ます。
なので公私問わず忙しい時期に入るというのがわかっている方は、一旦考えたほうがいいと思います。
あと、時間的制約ということでいうと「忙しさ」だけでなく「自分が費やせる時間」という意味での制約もあると思います。他の社員さんは業務時間内でもがっつり勉強に回したりイベント企画したり師匠との質問会に使えたりというのがありましたが、自分はそうはいかず、朝や夜、土日などの自分の私的な可処分時間をいかに費やせるかというところで対応してきました。なんだかんだでこれまで技術試練とコミュニティ活動合わせて90時間以上は使っています。もちろん、チャットのやりとりやら質問やらイベントへの参加やら、これ以外にもカウントされていない時間も合わせたら多分100時間は余裕で超えている気がします。
そういった膨大な時間を費やすことを考えたら完全に私的な時間だけで対応しなければならないのに比べれば、業務時間も使えたほうがお得なわけでそういう意味での制約も意識しておいたほうがいいと思います。

## 仲間とのコミュニケーションで助けられた
自分はこれに助けられました。先述の通り、他のメンバーに気付かさせてもらっていなかったら多分普通にドロップアウトしていたでしょう。本当にありがたい。そういう意味では情報交換できるメンバーがいるというのはかなり重要だと実感しました。

## ブログは継続しておけばよかった
これは余談的な話ですが、ブログ投稿は続けておけばよかったなと今振り返って思います。そうすれば、ユーザー会開催でNGとなったとしてもそっちでリカバリーできたなと。
ブログは4週間以内に3投稿で10pt認められるってことで期間と本数の条件が決まっているので当初その点を踏まえて週1本は投稿するようにしていました。これをずっと継続していたら…と今更ながら思います（苦笑）

# 終わりに
長々と書きましたが、プログラムの仕組みとかルールとか実情について自身の反省も踏まえて結構詳しくかけたのではないかなと自分では思っております。
駄文ではございますが、これがData Saber目指す皆様の一助になればこの上ない限りです。

以上、お粗末さまでした。


# 【Tableau Data Saber挑戦記】の最初の記事はこちら
こちらもぜひ

[【Tableau Data Saber挑戦記】1. はじめます](https://qiita.com/hetare/items/d55a7dda34f3b0e9073b)

https://qiita.com/hetare/items/d55a7dda34f3b0e9073b
deta.shのBaseにある予約データ__expiresに関しての注意点

## 結論
* putなどのメソッドにあるoptionでexpireInの指定をした場合登録される相対時間はサーバーの時間でなく、ローカルの時間。
  そのため、実際に削除される時間は想定よりサーバー時間とローカル時間のずれ分ずれてしまう
* put、putMany、insertはデータフィールドとoptionでexpireInを指定した場合、optionが優先される
* updateの場合、
    * set operationで__expiresを指定した場合、データフィールドが優先されてしまう
    * increment operationで__expiresを指定した場合、重複のデータを変更しようとするエラーが発生する

## やったこと
Deta Baseの予約データ__expiresに関してJavaScriptで検証を行いました。
確認したdetaのバージョンは以下の通りです。
```
"dependencies": {
  "deta": "^1.1.0"
}
```

## Deta Baseとは
Deta Baseとは[deta.sh](https://www.deta.sh/)のサービスのひとつです。
データを格納することができ、NoSQLデータベースの一種です。

## 予約データ__expiresとは
Deta Baseのデータを保持する期限です。
Unixタイム時間で管理されており、超えると自動で削除されます。
データを設定する際にoptionとして設定できます。

## 検証
各章は、実行コード、結果の順に記載していきます。
### データフィールドとexpireInオプションを同時に設定した場合
```
db.put(
  {
    __expires: 1000,
  },
  "data1",
  { expireIn: 100 }
);
```
__expiresにはopttionで指定した時間が設定されていました。
putMany、insertも同様。

### option設定したときに設定される時間はサーバの時間か、ローカルの時間か
```
db.put(
  {
    __expires: Date.now() / 1000 + 60,
  },
  "data2"
);

db.put(
  {
    data: "data",
  },
  "data3",
  { expireIn: 60 }
);
```
同じ__expiresが登録されました。
option指定してもローカル時間で登録される模様。

### updateのset operationで__expiresをセットした場合
```
{
  const { __expires } = await db.put(
    {
      __expires: "data",
    },
    "data",
    { expireIn: 600 }
  );
  // putした時の時間:1663328394
  console.log(__expires);
}
{
  const updates = {
    __expires: Date.now() / 1000 + 200,  // 200秒後なので相対的に400秒早い
  };
  await db.update(updates, "data", { expireIn: 600 });
  const { __expires } = await db.get("data");
  // updateした時の時間:1663327994
  console.log(__expires);
}
```
putした後の時間`1663328394`からupdateした後の時間`1663327994`でちょうど400小さくなっている。

### updateのincrement operationで__expiresをセットした場合
```
const updates = {
  __expires: db.util.increment(1000),
};

db.update(updates, "data", { expireIn: 600 });
```
例外発生
```
/home/path/to/projet/node_modules/deta/dist/index.js:187
                                error: new Error(message),
                                       ^
Error: Bad request: Conflicting operations on common attribute(s)
```

## まとめ
予約データの__expiresをユーザーが直接いじるのは、悪意があるのでおいておくにしても、
expireInで登録される時間が、サーバー時間でなくローカル時間なのは罠だと思います。

## おまけ
### データフィールドに__expiresを現在でセットした場合
```
db.put(
  {
    __expires: Date.now() / 1000,
  },
  "data"
);
```
確認される前に削除されていました。
自分でもきちんと設定できる模様。

### データフィールドの__expiresをStringにした場合
#### 実行コード
```
db.put(
  {
    __expires: "data",
  },
  "data"
);
```
例外発生
```
/home/path/to/project/node_modules/deta/dist/index.js:187
                                error: new Error(message),
                                       ^
Error: Bad expiration timestamp
```
階段滑り止めで高コスパ簡易PCスタンド

# 理想のPCスタンドを探し求めて

ノートPCに角度をつけて設置するためのPCスタンドを探していたのですが、市販のものにはどうも求める機能とコスパに合うものがなかなか見つかりませんでした。
しかし、ホームセンターなんかで売っている階段滑り止めが簡易PCスタンドとしてとっても優秀なことを発見したのでご紹介。

## 「階段滑り止め」とは？

階段の段々の角部分に貼り付ける細長いゴム製の滑り止めです。階段昇降時に、足を滑らせて階段を踏み外してしまうのを防止するための事故防止グッズの一種で、今回使用するのは階段の90度角になった部分に粘着剤で固定するタイプです。

## 簡易PCスタンドとしての使用方法

__注意__ 以下、製品の本来の使用用途と違うので、使用は自己責任でお願いします。

1. ホームセンターなどで階段滑り止めをバラで1本買ってきます。ただし、滑り止めは以下の要件を満たしていること。
    + ゴム部分が90度に折れたものであること。(階段の90度角とフィットさせて使用する製品)
    + ゴムの強度が十分あること。(ノートPCを載せると潰れてしまうほど弱いものは不可)

   私が使用しているのは川口技研[スベラーズ](https://www.kawaguchigiken.co.jp/products/safety/%E3%82%B9%E3%83%99%E3%83%A9%E3%83%BC%E3%82%BA%E5%AE%A4%E5%86%85%E7%94%A8-2) です。

1. そのままでは長すぎるのでお好みの長さ(ノートPCの横幅かもう少し長い程度)にカットします。
    - 滑り止め貼り付け用の粘着面の剥離紙を剥がしてしまわないように注意。
    - ゴムは結構固めなのでしっかりしたカッターナイフで作業したほうがよいでしょう。
1. 平らなデスク上、横水平に、カットした滑り止めを山型に置く。(剥離紙の貼ってある面を下向きに)
![78342FF8-CCD5-4A07-B7DF-B5008051F632_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847838/53d7a2ab-8ece-2a06-edfa-10403c1d8927.jpeg)

1. ノートPCの底面向こう側(手元より遠い側)を滑り止めの上に載せる。設置終了!
![02BD931F-D929-49F0-B136-7A8B4E717AE4_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847838/525084da-e857-2efc-6daf-a11260a8c07b.jpeg)

    - 通気孔を塞がないように。また、底面向こう側ギリギリに載せるとPCによってはヒンジに負荷がかかるかもしれないのでうまく調整のこと。 


## 階段滑り止めPCスタンドの良いところ

1. 安い!
バラ売り670mm製品1本で数百円程度です。長いので2台分はとれるでしょう。どこかで紛失したとしてもダメージは大きくありません。勤務先・自宅用とおいて置くのでもよいでしょう。
1. 軽い! 機動力抜群!!
1本120gなので、2本どりして60g程度。金属製の製品と比べると超軽量です。持って歩くのもそれほどかさばらず、苦になりません。
1. 長さ調整自由
自分のノートPCのサイズに合わせてぴったりサイズに調整できます。
1. 光る!?
もともと夜間の階段事故防止のための蓄光性ラインが入っていて、暗いところでぼうっと光ります。(これが役に立つかどうかはわかりませんが。)


## 階段滑り止めPCスタンドの短所

1. 設置スタイルに制限
デスク上に、PCを少しだけ角度をつけて置くことしかできません。デスク面から浮かせて設置することは当然できません。角度もほぼ固定です。
1. 設置場所に制限
デスク面に平らな空き場所があることが前提です。(狭い・不安定な場所ではPC落下等の可能性があるので気をつけましょう。)
1. デザイン
滑り止めのために凹凸が付けられています。これのデザイン的な良し悪しの評価は人それぞれでしょう。

## まとめ

ただ単に角度をつけるためのPCスタンドとして使うのであれば、コスパ最高かつ使い勝手も良いのではないでしょうか。
個人的には、M1 Macbook Airの筐体がアルミ切り出しのため、水平使用だと角が手首に当たって痛くてしょうがなかったのが、これで角度をつけるようにしてからその悩みが解消されました。
Pythonでディレクトリを読み込んで階層をJSON化。Directory to json with Python.

## Pythonでディレクトリを読み込んで階層をJSON化
## Directory to json with Python.

このような構造のディレクトリを読み込んで、
```
D:\DIR
│  file01.txt
│  file02.txt
│
├─dir01
│  │  file01.txt
│  │  file02.txt
│  │  file03.txt
│  │
│  └─dir01
│          file01.txt
│
└─dir02
        file01.txt
        file02.txt
```
以下のようなJSONにします。
```json:json
[
    {
        "label": "dir01",
        "path": "D:\\dir\\dir01",
        "children": [
            {
                "label": "dir01",
                "path": "D:\\dir\\dir01\\dir01",
                "children": [
                    {
                        "label": "file01.txt",
                        "path": "D:\\dir\\dir01\\dir01\\file01.txt"
                    }
                ]
            },
            {
                "label": "file01.txt",
                "path": "D:\\dir\\dir01\\file01.txt"
            },
            {
                "label": "file02.txt",
                "path": "D:\\dir\\dir01\\file02.txt"
            },
            {
                "label": "file03.txt",
                "path": "D:\\dir\\dir01\\file03.txt"
            }
        ]
    },
    {
        "label": "dir02",
        "path": "D:\\dir\\dir02",
        "children": [
            {
                "label": "file01.txt",
                "path": "D:\\dir\\dir02\\file01.txt"
            },
            {
                "label": "file02.txt",
                "path": "D:\\dir\\dir02\\file02.txt"
            }
        ]
    },
    {
        "label": "file01.txt",
        "path": "D:\\dir\\file01.txt"
    },
    {
        "label": "file02.txt",
        "path": "D:\\dir\\file02.txt"
    }
]
```
```Python:Python
import os
import re

targetDir="D:\\dir"
_count =0
def dirToJson(path) :
    global _count
    array = []
    files = os.listdir(path)
    files = sorted( files )
    for f in files:
        if f[0] !='.': #ドットで始まるファイルは読み込まない
            _count=_count+1
            fp=os.path.join(path, f)
            array.append('{"label":"' + f + '"')
            array.append('"path":"' + re.sub(r'\\', "\\\\\\\\",fp) + '"')
            if  not os.path.isfile(fp):
                fp=re.sub(r'\\', "\\\\",fp)
                array.append('"children":[' + dirToJson(fp) +']')
            array.append("}")
            
            if (_count >= 1000) : #読み込み制限
                break

    result = ",".join(array)
    return  re.sub(r',}', "}", result)
                 
result=dirToJson(targetDir)
jsonDir = "["+result+"]"

print(jsonDir)

```
SwiftUIでFirebaseを使うためには

# Firebaseの公式スタートガイドがわかりずらい
Firebaseの公式をディスっている訳ではありませんが、この記事に辿り着く人は少なからずそう思った人かと思います。
少なくとも私はそう感じていて、スマホで見るとページが重い、翻訳したからかわからないけど文章がわかりづらい、仕舞いには情報が遅れていると知った日には椅子からひっくり返りました。
私自身Swiftの勉強を始めたばかりで調べながらとなりますので、間違った情報がないとは言い切れませんが、優しく指摘していただけると幸いです。
# AppDelegate.swiftとViewController
スタートガイドを読んでいると、必ず目にするこのワード。SwiftUIを勉強中の皆様には何のこっちゃわからないでしょう。
これが何かというと旧バージョンにあったものか、Storyboardにあるものかのどちらかと思われます。
現バージョンのSwiftUIを使っている皆様がどう扱ったらいいのかご説明します。
<プロジェクト名>App.Swift内

     class AppDelegate: UIResponder,UIApplicationDelegate {
      func application(_ application: UIApplication,
                       didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        //ここに記載
        return true
      }

AppDelegateがないなら作ればいいじゃない。
AppDelegateというクラスを<プロジェクト名>App.Swift内内に作り、スタートガイドの記述をその中に記載します。これで同じ挙動をするという訳です。
もちろんimportは別です。クラスの外に記述します。
このような書き方は調べていると他の方が何の説明もなしにやっているので、常識かもしれません。

## じゃあViewControllerは？
これは簡単、ContentView.swiftのこと・・・というか、お好きな.swiftにどうぞ。
ただし、　var body: some View {　　の中にいれます。

#### 以上となります。
自分がSwiftUIを勉強する中で知ったこと、実装方法はメモがてら記事にしていきます。
初心者なので基本的なことばかりになると思います。
FlutterでAndroidの通知チャンネルを作成する

# 概要
通知チャンネルをFlutterで作成する方法を記載します。
通知チャンネルについては[こちら](https://developer.android.com/guide/topics/ui/notifiers/notifications?hl=ja#ManageChannels)。
[flutter_local_notification](https://pub.dev/packages/flutter_local_notifications)というパッケージを使用します。

# プラグインの初期化処理
プロジェクトのmain関数内に以下の処理を追加します。

```dart
final FlutterLocalNotificationPlugin notificationPlugin =
　　　　FlutterLocalNotificationPlugin();
await notificationPlugin.initialize(
  InitializationSettings(
　　   android: AndroidInitializationSettings('app_icon')),
);
```

AndroidInitializationSettingsの引数にアイコン（プッシュ通知のバナーに表示される）の指定が必須になっています。※ここでは'app_icon'としている
指定したアイコンはflutter_local_notificationのプラグインを使って通知を表示する場合に使われるので、必要に応じて設定を変更します。
任意で指定できる項目が他にもありますがここでは省略します。
iOSにも対応する場合はIOSInitializationSettingsの初期化が必要になります。

# プッシュ通知を受け取った際の処理
プッシュ通知を受け取った後のハンドリング処理に以下の処理を追加します。

```dart
final channelId = '1';
final channelName = 'SampleNotification';

final AndroidNotificationChannel channel = AndroidNotificationChannel(
  channelId,
  channelName,
);
await notificationsPlugin
    .resolvePlatformSpecificImplementation<
        AndroidFlutterLocalNotificationsPlugin>()
    ?.createNotificationChannel(channel);
```

channelIdやchannelNameは受け取ったプッシュの種類などに応じて変更します。
再チャレンジ！　「自社の記事・ツイートを自動検知し、炎上を防げるか？」

前回、『自社に関するニュースやSNS上のツイートを定期的に抽出して、
ネガティブな情報・誤った内容を検知することはできないか？』
にチャレンジしてみましたが、敢えなく撃沈しました。

前回のチャレンジはこちら
https://qiita.com/ak-ishi/items/39112287f6f815e234e4

あの後、改めて考えてみましたが、ふとGoogleのサービスをあれこれ
覗いてみたところ、Google アラートの機能が使えるのではないか？
ということに思い至りました。

そこで今回は前回とはやり方を変えて、ノーコード開発ツールの「Make」
と、Google アラートを組み合わせてスプレッドシートに出力する方式で
再チャレンジしてみたいと思います。

## １．今回使用するツール
・Make
・Google スプレッドシート
・Google アラート

## ２．イメージ
　Google アラートに事前にキーワードを登録し、抽出されたデータを
　スプレッドシートに書き出すというものです。

## ３．シナリオ作成
### ①　出力先のスプレッドシートを作成
　まずは、抽出した結果を出力するスプレッドシートを作成しておきます。
![２.スプレッドシートに検索結果を出力する準備.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/e617900b-ed6c-e05d-1755-40ceb99e48f9.png)

### ②　Googleアラートを設定
　本当は会社名などを登録するところですが、今回は「コロナ」で検索して
　みたいと思います。
![１.Googleアラート設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/bc912c39-46af-b69d-4720-8ca6d2c14a72.png)

　ここで配信先を「RSSフィード」にするところがポイントです。

### ③　「コロナ」のアラートよりRSSのURLをコピーしておきます。
![３.RSS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/59c56f27-f52d-f556-0114-df3abfced151.png)


### ④　ここからMakeでシナリオ作成に入ります。
　今回はGoogle アラートでRSSを取得し、Google スプレッドシートに書き出す
　という流れです。
![４.Makeでシナリオ作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/b1212f1c-d33c-4eec-0339-71011160cc10.png)

### ⑤　RSSのモジュール
　先ほどコピーしたURLをここに張ります。
![５.RSSを見に行くモジュール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/ea9ee3e6-d94b-252a-58f6-836abc12cbca.png)

　今回は20回実行してみることにします。

### ⑥　スプレッドシートに出力するモジュール
　①で作成したシートを出力先として指定し、項目も適当に選定します。
![６.スプレッドシートにアラートで抽出された情報を出力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/fa57e065-7a12-36cf-2271-ac70bfb541b9.png)

## ４．実行
　シナリオができたところで、さっそく実行してみます。
![７.実行.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/1ea2917a-a1d0-d8fe-bc97-1e80633503f7.png)
　さきほどの設定どおり、20件出力された模様です。
　では結果を見てみましょう。
![８.結果出力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802665/f5be3e88-9a66-c685-2fd6-6e24b42ee75b.png)

　上位20件の記事が出力されました。
　前回よりも、頭に描いたイメージに近いものができました！

## ５．今後の対応について

　前回、Googleで検索した結果がうまく出力できなかったのに比べると、
　今回は出力イメージはほぼ思ったとおりになったかと思います。

　あとは、このアプリを毎日定期的に実行されるようタイマーでセット
　する方法と、出力された記事やツイートがポジティブかネガティブかを
　判定する方法を考えてみたいと思います。
　ここまでくるとAIの出番になるのでしょうか？
　だんだんハードルが上がってきましたが、もう少し頑張ってみたいと
　思います。
react-draft-wysiwyg  html読み込み時に画像が📷になってしまう。

# カメラになっちゃう。。
画像挿入時は、表示されているが次回読み込み時にカメラになっちゃう。
![スクリーンショット 2022-09-16 19.32.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/957847/1b5bd7a0-011d-eb49-f6af-75174aa191f7.png)

## 解決
バックエンドのデータ(html)を EditorState　へ変更するときに、
```convertFromHTML``` でなく、 ```htmlToDraft```　を利用することで解決した。

:::note info
htmlToDraft は、<a href="https://www.npmjs.com/package/html-to-draftjs">こちら</a>
:::

--- 

### before
```ts
const conv = convertFromHTML(contents);

const contentState = ContentState.createFromBlockArray(
  conv.contentBlocks,
  conv.entityMap,
);
const data = EditorState.createWithContent(contentState);

const [val, setVal] = useState(data)
```
### after
```ts
const conv = htmlToDraft(contents); // 変更

const contentState = ContentState.createFromBlockArray(
  conv.contentBlocks,
  conv.entityMap,
);
const data = EditorState.createWithContent(contentState);

const [val, setVal] = useState(data)
```

## 参考
https://github.com/jpuri/react-draft-wysiwyg/issues/849#issuecomment-511862368
AWSにEC2（Ubuntu 22.04）を立ててJanusを使おう

### EC2の準備
EC2を起動する画面で、AMIにUbuntuを選択。
![スクリーンショット 2022-09-15 13.58.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/63e79b2d-c782-664a-80f6-f83be16fd4c6.jpeg)

ネットワーク設定ではSSH接続できるように「パブリックIPの自動割り当て」を有効化しておく。
git cloneや通話をするために使うのでセキュリティグループのインバウンドルールでHTTPSやHTTPも適宜許可しておく。
またJanusで通話をする際はセキュリティグループのインバウンドルールでポート8088を開放しておく。

SSH接続用にキーペアを作るのもお忘れなく。

無事にインスタンスが起動したらSSHで接続する。

---
### パッケージをインストールする前の下準備
```
$ sudo apt update
```

### 必要なパッケージをインストール
```
$ sudo apt install libmicrohttpd-dev libjansson-dev libnice-dev \
libssl-dev libsofia-sip-ua-dev libglib2.0-dev libopus-dev \
libogg-dev libcurl4-openssl-dev pkg-config gengetopt libtool automake
```

libsrtpはapt installで取得できないのでwgetで準備
```
$ wget https://github.com/cisco/libsrtp/archive/v2.4.2.tar.gz
$ tar xfv v2.4.2.tar.gz
$ cd libsrtp-2.4.2/
$ sudo apt install build-essential
$ ./configure --prefix=/usr --enable-openssl
$ make shared_library && sudo make install
```

### Janusの準備
```
$ cd ~
$ git clone https://github.com/meetecho/janus-gateway.git
$ cd janus-gateway/
$ sudo apt install autoconf  //sh autogen.shを叩くのに必要
＄ sh autogen.sh
$ sudo apt install libconfig-dev
$ sudo apt install libavutil-dev libavformat-dev
$ sudo ./configure --enable-post-processing --prefix=/opt/janus
$ sudo git config --global --add safe.directory /home/ubuntu/janus-gateway
$ sudo make
$ sudo make install
$ sudo make configs
```
### Janusの起動

```
$ cd /opt/janus
$ sudo ./bin/janus
```
[ServiceNow]メンバー編集画面にデフォルトでフィルターを設定したい

## はじめに
こんにちは！
久しぶりの投稿です！ゆっくりしていってね！

## 実装環境
ServiceNow バージョン：San Diego

## やりたいこと
メンバー編集画面(左右にぽこぽこするやつ)に、デフォルトで絞り込みをかけたい！
何も設定していない状態だと・・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/6b8061d3-b131-cb31-0211-cc50db512aaa.png)
空っぽ！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/b75e94ce-2123-9d49-6765-2aff7d93e0b1.png)

## 設定内容
早速やってみます！
リストコントロールを開いてー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/ab929a40-c040-8cdf-8a97-b774cdd9c904.png)
フォームデザインを開いてー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/c764b8ed-541b-057b-388c-9fce82e02bd8.png)
デフォルトのフィルターを編集を配置するよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/db146c76-831c-9568-7760-6f09ed220a27.png)
そしたら、リストコントロールに戻って、先ほど配置したフィルター項目を指定するよ
※保存時に「Omit edit button(編集ボタン省略)」は外してね
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/3068d030-432b-86dc-c689-01676b67d8b0.png)
メンバー編集画面を開くと・・・・指定したフィルターが表示されてる！！
やったね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/2cf67c6b-4fcc-5dcb-c5ee-de346e6c4cde.png)

## おわり
他の関連リストにも同じようにデフォルトフィルターかけれるので、
みんなもやってみてね！
【SwiftUI】関数の引数でBindingをとる方法

# 方法
```swift
func showModal(isPresented: Binding<Bool>) {
    isPresented.wrappedValue = true
}
```

:::note info
**型名**
`Binding<型名>`
:::

:::note info
**値の変更方法**
`wrappedValue`で元の値を取得する事ができます。
:::

# おわり
忘れたとき用にメモです
react-draft-wysiwyg で画像を入れた後に文字入力するとエラーになる

# エラー
react-draft-wysiwyg で画像を入れた後に文字入力するとエラーになる

エラーの表記は、下記のようになっていた。
```
Unknown DraftEntity key: null.
```

## 解決
draft-js のバージョンの問題だった。
0.11.* ではこのバグが発生するみたい。

### 0.11.* から 0.10.* に変更することで解決した。
```sh
npm i draft-js@^0.10
```

### 参考
公式ドキュメントにも 0.10 系が必要と書いてあった。

https://jpuri.github.io/react-draft-wysiwyg/#/docs


https://github.com/jpuri/react-draft-wysiwyg/issues/609#issuecomment-560334518
ASP.NET Coreの認証と認可でポリシー・ベースかつCookie認証を使用するwithout Identity.

# この記事の目的
ASP.NET CoreでWebアプリを作成中に認証と認可の仕組みが必要になった。
Cookieで認証情報（ClaimPrincipalと呼ばれるクラス）をクライアントへ渡すAPIを作る公式ドキュメントはある。
ポリシー（要件と認可のハンドラーのセット）・ベースの認可の仕組みを作る公式ドキュメントはある。
しかし、二つを繋ぐドキュメントが見当たらないので、メモしておく。
誰かの役に立てば幸い。

大部分の綺麗なコードは公式ドキュメントを見てほしい。
以下のコードはポイントになりそうな部分を抜粋した。

# メモ程度のコード
Program.csで初期化処理時に認可ポリシーを定義して、プログラムに登録する。
「認証スキームにはCookieAuthenticationDefaults.AuthenticationSchemeを使用するということ」を認可ポリシービルダー(AuthorizationPolicyBuilder policy)にAddAuthenticationSchemesで知らせている。
これは推測だが、認可側のエンジンに「ポリシーSomPolicyでは、使用している認証スキームはCookieAuthenticationDefaults.AuthenticationSchemeですよ」ということを知らせることでクレーム（認証時に認証エンジンによってクライアントへのレスポンスに付与される情報）の取り扱い方などを判断させているのだと思う。

認証処理に使用する認証スキームも登録する。

``` Program.cs
// Authorization
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("SomePolicy", (AuthorizationPolicyBuilder policy) =>
    {
        policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
        policy.AddRequirements(new SomeRequirement());
        // policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
        // policy.Requirements.Add(new SomeRequirement());
        // という書き方もできるようです。
    });
});
builder.Services.AddSingleton<IAuthorizationHandler, SomePolicyHandler>();
// Authentication
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();
```

認可ハンドラーは要件SomeRequirementを使用する（ジェネリックとして指定する）ハンドラーとしてAuthorizationHandlerを継承した上で実装する。
認可の処理は要件SomeRequirementとClaimがメソッドに渡されるので、それらを使って検証処理を行うようにする。
以下はSomePolicyHandlerの定義の部分の抜粋。

``` SomePolicyHandler.cs クラスの定義部分
public class SomePolicyHandler : AuthorizationHandler<SomeRequirement>
```

認可が必要なアクションにはAuthoriza属性をつける。
ここでは使用する認可ポリシーを指定する。
以下は認可を必要とするコントローラクラスのアクションメソッド部分を抜粋。

``` SomeController.cs
    public class SomeController : Controller
    {
        [HttpGet]
        [Authorize(Policy = "SomePolicy")]
        public IActionResult Index()
        {
            return View();
        }
    }

```

認証処理を実装するアクションで認証スキームとしてCookieAuthenticationDefaults.AuthenticationSchemeを使うことを第一引数で指定している。
Claimなどの扱いは公式ドキュメントを見てほしい。
以下は、認証処理を実施するコントローラクラスの認証アクションメソッド内にて実施が必要な処理の抜粋。

``` LoginController.cs ログイン処理を実装するコントローラ
    await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        new ClaimsPrincipal(claimsIdentity),
        authProperties
    );
```

参考
https://docs.microsoft.com/ja-jp/aspnet/core/security/authentication/cookie?view=aspnetcore-6.0
https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/policies?view=aspnetcore-6.0
https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-6.0
さくらクラウド契約から、SpringBootアプリケーション起動まで  (Windows)

## さくらクラウドでサーバーを立てる
今回はお試しでのデプロイだったので以下のような最低限の構成にしました。

> OS : CentOS
メモリ : 1GB
ディスクサイズ : 20GB
インストールされているパッケージをアップデートする → チェック
> ※ その他はデフォルト

以下のサイトを参考にSSH接続まで実行しました。

https://mebee.info/2019/11/09/post-3567/

ただ、上記サイトの説明のなかで、id_rsa.pubの中身を閲覧する方法が示されていなかったので、検索し、以下のサイトを利用しました。

https://online2pdf.com/

## javaをアプリケーションのコンパイラと合わせる
アプリケーションで使用しているjavaのバージョンがopenjdk 18.0.0.1だったので、それを上回るバージョンのjdkを使用しました。


## アプリケーションのjarファイルの用意
コマンドやeclipseやintellijなどのIDEを用いてjarファイルを用意します。

私はeclipseを使用していて、gradleで構成していたので以下サイトを参考にしてjarファイルを生成しました。

以下サイトに従い、bootjarというgradleタスクを実行します。

https://springhack.com/springboot%E3%81%A7%E5%AE%9F%E8%A1%8C%E5%8F%AF%E8%83%BDjar%E3%82%92%E4%BD%9C%E3%82%8B/#:~:text=SpringBoot%E3%81%AE%E5%AE%9F%E8%A1%8C%E5%8F%AF%E8%83%BDJar%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9,-Eclipse%E3%82%92%E4%BD%BF%E7%94%A8&text=%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%EF%BC%9E%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA,%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%8C%E3%81%A4%E3%81%91%E3%81%B0%E3%80%81%E6%88%90%E5%8A%9F%E3%80%82



### jarファイル配置
サーバーの｢~/｣にjarファイルをｓcpで配置します。

https://www.server-memo.net/memo/teraterm/teraterm-scp.html

## MySQLセットアップ

MySQLのインストールから起動までは以下のサイトを参考に行いました。
ただ、進める中で注意点があったので後ほど説明します。

https://kitsune.blog/mysql-install

### 注意点① : mysql-community-common-8.0.30-1.el7.x86_64.rpm の公開鍵がインストールされていません
上記のエラーが発生しましたが、以下のサイトを参考に解決しました

https://blog.proglus.jp/5095/

### 注意点② : テーブル定義を反映してからアプリケーションを起動する。
テーブル定義がある場合は、schema.sq;を実行した後アプリケーションを起動してください。
初期構成がある場合、その構成をせずにアプリケーションを起動するとエラーとなります。

## 接続
(サーバーのIPアドレス):8080 にアクセスし起動を確認します。


## おまけ
#### アプリケーションを実行し続ける方法
Tera Term から操作をしていましたが、接続を解除するとSpringBootアプリケーションの起動が中止されてしまっていました。
以下のようにnohupコマンドを利用し起動を続けるように設定しました。
```
nohup 処理 &
```
```
nohup java -jar XXXXXX.java &
```

参考 : 

https://stackoverflow.com/questions/40351243/how-to-keep-springboot-application-alive-after-exiting-putty

https://atmarkit.itmedia.co.jp/ait/articles/1708/24/news022.html
GolangのSlice挙動メモ：copy, append, len, cap, 関数に渡して変更したときどうなるか。

##### 注意事項
https://qiita.com/ysti/items/970dddb041a72e6efdb6#comment-92d43db90663c2b646fc
こちらでご指摘いただいている通り、
> append が再確保していないことを前提にするのは、特段の事情がない限りおすすめしません。

ということですのでご注意くださいませ。

## Goのスライスでハマった（定期）

スライスを関数に渡して関数内で長さが変わって増えた分が呼び出し元で見れない問題にハマった。
結論としては、長さを変えてやればOKだった。（変えれないと思っていたら変えれた）

---

```go
package main

import "fmt"

func main() {
	data := make([]byte, 0, 16)
	data = append(data, []byte("abcd")...)
	fmt.Println("1 ", string(data))
	newLen := repeater(data)
	fmt.Println("3 ", string(data)) // ここでは足されたデータが見えなーい
	data = data[0:newLen]           // 長さを変えると、世界が変わるー　（cap超えぬようにね）
	fmt.Println("4 ", string(data))
}
// 同じデータを繰り返して足す。長さが倍になる。
func repeater(data []byte) int {
	data = append(data, data...)
	fmt.Println("2 ", string(data))
	return len(data)
}
// 結果
// 1  abcd
// 2  abcdabcd
// 3  abcd
// 4  abcdabcd
```

https://go.dev/play/p/X5FVpSTXBdo



### メモ
- `append`は`cap`を超えると新しい配列になる。（基本だけど念の為。）
- [スライスの構造](https://qiita.com/kitauji/items/231e76506b51f7f5b810) （とてもわかりやすい！）
- [落とし穴](https://qiita.com/ktateish/items/1fdae8ac845da788a789)　（穴があったら落ちたいよね）
- `copy`
  - `copy(dst, src)`は`src`の`len(src)`分をコピー。
  - `len(src)`がゼロの場合はコピーされない。
- スライスへのアクセス
  - 長さゼロのスライスにアクセスしようとするとキャパシティが足りていてもエラーとなる。
  - **lenは更新できる。**
    - `slice = slice[0:newLen]`で`newLen`まで使えるようになる。
      - **注意** `cap`を超えるとエラーになるので実際にはチェックが必要。
- スライスを関数に渡す場合
  - 配列への参照がコピーされるため関数側で書き換えると呼び出し側にも反映される。
  - **関数内で長さが変わっても呼び出し元のスライスの`len`は変わらず、増えたデータへアクセスできない。**
    - **長さを変えればOK。**（`slice = slice[0:newLen]`）



```go
package main

import "fmt"

func main() {
	s := make([]byte, 0, 16)
	// s[0xc00001c030]:[]byte{}, len:0 cap:16
	_ = s[0] // panic: runtime error: index out of range [0] with length 0

	copy(s, []byte("abcd"))
    // s[0xc00001c030]:[]byte{}, len:0 cap:16 // no change.
	_ = s[0] // panic: runtime error: index out of range [0] with length 0

	s = s[0:4] // change len.
    // s[0xc00001c030]:[]byte{0x0, 0x0, 0x0, 0x0}, len:4 cap:16 // no data copied.
	_ = s[0] // OK.
	_ = s[4] // panic: runtime error: index out of range [4] with length 4

	copy(s, []byte("abcd")) // copy again.
	// s[0xc00001c030]:[]byte{0x61, 0x62, 0x63, 0x64}, len:4 cap:16 // data copied.

	efgh(s)
	// s[0xc00001c030]:[]byte{0x61, 0x62, 0x63, 0x64}, len:4 cap:16 // no change.

	s = s[0:8] // change len.
	// s[0xc00001c030]:[]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x64, 0x68}, len:8 cap:16 // as expected.
}

func efgh(s []byte) {
	// s[0xc00001c030]:[]byte{0x61, 0x62, 0x63, 0x64}, len:4 cap:16
	s = append(s, []byte("efdh")...)
	// s[0xc00001c030]:[]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x64, 0x68}, len:8 cap:16
}
```

https://go.dev/play/p/vTNgAqTKJbP


解決のヒントは本家のEffective Goというね。さすが。
https://go.dev/doc/effective_go#slices
ActivityとFragment間でViewModelを共有したい

### はじめに
前提として、deprecatedになっているViewModelProviders.ofやfragment-ktxを導入せずにViewModelを使ってデータ共有したいと思い調べた。

### 手順

- 引数なしのViewModel
- AndroidViewModel(application)を継承していて引数がapplicationだけのとき

であればViewModelProviderを使用した以下のコードでとても簡単に共有することができる。

~~~kotlin:MainActivity.kt
//FirstFragmentとSecondFragmentと共有
private val viewModel by lazy {
    ViewModelProvider(this)[MainViewModel::class.java]
}
~~~

~~~kotlin:FirstFragment.kt
//SecondFragmentとMainActivityと共有
private val parentViewModel by lazy {
    ViewModelProvider(requireActivity())[MainViewModel::class.java]
}
~~~
~~~kotlin:SecondFragment.kt
//FirstFragmentとMainActivityと共有
private val parentViewModel by lazy {
    ViewModelProvider(requireActivity())[MainViewModel::class.java]
}
~~~

activityのthisとfargmentのrequireActivity()で、ViewModelProviderに渡すViewModelStoreOwnerが同じであれば、共有することができる。

引数のあるViewModelであれば[androidx.lifecycle:lifecycle-*:2.5.0](https://developer.android.com/jetpack/androidx/releases/lifecycle#2.5.0)にて追加されている`InitializerViewModelFactory`を使ってviewModelfactoryを作るのが楽そう。


### 参考
javaの方を参考にしました。
できるならfragment-ktx導入したほうが良さそうですね。とても簡潔〜

https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

https://developer.android.com/guide/fragments/communicate#java
【cron】crontabのエディタをVSCodeに変更する方法

## 設定方法
crontab のエディタは`EDITOR`変数で変更できます。
`~/.zshrc`に以下のように記述すると vim に変更されます。
```~/.zshrc
export EDITOR=vim
```

しかしVSCodeに変更する際に以下のように記述するとVSCodeは開きますが、編集前に`crontab -e`コマンドが終了してしまうためcorntabの編集ができません。

```~/.zshrc
export EDITOR=code
```

```zsh:ターミナル
$ crontab -e
crontab: no changes made to crontab
```

編集前に`corntab -e`コマンドが終了してしまうのを回避するために以下のようにします。

まず以下の内容で`code-wait.sh`を作成します。

```code-wait.sh
#!/bin/zsh
code --wait "$@"
```

次に`code-wait.sh`に実行権限を与えます。

```zsh:ターミナル
sudo chmod +x /path/to/code-wait.sh
```
または
```zsh:ターミナル
sudo chmod 755 /path/to/code-wait.sh
```

そして`~/.zshrc`に以下を追記します。

```~/.zshrc
export EDITOR=/path/to/code-wait.sh
```

すると編集前に`corntab -e`コマンドが終了してしまうのを回避できます。

![スクリーンショット 2022-09-16 18.27.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/171d1539-16f6-ffde-50dc-c32bc91313da.png)
Java：複数のExcelドキュメントをマージする方法

Excelドキュメントを操作する際に、複数のExcelドキュメントを1つのドキュメントにマージするのは非常に実用的な機能です。この機能は、関連ドキュメントを一緒に配置するのに役立ち、後で検索するのに便利です。[Free Spire.XLS for Java](https://jp.e-iceblue.com/introduce/free-spire-excel-for-java.html)は、複数のExcelファイルのマージを簡単に実行するのに役立ちます。具体的な操作の詳細は次のとおりです。

## Spire.XLS.Jarのインストール
方法1：
mavenを使用している場合は、次のコードをプロジェクトのpom.xmlファイルに追加することで、JARファイルをアプリケーションにインポートできます。
```
<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.xls.free</artifactId>
        <version>5.1.0</version>
    </dependency>
</dependencies>


```
方法2：
mavenを使用していない場合は、[このリンク](https://jp.e-iceblue.com/download/free-spire-excel-for-java.html)からFree Spire.XLS for Javaをダウンロードできます。ダウンロードが完了したら、ダウンロードパッケージを解凍します。次にIDEAで新しいプロジェクトを作成し、「File」、「Project Structure」、「Modules」、「Dependencies」を順にクリックし、右側の緑の「+」の下の最初のオプション「JARs or Directories」をクリックして、前に解凍したファイルを見つけ、その中のlibフォルダの下にあるSpire.XLS.jarファイルをプロジェクトにインポートします。

## 複数のExcelドキュメントをマージする
次に、具体的な操作手順を示します。

* Excelファイルパスから文字列配列を作成します。
* Workbookクラスのオブジェクトを作成し、新しいワークブックを作成します。Workbook.Worksheets.Clear()メソッドを使用してワークブック内のデフォルトのワークシートを消去します。
* 別の一時的なWorkbookクラスのオブジェクトを作成します。
* 文字列配列をループし、Workbook.loadFromFile()メソッドを使用して、現在のワークブックを一時的なWorkbookのオブジェクトにロードします。
* すべてのシートをループし、Workbook.Worksheets.AddCopy()メソッドを使用して、現在のブック内のすべてのシートを新しいブックにコピーします。
* Workbook.saveToFileメソッドを使用して、結果文書を保存します。

```
import com.spire.xls.ExcelVersion;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;
import com.spire.xls.WorksheetCopyType;

public class MergeExcels {

    public static void main(String[] args) {

        // Excelファイルパスから文字列配列を作成する
        String[] inputFiles = new String[]{
                "C:\\Users\\Administrator\\Desktop\\file1.xlsx",
                "C:\\Users\\Administrator\\Desktop\\file2.xlsx"};

        // Workbookクラスのオブジェクトを作成する
        Workbook newBook = new Workbook();

        //デフォルトのワークシートを消去する
        newBook.getWorksheets().clear();

        //別の一時的なWorkbookクラスのオブジェクトを作成する
        Workbook tempBook = new Workbook();

        //文字列配列をループする
        for (String file : inputFiles)
        {
            //ワークブックを一時的なWorkbookのオブジェクトにロードする
            tempBook.loadFromFile(file);

            //現在のブック内のすべてのシートを新しいブックにコピーする            
for (Object obj : tempBook.getWorksheets())
            {
                Worksheet sheet= (Worksheet) obj;
                newBook.getWorksheets().addCopy(sheet, WorksheetCopyType.CopyAll);
            }
        }

        //結果文書を保存する
        newBook.saveToFile("MergeFiles.xlsx", ExcelVersion.Version2013);
    }
}

```
![2022-09-16_160711.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/5a690292-a9f2-3621-3dbe-b9be1565be53.png)
東大生の応用情報技術者試験対策〜委任・準委任〜

# この記事の概要
この記事では、応用情報技術者試験のストラテジ分野に含まれる、
- 委任（契約）
- 準委任（契約）
の 2 つについて、それぞれの違いや意味をまとめ、最後に過去問を 1 つ解いて確認とする。

#### 補足
あくまで応用情報技術者試験プラスアルファ程度のものを意識してまとめることにしたので、法律的に厳密な表現ができていない可能性もあるが、ご理解いただきたいです。


# 調べていて苦戦した点
法律の知識が必要になってくる分野なので、法律用語に苦戦することがあった。ただ、一つずつ理解し、メモしていく中で違いを把握し、問題は解けるようになった。


# 委任、準委任とは
## その前に...法律効果・法律行為とは
法律効果とは、ルールとして存在する法律が持つ一定の効力であり、法律で規定されている一定の条件（法律要件）を満たしたときにその効力を発揮する。法律効果が生じることを、「法律が適用される」と表現することもできる。例として、「xxx をした人は o 年の懲役に処する」といった法律があるが、この法律において　法律要件は、「xxx をした」ということであり、法律効果は、「o 年懲役」ということになる。

遊戯王のカードで例えるとわかりやすいと思うので例えてみると、
- 法律要件：カードの発動条件
- 法律効果：カードの効果の内容
のようになる。


法律行為とは、意思表示によって構成される、一定の法律効果を発生させる行為、別の言い方では、私法上の権利・義務を発生させる行為を指す。具体的には、「**契約**」 が挙げられる。契約が成立すると、契約内容に沿った権利・義務が帰属し、契約は正に法律行為であるといえるだろう。


最後に必要な用語として紹介するのは、債務不履行についてである。債務不履行とは上述したような、契約によって生じた契約義務を果たさないことである。具体的には「履行遅滞」「履行不能」「不完全履行」の三つがあるが、ここまでの理解は応用情報技術者試験の合格には必要がなさそうなので、これ以上深掘りをすることはやめる。
重要なことは、債務不履行では、損害賠償を請求されてしまうということである。つまり、契約義務を果たさないと何らかのマイナスの影響を受けてしまうことになる。


以上をまとめると
- **法律行為では、権利や義務が発生すること**
- **契約は法律行為であること**
    - **委任契約，準委任契約は全て法律行為**
- **契約義務を果たさなければ、債務不履行となり、損害賠償を請求されること**

ということになる。

## 委任契約・準委任契約とは
委任契約、準委任契約はここまでで説明した用語で述べることができる。共通点と相違点についてそれぞれ述べていく。


**両者に共通**していることは以下のようになる。
- 契約の一種であり、契約義務が生じる
- 決められた期間に定められた業務を誠実にやれば、成果が発注者の期待に及ばなくても債務不履行となることはない
    - 請負契約では成果が不十分だと債務不履行になり、損害賠償が請求される
- 瑕疵担保責任がない
    - 請負契約では、瑕疵担保責任が生じる



続いて、**両者の相違点**について述べる。
- 委任契約では、法律行為を委託するのに対し、
- 準委任契約では、法律行為でない行為を委託する。

ここで、再度法律行為という言葉が出てくるのがややこしくなるのだが、契約の説明のときに出てきた法律行為とは一旦関係ないので、ここで再度説明する。

少し曖昧になるが、委任契約において委託する法律行為とは、弁護士や医師など、法律に関わる行為を主とする行為を委託する場合は、委任契約になり、その他の事務作業などを委託する場合は準委任契約を結ぶという理解で差し支えはないと思われる。

ここまでの内容は、次の表のようにまとめることができる。
|共通点|相違点
|---|---|
|契約行為であり、義務が生じる。<br>  瑕疵担保責任がない <br> 誠実にやれば成果によらず債務不履行にならない|法律行為を委託するかどうか

|   |委任契約|準委任契約
|---|------|---------|
|例 |弁護士に訴訟行為代理を委託<br>税理士に確定申告を委託|事務スタッフとしての契約<br>ソフトウェア開発における要件定義の委託<br>セミナーの委託|

##### 注意
経済産業省の「モデル契約書」によれば、ウォーターフォール型開発では、各工程（要件定義、システム外部設計、システム内部設計・ソフトウェア設計・プログラミング、システムテスト、受入・導入支援）において準委任契約と請負契約のどちらを行うのが良いか、推奨がされているので参考にされたい。実際に過去問でも出ている。



# まとめ
委任契約と準委任契約は比較的成果に対しての責任が（請負契約より）緩い契約であることがわかった。契約である以上、権利・義務が発生し、債務不履行となるような契約も存在する。
両者の違いとしては、委任契約が法律行為の遂行を義務とするのに対し、準委任契約では非法律行為の遂行を義務とする。ソフトウェア開発において、委任契約が結ばれることはほとんどなく、大体が準委任契約か請負契約に該当する。


# 過去問
実際に過去問をやってみる！
ぜひ本記事を読み返したり調べ物をしたりして、正解に自力でたどり着いてみてください！

（平成25年度秋季問題 午前 問題80 より抜粋）
![スクリーンショット 2022-09-16 18.11.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847942/a298c075-405b-a926-d081-f45338aa5fb1.png)

答えは


・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
アになります！
解説：
ア：準委任契約は完成義務はないので正しい。
イ：リース契約（必要な備品のレンタル）
ウ：派遣契約である。派遣社員は派遣先の指示に従って行動する。
エ：請負契約である。請負契約では、提供するものは労働力ではなく、仕事の完成形、いわば労働成果物である。


# 最後に
初めての記事であったが、いきなりから非エンジニアの内容になってしまったことを後悔している。本来はバリバリにコーディングや設計などをしているので今後にご期待ください、、。
実際に調べていく中で、理系学生だから仕方はないが、知らない法律用語が多く存在することに気が付き、学びが多く、楽しくなった。そのため、ページが長くなってしまった、、。
最後まで読んでくださり、誠にありがとうございました！！
Docker GoでREST APIを作成、MySQLに接続する

# はじめに
本格的にアプリ開発を始める前に、練習として
Dockerを用いてGoコンテナ、MySQLコンテナを作成、
MySQLからデータを取得するAPIを作成しました。

作成の手順、参考にした記事をまとめてます。

# 使用技術
Go
net/http

# Dockerとは
以下の記事を参照

# 実施したこと

## DockerでGoコンテナを作成、Docker
Goコンテナ、MySQLコンテナを同時に作成する前に、
Goコンテナのみ作成しました。
初めてに触れるので、Dockerに慣れるために

DockerでGoコンテナを作成、
Docker上でGoサーバーを起動させました。

参考にした記事は以下の記事です。
https://www.yoheim.net/blog.php?q=20170403
https://zenn.dev/kenny/articles/b9dd668bf09efe
https://qiita.com/kooohei/items/0e788a2ce8c30f9dba53
https://docs.docker.jp/engine/reference/builder.html

### 調べたこと
〇DockerFileを作成
Dockerfileとは、DockerImageを作成するもの

コマンド
FROM ~
~というイメージをもとにDocker Imageを作成する
~には公式イメージが来ることが多い

ENV
環境変数の設定
環境変数とは、OSが動いているときに使える変数
https://wa3.i-3-i.info/word11027.html

RUN
RUNの後にイメージが実行されたときのコマンドを実行する
https://www.guri2o1667.work/entry/2021/06/08/%E3%80%90Docker%E3%80%91Dockerfile%E3%81%A7%E8%A8%98%E8%BF%B0%E3%81%99%E3%82%8BRUN%E3%81%A8CMD%E3%81%A8ENTRYPOINT%E3%81%AE%E9%81%95%E3%81%84%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6#RUN%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A8CMDENTRYPOINT%E3%81%AE%E9%81%95%E3%81%84

WORKDIR
各種命令を実行する際のカレントディレクトリを指定

バイナリ
https://wa3.i-3-i.info/word14226.html


○Goプロジェクトの作り方
・ディレクトリを作る
・main.goを作る
・go mod(モジュール管理のファイル)を作成


参考記事
https://zenn.dev/ryo_yamaoka/articles/595cf9e69229f9
https://zenn.dev/optimisuke/articles/105feac3f8e726830f8c

エラー解決の参考記事
https://castaneai.hatenablog.com/entry/2019/02/22/151213

Go moduleについて
https://osamu-tech-blog.com/go-go-modules/

## DockerでGo Server、MySQLを起動、接続する

mySQLコンテナを作る為に参考にした記事は以下
https://ponsanlabo.com/create-mysqldockerimage-from-dockerfile/
https://pointsandlines.jp/db-sql/mysql/docker-mysql#MySQL

参考にしたAPIの記事は以下
https://dev.classmethod.jp/articles/go-sample-rest-api/

Goについて
http://psychedelicnekopunch.com/archives/560

発生したエラーの解決するために調べた記事は以下
https://qiita.com/wakki_haya/items/a00ecdc231e131b4d18d
https://qiita.com/GalaxyNeko/items/0e365fe13d177c368acf
https://qiita.com/gbf_abe/items/2bf45206c515cea75d9b
https://rurukblog.com/post/docker-compose-file-update/
https://stackoverflow.com/questions/69615253/copy-failed-forbidden-path-outside-the-build-context-docker-compose
https://qiita.com/TKR/items/ac29ee783bc4684d0612

## docker内のMySQLに接続する
参考記事
[docker内のMySQLに接続したい](https://chaika.hatenablog.com/entry/2019/02/18/123000)

## mysqlをダウンロードする
参考記事
[MySQLをダウンロード](https://proengineer.internous.co.jp/content/columnfeature/6529)
[Docker-Composeで3306以外のポートでmysqlを起動](https://qiita.com/SFITB/items/2170fb8cadd820951f64)