OmniAICreator/Qiita-1.07M huggingface dataset:
SFTサーバのインストール

# やりたいこと
Wordpressサーバの構築の際に、wordpressコンテンツのみ参照できるftpユーザを作成したい為、覚書を作成。
誰かに役に立てばいいと思います。

# サーバ環境
**OS**：CentOS Linux 7（core）
**rootディレクトリ**：/var/www/html/public_html

# 確認すること
- vsftpdのインストール
- ftpユーザの作成
- ftpユーザのキーを作成(sftp接続のため)
- まずssh接続の確認
- sftp接続を確認
- sshを禁止
- ユーザの作業ディレクトリとコンテンツをマウント
- コンテンツの権限を変更

# 手順
## vsftpdのインストール
```sh:
yum install vsftpd
```
## インストールの確認
```sh:
yum info vsftpd
```
## ftpユーザ作成
```sh:
useradd -m sftp-user
```
## ftpユーザのパスワード設定
```sh:
passwd sftp-user
```
## ftpユーザのキー作成
```sh:
cd /home/sftp-user/
ssh-keygen -t rsa
```
## ftpユーザのキー作成
```sh:
cd /home/sftp-user/
ssh-keygen -t rsa
chmod 600 ~/.ssh/id_rsa.pub
mv id_rsa.pub authorized_keys
```
## 秘密鍵はlocalに転送し、権限変更
```sh:
chmod 600 ~/.ssh/id_rsa
```
## ssh接続の確認
```sh:
ssh -i ~/.ssh/id_rsa sftp-user@[PublicIP]
```
## sftp接続の確認
```sh:
sftp -i ~/.ssh/id_rsa sftp-user@[PublicIP]
```
## ssh禁止設定にする
```sh:
sudo su
vim /etc/ssh/sshd_config
```
### 下記に修正、追記する
```config:/etc/ssh/sshd_config
# override default of setting on a per-user basic
#Subsystem sftp /usr/libexec/openssh/sftp-server    // コメントアウト
Subsystem sftp internal-sftp -f LOCAL5 -l VERBOSE   // 追記 

Match group sftp-user　　　　　　　　　　　　　　　　　// 下まで追記
    ChrootDirectory /home/sftp-user/public_html
    X11Forwarding no
    AllowTcpForwarding no
    PasswordAuthentication yes
    ForceCommand internal-sftp
```
## ssh接続できないことの確認
```sh:
ssh -i ~/.ssh/id_rsa sftp-user@[PublicIP]
```
下記が出れば、設定完了

```
This service allows sftp connnection only.
```
## sftp-userのディレクトリとコンテンツディレクトリをマウント
まずユーザ配下に、作業ディレクトリを作成

```sh:
mkdir /home/sftp-user/public_html
```
コンテンツディレクトリとマウント

```sh:
mount /var/www/html/public_html /home/sftp-user/public_html
```
サーバ再起動後もマウントさせる為に、設定を追記

```sh:
vim /etc/fstab
```
```config:/etc/fstab
/var/www/html/public_html /home/sftp-user/public_html none bind 0 0
```
## sftp-userが参照や転送できるように権限変更
```sh:
chmod 755 /home/sftp-user
chown root:root /home/sftp-user

chmod 775 /home/sftp-user/public_html
chown root:sftp-user /home/sftp-user/public_html
```
これでsftp-userは、自分の作業ディレクトリのみ参照できる権限のため、上位ディレクトリに移動できない。
sftpでログインした際の初期ディレクトリは、`/home/sftp-user/public_html`になる。

# FTPクライアント
FilezillaというFTPクライアントで検証済みです。
https://filezilla-project.org/
「0から作るDeepLearning」の6章を写経した時のエラー原因１

こんにちは！

今日のエラー原因を書きます。

使用した本：「０から作るDeepLearning」

#１「optimizer_compare_mnist.py」の写経について
・38行目のfor文とグラフ描写のためのインテンドが合っていなかった。
正しい例

```Python:optimizer_compare_mnist.py
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    ---------------------------------------------------
plt.legend()
plt.show()
```
間違い

```Python:original_optimizer_compare_mnist.py
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    ---------------------------------------------------
　　plt.legend()
　　plt.show()
```

#エラー対策
インテンドを正しい例に直したら無事実行できました。

#所感
今回は全体を見落としていたことが原因でした。
後、今までのエラー原因は意外とケアレスミスが多いと思った。
（灯台下暗し）
Python でパスワード作成

# Chromeで「パスワード生成」がでない
Webサービスによってはlogin画面の作りが凝りすぎていてChromeなどのパスワード作成機能が働かないことがあります。そういうときのコードです。
# 方針
- argv でパスワードの長さ(plen) とスペシャルキャラクタ(spchr)を指定できるようにしたい。
- 大文字小文字数字を混ぜて上記のspchrを入れさせたい。
- stringからimportすればいいか
- そうすると、random.sampleで必要な文字数をとってspchrをくっつけて random.shuffleすればよいかな

```python:mkpasswd.py
#!/usr/bin/env python3
from sys import argv
from string import ascii_letters, digits
from random import shuffle, sample
def main():
  print("Usage %s <length> <spchars>\n$ %s 12 '-,' # length is 12, generated passwd contains '-' and ','"%(argv[0], argv[0]))
  plen, spchr = (12, '') # デフォルト値を設定
  try: plen = int(argv[1]) # argv[1]が数字なら置換
  except: pass
  try: spchr = argv[2] # argv[2]があれば置換
  except: pass

  lentotal = len(ascii_letters+digits+spchr)
  if plen > lentotal: plen = lentotal # plenが大きすぎるときは削る
  if plen <= len(spchr): plen = len(spchr) + 1 # plenが小さすぎるなら足す
  print("Generate length:%d, contains:[%s]"%(plen, spchr)) # 変更される可能性があるので表示してあげる

  pwd = sample(ascii_letters+digits, plen-len(spchr))+list(spchr)
  shuffle(pwd) # shuffleはインプレース置換
  print(''.join(pwd)) # printしておしまい
  return None
if __name__ == "__main__": main()
```

# 念の為ご注意
我ながら雑なコードですね。なお、spchrは__全て__出力されるパスワードで使われます。
Jamf Nowでデバイス管理するまでの導入手順

# Jamf Nowについて

Apple製品のモバイルデバイス管理(MDM)が行えるクラウドアプリケーション。

【特徴】
- 小規模組織向け（〜50台）
- サインアップ、即日利用可能
- トライアル可：1〜3台までは無料
- 年間　3000円／台
- 決済：クレジットのみ

通常、デバイスのキッティングは実物を触って行う必要があるが、Jamfを使うことで遠隔によるキッティングや統一された設定・一元管理を行うことができる。オフィスを経由せずともリモートで完結できるゼロタッチデプロイが実現できる。

# 導入手順

1. D-U-N-S Numberを取得
2. Apple Business Managerに登録
3. Jamf Nowにサインアップ
4. デバイスの登録
5. Blueprintで各種設定をセットアップする

## 1. D-U-N-S Numberを取得

Apple Business Managerに登録するには「D-U-N-S(ダンズ) Number」が必要となる。

以下のページにアクセスし、新規リクエストを行う。

https://fedgov.dnb.com/webform/index.jsp

登録が完了するとメールアドレス宛にD-U-N-S Numberが通知される。

## 2. Apple Business Managerに登録

Jamfでデバイス管理を行うにはApple Business Managerに登録する必要がある。

以下のページから登録を行う。この際、D-U-N-S Numberの入力が必要となるので、前手順を完了しておくこと。

https://business.apple.com/

なお、登録した電話番号にAppleから確認の電話が架かってくる。その電話で確認が取れれば登録完了となる。電話に出られなかった場合はこちらからサポートに電話をかける必要がある。

ここに記載の電話番号から窓口へと繋げてくれる。

https://support.apple.com/ja-jp/HT201232

```
日本
国内からかける場合：
0120-27753-5
海外からかける場合：
(81) 3-6365-47051
```

## 3. Jamf Nowにサインアップ

Jamf Nowのページから「始める」でサインアップを行う。

https://www.jamf.com/ja/products/jamf-now/

ここまでで下準備は完了。

## 4. デバイスの登録

### ① 自動登録

#### Apple Business Managerへお客様番号を登録
デバイス管理をするためにAppleお客様番号を設定する必要がある。

Apple Business Manager： 「設定」 > 「デバイス管理の設定」 

Appleお客様番号について

https://support.apple.com/ja-jp/guide/apple-business-manager/asmef1c47493/web

#### Jamf Nowで自動登録の設定
Jamf Now:  「デバイス」 > 「自動登録」 からデバイスの自動登録を行う

参考）

https://support.jamfnow.com/s/article/204764039-Setting-Up-Automated-MDM-Enrollment-via-the-Device-Enrollment-Program

https://docs.jamf.com/ja/best-practice-workflows/jamf-pro/enrolling-devices-automated-mdm/Apple_Business_Manager_%E3%81%8A%E3%82%88%E3%81%B3_Apple_School_Manager_%E3%81%A8%E3%81%AE%E7%B5%B1%E5%90%88.html

手順
1. プログラムの選択
2. ダウンロードキー
3. トークンのダウンロード
4. トークンのアップロード
5. セットアップの手順

##### 1. プログラムの選択

Jamf Now: 「Apple Business Manager」を選択

##### 2. ダウンロードキー

Jamf Now: パブリックキーをダウンロードする。

##### 3. トークンのダウンロード

App Business Manager:
「デバイス管理の設定」 > 「MDMサーバを追加」 で MDMサーバを追加する。
2のパブリックキーをアップロードする。MDMサーバの設定完了後、トークンをダウンロードする。

##### 4. トークンのアップロード

Jamf Now: 3のトークンをアップロードする。

##### 5. セットアップの手順

Jamf Now: 初回起動時のセットアップ手順を設定する。

ここまでで完了。なお、デバイスはJamf側で同期すると自動登録される。

### ② 手動登録

- Jamf Nowの 「デバイス」 > 「デバイスを登録」を選択
- 「名称」「Blueprint」を入力して「iOS構成プロファイルをダウンロード」でプロファイルをダウンロード
- 「enroll.mobileconfig」ファイルがローカルにダウンロードされるので、ファイルをタップしてプロファイルをインストールする
- 「システム環境設定」 > 「プロファイル」 > ダウンロードしたファイルを選択 > 「インストール」

これでJamf Nowのデバイスにプロファイルをインストールしたデバイスが表示され管理端末になる。

## 5. Blueprintで各種設定をセットアップする

デバイスが登録されているBlueprintにAppやセキュリティなどの設定項目がある。Blueprintに登録されているデバイスを一括で設定することができる。
Flutter 1 → Flutter 2 で変わったことと今後【概要】

# Flutter 2 の Release

3/4にFlutterが2.0になりました。
今回のバージョンアップで興味深い内容がありました。
Flutter:heart_eyes:な人でも、別のjs系フレームワークが好きな人でも、サクッと読めるように要約しました！

# On The Web

今回の目玉といって差し支えないのがWebサポートです。

## ベータ版から安定版へ

今までは１つのソートコードでiOS用とAndroid用のみでした。そこに、今までベータ版だったWeb用が安定板として追加されました。

今までFlutterでモバイル開発していた人たちは、今すぐに同じ機能のWebサービスを開始できるということです！

サボり精神が満ち溢れていますね！最高です！

# レンダリングエンジン

今まではHTMLベースのレンダリングエンジンを使用していました。
WebAssemblyで構築されたCanvasKitのレンダリングエンジンが追加され、パフォーマンス最適化の選択肢が増えました！

## その他

Web用として、下記のような機能が追加されました。

- テキストの自動入力（入力履歴の利用）
- アドレスバーのURLとルーティングの制御
- PWAマニフェストなど

# デスクトップアプリ

~~デスクトップアプリ用に使えるようになるのは少し先で、今年の後半にベータ版が出る予定です。~~
現在はベータとして使えるようですね。

https://flutter.dev/desktop#beta-snapshot-in-stable-channel

既に重要な機能が追加済みなようです。

- スクロールバー
- キーボードショートカット
- デスクトップ用のコンテンツ密度
- スクリーンリーダーサポート

# 組み込み機器

なんと、あの世界で最も売れている自動車メーカーである[**TOYOTA**](https://global.toyota/)と協力しながらFlutterを改善していくようです！車載のソフトウェアとして利用されていくということですね。

ここから、実際の利用環境でFlutterの機能が磨かれていく未来が容易に想像できますね！期待感アップです！

# 広告

[Google Mobile Ads for Flutter](https://pub.dev/packages/google_mobile_ads)のベータ版も同時にリリースされました。

とても簡単に[AdMob](https://admob.google.com/intl/ja/home/)の広告を付けられる未来が見えます。広告収益化も出来そうですね。

# Null Safety

ヌルセーフティーを大切にしていて、完全サポートしているようです。他の言語でもモダンな考え方として取り入れる動きが高まっており、これが無いと「[レガシー](https://qiita.com/koher/items/e4835bd429b88809ab33)」とまで言われてしまうようです。

C++やJavaなどで開発したプログラムでよく起こりがちな「ヌルポ」と呼ばれるバグは、このヌルセーフティーによって早期解決が見込めます。そもそも「ヌルポ」に出会えなくなります。

null safety に関してもっと分かりやすい記事を書いている方がいらっしゃいますので、ぜひ。

https://qiita.com/kabochapo/items/fbca2b2972546eeadcfa

# 元記事

もっと正確な情報をご覧になりたい方は下記の公式記事をご覧ください。

https://medium.com/flutter/whats-new-in-flutter-2-0-fe8e95ecc65

https://developers.googleblog.com/2021/03/announcing-flutter-2.html

# 他の目線

iOSエンジニア視点での記事を書いている方がいらっしゃいます。

https://qiita.com/tetsukick/items/a883f73b526eb2a63b8a

# まとめ

もし「要約してくれてありがとう」と感じたら、LGTMしていただけたら嬉しいです。
次の記事も頑張ります！

**Excelsior!**
PHPで AWS Aurora Serverless の Data API を利用してみた

## 前提条件
AWS SDK for PHP 3.x を利用
Data API の有効化など完了しているとする

## やってみた感想
可もなく不可もなく

## RDSDataServiceClientを利用して結果を取得する
```php:sample.php
<?php

use Aws\Exception\AwsException;
use Aws\RDSDataService\RDSDataServiceClient;

try {
    $client = new RDSDataServiceClient([
        'region'  => 'ap-northeast-1',
        'version' => 'latest',
        'credentials' => [
            'key'    => '****',
            'secret' => '****',
        ],
    ]);

    $result = $client->executeStatement([
        'secretArn'   => 'arn:aws:secretsmanager:ap-northeast-1:****:secret:****',
        'resourceArn' => 'arn:aws:rds:ap-northeast-1:****:cluster:****',
        'sql'         => 'SELECT * FROM hoge',
    ]);

    var_dump($result->get('records'));
} catch (AwsException $e) {
    echo $e->getAwsErrorMessage();
}
```

## 参考
[Aurora Serverless の Data API の使用](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/data-api.html)
[Class RDSDataServiceClient](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.RDSDataService.RDSDataServiceClient.html)
【個人的備忘】App Storeへの申請方法

##0. 前書き

★いつもこちらの記事[(https://qiita.com/kaneko77/items/ce918317e94c9f36441f)](https://qiita.com/kaneko77/items/ce918317e94c9f36441f)にお世話になっているのですが、久しぶりに申請しようとして記事が見つからず狼狽する未来が見えるので、以下自分用にまとめさせていただきました。

※2021-01-09に別媒体に記載したものの転記なので2021-01-09時点の情報です。

##1. 証明書発行

キーチェーンアクセスを開く→メニューバーの「キーチェーンアクセス」→「証明書アシスタント」→「認証局に証明書を要求」
- ユーザのメールアドレス: 入力
- 通称: 入力
- CAのメールアドレス: 入力不要
- 要求の処理: ディスクに保存

##2. Certificate

Apple Developer Programのサイトにログインする→ 「Certificates, Identifiers & Profiles」→ 「Certificates」→ 「＋」→ 「iOS Distribution (App Store and Ad Hoc)」→ 「Choose File」→ 「Continue」→省略

##3. App ID

「Identifiers」→ 「＋」→ 「App IDs」→ 「App」→省略

##4. ProvisioningProfile

「Profiles」→ 「＋」→ 「App Store」→省略

##5. App Store Connect

App Store Connectのサイトにログイン→ 「マイAPP」→ 「＋」→ 「新規App」→省略

##6. Xcode

※バージョン・ビルドナンバーの桁数はX.X.X。
バージョンとビルドで違っていて良い。
同じビルドナンバーで複数回アーカイブは出来ないので、失敗した場合もカウントアップする。

Xcodeを開く→メニューバーの「Product」→ 「Archive」
→ 「Validate App」→省略（基本初期値で問題なし）
→ 「Distibute App」→省略（基本初期値で問題なし）→ 「App Store Connect」→ 「Upload」→省略

##7. App Store Connectの編集→申請

省略
Rからpythonコードを実行できるreticulateパッケージが便利

# 背景
「[RstudioでPythonを使う](https://qiita.com/otsukimi200624/items/c707f87b95dcde2d8354)」で述べたように、Rstudio上で簡単にPythonを実行することができます。これだけでも便利なのですが、RとPythonの連携、例えば「**Pythonのライブラリで求めた結果をRオブジェトとして格納し、ggplot2で作図する**」ことができれば素敵です。reticulateはこれを可能にするRのパッケージです。

参考：[How to Run Python from R Studio](https://robotwealth.com/using-python-from-the-comfort-of-r-studio/)

# 環境
PC: MacBook Pro 2020
OS: macOS Catalina (10.15.5)
R : 4.0.2 (2020-06-22)
RStudio: 1.4.1103
reticulate: 1.18

#  方法・結果
### 1. reticulateパッケージのダウンロード、読み込み
通常のRパッケージと同様にinstall.packages()とlibrary()を使います。

```R
install.packages("reticulate")
library(reticulate)
```

### 2. pythonライブラリのインポート
reticulate::import（）を使ってPythonライブラリを読み込みます。変数に格納することで名前をつけることもできます。

```R
np <- reticulate::import("numpy") #「import numpy as np」と同義
plt <- reticulate::import("matplotlib.pyplot")
```
### 3. 読み込んだライブラリの使用
pythonでは「**．**」でメソッドを使用しますが、Rで読み込むと「**$**」でメソッドを使用できます。ここではnumpyを用いて乱数を生成しています。**引数の型を明示しないとエラーになる**ことがあるので注意が必要です。
下記の例ではint型を入力すべき部分がfloat型になっているとエラーが出ています。そのため、as.integer()でint型であることを明示します（Rの場合は数字の後に「L」をつけるとint型として認識するので「100L」でも動きます）。
参考：[reticulate does not work with R-Data frame and fit() function from Python](https://stackoverflow.com/questions/50272140/reticulate-does-not-work-with-r-data-frame-and-fit-function-from-python-typee)


```R
#乱数を生成、メソッドを使用するには「$」、引数の型を明示
x <- np$random$rand(as.integer(100))
y <- np$random$rand(as.integer(100))

# 引数の型を明示しないとエラーになる
np$random$rand(100)
# py_call_impl(callable, dots$args, dots$keywords) でエラー: 
# TypeError: 'float' object cannot be interpreted as an integer
```
### 4. 散布図を描画
matplotlibで散布図を描画し、Rのpng関数で保存します。

```R
png("scatter_py.png")
plt$scatter(x, y)
plt$title("Title")
plt$xlabel("x")
plt$ylabel("y")
plt$show()
dev.off()
```
![scatter_py.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363491/1b61a44b-f09b-7a85-09cc-b568a7388d30.png)

### 5. ggplot2で描画する
作図はRのggplot2を使うことが多いので、numpyで生成した乱数をggplot2で描画してみます。

```R
d <- data.frame(x = x, y = y)

png("scatter_r.png")
ggplot(data = d, aes(x = x, y = y)) +
        geom_point()
dev.off()
```
![scatter_r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363491/f0625616-2063-b79c-5e47-d13a2d0f9939.png)

### 6. pythonコードの読み込み
自作のpythonコードを読み込むこともできます。実行すると「Hello R！」と表示するhelloR.pyを作成しました。

```python
def helloR():
        print("hello R!")
```
source_python()でhelloR関数を読み込みます。

```R
reticulate::source_python("helloR.py")
helloR()
# hello R!
```

### 補足
使用するpythonのインタプリタは導入した方法によってuse_condaenv()、use_virtualenv()、use_python()で指定します。
Rstudio1.4以上の場合はTools -> Global OptionsのPythonで選択したインタプリタがデフォルトで選択されているようです。
[OpenCV] 画像の階調　[0,255] -> [0,1]の時の注意点

#1.はじめに
画像処理でいろいろ分かったので、備忘録として記録しておきます。

#2.画像の読み込み
まず、Lenaさんの画像を読み込みます。

```Python
import cv2
import numpy as np

img_raw = cv2.imread('./image/lena.png')
print('Type', type(img_raw))
print('data type: ', img_raw.dtype)
cv2.imshow('raw image uint8', img_raw)

#結果
Type <class 'numpy.ndarray'>
data type:  uint8　# 符号なし  8bit 整数
```
OpenCVで読み込んだ画像は、`numpyのndarray `で、そのデータ型は `uint8`です。
画像を出力すると下記のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/ad34eccc-cc35-0310-0f74-049ffe898996.png)


#3.画像の階調：[0,255] -> [0,1]

ニューラルネットワークに画像を入力するとき、階調を[0,255]から[0,1]に変換をお粉ます。

```Python
img_scaled = (img_raw/ 255.).astype(np.float32) 
print('Type', type(img_scaled))
print('data type: ', img_scaled.dtype)
cv2.imshow('scaled image float32', img_scaled)

#結果
Type <class 'numpy.ndarray'>
data type:  float32
```
データ型がfloat 32(単精度 浮動小数点数)に変わりました。
画像を出力すると下記のようになります。うん？先ほどのuint8, [0,255]の時と変わらないですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/bc2b3d4a-e6dc-2cea-0f47-965317c8b133.png)

では、ここで[0,1]の画像を保存してみます。

```Python
cv2.imwrite('./image/lena_0_to_1.png', img_scaled)
```
そして、保存したファイルをWindowsの別のプログラムで開いてみます。
真っ暗の画像に現れます。どうしてですか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/4f6d9513-344a-61d9-d3e2-8e1b382f854e.png)


これは、[0,1]の階調の画素のデータが、保存されるときにfloat32型に保存されず、0か１の整数型に変わってからです。ここで気を付けないといけないのは、OpenCVのimshow()は[0,1]のfloat 32型でも、綺麗に表示してくれます。


#4.解決方法

`numpy.clip()`を利用して、範囲を[0,1]から[0,255]に戻した後、データ型をfloat32型を uint8にキャストしてから保存すればいいです。
コードは下記のようになります。

```Python
img_restore = np.clip(img_scaled * 255, a_min = 0, a_max = 255).astype(np.uint8)
cv2.imwrite('./image/lena_restore.png', img_restore)
#結果
Type <class 'numpy.ndarray'>
data type:  uint8

```
先ほどのWindowsの画像表示プログラムで確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/882cb762-4a89-f667-6bac-451d1b88d48f.png)

#5. 気づきポイント

1. OpenCVのimshow()に騙されました。（笑）
2. データ型を常に意識しながらプログラムを組みましょう。
fixtureをrails_helperでまとめて読み込む

#はじめに
rspecでfixtureを使用する際、各ファイルで```fixtures :all```するのが面倒なとき、rails_helperでまとめて読み込むことができます。

#結論
```rubu:spec/rails_helper.rb
RSpec.configure do |config|
  config.global_fixtures = :all
end
```

すでに存在する```RSpec.configure do |config|```ブロック内に、```config.global_fixtures = :all```を格納します。
【Access VBA】csvデータを取り込み、データベーステーブルを作成するプログラム

#はじめに
csvファイルを取り込み、Accessデータベースのテーブルを作成するVBAのサンプルプログラムを作った。


#入力csvデータ
```FieldData.csv
会員番号,名前,住所,登録日付
```
取り込まれたcsvデータは、テーブルのフィールド名になる。

#サンプルプログラム

```
Option Compare Database

'csvファイルからフィールド情報を取得してテーブル作成
Sub Sample()

    Dim db As Database
    Dim Newtb As TableDef
    Dim tmp As Variant
    
    Set db = CurrentDb
　　'作成したいテーブルの名前を入力
    Set Newtb = db.CreateTableDef("TestTable")

    Dim buf As String

　　'取り込みたいcsvのパスを入力
    Open "C:\Folder\FieldData.csv" For Input As #1
        Do Until EOF(1)
            Line Input #1, buf
            tmp = Split(buf, ",", , vbTextCompare)
            
            '-------------------------------------------------------
            'フィールドのパラメータを設定する
            With Newtb
                .Fields.Append .CreateField(tmp(0), dbInteger, 6)
                .Fields.Append .CreateField(tmp(1), dbText, 10)
                .Fields.Append .CreateField(tmp(2), dbText, 255)
                .Fields.Append .CreateField(tmp(3), dbDate)
            End With
            '-------------------------------------------------------
            'フィールドのパラメータ設定をしないならこちらを使う(とりあえずテーブルを作成したい時など)
            'For i = 0 To UBound(tmp, 1)
                'Set fld = Newtb.CreateField(tmp(i), dbText, 255)
                'Newtb.Fields.Append fld
            'Next
            '-------------------------------------------------------
                        
            'テーブルの作成
            db.TableDefs.Append Newtb
            
            DoCmd.OpenTable "TestTable", acViewDesign
        Loop
    Close #1

End Sub
```

#結果
![Access_Table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/789979/f67e2e9a-06c7-ec6e-07c8-32422444bda6.png)
G検定の学習　その１

初めまして。3/20のG検定を受けるために、勉強中です。
G検定について学習したことをアウトプットしていきます。

G検定とは？
一般社団法人　日本ディープラーニング協会（Japan Deep Learning Association （略称：JDLA））によると、
>G検定概要
ディープラーニングの基礎知識を有し、適切な活用方針を決定して、事業活用する能力や知識を有しているかを検定する。
[G検定とは？](https://www.jdla.org/certificate/general/")

これから、AIが発達していく時代に、AIとはどんなもの？と質問された時に答えに困らない程度の知識を身につけることができる検定です。

合格率は受験者の50%程度と高めです。

まず、相手を試験の内容と攻略法について検索してみました。
そうすると。G検定は、内容が難しいですが、途中で検索可能です。
しかし、制限時間があり、「1問30秒のスピード」が必要という書き込みを目にしました。
そこで、おすすめされていたのが、マインドマップを事前に準備しておくことでした。

“キーワード集中解説"で最短合格 ディープラーニングG検定 ジェネラリスト 対策テキストを参考にして、MindNodeでマインドマップを作りながら学習を行っています。
[G検定のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527611/c8d4c99c-869e-187d-f02f-0336dfbe0f10.png)

今回は、第3次AIブームについてのアウトプットです。
なぜ、第三次AIブームから勉強するのか？というと、2010年から〜現在までという、比較的身近に起こっていることで、なじみがあり、理解しやすいからです。
では、早速みていきましょう。​!


>・キーワード
機械学習…膨大なデータをもとにルールを学習し、予測や分類を行う技術。
ディープラーニング(深層学習)…従来属人的で合った特徴量抽出を人工知能自らが行い、学習を行う技術。
ニューラルネットワーク…人間の脳の神経回路を模したモデル。
ILSVRC(ImageNet Large Scale Visual Recognition Challenge)…画像認識の精度を競う世界的な競技会。
AlexNet…ジェフリー・ヒントン率いるトロント大学のチームが開発したILSVRC2012年優勝モデル
AlphaGo(アルファ碁)…2015年にハンディキャップなしでプロ棋士に勝利したGoogle DeepMind社が開発した深層強化学習を用いた囲碁プログラム。
統計的自然言語処理…大量のWebページのテキストデータから対訳データを収集し、統計的に翻訳することでより自然な翻訳を可能にした。
シンギュラリティ(技術的特異点)…人工知能自身が自分よりも賢い人工知能を作ろうとした瞬間に、無限に高位の存在を作るようになるという概念。
“キーワード集中解説"で最短合格 ディープラーニングG検定 ジェネラリスト 対策テキスト"
出版社 : リックテレコム (2021/1/29)
発売日 : 2021/1/29
>

第二次AIブームはなぜ衰退したのでしょうか？
それは、人の手による知識の蓄積の困難さからでした。
現在、利用されているビッグデータを活用した「機械学習」が実用化されたことにより、第三次ブームが起こりました。
第二次ブームのときの課題であった知識の蓄積が「ディープラーニング（深層学習）」により、コンピュータ自らが行うことが可能になったからです。

アメリカ合衆国の発明家、実業家、未来学者であるレイ・カーツワイルはシンギュラリティが起こるのは2045年と予測しており、人工知能が人より賢くなるのは、2029年頃と予測しています。

マインドマップは、2週間後までには、完成させます。
今回は、以上です。
次回を楽しみにしていてください。

参考文献
https://ai-trend.jp/business-article/ai-certification/generalist-test/gkentei-feature/
AVILEN Inc. 、2020/06/25
東京都、都庁駅前データPointCloud


# デジタルツイン実現プロジェクト

[東京都、都庁駅前データ](https://www.geospatial.jp/ckan/dataset/tochomae-3d-pointcloud)

# 再生ツール
https://www.meshlab.net/#download

[CloudCompare](http://www.danielgm.net/cc/)

# そのほか
http://www.pointcloud.jp/
復習　Python tutorial #1　文字列

##文字列の操作
####コメント
このコードは何に使っているんだろうかと困ることが将来よくあることであろう。そのことを防ぐためには、コメントという機能を用いることで対処できる。コメントとは実際に書いたものをコード自体に影響を及ぼさなない。つまりシステムになんの影響も与えないもののことである。よって実行しても何も起こらない。コメントのやり方は下のコードのように前に'#'をつけることである。

```python
#これはコメントです。
```

####'\'によるエスケープ
特定の文字の前に\を入れるといろいろな処理を行うことができる。例えば\nを用いると改行ができる。

```python
print('Name: Anna\nFrom: Tokyo\nSchool: Stanford')
Name: Anna
From: Tokyo
School: Stanford
```
print()を用いて文字列を打つときに、""のなかに文字を入れるのだがその中に""が入っていたら、それを出力するとエラーが発生してしまう。それを防ぐためには、\を用いるか''を使って器用にこなすかである。

```python
print(""I like Pizza!", but,"I don't like Sushi"")

#実行結果
print(""I like Pizza!", but,"I don't like Sushi"")
            ^
SyntaxError: invalid syntax

print("\"I like Pizza!\", but,\"I don't like Sushi\"")
#実行結果
"I like Pizza!", but,"I don't like Sushi"
```
このようにして利用すると簡易的にコメントのような文字が打てる。

####'+'による連結

```python
print('I' + 'am' + 'Chicken')
#実行結果
IamChicken
```
####'*'による繰り返し

```python
print('Hi '*10)
#実行結果
Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi 
```
####'[]'による文字の抽出
ここでは対話型インタープリタ(ターミナル)を用いて実行していこう。

```python
letters = 'abcdefghijklmnopqrstuvwxyz'
letters[0]
# 実行結果
'a'
```
文字列はイミュータブル(変更できない)ので変更するにはreplace()を用いることで実行できる。しかしこれは一時的なものなのでその新しく変えたものを新しく変数として考えていく必要がある。またスライスというものを用いることも可能である。

```python
new_letters = letters.replace('a', 'b')
print(new_letters)
bbcdefghijklmnopqrstuvwxyz
print(letters)
abcdefghijklmnopqrstuvwxyz
new_letters_2 = 'n' + [1:]
print(new_letters_2)
nbcdefghijklmnopqrstuvwxyz
```
####スライスについてスライスは文字列から部分的な文字列を取り出すことができる。
*[:] 先頭から最後まで
*[X:]Xから最後まで
*[:X]最初からXまで
*[X:Y]XからYまで
*[X:Y:N]XからYまでをN文字ずつ順に取り出す。

```python
letters = 'abcdefghijklmnopqrstuvwxyz'

print(letters[:])
print(letters[3:])
print(letters[:3])
print(letters[3:7])
print(letters[1:20:3])
abcdefghijklmnopqrstuvwxyz
defghijklmnopqrstuvwxyz
abc
defg
behknqt
```
####そのほかの関数:len(),split(),join()
len():文字列の文字数を確認するものだ。
split():分割(リストを作成)
join():結合(リストから文字列を作成)
これらについてコードから詳しく考えてみよう。

```python
len(letters)
#実行結果
26
complex_letters = 'abc,def,ghi,jkl,mno,pqr,stu,vwx,yz'
simple_letters_with_list = complex_letters.split(',')
print(simple_letters_with_list)
#実行結果
['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz']
new_complex_letters = ', '.join(simple_letters_with_list)
print(new_complex_letters)
abc, def, ghi, jkl, mno, pqr, stu, vwx, yz
```
####文字列の区別と配置
これに関してはコードのみで説明する。

```python
letters_capi = letters.capitalize()
#最初だけ大文字
print(letters_capi)
'Abcdefghijklmnopqrstuvwxyz'
Greeting_patterns = 'hello, whats up!, wow'
Title_Greeting_patterns = Greeting_patterns.title()
#各文の最初の文字列を大文字にする。
print(Title_Greeting_patterns)
'Hello, Whats up!, Wow'
Upper_Greeting_patterns = Greeting_patterns.upper()
print(Upper_Greeting_patterns)
#全て大文字にする。
'HELLO, WHATS UP, WOW'
Lower_Greeting_patterns = Greeting_patterns.lower()
#全て小文字にする
'hello, whats up!, wow'
Greeting_patterns_center = Greeting_patterns.center(30)
print(Greeting_patterns_center)
#指定した数ないで文字を中心に寄せてくれる。
    hello, what's up!, wow    
#左寄せ
Greeting_patterns_left = Greeting_patterns.ljust(30)
#右寄せ
Greeting_patterns_right = Greeting_patterns.rjust(30)
print(Greeting_patterns_left)
hello, what's up!, wow        
print(Greeting_patterns_right)
        hello, what's up!, wow
```
SORACOMのログイン監査ログをcliで取得してみる

# これは
先日公開された、SORACOMのログイン監査ログ機能をcliから確認してみたという記事です。

https://soracom.com/ja-jp/news/20210303-2/

同じくNapterの監査ログをcliで取得した際の記事はこちらになりますので合わせてご参照いただければと思います。

https://qiita.com/kkimura/items/65dfed8e52a586f93aec

# やってみた

まずはcliをv0.7.0以降にバージョンアップします。
そして、監査ログを取得してみます。

```bash
% soracom audit-logs api get
[]
```

24時間以内にログインをしていませんので、空の配列が返ってきました。

続いて、SORACOMコンソールにログインしてから再度実行してみます。

```bash
 soracom audit-logs api get
[
        {
                "apiKind": "/v1/auth",
                "operatorId": "OP********",
                "remoteIpAddress": "***.***.***.***",
                "requestPath": "/v1/auth",
                "requestedTimeEpochMs": 1614835774508,
                "statusCode": 200,
                "userName": null
        },
        {
                "apiKind": "/v1/auth",
                "operatorId": "OP********",
                "remoteIpAddress": "***.***.***.***",
                "requestPath": "/v1/auth",
                "requestedTimeEpochMs": 1614835680417,
                "statusCode": 200,
                "userName": null
        }
]
```


無事取得できてますね。1つは最初にcliを実行したとき、2つめはコンソールにログインしたときのものと思われます。コンソールにログインしないでも2回コマンド実行するだけで良かったですね。

せっかくコンソールにログインしたので、コンソールの画面でも確認してみます。メニューのログ→監査ログで見られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59415/7142d1d4-740e-ef32-2c15-f535ca858605.png)


3件目は先ほどcliを実行したときのものですね。

# まとめ

とりあえずcliで取得できることを確認してみました。監査ログは直近24時間だけということなのでバッチで取得したり、他のサービスと組み合わせる場合はcliから取得するのが便利かと思います。

コマンドラインの機能名が「api」だから、きっと全てのAPI呼び出しのログが取得できるようになるんだろうなーと思ったら、公式ブログでも「鋭意開発中」となってましたので楽しみにしています！

https://blog.soracom.com/ja-jp/2021/03/03/audit-logs-release/
復習 Python Tutorial#0　環境設定

復習がてらやっていくのでここ違うなと思ったら編集リクエストお願いいたします！
##Python環境設定
①Anacondaをインストールする。
②Pycharmをインストールする。
③Pycharm内での設定

①Anacondaのインストール
Anacondaというものはpythonの環境を一気に整えられる便利な拡張ツールである。そのインストール方法は https://www.anaconda.com/products/individual
アクセス。Downloadをタップ。そして指示に従う。
②PyCharmをインストール
https://www.jetbrains.com/ja-jp/pycharm/download/ にアクセス。コミュニティをタップしてダウンロードそして指示に従う。
③PyCharm内設定
#####Create New Projectをタップ
![スクリーンショット 2021-02-24 9.34.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1146127/08acf1e0-d73e-f566-4f87-d1c9bd88ffbb.png)
#####Project Interpreterをタップ
![スクリーンショット 2021-02-24 9.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1146127/a98e2cc6-e4cd-1a1c-b77e-469a2ef4fa60.png) 
#####Existing interpreterをタップ
![スクリーンショット 2021-02-24 9.38.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1146127/5cd48762-eac8-638e-5711-8957eeb74108.png)
#####AnacondaのマークがあるまたはAnacondaと書いてあるものをタップ。
#####Createをタップする
#####ファイルをタップして新しいプロジェクトを作る。
#####右上にあるAdd Configurationをタップする
#####左上にある＋マークをタップする。
#####pythonを選択する。
#####Script pathに自分がいまさっき作ったProjectを選択する。そしてOKをおす。
#####Pythonをタップする

##ターミナルについて
ターミナルは対話型インタープリターと言って指示したことを直接対話的に回答してくれる感じのものである。使い方は簡単でターミナルを開いてpythonと打つだけである。

![スクリーンショット 2021-02-25 11.39.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1146127/c946222f-e242-098b-d63a-94b8cf1daa70.png)

使い方に関しては下のようにするとその変数の値もprintを使うことなく中身を確認できる。

![スクリーンショット 2021-02-25 11.41.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1146127/7cffe5f0-8807-5ac0-c627-a612190a7fad.png)

##変数
変数はプログラムの中で定義できるものでありpythonの場合=だけで定義することができる。

```python
greeting = 'Hello World'
#print()は文字を出力する関数
print(greeting)
   Hello World
```
pythonの変数というものはあくまで名前という扱いでしかないので、代入したからと言ってコピーされるわけではない。ここに注意が必要である。
またpythonでは予約ごと言って変数にできないようなものがいくつか存在する。そのうちのいくつかを紹介する

![IMG_0053.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1146127/46d140ac-df05-e381-311b-d0864fd05640.png)
(入門python３(p.25)より引用）


##型
ある値がどんな種類なのかをわかるようにするための関数

```python
type()
```
これをもちいることにより、ある値の型がわかる
####代表的な型の種類
整数:IntegerなのでIntが返ってくる
浮動小数点:Floatなのでfloatが返ってくる
文字列:StringなのでStrが返ってくる。
この中で整数を文字列に変えたりする時はstr()のようにその頭の部分をとって()を付ければできる。例えば

```python
a = 5
print(type(a))
<class 'int'>
a = str(a)
print(type(a))
<class 'str'>
```
ブール値（TrueとFalse)などはIntegerとして見てみると

```python
int(True)
1
int(False)
0
```
R shinyapp.io で web アプリをデプロイしてみた

# はじめに
[こちらの記事](https://qiita.com/ryamamoto0406/items/1bc520c39729b2e1a9b7)で簡単な R のアプリを試作してみた。これを[shinyapps.io](https://www.shinyapps.io/)を使ってデプロイしてみる。無料で5つまでのアプリケーションなら作成可能。

# ユーザー登録
E-mail アドレスかgoogle ID, GitHub IDを使ってログインできる。メールアドレスでログインした場合、「Please verify your email address」のメールが届き、アドレスの確認を求められる。URLをクリックして登録が完了する。

# パッケージのインストールとアプリの登録
Dashboard上の案内に従ってアプリの登録までを行ってみる。

## STEP 1 – INSTALL RSCONNECT
アプリのデプロイには`rsconnect`というパッケージが必要なよう。これをRコンソールからインストールする。

```R
install.packages("rsconnect")
```

## STEP 2 – AUTHORIZE ACCOUNT
アカウントの承認が必要なよう

> The rsconnect package must be authorized to your account using a token and secret. To do this, click the copy button below and we'll copy the whole command you need to your clipboard. Just paste it into your console to authorize your account. Once you've entered the command successfully in R, that computer is now authorized to deploy applications to your shinyapps.io account.

rsconnectパッケージは、トークンとシークレットを使用してアカウントに承認する必要があるそう。承認を行うための必要なコマンドがクリップボードにコピーされるので、それをRコンソールに張り付けるだけでアカウントを承認できる。このコマンドを入力することで、そのコンピューターが shinyapp.io アカウントにアプリケーションを展開する許可を与える。

という事なので、実行してみる。

```R
rsconnect::setAccountInfo(name='ryamamoto0406', token='XXXX', secret='XXXX')
```

特に戻り値などは無いよう。

## STEP 3 – DEPLOY

> Once the rsconnect package has been configured, you're ready to deploy your first application. If you haven't written any applications yet, you can also checkout the Getting Started Guide for instructions on how to deploy our demo application. Run the following code in your R console.

rsconnectパッケージを構成すると、最初のアプリケーションをデプロイする準備が整う。 まだアプリケーションを作成していない場合は、デモアプリケーションをデプロイする方法について、スタートガイドを確認することもできる。 Rコンソールで次のコードを実行する。

との事なので、[こちらの記事](https://qiita.com/ryamamoto0406/items/1bc520c39729b2e1a9b7)で作ったアプリをデプロイしてみる。

```R:
library(rsconnect)
rsconnect::deployApp('path/to/your/app')
```

```:出力
Preparing to deploy application...DONE
Uploading bundle for application: 3733328...Detecting system locale ... ja_JA
DONE
Deploying bundle: 4298703 for application: 3733328 ...
Waiting for task: 882670952
  building: Processing bundle: 4298703
  building: Building image: 4915666
  building: Installing packages
  building: Installing files
  building: Pushing image: 4915666
  deploying: Starting instances
  rollforward: Activating new instances
  success: Stopping old instances
Application successfully deployed to https://ryamamoto0406.shinyapps.io/shiny_app/
```

となり、自動でデプロイできた。作ったアプリは [https://ryamamoto0406.shinyapps.io/shiny_app/](https://ryamamoto0406.shinyapps.io/shiny_app/) でアクセスができる。

# おわりに
shinyapp.io を使って簡単にアプリをデプロイすることができた。特に知識などは必要なかったので、今度はAWSなどの環境に shiny を導入し動かしてみる事などに挑戦してみたい。また、アプリも複雑なものを作っていきたいとも思う。
Pythonの分割代入での型アノテーション

型アノテーションは単体に対して使えない。
下記のように事前に定義して書くしかなさそう。
参考:[PEP526](https://www.python.org/dev/peps/pep-0526/#global-and-local-variable-annotations)

#### 動く

```python
a: int
b: str
a, b = 1, "hello"

from typing import Tuple
c: Tuple[int,str] =1, "hello"

```

#### これらはできない

```python
(a,b) :Tuple[int,str] = 1, "hello"
```

```python
a, b :int, str = 1, "hello"
```
[WordPress] 海外有料テーマEnfoldのAdvanced Layout Editorがロードされない問題と解決法

# ことのはじまり

Enfoldという海外有料テーマを使用している既存のWordPressサイトを引き継ぎ、手を入れていた時のこと。

Enfoldには「Avia Layout Builder」というリッチなエディタが装備されており、そこを触っていたら、ふとした拍子にエディタがLoading画像くるくる状態のままになってしまったのです。

じゃあクラシックエディタに戻そうかと思っても、ボタンが押せない。つまり全然編集できない。
PC再起動しても、キャッシュとクッキー全消しでログインし直してもだめ。

…これはまずいやつなのでは…

# 現状把握
冷や汗をかきつつ、まずは現状把握。
この現象が起きるのは固定ページの編集画面だけ。カスタム投稿含む投稿ページは至って問題なし。

Chromeのデベロッパーツールでコンソールを確認すると、

```
Uncaught Error: cannot call methods on sortable prior to initialization; attempted to call method 'toArray'　
```
とか赤文字で言われてます。何それ。

# 類似事例を発見

Google先生に思いつく限りのワードを打ち込んで、色々試してはダメでお腹が痛くなりそうだった頃、ようやくそれっぽいものが見つかりました。助かった…

ずばりお膝元（このテーマ開発元）のフォーラムです。さすがです、頼りになります。
[ADVANCED LAYOUT EDITOR not working? Try this, worked for me.]
(https://kriesi.at/support/topic/advanced-layout-editor-not-working-try-this-worked-for-me/page/2/#post-730036)


> I looked at the console and the error given was: “Uncaught Error: cannot call methods on sortable prior to initialization; attempted to call method ‘toArray'”.

この質問者さんも、固定ページはダメで投稿ページはOKって言ってるし、コンソールエラーの内容がまさに同じ！

そして彼は「エディタのボックスレイアウトを変えようとした時に壊れた（と思う）」って言ってるんだけど、よくよく思い返せば、何かをコピろうとしてドラッグした時にうまくできなくてちょっと動いちゃってた…かも。結果的にボックスを移動させたような挙動をしてしまってた。これだ、同じだ。

さて、それではどうすればいいかというと、一つ目の解決策としては「新しい管理者を作ってそれでログインすると正常に動くよ」

うーん、確かに。
でもなんかきちんと解決してなくて気持ち悪いな。

同じ質問者さんが
>In the wordpress table “_usermeta” there exists a “meta_key” called “meta-box-order_page” for each “User_id”. 

とも言ってます。よくわからないけど、「_usermeta」とか「meta-box-order_page」あたりがキーになりそうじゃないですか？

と思い、またGoogle先生にお尋ね。
そしてわかりました。

# 解決編

参考にさせて頂いたのはこちらの記事。ありがとうございました。
[Advanced Custom Fields(ACF)でフィールドの表示位置が変更できない時の解決方法](https://whitewood-hp.com/web-tips/archives/2603)


つまり結論から言うと（おそらく）こういうことです。
**「meta-box-order_page」が壊れていた** と。
（投稿はmeta-box-order_postなので、そちらの編集画面は無事だったのでした）

ちなみにmeta-box-order_page/postとはなんぞや？と言うと、編集画面でボックスの位置を動かした時に、その位置情報をWordpress側で覚えておくためのものらしいです。
今回はこれが何かの拍子におかしくなってしまったのだろうということです。

# 修復作業

理由がわかればあとは修復するだけ。
meta-box-order_pageをリフレッシュします！

functions.phpの最後尾に以下を貼り付け。

```php
function clear_meta_box_order(){
    // 通常の投稿ページの編集画面
    delete_user_meta( wp_get_current_user()->ID, 'meta-box-order_post' );
    // 固定ページの編集画面
    delete_user_meta( wp_get_current_user()->ID, 'meta-box-order_page' );
}
add_action( 'admin_init', 'clear_meta_box_order' );
```


これで、今ログインしているユーザーのボックス配置データをクリアにします。

恐る恐る固定ページの編集画面に戻ってみると…Advanced Layout Editorが復活してる！よかったー！！！

上記のコードを残したままだとボックスレイアウトが記憶されないので、それはイヤだなという場合は、表示が正常に戻ったら消しちゃえばOKです。

enfoldを使ってる方は少ないかもしれませんが、また自分がやらかす時のためにも書き残しておきます。
Go: Synology の WebDAV にアクセスする

こちらのライブラリーを使いました。
[studio-b12/gowebdav](https://github.com/studio-b12/gowebdav)

フォルダーの一覧

```go:webdav_list.go
// ---------------------------------------------------------------
//
//	webdav_list.go
//
//					Mar/04/2021
// ---------------------------------------------------------------
package main

import (
	"fmt"
	"os"
	"github.com/studio-b12/gowebdav"
)

// ---------------------------------------------------------------
func main() {
	fmt.Fprintf (os.Stderr,"*** 開始 ***\n")

	server := "https://example.synology.me:5006"
	user := "scott"
	password := "secret"

	cc := gowebdav.NewClient(server, user, password)

	files, _ := cc.ReadDir("/homes/scott/tmp")

	for _, file := range files {
		fmt.Println(file.Name())
	}

	fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

ファイルのアップロード

```go:webdav_put.go
// ---------------------------------------------------------------
//
//	webdav_put.go
//
//					Mar/04/2021
// ---------------------------------------------------------------
package main

import (
	"fmt"
	"os"
	"github.com/studio-b12/gowebdav"
)

// ---------------------------------------------------------------
func main() {
	fmt.Fprintf (os.Stderr,"*** 開始 ***\n")
	server := "https://example.synology.me:5006"
	user := "scott"
	password := "secret"

	cc := gowebdav.NewClient(server, user, password)

	webdavFilePath := "/homes/scott/tmp/tmp02.txt"
	localFilePath := "./tmp02.txt"

	file, _ := os.Open(localFilePath)
	defer file.Close()

	cc.WriteStream(webdavFilePath, file, 0644)

	fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

ファイルのダウンロード

```go:webdav_get.go
// ---------------------------------------------------------------
//
//	webdav_get.go
//
//					Mar/04/2021
// ---------------------------------------------------------------
package main

import (
	"fmt"
	"os"
	"io"
	"github.com/studio-b12/gowebdav"
)

// ---------------------------------------------------------------
func main() {
	fmt.Fprintf (os.Stderr,"*** 開始 ***\n")
	server := "https://example.synology.me:5006"
	user := "scott"
	password := "secret"

	cc := gowebdav.NewClient(server, user, password)

	webdavFilePath := "/homes/scott/tmp/tmp01.txt"
	localFilePath := "./tmp01.txt"

	reader, _ := cc.ReadStream(webdavFilePath)

	file, _ := os.Create(localFilePath)
	defer file.Close()

	io.Copy(file, reader)

	fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

実行方法についてはこちら
[https://qiita.com/ekzemplaro/items/0781f7d242cdda52eb87](https://qiita.com/ekzemplaro/items/0781f7d242cdda52eb87)

次のファイルが作成されます。

```text
go.mod
go.sum
```
discord.pyで設定機能を追加する(制限あり)

※このコードでは再起動するとデータが初期化されるので注意。

```python
@bot.command()
async def config(ctx, config_name, config_arg):
    # /sayaka 設定の名前、数値の順
    if config_name == 'langage':
        #名前がlangageの時
        if config_arg == 'ja':
            set_langage = 'ja'
            config_output = '言語を日本語に設定しました'
        elif config_arg == 'en':
            set_langage = 'en'
            config_output = '言語を英語に設定しました'
        else:
            config_output = '構文エラー。jpまたはenを指定してください。'
        
    await ctx.send(config_output)
```
この設定を使うにはifで指定してやればおk。
Postmanでparameterized testをする

# モチベーション
Postman でAPIを叩く際に、パラメータやリクエストボディにバリエーションを持たせて複数回実行したい場合があるので、なんとかしたい

# この記事でやること
fake REST APIを作成し、それに対してGETを実行する（テストも書く）。
そのさい、.csvファイルでパラメータを複数個設定し、その分だけAPIを叩く。

# 今回の構成
* Postman v8.0.6
* [json-server](https://github.com/typicode/json-server)
* windows 10

# 手順
#### json-server をインストールする
```
npm install -g json-server
```

#### APIを叩いたときに取得するデータを、.jsonファイルとして作成する
```db.json
{
  "posts": [
    { "id": 1, "title": "json-server1", "author": "typicode" },
    { "id": 2, "title": "json-server2", "author": "typicode" },
    { "id": 3, "title": "json-server3", "author": "typicode" },
    { "id": 4, "title": "json-server4", "author": "typicode" },
    { "id": 5, "title": "json-server5", "author": "typicode" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "typicode" }
}
```

#### json-serverを起動する
db.jsonが保存されているディレクトリで、以下のコマンドを実行する

```
json-server --watch db.json
```

#### Postmanを起動し、リクエストとテスト、環境変数を書く
環境変数：
![env.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77762/97c6b85e-71e3-e1b6-b965-d484263eda6f.jpeg)
リクエストとテスト：
![request_test.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77762/c8cc48ff-b211-c503-27af-e3ccffe814bc.jpeg)

```test.js
var jsonData = pm.response.json();

pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});

pm.test("idの値がリクエスト通りである", function () {
    pm.expect(jsonData.id).to.eql(parseInt(pm.iterationData.get("id")));
});

pm.test("titleの値がリクエスト通りである", function () {
    pm.expect(jsonData.title).to.eql(pm.iterationData.get("title"));
});

pm.test("authorの値がリクエスト通りである", function () {
    pm.expect(jsonData.author).to.eql(pm.iterationData.get("author"));
});
```

#### テストデータを記載した.csvファイルを作成する
```test-data.csv
id,title,author
1,json-server1,typicode
2,json-server2,typicode
3,json-server3,typicode
4,json-server4,typicode
5,json-server5,typicode
```

#### collection runnerで、.csvファイルを読み込む
![runner1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77762/39e3312f-dd46-31b7-91f3-36fc1312a3df.jpeg)
![runner2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77762/d4611593-71e2-978a-2f3b-f32028b8132f.jpeg)

#### APIを叩く
collection runner のRun json-server ボタンをクリックすると実行が始まる
![result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77762/263d09b3-77a5-3fac-7c6f-2e88e1ecf8e3.jpeg)
今回は、test-data.csvに5件分のパラメータを設定しているため、リクエストが5回実行される。
そのため、実行結果にIteration 1から5まで表示されていれば成功。
また、それぞれのイテレーションでテストがパスしていればOK。

# 参考文献
* [Looping through a Data File in the Postman Collection Runner](https://blog.postman.com/looping-through-a-data-file-in-the-postman-collection-runner/)
* [json-server](https://github.com/typicode/json-server)
獣医師が必死にバイオインフォマティクスPythonによる実践レシピをwin10で動かす（その2）

## rpy2によるRの実行  
下記コードを実行せよと書かれている

```
!rm sequence.index 2>/dev/null
!wget -nd ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/historical_data/former_toplevel/sequence.index -O sequence.index
```

winでwgetが使えないので、しょうがなく普通にDL
普通に長いので経過を表示するプログラムも借りて作成  

```Python:DL.py
import urllib.request
from colorama import init, Fore, Back, Style

# 進捗を表示させるためのコールバック関数
# イメージ：[=====>    ] 50.54% ( 1050KB )
def progress_print(block_count, block_size, total_size):
  percentage = 100.0 * block_count * block_size / total_size
  # 100より大きいと見た目が悪いので……
  if percentage > 100:
    percentage = 100
  # バーはmax_bar個で100％とする
  max_bar = 50
  bar_num = int(percentage / (100 / max_bar))
  progress_element = '=' * bar_num
  if bar_num != max_bar:
    progress_element += '>'
  bar_fill = ' ' # これで空のとこを埋める
  bar = progress_element.ljust(max_bar, bar_fill)
  total_size_kb = total_size / 1024
  print(
    Fore.LIGHTCYAN_EX,
    f'[{bar}] {percentage:.2f}% ( {total_size_kb:.0f}KB )\r',
    end=''
  )

def download(url, filepath_and_filename):
  init()
  print(Fore.LIGHTGREEN_EX, 'download from:', end="")
  print(Fore.WHITE, url)
  # コールバックでprogress_printを呼んで進捗表示
  urllib.request.urlretrieve(url, filepath_and_filename, progress_print)
  print('') # 改行
  print(Style.RESET_ALL, end="")

url = 'ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/historical_data/former_toplevel/sequence.index'
download(url, './sequence.index')
```
なんか矢印が動いているのを見ると楽しい。
C,C++の安全なメモリ解放

メモリ解放で気をつけることは、

* メモリの参照を失わないこと
* 多重開放を行わないこと

```
class Hoge
{
private:
    void *m_buffer_ptr;
public:
    Hoge():m_buffer_ptr( nullptr ){}
    int init( size_t size )
    {
        if( m_buffer_ptr ){
            free( m_buffer_ptr );
        }
        m_buffer_ptr = malloc( size ); // 注意：事前に開放していなけれは、この代入で参照を失いリークする
        if( !m_buffer_ptr ){
            return -1;
        }
        return 1;
    }
    void term()
    {
        if( m_buffer_ptr ){
            free( m_buffer_ptr );
            m_buffer_pter = nullptr; // 多重開放を防ぐために、ヌルを入れる
        }
    }
}
```
参考／元ネタ：
MEM31-C. 動的に割り当てられたメモリは一度だけ解放する
https://www.jpcert.or.jp/sc-rules/c-mem31-c.html

MEM01-C. free() した直後のポインタには新しい値を代入する
https://www.jpcert.or.jp/sc-rules/c-mem01-c.html
HTML~フォーム作成②~

前回の続きから始めていきます！
前回の続きはこちらからどうぞ👍▶　https://qiita.com/akari_0618/items/86e5e8b1535c5cec5d7f　

https://qiita.com/akari_0618/items/3526fd7b751d9387667d

前回入力したものをブラウザで表示するとこうなっているかなと思います！
![スクリーンショット 2021-03-04 13.23.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/e87b8467-28e4-b49e-d7b8-8c7dc2173941.png)

これだと何を入力するのかわからないので名前をつけてあげましょう！
この名前を付けるのは"label"を使いましょう！

その際に使うのが"id属性"と"for属性"です。この子達がlabelの名前とinputで入力した値を紐付けてくれます！
紐付けではいくつかあるみたいなのですが、気になる人は自分で調べてみてください！！
id属性とfor属性についてはこちらを▶https://qiita.com/akari_0618/items/3526fd7b751d9387667d

```index.html
<label for="name">名前：</label>
<input type="text" id="name">
<textarea></textarea>
<label for="password">パスワード：</label>
<input type="password" id="password">
```
![スクリーンショット 2021-03-04 14.00.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/bac6b704-2e0f-9283-f168-b30426adfc9e.png)

id属性とかわかんないからめんどくさい！って思った方！
私もそうだから省略しちゃいましょう😇

```index.html
<label>名前：<input type="text"></label>
<textarea></textarea>
<label>パスワード：<input type="password" ></label>
```
はい！こんな感じに楽になりましたね👌
zshを用いたBasic認証の導入方法

## 記事の概要
・シェルとは
・zshについて
・zshを使ったBasic認証の導入
・環境変数をRailsアプリケーション側で読み込む設定
・Basic認証を確認

## シェルとは
シェルは、「ターミナルとOSを繋ぐ窓口役」と呼ばれています。
ターミナルにコマンドを打ちこむと、その指示をOSが読み取って結果を返しているように見えますが、実際にはこの「シェル」が間に挟まり、コマンドによる命令と実行結果の橋渡しをしています。


## zshについて
zshはシェルの一つで、2019年のmacOS Catalina以降で使われているシェルです。それ以前に使われていたbashというシェルと比較して、コマンドを実行する際に大きな違いはありませんが、分かりやすい違いとしては、bashのプロンプトは$なのに対し、zshのプロンプトは%であるという点が挙げられます。

## zshを使ったBasic認証の導入
通常、Basic認証のためのユーザー名とパスワードは、セキュリティ維持のためGitHub上の公開リポジトリで管理せず、zshなどのシェルの設定ファイル内で環境変数として管理します。
まずはじめに、以下のコマンドをターミナルに打ち込みます。

```
vim ~/.zshrc
```
vimは、サーバー上で使用できるテキストエディタで、上記のvimコマンドを用いることで指定したファイルの編集をターミナルから行うことが可能になります。
vimには、
「通常モード」: コマンドを打つことでファイルを保存したりvimを終了したりできる
「インサートモード」: ファイルに編集を加えることができる
の2つのモードがあり、今回は環境変数の設定にあたりファイルの編集が必要なため、インサートモードを使います。
vim ~/.zshrcのあと、「iキー」を押して、インサートモードに移行します。
[![Image from Gyazo](https://i.gyazo.com/bb49b393bb7df528420320ae15997d7e.png)](https://gyazo.com/bb49b393bb7df528420320ae15997d7e)
上記のように、ターミナルの左下に「INSERT」と表示されたら成功です。
その後、ユーザー名とパスワードの設定を追加します。

```
export BASIC_AUTH_USER='admin'
export BASIC_AUTH_PASSWORD='2222'
```
記述を追加したら「escキー」を押して、 「:wq」と入力します。
入力後、「Enterキー」を押して終了です。

そして、以下のsourceコマンドをターミナルに打ち込み、「Enterキー」を押したら完了です。

```
source ~/.bash_profile
```

「sourceコマンド」は、シェルに記述された内容を実行する役割を担うため、最後にかならず実行しておきましょう。

# 環境変数をRailsアプリケーション側で読み込む設定
最後に、設定した環境変数をアプリケーション側で読み込む記述が必要です。
application_controller.rbに以下のような記述をします。

```
 private

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]  # 環境変数を読み込む記述
    end
  end
```

これで、環境変数を使って、Basic認証を行えるユーザー名とパスワードを定義できました。

## Basic認証を確認
サーバー再起動後、Basic認証を試みます。環境変数として設定したユーザー名とパスワードでログインができれば、正しく実装できています。
もしうまくいかない場合は、シークレットウィンドウで再度確認してみましょう。
LaravelでぐるなびAPIを叩く方法（Guzzle）

Laravel5.8を使用している。

#手順
##guzzleをインストール

```
composer require guzzlehttp/guzzle
```

##コントローラーに処理を書く

今回はぐるなびAPIでレストラン検索をするから、
RestaurantControllerを作成し、その中にget_restaurantアクションを作成した。

```php:RestaurantController
public function get_restaurant()
    {
        $client = new \GuzzleHttp\Client();
        $response = $client->request(
            'GET',
            'https://api.gnavi.co.jp/RestSearchAPI/v3/',
            ['query' => [
                'keyid' => '123123123123123',
                'pref' => 'PREF39', 
                'freeword' => '餃子',   
                'hit_per_page' => 30
            ],
            'http_errors' => false //404エラーも通す指定
            ]
        );

        $data = [
            'res' => json_decode($response->getBody(), true)
        ];
        return view('restaurant.index', $data);
```

まず、Clientのインスタンスを作成し、その中に
`メソッド` `URL` `クエリ`
を入れて、リクエストとして送っている。

getBody()メソッドで中身を取得することはできるが、これはオブジェクトが返されるため、
json_decodeでjson形式に変換している。

また、requestメソッドの第３引数に400番台のエラーも表示の対象にする指定を追加している。

##ビューを編集

```php:restaurant/index.blade.php
@foreach ($res['rest'] as $r) 
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">おすすめ</div>

                <div class="card-body">
                    <h4>{{ $r['name'] }}</h4>
                    <br>
                    <p>{{ $r['pr']['pr_long'] }}</p>
                </div>
            </div>
        </div>
        @endforeach
```

ぐるなびAPIのレストラン検索機能では、
['rest']の中に複数のお店の情報が格納されており、さらに、その一つ一つのお店に
店名やその他詳細がぞれぞれ格納されているから、

```
rest-0-name
      -url
      -pr
  
    -1-name
      -url
      -pr

    -2-name
      -url
      -pr

```

このような順番で格納されている
コールバック関数

```.js
// これがコールバック関数
function greeting(name) {
  alert('Hello ' + name);
}

// 2. callbackという仮引数名でgreeting関数を受け取る
function processUserInput(callback) {
  
  // 3. 入力フォームを表示させ、入力値を変数に代入
  let name = prompt('Please enter your name.');

  // 4. 3の変数を引数に渡してコールバック関数実行
  callback(name);
}

// １. greeting関数を引数で渡す
processUserInput(greeting);
```
[MySQL] ERROR 1227 (42000) at line 18: Access denied; you need (at least one of) the SUPER privilege(s) for this operation

# エラーメッセージと発生箇所

MySQL上でdumpファイルを読み込もうとした時に発生。

```
ERROR 1227 (42000) at line 18: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
```

# このエラーが起きた背景

MySQLサーバー上に複数のdatabaseが存在し、そのうちの一つのdatabaseがうっかりdropされてしまった。Staging環境だったのでデータについては神経質にならずに一日前に取得していたmysqldumpから復旧しようとしたが、なぜか取得したmysqldumpを流そうとしたら表題のエラーが生じた。

流そうとしたmysqldumpの取得はdatabase別に行われていた。そのため、消えたdatabaseにだけ、dumpファイルからimportを行おうとした。
mysqlのユーザーは、普段このdatabaseの読み書きを行うアプリケーションで使用しているユーザーを使用した。

ちなみに、エラーが出たときには気づいていなかったが、**mysqldumpを取得した時**には下記の警告メッセージが出ていた。

```
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events. 
```

# エラーが起きた原因

mysqldumpを実行した時に`--set-gtid-purged=OFF`オプションをつけていなかった。これによって取得されたdumpファイルの中にGTIDに関するコードが入り込んでおり、部分的にdatabaseを更新する際に表題のエラーが生じた。

# 暫定対処

## 何をするかの概要

とりあえずエラーを解消してデータのリストアをするために、mysqldumpからGTIDに関するコードを消してから、インポートを行う。

## GTIDに関する記述を消す

### dumpファイルの上の方の記述を消す

dumpファイルの上の方にある下記の行を全て消す。コメントは別に消さなくても良い。

```sql
-- SETの3行を全部消す。

SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;

--
-- GTID state at the beginning of the backup 
--

SET @@GLOBAL.GTID_PURGED='';
```

### dumpファイルの下の方の記述を消す

```sql
-- この行を消す
SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;
```

### dumpファイルを流し込む

エラーが生じなくなるので、データを流し込む。もしここで流し込めなかったら、この記事で説明するのとは別の原因でエラーが発生している可能性がある。

# 恒久対処

## 何をするかの概要

部分的にmysqldumpを取得する場合は、`--set-gtid-purged=OFF`オプションをつけるようにする。

## `--set-gtid-purged=OFF` の効果

`--set-gtid-purged=OFF`オプションをつけた時とつけない時でdumpファイルの差分を出すと、「暫定対処」で消した部分にだけ差分が出ていることが分かる。

上の方。

![upper-position.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265900/de9c0a35-5b94-84fb-fda8-87c96acd3ccc.png)

下の方。（一番下のはただのコメント）

![lower-position.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265900/969bc084-3b53-e79a-a57b-d3d1521fa557.png)

# 参考

- https://support.acquia.com/hc/en-us/articles/360056635953-Troubleshooting-ERROR-1227-42000-at-line-18-Access-denied-you-need-at-least-one-of-the-SUPER-privilege-s-for-this-operation-