OmniAICreator/Qiita-1.07M huggingface dataset:
どこでも固定IPが欲しい？なら最速で自前VPNを作っちゃえ！

# はじめに
サーバー管理だったり、本番環境の動作確認で毎回IPが変わってしまうと、
開発やメンテでアクセスしてるのか？
それとも、サーバーが攻撃を受けてるのか分かりづらい。
毎回固定IPが振られる環境にいるといいけど、なかなかそう行かないので、IP固定のためにVPNに接続したい！！

# そもそも
VPNを自分で整備しなくても、GCPやAWSにはVPNサービスもあるのでそれ頼れば解決だが個人で使うには**お高い**!

固定IPだけが欲しいのに、利用コストが高いし従量課金は悩ましいと考えたときに、固定IPサービスの[マイIP](https://www.interlink.or.jp/service/myip/)(株式会社インターリンク)もあったりする。
リーズナブルに利用できていいけど、複数端末からの同時接続やかゆいところに手が届かないことが多々...
検証だったり、開発に使うならPCだけじゃなく複数のスマホからのアクセスもできるようにしたい。  

そこで、エンジニアならエンジニアらしく柔軟に使えるVPNを低コストで自前で構築した。

# サーバーの検討

VPNを構築するにあたって  

+ VPS
+ ポートの制約が少ない
+ 転送量課金がない
+ 回線が安定してる(してそう)
+ 安価   
を考慮して決める。

VPSとして一番に思い浮かぶのがConoha やさくらVPSが一番に思い次ぐが、
そこまで、スペック必要ではないので今回はNTTPCのindigo VPSを使った。

今回使ったVPSは 

+ vCPUx1, RAM1GB, SSD20GB　0.55円/時間　月額上限349円  

お財布にとっても優しいだけでなく、格安VPSでは珍しい転送量制がない！！

#  VPSの用意
OSはindigo VPS標準のUbuntu18.04LTSを使う。
(個人用だからLTSじゃなくて最新のでも良かったけど...)

VPSにSSHでアクセスできるように自分好みに設定を...

とりあえず、既存のパッケージくらいは更新したほうがいいかも

https://qiita.com/devzooiiooz/items/46846b2c97dd5f069ff6

# 爆速でOpenVPNの導入
OpenVPNの導入は意外と複雑でめんどくさいです...
~~とにかく情報量が多い~~

しかし、OpenVPNの設定や導入を爆速でできるインストーラーが世の中にあるのでそれを使っていきます！

https://github.com/angristan/openvpn-install

サーバーにrootでアクセスして以下のコマンドを実行していくだけ

```
curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
chmod + x openvpn-install.sh
./openvpn-install.sh
```
あとは、設定項目を聞いてくれるので、質問に答えつつ気長に見守るだけで終わります！！
（~~とりあえずVPNが使えたらいいって人はエンターひたすら押すだけでも使えますが、よく理解して進めていく方が良いかと...~~）

# vpnに接続
VPSのホームディレクトリに`.ovpn`拡張子のファイル（OpenVPNの構成ファイル）が生成させるので、接続したい端末に転送する。

あとは、それぞれのOSのあったOpenVPNのクライアントをインストールして、転送してきたファイルを開くだけ!

mac: 

https://tunnelblick.net/

win:

https://www.openvpn.jp/document/openvpn-gui-for-windows/


# 接続端末を増やしたい?
このままだと、OpenVPNの構成ファイル１つで１台しか接続できません。
自前VPNだから柔軟に接続端末増やしたくなりますよね？

そんなときも、インストールで使ったインストーラーを使えばかんたんです！
サーバーにrootでアクセスして以下のコマンドでインストーラーを再度実行していくだけ

```
./openvpn-install.sh
```
すると、ユーザー追加、ユーザー削除、OpenVPN削除を聞いてくれるのでかんたん！

# 終わりに
いずれ、楽して構築できるOpenVPNだけじゃなくてL2TP/IPSecなプライベートVPNを構築したい...
そのまえに、業務用ルーター買わなければ
ROSの勉強　第28弾：移動ロボットの作成（1）

# #プログラミング ROS< 移動ロボットの作成（1） >

## はじめに
1つの参考書に沿って，ROS(Robot Operating System)を難なく扱えるようになることが目的である．その第28弾として，「移動ロボットの作成（1）」を扱う．

## 環境
##### 仮想環境
|||
|:-:|:--|
|ソフト|VMware Workstation 15|
|実装RAM|2 GB|
|OS|Ubuntu 64 ビット|
|isoファイル|ubuntu-mate-20.04.1-desktop-amd64.iso|

##### コンピュータ
|||
|:-:|:--|
|デバイス|MSI|
|プロセッサ|Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz|
|実装RAM|8.00 GB (7.89 GB 使用可能)|
|OS|Windows (Windows 10 Home, バージョン：20H2)|

##### ROS
|||
|:-:|:--|
|Distribution|noetic|

## 移動ロボットの作成
ROSを使って，ほとんどの新しいロボットを制御する手順は次のようである．

**1. ROSのメッセージインタフェースを決める．
2. ロボットのモータ用ドライバを書く．
3. ロボットの物理構造を書く．
4. Gazeboのシミュレーションで使用できるようにモデルに物理的特性を追加する．
5. tfを介して座標変換データを配信し，rvizでそれを可視化する．
6. センサを追加する．ドライバとシミュレーションのサポートも必要．
7. ナビゲーション等の標準的なアルゴリズムを適用する．**

移動ロボットを例にその流れを確認していく．
今回はその1つ目ということで，1と2をまとめて移動ロボットの作成（1）として扱うこととする．

## 手順1:ROSメッセージインタフェース

* 最初に行うべきことは移動台車を制御すること
 - ハードウェア（移動台車）と通信するROSノードを何らかの方法で書き，システムのほかの構成要素に標準的なROSのインタフェースを提供する．

これが抽象化という**ROSにおいてコアとなる概念** 
ROSはどのようなロボットでも汎用的に扱いたいと思っている．そうすることで，標準的なインタフェースで動作するように設計されたツールとライブラリからなるエコシステムの全てを再利用することができるようになる．

例：TortoiseBot
三輪車と同じ動作で，前進(x軸方向)と回転(z軸周り)に動くことが可能で，
それ以外の動きはできないと考えられる．

ゆえに，TortoiseBotはx軸上の並進速度とz軸周りの回転速度に対して，
目標値を設定することで，動きを制御できることになる．

vx : x軸上の並進速度（前方を正）

vyaw :z軸周りの回転速度（反時計回りを正）

この結果として，ロボットが(x, y, yaw)のような平面内での位置と向きを報告することが期待される．

* ROSコミュニティは次のようなメッセージインタフェースに行き着く

**geometry_msgs/Twist (cmd_velトピック)
　　　　- ロボットの目標速度（コマンドとしてロボットに送信する）**

**nav_msgs/Odometry (odomトピック)
　　　　- ロボットの位置と向き（データとしてロボットから送信される）**

##### geometry_msgs/Twist
![image](https://user-images.githubusercontent.com/61382602/112425971-69790f00-8d7a-11eb-9f5b-280904cd4a30.png)
##### nav_msgs/Odometry
![image](https://user-images.githubusercontent.com/61382602/112426003-78f85800-8d7a-11eb-91e8-097ed839e7e3.png)

https://qiita.com/HMMNRST/items/0a4ab86ed053c770ff6a

四元数についての説明はここを参考にするとよいかもしれない．

* 必要な部分だけ使って，残りは空の状態で使える．自分で必要な部分だけで構成されたメッセージインタフェースを定義することもできるが，ほかのツールやライブラリとの互換性がなくなるかもしれない．

* ゆえに，自分が扱うロボットが既存のツールとライブラリを最大限に再利用できる方法を慎重に探すべきである．

これにより，地上を走るものであろうと，空中を飛ぶものであろうと，このインタフェースを
使う移動型のロボットと同じように自身のロボットも共通のツール群を使って操作することが
できるようになる．

## 手順2:ハードウェアドライバ

* ドライバを書くステップは，ロボットのハードウェアがどのように設計され，
　そのハードウェアとどうやって通信を行うことができるのかに強く依存する．

* 通信の内容がどんなものであっても，ドライバノードで何らかの計算をして，
　ロボットが提供するコマンドとデータの表現形式と，私たちが**ROSのインタフェース
　としてサポートするcmd_vel/odom間での変換を行う必要がある**．

* 移動台車を制御するための汎用的なドライバのコードはないが，ROSエコシステム内
　には，参考になるサンプルがたくさんある．

## 感想
今回から，ようやく自作の移動ロボットを構築していく手順について学ぶことができる．いよいよロボットの構築に触れることができるということで非常に楽しみである．今回は，まだ導入のような形ではあるが，1つ1つ丁寧に学習を進めていき理解を深めていきたい．


## 参考文献
プログラミングROS Pythonによるロボットアプリケーション開発
　　　　　　　　Morgan Quigley, Brian Gerkey, William D.Smart 著
　　　　　　　　　　　　　　　　　　　　　　　河田　卓志　監訳
　　　　　　　　　　  　松田　晃一，福地　正樹，由谷　哲夫　訳
　　　　　　　　　　　　　　　　　　オイラリー・ジャパン　発行
DiscordボットでGCEインスタンスを起動・停止する

はじめに
---
GCEのインスタンスをDiscordBotで起動・停止させるための手順を書こうと思います。
この記事では

https://qiita.com/kkst/items/2942db4ba9a14a0e926f

の記事で作ったインスタンスを例に起動・停止できるようなコードを書いていきます
Discordbot用のVMインスタンスを作成
---
 GCEの永続無料のプランで構成していきます(pythonのコードを実行し続けるだけのサーバーなのでたいしてスペックは必要ない)

| 項目       　　　　| 無料枠　　　　　　　|
|:-----------------|:------------------
| インスタンス       | ~~f1-micro~~ **e2-micro**(2021/8/1に変更されました)
| ストレージ           | 一ヶ月あたり30GB(HDD)
| スナップショット             | 一ヶ月あたり5GB
| データ転送(外向き)         | 一ヶ月あたり1GB  
![スクリーンショット 2021-08-13 190301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289356/aed401b5-e29a-a3a1-5d61-9ab0dca2cabf.png)


https://cloud.google.com/free?hl=ja 参照

なおosはcentos7を用いて説明します

Discord bot作成
---
https://qiita.com/1ntegrale9/items/cb285053f2fa5d0cccdf

この記事がわかりやすいので是非

---
先ほど作成したVMインスタンスにsshで接続をしたら、以下のコマンドを実行していってください

```
sudo yum update
sudo yum install python3 python-pip
sudo pip install --upgrade pip

#Discord.pyを導入
python3 -m pip install -U "discord.py[voice]"
```

これで一通りの設定は終わりです
次にpythonでbotのコードを書いていきます(ここで説明するのは最低限のコードのみ)

```main.py
import discord
import os

TOKEN = botのToken
client = discord.Client()

#ボットが正常に起動したときにコンソールに表示される文字を指定
@client.event
async def on_ready():
    print(コンソールに表示させたい文字)

#ボットが入っているサーバーで誰かがテキストを送信したときに走るプログラム(引数のmessageが誰かが送信したメッセージ(引数名は自由に変えられる))
@client.event
async def on_message(message):
    #メッセージの発信者がボットだったら無視
    if message.author.bot:
        return

    #誰かが/server-upと送信したら特定のVMインスタンスを起動する(もちろん/server-upじゃない別の文字列に指定してもOK)
    if message.content == "/server-up":
    await message.channel.send("VMインスタンスを起動中...")
    os.system(起動させたいVMインスタンス ※1)

    if message.content == "/server-down":
    await message.channel.send("VMインスタンスを停止中...")
    os.system(停止させたいVMインスタンス ※2)
```
※1 僕のbotだと gcloud --account=,,,,,,@sample-project-6桁の数字.iam.gserviceaccount.com compute instances start mod-server12-4 --project sample-project-6桁の数字 --zone asia-northeast2-a
※2 僕のbotだと gcloud --account=,,,,,,@sample-project-6桁の数字.iam.gserviceaccount.com compute instances stop mod-server12-4 --project sample-project-6桁の数字 --zone asia-northeast2-a　

botを常時稼働させる
---
作成したmain.pyをVMインスタンスにアップロードします

```
sudo nohup python3 main.py &
```

と実行するとVMインスタンスが起動さえしていればSSHログインを解除してもbotが常時稼働するようになります

botのコードを変更する
---
常時時稼働させたいpythonファイルを改善した場合には、
常時稼働させていたnohupを解除して、改善したpythonファイルをnohupに指定してあげなければいけません

```
#現在実行中のプロセスを全部表示
ps ax
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289356/2120f30e-6ad3-6bf0-53cd-ea16e8e2c945.png)
sudo nohup python3 main.pyを探し、そこのPID(一番左の数字)を確認
なお、PIDの数値は毎回変わります

```
#nohupのプロセスを強制終了 (省略可能)
sudo kill (pid)    #今回の場合だとsudo kill 557

#これまで使われていたmain.pyを削除
rm main.py

#コードを変更したmain.pyをアップロード
sudo nohup python3 main.py
```
これだけです


分からないこと等がありましたらコメントでお願いします
Flutter FutureBuilderでcurrentUserが使えなくなってた（Firebase Authentication）

#環境

```yaml:pubspec.yaml
environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.3
  firebase_core: ^0.7.0
  cloud_firestore: ^0.16.0+1
  firebase_auth: ^0.20.1
```

#The argument type 'Stream<User>' can't be assigned to the parameter type 'Future<dynamic>'.
このエラーは恐らくバージョンの問題かと思われる。。。
非同期の処理を指定する`future`の部分に、`currentUser`を入れたいのだが、どうもエラーになる。。。:expressionless:

```dart
 Widget build(BuildContext context) {
    return FutureBuilder(
        future: FirebaseAuth.instance.currentUser, // ここでエラー
        builder: (ctx, futureSnapshot) {
          if (futureSnapshot.hasData) {
            User user = futureSnapshot.data;
            return Dashboard();
          }
          return LoginScreen();
        });
  }
```

理由は正直よくわかりませんが、`StreamBuilder`を使うと同じようなことができるようになりました。

#StreamBuilderとauthStateChangesで代用？

```dart
 Widget build(BuildContext context) {
    return StreamBuilder(
        stream: FirebaseAuth.instance.authStateChanges(),
        builder: (ctx, futureSnapshot) {
          if (futureSnapshot.hasData) {
            User user = futureSnapshot.data;
            return Dashboard();
          }
          return LoginScreen();
        });
  }
```

https://www.debugcn.com/ja/article/62851070.html#google_vignette

一応これで同じような？処理にはできたっぽいです。。
なんで`FutureBuilder`ではダメなのか、色々と調べましたが結局よくわからずです。誰かわかりやすく解説してください:sweat_smile:
outlook2016でユーザアカウント設定なしで起動できない

マルウェア解析環境を作り直している際にOutlook2016で落とし穴があったので事象と回避方法を共有します。

# 事象
Outlook2016では起動時にユーザアカウントの設定が必須となっており、この設定を行わなければメイン画面に入ることができない。
マルウェア解析するときは、メール添付されたファイルの解析を行うことが非常に多いため、Outlookでeml/msgファイルを開封することが必須の要件となっている（わたしにとって）

↓起動時に必ずこのウィンドウが出現してしまう。（スキップできない）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102081/e0d0cf9a-58d8-4d9d-81ab-f469c65b0b3d.png)

# 一般的な回避策
## 方法1.引数をいれてポップアップスキップ
[マイクロソフトの公式FAQによると、引数を指定することで回避が可能だとしている。](https://support.microsoft.com/ja-jp/office/%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AA%E3%81%97%E3%81%A7-outlook-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B-477a1fc3-4423-4156-bef4-67489edfdbef)
>[実行] ウィンドウで Outlook.exe /PIM <your profile name> を入力し、[ OK]をクリックします。 メールアカウントなしで Outlook に新しいプロファイルが作成されます。 次に、Outlook を使用して、連絡先、タスク、予定表の情報を保存することができます。
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102081/f32aec38-6217-ab92-f47c-4f6b91264d3e.png)

が、私の環境では「Microsoft Outlook を起動できません。コマンドラインの引数が正しくありません。使用しているスイッチを確認してください。」のエラーで実行できなかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102081/5b6c650a-3207-b951-d774-d2e66e44ea7c.png)
## 方法2.レジストリにキーを新規作成
下記のレジストリキーを登録する
HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Office\16.0\Outlook\setup
DisableOffice365SimplifiedAccountCreation = 1
→反映されるときとされないときがあり設定が安定しなかった（原因不明）

# 回避策（自己流）
いろいろググってやってみたのですがどれもうまくいかず、
最終的に「Fakednsとinetsimを立ち上げて架空のメールアドレスの登録をする」という荒業で試しました。

## fakednsとinetsimを利用した回避手順
１）fakenetとinetsimを構築して、Windowsマシンを向ける
具体的には下記のブログで書かれているような構成にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102081/e9bb1ab5-1220-6678-1bc7-6ee10fee8307.png)

https://soji256.hatenablog.jp/entry/2018/08/05/130801

２）Outlookを起動し、実在しない適当なユーザアカウントを設定する
３）ユーザアカウントが登録され、Outlookを起動させることができる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102081/2574d9ef-36f1-e136-fa30-95cdc437dc37.png)


## おまけ：他に試したこと
１）あらかじめユーザなしのプロファイルを作成し、そのプロファイルを指定して実行
→ポップアップが同様に出てしまってだめ
２）特定のemlファイルだけを指定して開けるか試す
OUTLOOK.EXE /p {test.eml}
→エラーが出現してしまいNG
３）過去のバージョンのpstを移行して使う
→これはやろうとしましたが上記の方法で解決したので実際には試していません。
１のプロファイル作成と似たような方法になるのでうまくいかない予感はする。

なんかニッチすぎて誰の役にも立たなそうな気はしますが備忘録として書きました！
以上。
seedで１０人ユーザーを作って1人５つの記事を持たせるユーザーを作成する

### 開発環境
環境<br>ruby:2.6.4<br>rails:6.0.3
userにはusersモデル、username,email,password,password_confirmation(確認用)を持たせ、
投稿にはarticlesモデル、title,textカラムを持たせています。
画像のアップロードはactivestorageを使用してavatarとしています。
gem 'Faker'を使用しています。
### 題名の通り早速作っていきます
アカウント=10人
1人のアカウント=5つのarticle（記事）
Faker::Name.nameはランダムに名前を作成してくれるfakerの機能、
Faker::Internet.emailはランダムにemailを作成してくれる機能、
Faker::Hacker.say_something_smartはランダムで文字を作成してくれる機能だと思います。
これに関してはあまり理解しておらずとりあえず文字を作成してくれたので使用しています
指定の文字を入れたい場合は
titel: "任意の文字"
text:  "任意の文字"
とすれば良いと思います。
avatarには/assets/imagesに保存してある画像を登録するようにしてあります。
 
~~~seed.rb
puts 'users ...'
10.times do
  user = User.create!(
    username: Faker::Name.name,
    email: Faker::Internet.email,
    password: 'foobar',
    password_confirmation: 'foobar',
  )
    user.avatar.attach(io: File.open('app/assets/images/cat.jpg'),filename: 'cat.jpg')
end

puts 'articles ...'
5.times do |n|
  User.all.each do |user|
    user.articles.create!(
      title: Faker::Hacker.say_something_smart,
      text: Faker::Hacker.say_something_smart
    )
  end
end
~~~

~~~ruby
user.avatar.attach(io: File.open('app/assets/images/cat.jpg'),filename: 'cat.jpg')
~~~

上のavatarを登録するコードですが必ず()の外で書くようにしてください。
（）の中で書くと誤字のエラーがでます。僕はこのエラーに５時間ほどハマりました。
それにactivestorageの場合あまり情報が少ないので本当にこの記述で正解なのかもわかりませんがとりあえず成功できているので良いと思います。
これで内容がよければ

```
rails db:seed
```
と打てば完了になります。

### 最後にいつでもログインできるアカウントを作る

migrate:resetしたときにいちいちアカウントを作り直すのもめんどくさいのでseedにいつでもログインできるようにメール認証もいらないアカウントを作ります。
人気俳優のお二人に参加してもらいます。
user1.skip_confirmation!
これはメール認証はスキップするコードみたいです。
しかしこのまま実行するとアカウント作成は成功したもののメール認識のスキップはできていませんでした。
そこで最後に
user1.save!と保存し、実行してみると見事成功していました。
今回は画像を保存するのは面倒だったのでコードは書きませんでしたが上と同じようにすることでできるかと思います。

~~~seed.rb
user1 = User.create!(
  username: "横浜流星",
  email: "任意のアドレス",
  password: '123456',
  password_confirmation: '123456',
)
user1.skip_confirmation!
user1.save!

user2 = User.create!(
  username: "成田凌",
  email: "任意のアドレス",
  password: 'abcdef',
  password_confirmation: 'abcdef',
)
user2.skip_confirmation!
user2.save!
~~~
rails初学者が書いた記事なので間違いがあるかもしれません
もし間違いがある場合報告してもらえますと助かります。
Windows で古いファイルを削除するコマンド（バッチ）

bat で古いファイルを削除したいという要望があり、調査した結果のメモです。

## コマンド
###### 例：「D:\FTP」フォルダーにある、30日以上前の csv ファイルを削除する。
```
forfiles /p D:\FTP /d -30 /m "*.csv" /c "cmd /c del @file"
```

## 動作確認
###### 1. ダミーファイルを作成する
```
copy nul 1日前.txt
copy nul 2日前.txt
copy nul 3日前.txt
copy nul 4日前.txt
copy nul 5日前.txt
copy nul 6日前.txt
copy nul 7日前.txt
```

###### 2. ダミーファイルのタイムスタンプを変更する(PoweShellで実行)
```
Set-ItemProperty "1日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-1)
Set-ItemProperty "2日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-2)
Set-ItemProperty "3日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-3)
Set-ItemProperty "4日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-4)
Set-ItemProperty "5日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-5)
Set-ItemProperty "6日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-6)
Set-ItemProperty "7日前.txt" -Name LastWriteTime -Value (Get-Date).AddDays(-7)
```

###### 3. 3日前より古いのファイルを削除する(C:\tmp にファイルがあるとする)
```
forfiles /p C:\tmp /d -3 /m "*.txt" /c "cmd /c del @file"
```

###### 4. 結果確認
```
C:\tmp>dir
(省略)
2021/03/24  14:19                 0 1日前.txt
2021/03/23  14:19                 0 2日前.txt
(省略)
```
nuxt2.14 - 2.15での注意点


2.14.7以前のバージョンだと、動的ページで静的書き出しを設定しないばあいにpayload.jsが404というようなエラーがjsでたくさん出ます。
表に見える分の直接的な問題はないですが、うしろでエラーが出ているのは気持ち悪いです。
この問題は2.14.8以降で解決されてるそうです。

https://github.com/nuxt/nuxt.js/issues/7717

2.15にすると、コンポーネントを自動でロードする仕組みが変わってます。

https://github.com/nuxt/nuxt.js/issues/8851

componentsの中にディレクトリを作って管理している場合は、booleanではなく配列で、パスを指定してやる必要があります。

https://github.com/nuxt/components
appsettings.jsonをReleaseやDebugで切り替える

AWSのElastic BeanstalkにASP.NET Core アプリケーションをデプロイする際、appsettings.jsonの切り替えが意外にも困ったのでまとめ。

appsettings.jsonとappsettings.Development.json、その他appsettings.xxxx.jsonなど「実行環境」の選択でappsettingsを切り替えることは簡単だが、ReleaseやDebugなど「ビルド構成」で切り替える機能は.NET Coreのアプリにはない。
いろんな方法があると思うが、csprojにmsbuildのコピーコマンドを手で追記することで、シンプルにビルド後にビルド後のディレクトリ内でappsettings.jsonをappsettings.xxx.jsonで上書きすることができた。

```xml:sample.csproj
  <Target Name="CopyStaging" AfterTargets="Build">
    <Copy SourceFiles="$(TargetDir)\settings\appsettings.$(Configuration).json" DestinationFiles="$(TargetDir)\appsettings.json" SkipUnchangedFiles="false" />
  </Target>
```
ローカルでのエラーAccess denied for user 'root'@'localhost' (using password: NO)が出たとき。

・エラー：Access denied for user 'root'@'localhost' (using password: NO)

・問題は『PWがないので開かない。』ということです。

・解決方法
　・root ユーザーのPW設定を無くして、rails sで動くようにする。
　・mysqlで設定したパスワードをdatabase.ymlに書く。

・手順
　・mysqlの起動　
　　sudo service mysql start
  
　・mysqlにログイン　
　　mysql -u root -p
  
　・使用するデータベースを選択する。　
　　mysql> use mysql;
  
  ・パスワードを空にする。
　　mysql> update user set authentication_string='' where user='root';
　
　・変更が成功したらmysqlを閉じる。
　　mysql> exit
  
  ・変更を反映させるため、,mysqlをストップ。
　　sudo service mysql stop
  
  ・再び起動。
　　sudo service mysql start
  
  ・パスワードなしで、ログインできることを確認。
　　mysql -u root

  ・rails s　立ち上げる（rails s　をしていた場合は一度閉じてからもう一度立ち上げる）。


以上、お疲れ様で〜〜〜す。
AWS DynamoDBに接続する

# AWS DynamoDBに接続する
AWS DynamoDBを使用するWebサイトを開発するにあたって、
まずはサイトからDynamoDBに接続するための設定を行う必要がある。
いくつか方法があるようだが、マシンにAWSへの接続情報を持たせる方法についてメモ。

ローカルに開発環境を作成するための備忘録。

## AWS認証情報の取得
まずは、AWSに接続するためのアクセスキー（認証情報）を作成し、保存する。

１．AWS マネジメントコンソール にサインインし、IAM コンソールを開く。
２．ユーザー→認証情報→アクセスキーの作成をクリック
３．アクセスキーが生成され、表示されるのでコピペするかCSVダウンロードするなりして保存

## 認証情報をサーバーに設定する

取得したAWSアクセスキーを、サーバーの環境変数に設定する。

AWS_ACCESS_KEY_ID：＜取得したAccess key ID＞
AWS_SECRET_ACCESS_KEY：＜取得したSecret access key＞

以上で、Webサーバーへの認証情報の設定は完了！
DynamoDBにつながるようになったよ！

#### 試してみた環境（ローカルの開発環境）
　Windows10
　PHP/Laravel/Vue.js

## 参考
公式ドキュメントのこのあたり
DynamoDB (ウェブサービス) のセットアップ
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/SettingUp.DynamoWebService.html#SettingUp.DynamoWebService.GetCredentials
環境変数からの認証情報の使用
https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/guide_credentials.html
任意サイトのサブドメインを列挙する

## 何？

あるサイトのサブドメインを探して列挙したい。
例えば`example.com`なら`ftp.example.com`や`ws3.example.com`などがサブドメインに当たる。
調べたところ[いくつかツール](https://github.com/search?o=desc&q=subdomain+enumeration&s=stars&type=Repositories)がヒットした。その中でも`sublist3r`がシンプルで良かったので紹介する。

## `sublist3r`

[aboul3la/Sublist3r](https://github.com/aboul3la/Sublist3r)は、各検索エンジンのクローラが拾ったレコードからサブドメインを検索し列挙するコマンド。(メンテされてるか微妙だが2020-03-25現在使用できた。)

インストールは:

```bash:Terminal
# pypiには第三者がアップロードしているので本家repoから
$ git clone https://github.com/aboul3la/Sublist3r && cd Sublist3r
$ pip install -r requirements.txt
$ pip install -e .
$ sublist3r --help
```

```text:Help
usage: sublist3r [-h] -d DOMAIN [-b [BRUTEFORCE]] [-p PORTS] [-v [VERBOSE]] [-t THREADS]
                 [-e ENGINES] [-o OUTPUT] [-n]

OPTIONS:
  -h, --help            show this help message and exit
  -d DOMAIN, --domain DOMAIN
                        Domain name to enumerate it's subdomains
  -b [BRUTEFORCE], --bruteforce [BRUTEFORCE]
                        Enable the subbrute bruteforce module
  -p PORTS, --ports PORTS
                        Scan the found subdomains against specified tcp ports
  -v [VERBOSE], --verbose [VERBOSE]
                        Enable Verbosity and display results in realtime
  -t THREADS, --threads THREADS
                        Number of threads to use for subbrute bruteforce
  -e ENGINES, --engines ENGINES
                        Specify a comma-separated list of search engines
  -o OUTPUT, --output OUTPUT
                        Save the results to text file
  -n, --no-color        Output without color

Example: python /home/eggplants/.local/bin/sublist3r -d google.com
```

## 実際に列挙

`sublist3r -d <domain>`で実行できる。プレーンテキストで保存するには`-o <filename>`を使う。

今回は筑波大学のドメイン`tsukuba.ac.jp`で試してみる。

```bash:Terminal
$ LANG=C date
Thu Mar 25 11:25:01 JST 2021 
$ sublist3r -d tsukuba.ac.jp -o subdomains.txt
...(略)...
$ wc -l subdomains.txt
13876
```

結果は[こちら](https://gist.github.com/eggplants/a66fffa1bee3db8fb50d82319b4040f5)

## 応用

```bash:Terminal
# 自己責任で
$ (echo 'url,res_code,content_type,res_time'
  cat subdomains.txt | xargs -n 1 -P 5 -I@ \
  curl "@" -m 2 -s -o /dev/null \
       -w "@,%{http_code},%{content_type},%{time_starttransfer}s\n" | sort) > res.csv
# httpでなにか配信されているものの列挙
$ (sed 1\!d res.csv;grep -v ,, res.csv | grep ,200,) > res_200.csv
$ echo $[`wc -l<res_200.csv`-1]
279
# httpsとかへの転送(301)
$ (sed 1\!d res.csv;grep -v ,, res.csv | grep ,301,) > res_301.csv
$ echo $[`wc -l<res_301.csv`-1]
180
```

結果は[こちら](https://gist.github.com/eggplants/b42c4136243317e27c2cdc0d04d78755)
またこれらの処理をまとめた[スクリプト](https://github.com/eggplants/sres)を書いた。

## 結論

お手軽。
PC リプレイス・交換時にクイックアクセス・ピン留めを移行する方法

# やりたいこと
PC リプレイスの時期きたユーザーからデスクトップ・マイドキュメントの移行の他、エクスプローラーに表示されている**「クイックアクセスのピン留め」**も移行して欲しいという依頼があり調査しました。

# 調査結果
クイックアクセスの保存場所がわかりました。このファイル移行元PCで取得し、移行先PCにコピーすれば移行されます。移行後は F5 キーを押せば表示されます。

#### ・クイックアクセスの保存場所
```
%AppData%\Microsoft\Windows\Recent\AutomaticDestinations\f01b4d95cf55d32a.automaticDestinations-ms
```

# バックアップ・リストア

#### ・バックアップ例（デスクトップに保存する）
```
copy /y %AppData%\Microsoft\Windows\Recent\AutomaticDestinations\f01b4d95cf55d32a.automaticDestinations-ms %USERPROFILE%\Desktop\.
```

#### ・リストア例（デスクトップから復元する）
```
copy /y %USERPROFILE%\Desktop\f01b4d95cf55d32a.automaticDestinations-ms %AppData%\Microsoft\Windows\Recent\AutomaticDestinations\.
```
salesforceライブラリにあるファイルのチェック

■ライブラリ
（ContentWorkspace）

select Id, Name, WorkspaceType from ContentWorkspace where Name = 'XXXX' <- ライブラリの名前

■コンテンツドキュメント
（ContentWorkspaceDoc）

select id, ContentDocumentId from ContentWorkSpaceDoc where contentworkspaceid = '(ContentWorkspace.Id)'

■コンテンツのオブジェクト（ER）
https://developer.salesforce.com/docs/atlas.ja-jp.object_reference.meta/object_reference/sforce_api_erd_content.htm
【Go】「binary.Write: invalid type 」が発生してバイナリ書き込みができない


# 問題

以下のような構造体をバッファに書き込もうとしてエラーが発生した。

```go:main.go
type T1 struct {
	A int8
	B int8
}

type T2 struct {
	T1
	C string
	D int8
}
var (
    t1 T1
    t2 T2
)

t2.T1 = t1
t2.C  = "hoge"
t2.D  = 1234

buf := new(bytes.Buffer)

// ここで該当のエラーが発生
//
// binary.Write: invalid type *main.T2
err := binary.Write(buf, binary.LittleEndian, &t2)


```

# 原因
埋め込みがまずいと予想していたが、どうやら**string**を書きこもうとして出力されるエラーだとわかった。

ドキュメントによると、[^1]
>Write は data のバイナリ表現を w に書き込みます。 data は，固定サイズ値または固定サイズ値のスライス，あるいはそのようなデータへのポインタでなければなりません。

# 対処法

なので、**string**を**固定長byte**に変換して、構造体へコピーすれば良さそう

[The Go Playground](https://play.golang.org/p/vG7vHTL2mgn)

```go:main.go
type T1 struct {
	A int8
	B int8
}

type T2 struct {
	T1
	C [10]byte
	D int8
}


var (
	t2 T2 // 書き込み用
	r2 T2 // 読み込み用
)

// 固定長byteにコピー
copy(t2.C[:], "hoge")

buf := new(bytes.Buffer)

// バッファに書き込み
err := binary.Write(buf, binary.LittleEndian, &t2)

// バッファから読み込み
err = binary.Read(buf, binary.LittleEndian, &r2)

// 固定長byteをstringに変換
fmt.Println(string(r2.C[:]))

```

# 参考
[^1]:https://xn--go-hh0g6u.com/pkg/encoding/binary/

[^2]:https://stackoverflow.com/questions/8039245/convert-string-to-fixed-size-byte-array-in-go

[^3]:https://groups.google.com/g/golang-nuts/c/jStV8yFcZiA?pli=1
Laravelエラーの解決方法 メモ

※随時追加していく

基本的にlaravel 6.x

##Seederでダミーデータ作成時

```..実行したコマンド
php artisan db:seed --class=FooSeeder
```

```..エラー
   Illuminate\Contracts\Container\BindingResolutionException  : Target class [FooSeeder] does not exist.

  at /var/www/project/vendor/laravel/framework/src/Illuminate/Container/Container.php:805
    801|
    802|         try {
    803|             $reflector = new ReflectionClass($concrete);
    804|         } catch (ReflectionException $e) {
  > 805|             throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
    806|         }
    807|
    808|         // If the type is not instantiable, the developer is attempting to resolve
    809|         // an abstract type such as an Interface or Abstract Class and there is

  Exception trace:

  1   ReflectionException::("Class FooSeeder does not exist")
      /var/www/project/vendor/laravel/framework/src/Illuminate/Container/Container.php:803

  2   ReflectionClass::__construct()
      /var/www/project/vendor/laravel/framework/src/Illuminate/Container/Container.php:803

  Please use the argument -v to see more details.
```

```..解決方法
composer dump-autoload
```
Laravel クエリビルダー メモ

よく忘れるのでメモ
※随時追加していく

##ANDとORの入れ子かつ変数を使いたいとき

`orWhere` と `use` を使う

条件の例(まともな例じゃないけどとりあえず)
`active = 1` かつ 
((`price < 100` かつ `status = 1`) または (`fruit = 'apple'` かつ `status = 2`))

```php 
$price = 100;
$fruit = 'apple';

$foo = Foo::where('active', 1)
    ->where(function ($query) use ($price) {
        $query->where('price', '<' $price)
            ->where('status', 1);
    })
    ->orWhere(function ($query) use ($fruit) {
        $query->where('fruit', $fruit)
            ->where('status', 2);
    })
    ->get() 
```

##複数の条件でjoinSubするやつ(あとで書く)
Raspberry Pi 4B にWindows10ARMを入れて SSDからブート その後１

前回投稿してから、再度 Windows 10 arm64を再インストールしてみました

SSD： Logitec LMD-SPA240U3
OS：Feature update to Windows 10, version 2004 (19041.906) arm64

手順は毎度お馴染みの方法です

SSDをラズパイのUSB3.0ポートに接続し、起動、セットアップが無事できました
今回はOCをしないでデフォルトの状態で行いました

今の所気づいた問題点が一つあります
USBメモリーを接続して、本体から取り外すとエラーメッセージが表示され
リブートしてしまいます
シャットダウンしてからUSBメモリーを取り外すようにしています

SSDをUSB3.0ポートで接続できるので、一歩前進ですね

３月２８日追記
一つポイントがあって、ISOファイルの作成を Windowsではなくて Ubuntu で行いました
SSDへの書き込みは Windowsで行いました

玄人志向GW2.5CR-U3 ではUSBメモリーの取り出しでもリブートしませんでした

ビルド情報がインストール直後19041.1になってしまうので、OSの versionを19041.906に変更しました

３月２８日追記 Part2
Windows ではどうしたら良いでしょうか、ということでチャレンジしてみました
UUP　dumpからダウンロードして展開したしたら ConvertConfig.ini というファイルがあります
メモ帳で開いて AddUpdates = 1 を 2に変更して保存してください
あとは通常の手順でOKです

この続きは　https://qiita.com/jibri/items/9113eeffbf5daa31c0e2
README　画像挿入の仕方

## README　画像挿入
Qiita記事では多くのREADMEについての画像の挿入の手順を解説している記事があります。
今回私は、上記記事でのやり方とは違った、googleの拡張機能を使用した画像作成・READMEに画像挿入までの手順を解説します！！

というのも、閲覧記事で参考になったものは多くありましたが、googleの拡張機能を使用した画像挿入についての記事は、調べたところでは見当たらなかったので、
自身で挿入から、解決まで行いました。

ご参考までにしていただけたら幸いです。

## なぜ他記事を参考にしなかったか
今回、自身で作成したポートフォリオでは、トップページだけでもかなり下にスクロールして全体像が見えるという、課題がありました。
通常のスクリーンショットでは、一画面に収まりせんでした。
gif画像でもgyazoを使用して全体を撮影することも実行しましたが、
撮影秒数が決められたなか全てを撮影するのは困難且、見にくい画像となってしまいました。

そこでgoogle拡張機能の「Awesome Screenshot」を使用し、全体を撮影できるようにしました。

## Awesome Screenshot
googleの検索で「Awesome Screenshot　拡張機能」と検索していただいたらでききます。
インストールを行ったら順位完了です！

Awesome Screenshotではフルページ画像がとる事ができ、非常に使い勝手が便利な拡張機能となっています。

## 画像撮影手順
インストールしたAwesome Screenshotを撮影したいHPでクリックします。

1.クリック後上部バーで「レコード」「キャプチャ」の選択蘭があるので、「キャプチャ」をクリック

2.「キャプチャ」をクリックしたら、「フルページ」をクリック

3.「フルページ」をクリック後、自動でページを撮影できます

4.撮影した画像をダウンロードして完了


非常に簡単な手順でフルページの撮影ができるのでおすすめです！！

## READMEに画像情報記載
ダウンロードした画像を、自身の開発中コードのディレクトリに挿入します。
※画像専用のディレクトリを作成しておくことをおすすめします

私の場合、ダウンロードした画像を
public/imagesディレクトリに格納しています。

後は、格納した画像をREADMEに記述するだけで画像挿入ができます。

```
<img src="public/images/画像名">
```

## まとめ
非常に簡単に且フルページでの画像挿入ができるので、スクリーンショットで何枚も画像をとる手間を省けます！！

今回掲載した内容は他のqiita記事には調べた限りなかった為、
共有させていただきます！！

issueを利用した画像挿入の仕方もあるので、その際は他の記事にも乗っているのでそちら参考にしていただけたらと思います！！

宜しくお願いします。
liタグの点を消す

#liタグの点
liタグの点はビュレットと呼ばれる。ビュレットを消してスペースを詰めるには

~~~css
li{
   list-style-type: none;
   padding-left: 0;
}
~~~

とする。

#参考
[横並びのリストを中央寄せにする5つの⽅法 - CSSテクニック - acky.info](https://www.acky.info/tips/css/00011.html)
PythonでGoogleNewsを日本語かつjsonで取得する

Googleのニュースは、例えばビットコイン関連のニュースが取得したい場合、実は以下のようなURLで取得できる
https://news.google.com/rss/search?q=ビットコイン&hl=ja

[参考]↓
[Google News Rss(API)](https://qiita.com/KMD/items/872d8f4eed5d6ebf5df1)

ただ、これだと結果がxmlなのでちょっと扱いづらい…
検索すると以下のようなライブラリがあったので使用してみた

https://pypi.org/project/GoogleNews/

ドキュメントの通り、以下のように書いて動かしてみたが、エラーが出る

```python
from GoogleNews import GoogleNews

googlenews = GoogleNews(lang='ja', encode='utf-8')
googlenews.get_news('ビットコイン')
result = googlenews.results()
print(result[0])
```
```
'ascii' codec can't encode characters in position 14-19: ordinal not in range(128)
```

Pythonが3になって以来、とんと見かけなくなったエラーだったので焦ったが、どうやら以下の記事によると、日本語や中国語に対応していないらしい。

https://clay-atlas.com/us/blog/2020/01/21/python-english-note-package-googlenews-get-google-news/

なので、引数をurlエンコードして渡してやればうまく動いた。

```python
from GoogleNews import GoogleNews
import urllib.parse

googlenews = GoogleNews(lang='ja', encode='utf-8')
googlenews.get_news(urllib.parse.quote('ビットコイン'))
result = googlenews.results()
print(result[0])
```
2021/03/25 12:40時点での実行結果は以下の通り

```
{'title': '指標が示すビットコインの強気相場：リザーブリスクとは', 'desc': 'ブロックチェーン・データは、保有者や購入検討者にとってビットコインが依然として魅力的であることを示している。相場は最高値をつけた以降、小康状態に ...', 'date': '19 時間前', 'datetime': datetime.datetime(2021, 3, 24, 8, 7, 25), 'link': 'news.google.com/./articles/CAIiEJ1D6QqbEkjOiubGSaHHO8oqMwgEKioIACIQKQ8vX7rIbv4J-a3Vk64LmCoUCAoiECkPL1-6yG7-Cfmt1ZOuC5gwtazdBg?hl=ja&gl=JP&ceid=JP%3Aja', 'img': 'https://lh3.googleusercontent.com/UMKcCAW6LczwEg3VALRBEq2G4NMvb3qoL7daQxDrnY62oGIhQf3NIb002kqxWK5ENcX-3N6uJ51M5vJiRf5J=-p-df-h100-w100', 'media': None, 'site': 'コインデスク・ジャパン'}
```
SQL基礎　sum,avg,maxなど

こちらの記事では、私が学んだSQLについて記載しております。
自身の忘れないためのメモとしております。
間違っている部分もあるかもしれませんので、ご了承ください。


#sumで合計値を出す

```
select
	sum(カラム)
from
	テーブル名
where
	カラム名 >= '日付'　　
and カラム名 < '日付';　　　　←範囲の条件式
```


#avgで平均を出す

```
select avg(カラム名) from テーブル名;
```

#minで最小値を出す

```
select min(カラム名) from テーブル名;
```

#maxで最大値を出す

```
select max(カラム名) from テーブル名;
```

#countで数を数える

```
count(*)とすると、テーブルの行数を取得できる！

select count(*) from テーブル名;
```

#countを使用して限定を行う（ユニークユーザー数を求める場合）

```
・count(distinct カラム名)　を入れることで重複を避けるcount方法になります。
同じuserをカウントしないため！

select 
　　count(distinct user_id)　←カラム名
from 
	access_logs　　←テーブル名
where
	month = '日付';　←カラム名
```

#group byを使用して、グループ化を作成する

```
・カラム名_aをグループ化して分ける
select カラム名_a, count(*) from テーブル名 group by カラム名_a;

・下記は、重複したuser_idは避けて、月毎にユーザー数をカウントしてます。
select 
  month, count(distinct user_id)　同じuserは省かれる！
from 
  access_logs 
where 
  month >= '2020-01-01' 　where...and...で期間の限定！
and 
  month < '2021-01-01'
group by 
  month;　　　月ごとの結果を出すよう指定！
```

#havingを使用して条件式の追加を行う

```
・記述方法 havingは、group byの後に書くことが重要！！！！！！
select
  カラム名
from
　テーブル名
where
　条件式
group by
　カラム名
having
　条件式

・having テーブルのデータを集約した結果に大して、条件式を適用する
select 
  month, count(distinct user_id)
from 
  access_logs 
where 
  month >= '2020-01-01' 
and 
  month < '2021-01-01'
group by 
  month
having count(distinct user_id) >= ５００;  500以上のユーザー数をカウント　重複は省かれる！
```


#補足

###null(コラム）

```
０という意味ではなく、値がないことを示す特別な表現になる。
nullを使用する前に、別の方法で使用できないか検討した方が良い！！
```

###SQLの記述の順序/実行順序
```
記述順序　　　　　　　　　　　　　　　　　　　実行順序
select・・・・・取得カラムの指定　　　　　　　　　　from・・・・・・・対象テーブルの指定
from・・・・・・・対象テーブルの指定　　　　　　　　　where・・・・・・絞り込み条件式の指定
where・・・・・・絞り込み条件の指定　　　　　　　　　group by・・グループ化の条件を指定
group by・・グループ化の条件指定　　　　　　　　having・・・・・グループ化した後の絞り込み条件を指定
having・・・・・グループ化した後の絞り込み条件指定  select・・・・・取得カラムの指定
order by・・・並び替え条件指定　　　　　　　　　 order by・・並び替え条件を指定
limt・・・・・・・・取得する行数の制限　　　　　　　　 limit・・・・・・取得する行数の制限
```
Google workspace や Gmailのメールアドレスを使って、pythonから送信する。

# 本記事の対象者

 - GCPでサービスを作り、メールを送信する仕組みを無料で作りたい人。(サービスのホスティングが無料ではなく、メール送信部分だけ)


# 目的
sendgridなどの外部のサービスを使わずに、pythonを使ってgmailを送信する。

# 必要なもの
 - Gmail または、Google workspaceのアカウント (Google workspaceは管理者権限が必要)
 - pythonを動かす環境

# メールの設定
### 送信者の設定

[設定](https://myaccount.google.com/intro/security)から二段階認証を有効にする
![スクリーンショット 2021-03-25 11.24.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/d628628e-b797-bccd-0bed-8e1ae312e115.png)

二段階認証有効後、アプリパスワードを作成する
![スクリーンショット 2021-03-25 11.31.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/bb45e9be-d7bf-c48c-084a-4fa6fcc85320.png)


メールを選択し、「その他」を選び、「〇〇用」などとラベルを決める
![スクリーンショット 2021-03-25 11.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/27d8b545-6cbb-ef26-7765-54e844b8a02d.png)

「生成」ボタンを押すと、パスワードが表示される(再表示は不可能)ので、パスワードをメモする。


### Google workspaceの設定
[管理画面](https://admin.google.com/u/1/?hl=ja)からアプリを選択
![スクリーンショット 2021-03-25 10.58.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/816e5a2e-962f-e4f8-df2f-4fa9429a2a88.png)

アプリから「Google Workspace」を選択
![スクリーンショット 2021-03-25 11.01.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/8b8765d2-b4d1-afdc-b0b6-54c7ccd02989.png)

「Gmail」を選択
![スクリーンショット 2021-03-25 11.02.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/d04ad02a-5375-a580-37f2-bf83115f568e.png)

「ルーティング」を選択
![スクリーンショット 2021-03-25 11.04.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/f31674bc-7caa-1cac-573b-8b076b8940fc.png)

SMTPリレーサービスの設定をクリック
![スクリーンショット 2021-03-25 11.06.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/2cd29d9d-f8bf-aac6-1fcb-1ad8f51c03ab.png)

設定項目を下記のように入力(名前は利用内容を書いてください)して保存
![スクリーンショット 2021-03-25 11.07.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38197/4340ac3c-667b-b6ba-39a0-6a27cd28382b.png)


# pythonでの処理

```python
import smtplib
from email.mime.text import MIMEText


message = "メール本文"
msg = MIMEText(message, "html")
msg["Subject"] = "メール表題"

# 587はポート番号
smtpobj = smtplib.SMTP('smtp.gmail.com', 587)

smtpobj.ehlo()
(250, b'smtp.gmail.com at your service, [27.82.28.239]\nSIZE 35882577\n8BITMIME\nSTARTTLS\nENHANCEDSTATUSCODES\nPIPELINING\nCHUNKING\nSMTPUTF8')

smtpobj.starttls()
(220, b'2.0.0 Ready to start TLS')

smtpobj.ehlo()
(250, b'smtp.gmail.com at your service, [27.82.28.239]\nSIZE 35882577\n8BITMIME\nAUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH\nENHANCEDSTATUSCODES\nPIPELINING\nCHUNKING\nSMTPUTF8')

smtpobj.login("送信設定したメールアドレス", "生成したアプリパスワード(メールのパスワードではない)")
(235, b'2.7.0 Accepted')

# 送信実施
smtpobj.sendmail("送信設定したメールアドレス(from)", "送信するメールアドレス(to)", msg.as_string())
```
Kotlinで二重list

#概要
Kotlinで二重listを作る。

#動機
AtCoderで使いたかった。調べてもなかなか出てこなかったので記事にした。

#やり方
```
var xy_list = MutableList(3){ MutableList(4){0} }

//結果
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
```
ポートフォリオのHTTPSの読み込みが遅いのを改善した話

#HTTPS化したらやたらと読み込みが遅い時がある...

HTTPSでサイトにはアクセスできているのに、5回に一回くらい読み込みがされない...なんでだろうか？


##結論から言ってしまうと...

**ロードバランサーの役割をしっかり理解していないのが原因でした。**

##ロードバランサーとは？

ロード(load、負荷)＋バランサー(Balancer、平衡を保つためのもの)で、サーバーやネットワークに関連する用語であり、装置の名称です。
この仕組みにより、**Webサイトへのアクセス集中やサーバー故障などの場合でも、アクセス中の利用者に安定したサービス提供を継続可能になります**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918117/f93fee75-6948-9897-30c0-092f3a2259bd.png)


まとめるとロードバランサーの役割は大きく2つです。

①パフォーマンスの向上
サーバの追加台数分、クライアントへの対応を処理可能

②可用性が向上
特定のサーバがダウンしても、別のサーバでサービス継続可能

##今回の謎の経緯

HTTPS化の方法はたくさんあるのですが、今回は「AWS Certificate Manager（ACM）」でやりました。
それに伴って、ロードバランサーは「Application Load Balancing（ALB）」を使用しておりました。

最初は「通信環境の不調なのか」、「インスタンス等の設定に不具合があるのか」はたまた「取得したドメインに問題があるのか？」など、今思うと的外れな心配ばかりしていました。色々と記事を辿っていくと「JavaScriptや画像が重いと読み込みが遅くなる」という内容の記事をいくつも見つけ、「なんかこれっぽいな...」と勝手に決めつけ、一つ一つ手当たり次第に原因を潰していく...といった感じで何に原因があるのかも理解できていない状態でした。

そこから検索のワードを少しずつ変えて記事を調べていくと、この記事に辿り着きました。

https://qiita.com/TakenoriHirao/items/a3ace404d785e6a4db22

すぐに自分の直面している状態と似ていると思い、ロードバランサーの設定を見直しました。


##ロードバランサーの設定を見直す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918117/a42f887b-45d4-7dcc-84ac-ce92a5cfa7fd.png)

この時に本来であれば「パブリックサブネット（外部からのアクセス可能な空間）」を2つ選択しないとロードバランサーの意味を成さないのですが、今回作成したVPCには「パブリックサブネットが１つ」と「プライベートサブネットが２つ」しかなく、「少なくとも2つのサブネットを指定する必要あります」というメッセージ通りに設定するとなると、必然的に片方を「プライベートサブネット」にしなければ先に進めない状態でした。

**原因はこれです。**

「サブネットにアタッチされたインターネットゲートウェイが存在しません」という注意勧告を出していてくれたのにも関わらず、無知な僕は先に進めることを良しとし、メッセージの意味を理解していませんでした。

ロードバランサーは最初にも説明した通り「負荷分担装置」です。
その役割は、ユーザーからのアクセスを平等に割り振ることです。
察しの良いみなさんなら勘づいているでしょうが、「プライベートサブネット」に割り振られてもアクセスできないため、結局はもう一方の「パブリックサブネット」へと戻されます。

**「読み込みの遅い」**というのは、つまりそういうことでした。
来た道を戻ってまた別の道に行っていたらそりゃ遅くなりますよね。


##解決方法

解決方法は簡単です。
VPCに「パブリックサブネット」を新たに追加してあげるだけです。
追加したサブネットをロードバランサーの作成時に設定してあげれば、通信がどちらに割り振られてもサーバーへのアクセスが可能となり、読み込み速度が改善されました。


##最後に

今回の「ロードバランサー」同様に、**性能の有能さに甘えてしまって、なんとなくで使ってしまっているツール**がたくさんあるので、これを機にしっかりとその子が何を得意としているのかを理解してあげることが大事なんだなと痛感しました。
最後までお付き合いいただきありがとうございます。
PythonでNewsAPIの日本語記事を取得する方法

NewsAPIで日本語記事を取得しようと思ったらうまくいかなかったのでメモ

https://github.com/mattlisiv/newsapi-python

上記のライブラリを使用する。


https://newsapi.org/docs/client-libraries/python

上のドキュメントを参考にすれば、

```python
# /v2/top-headlines
top_headlines = newsapi.get_top_headlines(q='ビットコイン',
                                          language='ja',
                                          country='jp')
```

とかすれば取れそうだが、これだと取得できない。

https://newsapi.org/docs/endpoints/sources

どうやらlanguage項目に'ja'がないらしい。
というわけで、

```python
# /v2/top-headlines
top_headlines = newsapi.get_top_headlines(q='ビットコイン',
                                          country='jp')
```
とかやってみたら取れるかと思ったらこれまた取れない…
ライブラリを覗いてみると、

```newsapi_client.py
 def get_top_headlines(  # noqa: C901
        self, q=None, qintitle=None, sources=None, language="en", country=None, category=None, page_size=None, page=None
    ):
```

なんとlangugeのデフォルトの引数が"en"に設定されている。
なので明示的にNoneを渡してやれば動く。

```python
# /v2/top-headlines
top_headlines = newsapi.get_top_headlines(q='ビットコイン',
                                          language=None,
                                          country='jp')
```
これで取得できた
【21.03.25】Githubのprivateリポジトリをpublicに変更する

#経緯
PFに経歴など個人情報を書いてるので、初めてprivateリポジトリを作成した。
メンターさんにソースコードを共有するために、共有リンクが欲しいのだが、そのままのリンクを送ると404エラーになってしまう。
デザイナーのメンターさんなので、githubのアカウントも持ってないらしいので、仕方なくpublicリポジトリにすることにした。


#やり方

①publicにしたいリポジトリのページにいってSettingへ
![スクリーンショット 2021-03-27 9.46.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619224/d995460a-ed4e-7fe3-6f2e-2e2f2bc0516b.png)

②settingの下のほうにあるDangerous Zone > Change repository visibility > change visibilityボタンをクリック

![スクリーンショット 2021-03-27 9.54.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619224/f58fd084-7e0b-b4c7-73f7-5035b50b4989.png)


③変更用のタブが出てきて、privateにチェックが入ってるので、publicに変更し、アカウント名/リポジトリ名を入力したら完了


めちゃくちゃ簡単でびっくりした

#Githubアカウントを持っている人に共有する場合

は、以下のリンク通りにやればできそう

https://docs.github.com/ja/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository
【laravel】`base table or view already exists 1050 table 'users' already exists`が出た時の、php artisan migrate:fresh以外の解決法

# はじめに
　laravelでmigrationをタイポで間違えて、やり直した際に、`base table or view already exists 1050 table 'users' already exists`が出た際に、よくある解決法が、`php artisan migrate:fresh`


でも、ローカルのDBをリセットしたくない！！　って思いませんか。
そんな思いを持った私が見つけたもう一つの解決方法です！！

ぜひ、`php artisan migrate:fresh`をせずに、マイグレーションを成功させましょう！

#前提

##環境
PHP 7.4.16 
Laravel  6.20.17
mysql   8.0.23
nginx 1.18.0

##  作りたいテーブル
`location_tagテーブル`

|  カラム名  |  型  | 外部キー |
| ---- | ---- | ---- |
|  id  |  int  ||
|  location_id  |  int |○ |
|  tag_id  |  int |○ |

## エラー文　（php artisan migrate 実行時）
```
   Illuminate\Database\QueryException  : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'location_tag' already exists (SQL: create table `location_tag` (`id` bigint unsigned not null auto_increment primary key, `location_id` bigint not null, `tag_id` bigint not null, `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')

```


#解決方法
##1
`php artisan tinker`で`tinker開く

##2
テーブルが存在するか確認する

```
＄Schema::hasTable("location_tag");
//location_tagはデーブル名
=> true
```

##3
特定のテーブルだけ削除する

```
＄Schema::drop("location_tag");
```

##4
テーブルが消えたか確認する

```
＄Schema::hasTable("location_tag");
//location_tagはデーブル名
=> false
```

##5
tinkerを終了し、マイグレーションの状態を確認する

```
php artisan migrate:status
```

##6
マイグレーションをrollbackする

```
php artisan migrate:rollback

```
##7 
再度、migrateする

```
php artisan migrate

```


これにて完了！！



# 参考
https://readouble.com/laravel/6.x/ja/migrations.html
オンライン施設予約システムを実現する#2ツール紹介編

#はじめに
[前回の記事](https://qiita.com/dorarobo/items/8c03c81fff1ee1793cb3)
でシステムの簡易的な説明を書きました。
今回は利用したツールについて書いていきます。

#ツール（予約システム）

###Office365
* MSTeams
* SharePoint
* PowerAutomate
* PowerApps

###Google
* カレンダー
* Gmail

##MicrosoftTeams
https://www.microsoft.com/ja-jp/microsoft-teams/group-chat-software
（申請者）【機材・施設申請システム】の申請タブから申請・申請取り消し・空室状況等の確認ができます。
（承認者・スタッフ）【機材・施設スタッフ用】から承認処理・貸出処理ができます。
（システム管理者）【CLC運用システム】チームに所属することで各システムの編集権限を取得できます。

システムとしては申請権限を【機材・施設申請システム】チームのメンバーで管理をしています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/2e6916ee-6bca-c7a3-a705-3932754938f7.png"width=70%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/4992d3aa-c8ce-df7e-d4f8-3c5907d2c8ae.png"width=41.5%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/d457feab-6a19-8b3c-55c7-9f67ca114795.png"widht=50%>

##SharePoint
https://www.microsoft.com/ja-jp/microsoft-365/sharepoint/collaboration
システムの基盤としてSharePointを活用しています。

* 申請管理（リスト機能）
* 権限管理（Teamsの各チームメンバー毎にアクセス編集権限を管理）
* ポータルサイトとして使用
* ツールとしては機能は多いですが設定方法等が複雑です・・・

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/40583764-9f69-ab21-4f30-429797cfc9b9.png"width=70%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/c4fcc1eb-e947-6dce-574b-f5c966995497.png"width=70%>

##PowerAutomate
https://flow.microsoft.com/ja-jp/
ブロックベースでフローを作ることができます。基本的にノープログラミング！

申請をトリガーとして承認要求・受付メール・カレンダー登録など自動で処理をしてくれます。
紙での申請と比べて様々な作業を自動ができるのでスタッフの負担軽減になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/418ba09c-35e3-d323-f70e-2818eff66132.png)

##PowerApss
https://powerapps.microsoft.com/ja-jp/
申請時等に使用するアプリを作成します。
PowerPoint感覚で簡単に画面と機能を配置していくことができます。

スマホアプリとして作ることもできるので可能性が無限大ですね
（別でバーコードを使った管理アプリ作って作業効率化してます）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/4ec01e1a-14f3-598a-24cd-2d97a1fcb85c.png"width=80%>

##Googleカレンダー
空室状況の確認とサイネージ用データとして利用。
記入はPowerAutomateで自動化（別章で紹介します）

##Gmail
申請者宛に予約受付完了・承認・却下など申請状況をメールでお知らせします。
Office365単体でメール送信できますが送信メールアドレスの関係で利用しています。


#次回
いよいよ開発編に入りたいと思います！
「ゼロから作るDeep Learning」の 503 Service Temporarily Unavailable の対処法

mnistのダウンロードエラー、kerasで対応してたのですが

```
from keras.datasets import mnist
from keras.utils       import np_utils
(x_train, t_train), (x_test, t_test) = mnist.load_data()
# データをfloat型にして正規化する
# データ数×縦ピクセル数×横ピクセル数のデータをデータ数×784の方にする
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test  = x_test.reshape(10000, 784).astype('float') / 255

# ラベルをone_hot形式に変換
t_train = np_utils.to_categorical(t_train, 10)
t_test  = np_utils.to_categorical(t_test, 10)
```
7章あたりのtrain_convnet.pyなどでは、
`ValueError: not enough values to unpack (expected 4, got 3)`
のエラーなどがでて動きませんね。

```
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
```

ダウンロードのところを以下の処理に変更したら動きました。

```
from keras.datasets import mnist
from keras.utils import np_utils
(x_train, t_train), (x_test, t_test) = mnist.load_data()
x_train = x_train.astype(np.float32)
x_test = x_test.astype(np.float32)

x_train = x_train.reshape(-1, 1, 28, 28)
x_test = x_test.reshape(-1, 1, 28, 28)
```
HTTPレスポンスステータスコードとは（見方まで図解）

#HTTPレスポンスステータスコード　とは#
結論、

`サーバーからページ取得時の状態を教えてくれるコード`

図にしてみると、こんな感じ

![無題の図形描画.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679667/5ff9a4f5-edfd-459e-d127-e362e2198f98.png)

この「404」という数字がHTTPレスポンスステータスコード:mountain:

#HTTPレスポンスステータスコードの種類#

種類は下記の通り。

```
①情報レスポンス (100番台)
②成功レスポンス (200番台)
③リダイレクト (300番台)
④クライアントエラー (400番台)
⑤サーバエラー (500番台)
```

一桁目を見れば、どんな状態かが分かる。

よく使われるのは下記。

```
202:OK　　　　　　　　　　　　　成功
301:Moved Permanently　　　　ページが永久的に変更されたところへ移動
302:Found　　　　　　　　　 　 ページが一時的に変更されたところへ移動
400:Bad Request　　　　　　　 アクセス方法に問題あり
403:Forbidden　　　　　  　　 ページのアクセス権がない
404:Not Found　　　　　 　　  ページがない　（一番みるやつ）
500:Internal Server Error　 サーバー側で謎のエラー
503:Service Unavailable　   アクセス集中の過負荷などで接続できない
```

#HTTPレスポンスステータスコードの見方#

**① ⌘ + U + I　でディベロッパーツール起動**

**② Network　をクリック**

**③ ページを更新または遷移**

**④ status　を確認**

![スクリーンショット 2021-03-25 0.46.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679667/c4d1f0ea-62ad-a9a6-af66-2b881d16d4d0.png)

#HTTPレスポンスステータスコードのメリット#
HTTPレスポンスステータスコードを理解することで、

◎ページの状態やエラー時の原因が分かる
◎ サーバとクライアント間の開発がスムーズに進む
◎設定次第でSEOに大きく関わってくる

以上。
Macにgrpcをインストールする方法

#解決方法
Mac(Big Sur)にfirebase-admminをインストールしようとしたらgrpcのpipでコケたので対応した。
以下の環境変数を設定するとうまくいった

```
export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=true
```

どうやらCatalinaとBig Surだとうまくいかないらしい。

#参考
https://stackoverflow.com/questions/65807966/poetry-install-grpcio-fails-with-envcommanderror
https://bleepcoder.com/fr/grpc/737099678/grpc-does-not-compile-on-mac-os-catalina-10-15-6-big-sur-11
卒業制作で初めてリーダをしたときの経験備忘録


# 最初に
当時情報系の専門学校に通っていた時の話。
もう卒業してだいぶたっているので、時効かなと思って備忘録を作成しました。
社会人の皆様から見たら当たり前のことばかり書いてありますが、未熟な学生時代の話ということでご容赦ください。

# 目次
- 卒業制作概要
- 発生イベント（ほぼ時系列順）
    - １．チームメンバーの知識不足への対応
    - ２．ルールの策定
    - ３．そのほかの対応
    - ４．早期出社により１名が離脱、そして機能縮小
    - ５．勉強会
    - ６．システム結合
    - ７．そして成果外部発表、優秀賞へ
- 全体を通して
- 最後に

# 卒業制作概要
チームメンバーは自分含めて７人。メンバー分けは先生が行った。
メンバー全員が３年課程の同じカリキュラムを学ぶクラスに所属。
Java以外ほとんど授業で触ることはなく、実習ではWebアプリケーションを中心に作成していたため、卒業制作でもWebアプリの作成を行った。
リーダ決めは秒で私以外の全員一致して私に。
前期は他の授業と並行して要件定義や基本設計書などの作成を行い、後期からコーディングに入った。

# 発生イベント（ほぼ時系列順）

### １．チームメンバーの知識不足への対応
卒業制作に入る前の授業で発覚したのだが、チームメンバーのうち３人は基礎知識から抜けていた。

最初のころは他の授業も並行で進んでいたため、放課後の時間を利用して先生方から授業資料を~~パクって~~頂戴してチームメンバーに授業を行った。

### ２．ルールの策定
そんな状態だったので、コーディングに入っても、自分が一体何がわかっていてわかっていないかわからない状態。
質問しようにも、どう質問したらいいかわからないということで、いくつかのルールを最初に策定した。

- 10分自分でググってわからなければ誰かに質問をする
    - 質問の際はエラーコードとソースコード必須。
    - エラーに対して自分が何を調べて何を実施したかを必ずいう。
- 作業終了時刻五分前に終礼の実施
    - 内容は進捗状況報告や伝達事項など
- 朝の時点で全員への連絡事項や問題提起があれば朝礼の実施
- １週間に１回、ゼミ担当の先生を含めた会議または勉強会の実施
    - 勉強会はあまり中身は問わない、息抜き的なもの

結果的に知識不足のメンバーは他メンバーと同じレベルまで成長した。


### ３．そのほかの対応
状況に応じていくつかの対応を行った。中でも効果の上がったことを書く。

- 開発に消極的なメンバーのデスクをリーダ（私の隣）に配置
- ペアプログラミング（もどき）の実施
- その日の進捗状況や作業状態に対してのフィードバックを終礼で行い、記録しておく
- 必要に応じてメンバーとゼミ担当の先生を含めた個別面談

特にペアプログラミングの実施は、各メンバーにとってとてもいい影響を与え、結果的にチーム全体の能力向上につながった。
隣にすぐコードについて聞ける、一緒に調べてくれる人がいるという状況がよかった模様。
私にとっても、リーダ業務に専念することができ、また質問自体の質が向上したためとても良い取り組みになったと思う。
また終礼で必ずフィードバックを行っていたため、チーム全体のコミュニケーションが活発化。風通しの良い雰囲気を作ることができた。

### ４．早期出社により１名が離脱、そして機能縮小
かなり頼りがいのあるメンバーだったこともあり、作業予定を見直したところ、機能の縮小は避けられない結果となった。
この品質と納期、メンバーへの仕事を割り振るバランスなどが難しかった。

### ５．勉強会
上のほうでも息抜きがてらの勉強会を週１で行ったことを書いたが、これが非常にメンバーからの評判が良かった。
特に評判がよかったのは、一人一つお題をランダムに決め、それについて調べてパワーポイントにまとめ、次回の勉強会で発表を行うというものであった。
お題も技術関係ではなく、「メガネの歴史」「バナナについて」など、息抜きになるものを出し合って決めた。

実は卒業制作の合間に進捗状況など他チームや先生方に対して発表を行うイベントが存在していたため、発表やパワーポイント作りの良い練習になったようだった。
これにより最終的に成果発表時に緊張が薄れたという効果もあったとのこと。

### ６．システム結合
何が一番大変だったかというと、システム結合が大変だった。
特に初期の知識不足だった時のコードがコード設計などを無視したものになっており、結合したときにエラーをはきまくったり、コメントがほとんどなかったりしたため、コードを読むにも一苦労だった。
そして他人のコードを解読して結合できるスキルと時間があるのは私のみだったため、この結合作業をほとんど私が行い、結合終了したところからテストを他メンバーにしてもらった。

こればっかりはしょうがないが、今思えば初期の時点でコードレビューを実施しておけばコードが難読化することはなかったと思っている。

また、ここで次があればぜひ参考にさせていただきたいと思ったコードレビューの投稿を共有させてほしい。

https://qiita.com/gakuri/items/f4970aea8de5fa9bf016

### ７．そして成果外部発表、優秀賞へ
成果発表は内部で行われるものと、内部で先生方や学生のアンケートで評判がよかったものがいける外部発表があった。
そのなかで私たちは認められ外部発表へ行くことができ、優秀賞を受賞することができた。

# 全体を通して
知識不足は努力次第で何とかなるが、コミュニケーションが不足するとどうにもならないことがよく分かった。
他チームがコミュニケーション不足でボロボロになっていくところを間近に見ていたので、これから初めてチームで一つの作品を作る人や、卒業制作をする人は特にコミュニケーションを重視してほしい。
また、チームメンバーが私（リーダ）に対して協力的であったことも助かった。
そうでなければ対応策も取れなかったと思う。

また、いろいろなトラブル対応をしていくうえで、致命傷ではないたいていのことは「おもしろくなってきた」と軽く流せるようになった。
正直社会人になってからはこれが一番役に立っていることかもしれない。

# 最後に
結果としてはとてもいい状態で終わることができ、良かった。
初めてほかの人と大きなプロジェクトを行うことで、いろいろな経験をし、スキルアップできたと思う。


あとは、初めてチームで一つの作品を作る人や、卒業制作をする人の参考になれば幸いです。
ChromeブラウザでGoogleドライブにファイルをアップロードできない問題があった場合の対処法

```
サーバーでエラーが発生しました。しばらくしてからもう一度お試しください。
```
```
アプリの読み込み中に問題が発生しました。
```
などのアラートが出てファイルのアップロードやパンくずが表示されなくなる問題が発生した場合の対処方法のメモ。

### 大抵の場合機能拡張が原因
機能拡張を全てOFFにしたあと、一つづつ機能拡張をONにして、Googleドライブの画面を更新して原因を探る

### 過去にGoogleドライブで問題があった機能拡張
CORS Unblock
VBA: メッセージとログの作成

処理内容を言葉で表示したい場面があります。

* 進行状況をステータスバーに表示したい
* 処理成功時に完了メッセージを表示したい
* 処理失敗時にエラーメッセージを表示したい
* 自動実行時にログを出力したい

上記を効率よく行うにはどうすればいいか迷うことがあったので、Excel VBA でサンプルを作成してみました。あまり言語を問わないことなので、他の言語でよく行われているやり方も知りたいと思っています。

```VB:log1.bas
Sub 個別処理(item, Optional ByRef msg As String)

On Error GoTo Catch:
    
    Application.StatusBar = "処理1を実行中"
    '処理1
    
    Application.StatusBar = "処理2を実行中"
    '処理2
    
    Application.StatusBar = False  'StatusBarをExcelに返す
    msg = "完了しました: " & item
    GoTo Finally

Catch:
    msg = Application.StatusBar & "にエラーが発生しました( " _
          & Err.Number & "): " & item

Finally:
    MsgBox msg  'メッセージ表示（必要な場合）

End Sub
```
どの段階でエラーになったかを示すために、エラーメッセージの中に
`Application.StatusBar = なんとか` の部分がコメント代わりになるという効用もあります。`GoTo Finally`を忘れるのはよくあるミスです。上記はSubにしましたが、Functionにして成功/失敗を`True/False` で返すのもよさそうです。

呼び出し元は（ざっくりですが）下のようになります。

```VB:log2.bas
Sub 全体処理()    

    Dim msg As String, log As String    

    Dim item, items
    For Each item In items
        Call 個別処理(item, msg)
        log = log & msg & vbCrLf
    Next i   

    Debug.Print log

End Sub
```
Viteでrobots.txtを公開する

Viteでrobots.txtを公開する方法です。

本ページはReact + Typescriptのプロジェクトを作成した場合の例になります。

## `public`ディレクトリーを作成してファイルを配置

```
：
├ my_app/
│　├ dist/
│　├ node_modules/
│　├ public/
│　│　└ robots.txt
│　└ src/
：
```

## `vite.config.ts`を編集

`assetsInclude: ["robots.txt"]`をコンフィグに追記します。
デフォルトでは`public`ディレクトリーを参照するようになっていますが、変更することもできます。

```typescript
import { defineConfig } from "vite"
import reactRefresh from "@vitejs/plugin-react-refresh"

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [reactRefresh()],
  assetsInclude: ["robots.txt"],
})
```

## 確認

ローカル環境で確認するには`yarn dev`を実行して`http://localhost:ポート番号/robots.txt`で`robots.txt`の中身が表示されれば成功です。

## 補足

`yarn build`を実行すると`dist`ディレクトリーにファイルをコピーします。そのため`dist`ディレクトリーにファイルがあるかどうかで確認することもできます。