OmniAICreator/Qiita-1.07M huggingface dataset:
2022/03/28、railsにてrefileをbundle installしようとしたら、少し変わったgitエラーが起きた時の対処法。(備忘録)

アプリ開発の下準備中、Gemfileに以下を記載。

```
gem "refile", require: "refile/rails", github: 'manfe/refile'
gem "refile-mini_magick"
```

いつも通りにターミナルでbundle installしようとしたら、、、、

```
fatal: remote error: 
  The unauthenticated git protocol on port 9418 is no longer supported.
Please see https://github.blog/2021-09-01-improving-git-protocol-security-github/ for more information.

Git error: command `git clone 'git://github.com/manfe/refile.git'
"/home/ec2-user/.rvm/gems/ruby-2.6.3/cache/bundler/git/refile-197f44e2ac4e44430807f905ad7632ff5c702ce5" --bare --no-hardlinks
--quiet` in directory /home/ec2-user/environment/作成中のアプリケーション名 has failed.
```

**ふぁ！！！？君、一週間前までインストール出来てたよね！？なんでい！？**

と焦りながらも、ターミナルに記載されているurlを確認してみた。
```
↓この部分である↓
https://github.blog/2021-09-01-improving-git-protocol-security-github/
```

ほうほう、、、03/25?から、`git://`は永久的に使えなくなってこれからは`https://`を使っていきます、と、、、


何かよくわかんないけど、`git://`のところを`https://`に変えればいいんですね！？
　
　

ということで、メンターさんの協力のもと、エラー解除ができたのでメモ代わりにqiitaに残そうと思いました。

## refileの`git://`のところをなんとかして`http://`に変えたい！
実のところ、メンターさんに質問したところ本当に変わったのは最近なので、対処法を良くわからなかったみたいなんですよね。
お互いにどうにかinstall出来ないかネットで調べていたところ、今回解決につながった神ブログを見つけた。
　
それがこちら
→https://hachimaki37.hatenablog.com/entry/2022/03/28/113142
　
僕が起こしたエラーとは少しかけ離れてますが、似たエラー、しかも最近、、
って、八時間前じゃないですか:joy:
こちらの記事を参考に、メンターさんがあることをひらめく。
## 解決方法
`Gemfile`の**一番上**に以下のコードを記載。
```
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
```
こちらのコードは先ほど紹介したブログに載せられたコードである。
そのあと、ターミナルにて`bundle install`を実行すると、、、

### Bundle complete! 
　
無事に`bundle install`が出来ました！！！素晴らしい！！！やったね！！！
　
## 注意点
最後に一つだけ注意点。
コードを**一番上**に記載するのには意味があります。
最初、メンターさんが解決策を考えている裏で僕はこっそりとこちらのコードを`gem 'refile'`より下、`Gemfile`の一番下に記載して実行してみてました。解決できませんでした。
僕はまだヒヨコなので、なんとなくで理解してるんですけど、
**コードは上から下へとデータが読み込まれる**ので、`gem 'refile'`が書かれているコードより下に書くと、変換したい`git://`のところを`https://`に変換されずに読み込んでしまうから変わらずエラーが起きるんじゃないかなぁ、と考えてます:thinking:（間違っていたら教えてくださると嬉しいです！）
なので、先ほど記載したコードは一番上に記載することによって、変換したい`git://`のところを`https://`に変換でき、installが出来るようになったんだと思ってます！(多分！)

閲覧ありがとうございました！
Clean Codeの本を読んでコードに対する意識がガラッと変わった話

# 始めに
エンジニアとしてキャリアを始めてから5年ほど経ちました。
主にデータを集め、整理するプログラムを書いています。

少し前になりますが、エンジニアを始めてから数年の頃、上司に「コードクオリティを高めた方が良い」とフィードバックを頂きました。恥ずかしながら、それまではコードクオリティをほとんど意識したことはなかった為、今から考えると当時書いてたコードは読みづらく、他のエンジニアの方はもちろん、自分ですらメンテナンスしづらいコードを書いていました。

そんな自分が「[Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.co.jp/Clean-Code-Handbook-Software-Craftsmanship-ebook/dp/B001GSTOAM)」の本に出会い、半年間かけて学び、実践することでコードクオリティが向上しただけでなく、エンジニアとして非常に多くの学びを得ることになりました。今回は少しでも参考になることがあればと当時の学んだことを書き残したいと思います。

# 本を読む前に自分が持っていた思い込み
1. エンジニアの好みによって、きれいなコードは人それぞれ違う
1. 自分が足そうとしているコードの周辺に少しおかしなコードがあっても、誰かがいつかリファクタリングをしてくれるので、少し変でもそのまま新しいコードを足せばいい
1. エンジニアとして経験を積むにつれて、その内自然とコードクオリティは良くなっていく

実際に書いていて、恥ずかしいですが、これらの思い込みは次第に変わっていきました。

# この本から学んだこと
- きれいなコードとは何か
- なぜきれいなコードを書くのが大切なのか
- きれいなコードを書く為の方法

大きくまとめるとこの３つを学びました。
それらを一つ一つ理解し、実際に現場で実践し、何度も何度も読み直して、自分のコードと照らし合わせていくと、徐々にきれいなコードが書けるようになってるという実感が持てました。

# 本を読んだ後の自分の考え方の変化
~~1. エンジニアの好みによって、きれいなコードは人それぞれ違う~~
- 少なくともどんなコードが読みづらいコードなのかが分かるようになりました。
- コードクオリティにもベストプラクティスが存在し、それを生かしてコードを書くと読みやすくなりました。
- 読みやすいコードを書くことはコードレビューや今後メンテナンスをしてくれるエンジニアの方々の為になることを学びました。実際に周りの方が読みやすいコードでプルリクエストを出すと変更を依頼されることが格段に減ると実感しました。
  
~~2. 誰かがいつかリファクタリングしてくれるので、少し変でもそのまま新しいコードを足せばいい~~
- 自分がしないように、他の方もリファクタリングしてくれないと気づきました笑
- 例え自分が書いたコードでなくても、おかしなコードを見た場合は少しでも読みやすいコードになるように小さなリファクタリングをしようと気持ちを入れ替えました。
- 読みやすい、メンテナンスしやすいコードにリファクタリングすると新しいコードを追加しやすくなりました。
- 気がついた時に少しづつでも改善するように心がけると、長期的に圧倒的に読みやすくメンテナンスしやすいコードになると実感しました。

~~3. エンジニアとして経験を積むにつれて、その内自然とコードクオリティは良くなっていく~~
- これはあながち間違ってはいないかもしれませんが、特別に経験のあるエンジニアでなくても、コードクオリティ向上の方法を学び、実践していくと、コードクオリティは向上することが分かりました。
- 今まで同じチームの良いエンジニアの方が他の箇所で書いたコードをコピペすることがあったのですが、それが無くなりました。仮に参考にすることがあっても、コピペをするのではなく、コードを良く読み理解し、その時の自分が出来る最善のコードを書くようにしました。
- その場その場で最善なコードを書く為に学ぶことによって、時間はかかりましたが少しづつ自分の書くコードに自信が付くようになり、コードを書くことがとても楽しくなりました。
- 学ぶことが習慣化され、自分に自信がついてくると、「もっとメンテナンスしやすいソフトウェアを作りたい！」とエンジニアとして開発に対する姿勢が大きく変わりました。

# まとめ
- 「[Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.co.jp/Clean-Code-Handbook-Software-Craftsmanship-ebook/dp/B001GSTOAM)」の本からきれいなコードの書き方や必要性を学び、実践したことによってコードクオリティが格段に上りました。
- コードクオリティは向上すると、メンテナンス性の向上やコードレビューの容易化など開発のあらゆる所に生かすことが出来ると実感しました。
- 学ぶ習慣が身に付き、自分の書くコードに自信が付くと、より良いソフトウエアを開発したいという姿勢に変わりました。

# 最後に
上司にコードクオリティを向上するようフィードバックをもらえたこと、本当に感謝しています。当時、必死になって学んでも、中々実践出来なかったり、すぐには結果が伴わなかったりした時など辛い時もありましたが、自分自身、この本からエンジニアとして大切のことを沢山学ばさせていただきました。この記事が参考になり、少しでも多くの方に読んでいただけたら大変嬉しく思います。
Selenium WebDriver Java Simple Program - Login

# Outline
Selenium WebDriverで実際にE2E テストを作る。
初心者にとって、E2Eテスト自動化がどのようなものかを知るため、簡単なログイン機能のテストを実際にコードにしてみた。
尚、開発環境構築は　https://qiita.com/emurin/items/b4c04e5030835b98159a　を参考のこと。

# Test Scenario

1. Browserを開き、my.rakutenに遷移する
2. ログインをクリックする
3. Rakuten IDとpasswordを入力する
4. ログインをクリックする
5. ログインの可否を、名前が正しいかで判断する
6. Browserを閉じる

# Repositories

プログラミングする前に、操作対象となるHTML要素（repositories)を抽出する。
たとえば、my.rakuten.co.jpの「ログイン」のボタンを特製するとき、chrome developer toolで下図のように、html要素を確認し、ろのログインボタンを一意に特定する要素を取り出す。

今回のプログラムでは、Xpathを用いて特定した。
　<B>//a[@class='btn loginbtn']</B>
こちらが、ログインボタンの要素である。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/ba1f963f-a1df-83ce-5fa5-7c8854bd961f.png)


このようにして、テストシナリオに必要なrepositoriesをすべて抽出する。


# Program

```
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;

import net.bytebuddy.asm.Advice.This;
import static org.junit.Assert.assertEquals;

public class SampleScript {
	
	
	protected static String id;
	protected static String pwd;
	protected static String username;
	

	public static void main (String[] args) {
		WebDriver driver = new ChromeDriver();

		id = "Rakuten ID";
		pwd = "Rakuten ID password";
		username = "User ID name";
		
		// 1. open browser
		driver.get("https://my.rakuten.co.jp/");

		System.out.println("[INFO] Click login");
		Actions builder = new Actions(driver);

		// 2. go to login page		
		WebElement buttonMypagelogin = driver.findElement(By.xpath("//a[@class='btn loginbtn']"));
		builder.click(buttonMypagelogin).perform();

				
		System.out.println("[INFO] Input ID & Password");
		// 3. input ID & password
		WebElement loginInner_u = driver.findElement(By.xpath("//input[@id='loginInner_u']"));
		builder.sendKeys(loginInner_u,id).perform();
		
		WebElement loginInner_p = driver.findElement(By.xpath("//input[@id='loginInner_p']"));
		builder.sendKeys(loginInner_p,pwd).perform();
		
		System.out.println("[INFO] Click LoginButton");
		// 4. click login
		WebElement loginButton = driver.findElement(By.xpath("//input[@class='loginButton']"));
		builder.click(loginButton).perform();
		
		// 5. validate login status
		WebElement mystatus_name = driver.findElement(By.xpath("//em[@id='mystatus_name']"));
		String mystatus_name_innertext = mystatus_name.getText();

		System.out.println("[INFO] Validate mystatus_name_innertext = " + mystatus_name_innertext);
		assertEquals(username, mystatus_name_innertext);
		
		// 6. close browser
		driver.close();
				
	}
}

```

プログラムにあたっての特出するポイント
- https://www.selenium.dev/ja/documentation/webdriver/ のseleniumのIF仕様を参考
- 基本的にRepositoriesを取得し、アクションするの繰り返し
- assertionはJUnitの関数（assertEquals）を使用（対象のサンプルをJUnitを使えるようにすること）
- ID,Password,Usernameは自分で用意すること


# Result

![Videotogif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/a6a2494a-b4f5-9715-7ace-5e7f32d5a179.gif)
自宅サーバー構築譚：NTPクライアント

# 能書き

[自宅サーバー構築譚：基本構想](https://qiita.com/katz_engineer/items/cb592be44daa28a51d9b)に基づく自宅サーバー構築。将来の Kerberos の設定を睨んで、時刻をきちんと設定する事にしました。

時刻同期はサーバーのみならずクライアントでも必須です。テスト用には時刻をわざとずらせるようにした方が都合が良い事も多いんですが、それはまた別の話。

systemd-timesyncd が勝手に動いてるので放置しておけば良いのですけども。日本人が日本にサーバーを立てるなら、NTP サーバーはやはり ntp.nict.jp ではないかと考える次第です。

参考文献1：[日本標準時 に直結した時刻サーバ - 公開ＮＴＰ - 日本標準時グループ](https://jjy.nict.go.jp/tsp/PubNtp/index.html)
参考文献2：[[Q.1-7]	個人ユーザですが、stratum 1 にアクセスしても構いませんか？ - NICT公開NTP FAQ - 日本標準時グループ](https://jjy.nict.go.jp/tsp/PubNtp/qa.html#q1-7)

と言う訳で、NTP サーバをデフォルトから変更します。

# 準備

今回は```/etc```の修正だけなので、スナップショットは不要でしょう。気になる方は撮って下さい。

NTP クライアントが動いている事を確認します。

参考文献：[NTP サーバー : NTP クライアントの設定 - ServerWorld](https://www.server-world.info/query?os=Ubuntu_20.04&p=ntp&f=3)

```console
systemctl status systemd-timesyncd
```

または

```console
timedatectl timesync-status
```

# 設定

```console
sed -i -e"/^#NTP=/c NTP=ntp.nict.jp" /etc/systemd/timesyncd.conf
systemctl restart systemd-timesyncd
```

# 確認

準備と同じコマンドを実行して確認します。

特に難しい事も無いので、一発で行けるでしょう。

# 完了

```console
cd /etc
svn ci -m"setting NTP client"
```

やったね！:thumbsup_tone2:
typescriptでscalaのcase class#copyみたいなことがしたい

普段Scalaを書いている時にはcase class無しでは生きられないくらいお世話になっているわけですが、typescriptでもimmutableなcase classっぽいものを使いたいのです。

classをimmutableにするだけならコンストラクタ引数を全部`public readonlyにすれば良いだけなので簡単です。

``` typescript
class User {
  constructor(
    public readonly id: number,
    public readonly name: string,
    public readonly age: number
  ) {}
}
```

楽勝！
でもこれだけじゃ足りない。`copy`メソッドも欲しい！どうしたものか。。。

と、考えた結果`Partial`を使って自前実装するのが良いんじゃないかという結論にたどり着きました。

``` typescript
  // 名前がcopyでないのは好みの問題です
  public cloneWith(v: Partial<User>) {
    return new User(
      this.id,
      v.name || this.name,
      v.age || this.age,
    )
  }
```
なにげに`id`は置き換え不可とかの制御ができるのも良いところだと思います。

問題があるとしたらコンストラクタ引数が増えるとそれに合わせて`cloneWith`の方も直さないといけないのでタイプ量が増えるという点かと思いますが、今の時代もはやそれ、**どうでもいいんじゃないですかね**。

だって、コンストラクタの方にだけ引数足したらコンパイルエラーだし、しかも今の時代コンパイルせずともエディタがリアルタイムでエラーを指摘してくれるわけですし。補完も効くのでそうそうミスは起きません。

型のないpure javascriptだったらtypoの可能性があるので極力タイプ量を減らしたいというのはわかります。(他にも全フィールドに対してテスト書け、とか言われたりね)

しかし、IDE前提の現代のtypescriptでは変にループとreflection的なテクニックを駆使して汎化するよりもこれで十分じゃないの？と思ったりします。
ファイルサーバーを読み取り専用にする方法

# 概要 #

ファイル サーバー の移行作業時に差異が生じないよう移行元のファイルサーバーを特定のタイミングで読み取り専用にしたい

との要望がありその対処方法について調べたのでその結果を記します。


# 対処方法 

共有アクセス許可で Everyone のアクセス許可を[読み取り専用]としてその他の共有アクセス許可を削除

NTFS のアクセス許可エントリーを変更する際には各フォルダ、ファイルの権限付与の変更をするのに時間がかかりますが
共有アクセス許可であれば時間がかからず即時に変更可能です。
Elasticsearch のデータを pandas で分析する

Elasticsearch(es) にあるデータを、pandas 使って分析したくなり、どうやって es のデータを pandas にロードするか調べました。

1. Python の es client でクラスターに接続
1. search API で読み込んだデータを pd.json_normalize() する
1. 以下ループ処理

このような例が見つかりますが、私が対象としているデータは割とたくさんあるので、もっと気軽にできるツールはないかとさらに調べたら、[eland](https://eland.readthedocs.io/en/v8.0.0/index.html#) を見つけました。

eland を使うと、es のデータをローカルに持ってこなくても、pandas API を使ってデータ分析ができます。

```python
import eland as ed
from elasticsearch import Elasticsearch

es = Elasticsearch(
    'https://es_cluster:9200',
    ca_certs='ca.crt',
    basic_auth=("elastic", "password")
)

df = ed.DataFrame(es, es_index_pattern="your_index")
```

およそこのような感じです。DataFrame として操作できますが、データ自体は es にあるので、ローカルマシンがデータで溢れることがありません。

```python
df.info()
<class 'eland.dataframe.DataFrame'>
Index: 1385743 entries, AWISKaLgkLsdlAHXZMg1 to AXOUE9QOl2VpoF9pPHim
Columns: 118 entries, aaa to zzz
dtypes: bool(6), datetime64[ns](5), float64(39), int64(45), object(23)
memory usage: 64.000 bytes
Elasticsearch storage usage: 3.995 GB
```

eland が提供する pandas 互換APIは限られているので、本家 pandas に変換したいかもしれません。その場合も一行で OK です。

```python
pd_df = ed.eland_to_pandas(df, show_progress=True)
2022-03-28 11:32:50.850852: read 10000 rows
2022-03-28 11:32:57.377126: read 20000 rows
2022-03-28 11:33:03.149467: read 30000 rows
2022-03-28 11:33:13.091023: read 40000 rows
2022-03-28 11:33:24.209532: read 50000 rows
2022-03-28 11:33:31.095330: read 60000 rows
2022-03-28 11:33:37.367170: read 70000 rows
2022-03-28 11:33:45.943025: read 80000 rows
2022-03-28 11:33:51.439257: read 90000 rows
2022-03-28 11:33:58.801443: read 100000 rows
```
Static factory methodの使い所

## 結論
副作用があるコンストラクタが必要な場合は、代わりにStatic factory methodを用いる。

## だめな例

```java
public class World {

    private final AnimalController animalController;
    private final TerrainController terrainController;

    public World() {
        this.animalController = new AnimalController();
        this.terrainController = new TerrainController();
        ExecutorService executorService = Executors.newWorkStealingPool();
        executorService.submit(animalController::spawnRandom);
        executorService.submit(terrainController::generateSurface);
    }
}
```

この例では、Worldのコンストラクタが呼ばれると、AnimalControllerとTerrainControllerが初期化され、非同期で地形を生成して動物を出現させている。この例がなぜだめなのかというと、Worldの内部実装を知らないプログラマーが
```java
new World();
```
したときに、おそらくそのプログラマーは同時に地形や動物が出現するとは想定できないところである。またそれ以外にもスレッドプールを作成しているため、プログラマーはコンストラクタを呼び出したときにスレッドの処理や破棄のタイミングといった方法まで考えなくてはいけない。コンストラクタは非常に高い頻度で使用されるため、コンストラクタを呼び出したときに一々副作用を考えなくてはいけないのはプログラマーにとって理想的でない。

プログラマーはデフォルトコンストラクタを見ると、そのオブジェクトがPOJOとして利用されているか、少なくともコンストラクタは外部に対して影響を及ぼさないと考えることが多い。

したがってコンストラクタを呼び出したときに、外部に副作用をもたらすコードは望ましくない。

## 良い例

```java
public class World {

    private final AnimalController animalController;
    private final TerrainController terrainController;

    public World(AnimalController animalController, TerrainController terrainController) {
        this.animalController = animalController;
        this.terrainController = terrainController;
    }

    public static World createEarth() {
        AnimalController animalController = new AnimalController();
        TerrainController terrainController = new TerrainController();
        World world = new World(animalController, terrainController);

        ExecutorService executorService = Executors.newWorkStealingPool();
        executorService.submit(animalController::spawnRandom);
        executorService.submit(terrainController::generateSurface);

        return world;
    }
}
```

上のコードでは、Worldがコンストラクタの他にもStatic Factoryメソッドを持っている。これによりWorldのコンストラクタを呼んでも副作用が発生しないだけでなく、ユニットテストのしやすさを上げることにもつながる。

## 注意点

### クラス名から副作用があることを推測できる場合はコンストラクタに副作用があっても良い

InputStream、OutputStream、Writer、Reader等の接尾辞がクラス名に付く場合は、コンストラクタに副作用があっても良い。コンストラクタを呼び出すとき、クラス名から副作用があることが推測でき、副作用の存在を忘れて不具合を発生させることがないためである。

### 副作用がない場合でもStatic method factoryは使用できる。

Boolean#of、Integer#valueOfといったメソッドは副作用がないがStatic method factoryである。これら副作用のないStatic method factoryの多くは、慣用的なメソッド名（of、valueOf等）を使用していることが特徴である。
【Laravel】APIのcontroller作成時に使える--apiオプション

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## --apiオプション
下記のコマンドで、```create```や```edit```メソッドを含まないAPIリソースコントローラを素早く生成できる。

```
php artisan make:controller Api/PostController --api
```

```php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}
```


## 参考
https://readouble.com/laravel/8.x/ja/controllers.html
<備忘録>gitのブランチ名を間違えてしまった

# gitのブランチ名間違えてしまった

gitのリモートリポジトリ作成時スペルを間違えてしまった。

```
git checkout -b acount-activation
```
を
```
git branch -m account-activation #今開いているブランチ
git branch -m acount-actication account-activation #開いていない場合
```

で変更できます！

### 参考文献
https://qiita.com/suin/items/96c110b218d919168d64
ロール切り替え（スイッチロール）した時のアクセス許可は累積されない（ドキュメントを読むことの重要性も）

## 最初に

こんな勘違いをする人はあまりいないかもしれませんが、ロール切り替え（スイッチロール）した時のアクセス許可について、自分に対してのメモも兼ねて記しておきます。

## ロール切り替え（スイッチロール）した時のアクセス許可は累積せず、ロールに設定されているアクセス許可だけが有効になる

ロールの切り替えをユーザーに許可して、実際にロールの切り替えを行った際、有効になるアクセス許可の内容は「ロールに記載されたアクセス許可のみ」となります。

私は当初、ユーザー及びユーザーが属しているグループのアクセス許可との累積になると思い込んでしまっていました。実運用に入る前にその認識が間違っていることに気がつけたので良かったのですが、ドキュメントにはしっかりと書かれていました。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_switch-role-console.html

> 重要
>IAM ユーザーと切り替え後のロールのアクセス許可は、累積されません。同時に有効になるアクセス権限のセットは 1 つのみです。ロールを切り替えると、ユーザーアクセス権限が一時的に無効になり、切り替え後のロールに割り当てられたアクセス権限が有効になります。そのロールを終了すると、ユーザーアクセス権限が自動的に復元されます。

## 何故勘違いをしたのか？

この件に関して言えば、もう単純に「アクセス許可は累積するものだと思い込んでいて、ドキュメントを読まなかった」ことがその理由だと思っています。

## どうすれば良かったのか

AWSのドキュメントは分量が多く、読み込むことは決して楽ではないと思います。ですが、公式のドキュメントがある以上、読むべきものだと思います。それに、一回読んだだけでは理解しきれなくとも、何度か読んでいるうちに見えてくることもあります。

また、AWSに限ったことではありませんが、何かを使うのであれば、ドキュメントを読んで裏付けを取っておくことは重要だとも思います。誰かに「この実装をした理由は何でしょうか？」と聞かれた時に「このような形でドキュメントに書かれていて、実際に挙動も確認しています」と言えた方が、話す内容に説得力があります。

## 実際の挙動で確認できたとしても、ドキュメントは確認しておく

機能を理解するには、動かしてみるのが早いと私は思っています。ドキュメントの読み込みもそこそこに、まずは動かしてみることが多いと自分では認識しています。

ただ、以前は自分で動かしたことだけを根拠にして物事を話すことが多く、ドキュメントの読み込みが不十分なために、実装した部分の説明を求められた時に確実な説明ができなかったこともしばしばでした。

最初のうちは細かくつっこんでこない人もいますけれど、実装してからしばらく時間が経ち、実装した部分で何かあった場合には「何故そういう実装をしたのか、その時に確認した情報は何だったのか、どういう理解をして実装をしたのか」などと細かく聞かれることになります。

今回の件は、実装時には見逃してしまったとしても、評価を行っていればその時点で気がついたことだとは思うのですが、評価項目の設定自体を誤っていたら結局は見過ごされることに繋がっていたとも思います。幸いにもこの時は実装中に気がついたので良かったのですが、運が悪ければどうなっていたことかと考えさせられました。

そんなこともあり、今ではドキュメントを読むこと意識しています。「言うは易し行うは難し」ではあるのですが、それでもAWSに関わるなら意識していきたいと思います。
プロジェクトから退去するときの手続き

# これはなんですか
IT関連、特に開発のプロジェクトを去るときの手続きについてのメモ
ものによっては社員として働いた会社を去るときとかぶる部分があるが、そうではなく、請負か派遣で入っていた先を正規の手順で去るときの手続きを示す。

# 退去日時と作業内容、退去執行責任者について
いつ（何日の何時に）自分がプロジェクトの要員ではなくなるのか、やめるまでの作業内容は何かをあきらかにする。
主に現場の上長になると思うが、退去について指示を出し、責任をとるマネージャーまたは監督者を確認する。

# 貸与された物品、電子情報
##  物理的なもの
原則として貸与されたときの状態に戻すか初期化するか自分に関する情報を全て消す。
たとえばPCやストレージ、物理鍵、カードなどは貸与されたときの状態に復元し返却する。

汚損、破損、紛失した場合はその時点で届出ていると思うが、企業が一番恐れるのは物品損害ではなく、データの流失である。

鍵の複製は作ってはいけない、カードの情報は無力化してはいけないしコピーもしてはいけない。
仮に作ったとしたらそれらは必ず破棄する。

~~鍵といえば以前、オフィス入り口の物理鍵をYOKARANU-MOKUTEKIに使ったとか豪語してた猛者がいるがそういうことはやめる。~~
立派な器物損壊であると思う。やってたとしてもその事実を**告げてはいけない**。

## アカウントやアクセス情報
原則削除する、どうやってもアクセスできない状態にする。
バックドアなどは絶対に残さない、作らない。

アカウント情報の忘却という手段もあるが、期限がないものが残り続けて悪さをする可能性があるため、必ず無力化すること。
自分で消せないものは退去後に無力化してもらうため、退去後に後述の目録を作成して管理者に渡す。
たとえばAWSのIAM。

Chromeなどのブラウザのパスワード管理になにか残っていても、アクセスできないところを目標にする。

## サービスを紐付けられた自分のアカウント
自分で管理するあるいは所属する法人のアカウントに紐付いたものは、その紐付けを切るように依頼する。
たとえばgithub。

## 自分が作った成果物
何か事件があったときに嫌疑がかかることを避けるため、びたいち持ち出さない。
こういう面白い事件が世の中にはあります。
https://www.itmedia.co.jp/news/articles/2101/29/news107.html

といっても消したかどうかはプロジェクト側の人からはわからないため、契約による縛りと、性善説に基づくのもまた事実ですが。

## ダウンロードしたプロジェクトのドキュメントやデータ
一箇所のディレクトリに集めておいて完全に削除する。ダウンロードフォルダの中のチェックもお忘れなく。
できればPCごと初期化したいが、それができない人向け。

## 引き継ぎ
退職が確定した時点で引き継ぎに関する動きを起こす、主なものについては下記。
1. 自分が作成した、関わった物の目録を作成し、後継者あるいは管理者と議論する
    1. これがない状態で何かをしようとしても必ず取りこぼしが出る。
1. 前述の貸与された、または関連のあるアクセス情報等についての目録を作成し、プロジェクトから除外するか除外してもらうように依頼する。

## 退職後の連絡先
これを渡すかどうかは熟考されたし。

現場との関係によるが、あまりいい印象を持ってない現場に対しては渡さないほうがよい。
大丈夫だと判断した人には教えない。
電話番号よりは難癖つけてきても無視できるメールアドレスがよいでしょう。

SNSのアカウント、いきつけの店などを通して性癖までバレてる人は、私からは掛ける言葉がないので自分でなんとかしましょう。

## お別れを言う
お世話になった人に、どうお世話になったのか、何を感謝しているのかを明示して感謝の意を伝える。
特に感謝することがない人に対しては、あたりさわりのない挨拶にする。

この先はかすれていて読めない。
【AWS環境構築メモ⑧】Route53でAレコードのエイリアスを作成する

## 0.はじめに

**HTTPS通信するための最後のタスクとして、Route53でELBのDNSレコード(Aレコード)のエイリアスを作成します。**

![スクリーンショット 2022-03-28 19.55.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/54e7063e-b73d-3a04-2067-8ecbdd61a2af.png)

## 1.前回の記事

**[【AWS環境構築メモ⑦】ELBを作成する](https://qiita.com/yuuichimizuta/items/d7dabc1b4b21de0e7e60)**

## 2.前提条件

- **AWSアカウント作成済み**
- **リージョンはアジアパシフィック(東京) ap-northeast-1**
- **VPC作成済み**
- **セキュリティーグループ作成済み**
- **EC2インスタンス作成済み**
- **SSL証明書発行済み**
- **ELB作成済み**

## 3.作成手順(サマリー)

|順番|手順|
|---|---|
|1|Aレコードのエイリアスを作成する|

## 4.作成手順

### 1.Aレコードのエイリアスを作成する

![スクリーンショット 2022-03-28 18.58.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/7a2f1d8c-b71f-4b60-8836-5b73b79d07f9.png)

- **サービスよりRoute53を選択 → ホストゾーン → 対象のドメイン名をクリックする**

![スクリーンショット 2022-03-28 18.58.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/7ecdef99-d655-aafa-9123-520da1117235.png)

- **[レコードの作成]をクリックする**

![スクリーンショット 2022-03-28 19.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/50bb03fc-fc55-94cb-5ee5-77d036e76fbc.png)

**レコードの作成**

- **レコード名**
  - 任意(私は未入力でした)
- **レコードタイプ**
  - Aレコードを選択
- **エイリアスを選択**
- **トラフィックのルーティング先**
  - [Application Load BalancerとClassic Load Balancerへのエイリアス] を選択
  - [アジアパシフィック(ap-northeast-1)]を選択
  - ELBのDNSレコード(Aレコード)を選択
- **[レコードの作成]をクリックする**

<font color="Green">**Aレコードのエイリアスを作成できました**</font>

## 5.最後に

以上でHTTPS通信が可能になります。
最終確認は後のタスクで行います。

**次回はRDSの作成をしていきます**

**次回 : [【AWS環境構築メモ⑨】RDSを作成する](https://qiita.com/yuuichimizuta/items/ac43d5e2be0c1d8f1bc2)**

## 6.参考

https://mseeeen.msen.jp/access-your-ec2-web-server-via-elastic-load-balancing/

https://prograshi.com/platform/aws/how-to-set-arias-code-in-route53/
SeleniumとEdgeDriverでデフォルトのダウンロードフォルダを変更する（msedge-selenium-tools）

# 追記
msedge-selenium-toolsは非推奨らしいので、selenium4で対応する方法をかきました
https://qiita.com/pm00/items/1eaf7d76ad68a4dcdf4d

# はじめに
Pythonとseleniumを使ってMicrosoft Edgeのダウンロードフォルダを指定する。


# 準備
## Edgedriverをダウンロード
PCにインストールされてるEdgeに対応するバージョンのEdgedriverをダウンロード
hしておく
https://developer.microsoft.com/ja-jp/microsoft-edge/tools/webdriver/

## ライブラリのインポート
```
pip install selenium
pip install msedge-selenium-tools
```

※ただし、msedge-selenium-toolsは非推奨？になっているっぽい。selenium4に統合されたのでそっちを使えとのこと。
※以下はMicrosoft公式のマニュアル。日本語翻訳は機械翻訳がアレなので英語版で読むのを推奨
https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/?tabs=python
https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options


# 実装
```py
#%%
from msedge.selenium_tools import Edge, EdgeOptions
options = EdgeOptions()
options.use_chromium = True
options.add_experimental_option("prefs", {
  "download.default_directory": path_downloads
})
driver = Edge(executable_path=path_edgedriver, options=options)
```

# おまけ
`subprocess`でEdgeのバージョンを取得する。
`powershell`に渡すコマンドの中に、`"`も、`'`も、どちらも使われているので、`"""`で囲むことにした。

```py
#%%
t="""powershell -Command "(get-item 'c:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe').VersionInfo.FileVersion"""
import subprocess
s=subprocess.run(t,shell=True,capture_output=True)
print(str(s.stdout).split(".")[0][2:])
```
[C#] データアクセス層を作って拡張性の高い外部サービスとの連携機能を作る

# はじめに

外部のサービスと連携した機能を作りたいとき、拡張性を高くするために行った設計をまとめます。

# データアクセス層を作る

構成管理ツールと連携するための機能を題材に設計を行いましたので、それを例にして説明します。

構成管理ツールにはGitHub、GitLab、BitBucket、SVNのように様々ありますが、コミットやマージなど、どのサービスでも同じような操作があります。
その操作をシンプルに表したI/Fを作ることで、アプリケーション内部では具体的なツールを扱うことなく、抽象的なI/Fを使用して、アプリケーションとして提供したいサービスを作ることができます。
これにより、連携先のツールが増えても変更する箇所がほぼI/Fの実装部分に限定され拡張性が高くなります。
連携先のツールを表すインスタンスを生成するためのファクトリなどに手を加える必要がありますが、アプリケーションサービス自体は具体的なツールを知らない状態で作っているため、そこの変更が無くなり、拡張性が高くなると思います。
図にすると以下のような設計になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/fe5cb519-d6a3-692f-b39a-3e7344f1f283.png)

# さいごに

外部サービスとの連携に限らず、保存やWebサービスのデータを取得するためのサーバーへのアクセスなども、同じ考え方が使えます。データアクセス層を用意することで、アプリケーション内では具体的な保存方法や、サーバーのための実装を意識せずに、抽象的なI/Fを使用してアプリケーションとして必要なサービスを実装でき、拡張性高く作ることができると思います。
一般的な考え方ですので覚えておきたいです。
2回目（インフラ）

今回は「インフラ」について、
![インフラ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/6c508aa2-2bba-d2ad-9178-20db69b09e7b.png)

第一階層の分岐は種類（勉強や専門分野の方向性で分けてみた）
第二階層の分岐は具体例（）
言葉の意味はアプリやシステムが使えるようになるための基盤
![インフラ２.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/65dbb47c-0ea3-3017-5966-c8604a419c7c.jpeg)

サーバーはサービスを提供するもので、利用者の要求に応じてデータを送ります。
例えばWebサーバーであれば、Webブラウザの要求に応じて、画像やHTML/CSSを送ります。
Nginx（エンジンエックス）というものが聞いたことがある。
メールサーバーであれば、メールの送受信を行うプロトコルがある。
結論は　データの処理や加工するために必要となるサーバーの設計方法や運用方法を学ぶ

ネットワークは、つなっがているという状態を表す言葉の意味合いが強く、ネットワークを構築するイメージとしてはA町とB町の間のトンネルが完成した。といった感じです。つなげるためには色々なモデルやプロトコルがあるので勉強しないといけない。
例えば、LAN＜WAN＜インターネットの順で広いネットワークの形
結論は　サーバにアクセスするための経路であるネットワークの構築方法や保守方法を学ぶ

データベースは、データを保存する場所。
保管の大きさや仕組みが違う。
言語のひとつにMYSQLがあって、データを取り出したり、更新したりする。
結論　とりあえずは放置

インフラエンジニアでの面接で、サーバーがやりたいか、ネットワークがやりたいかを聞かれて迷ってしまったためまとめました。
サーバーエンジニアはサーバーのセキュリティチェック、バックアップするイメージ。そのためLinux・UNIX・Windows Serverといったサーバー向きのOSの知識が必要。

ネットワークエンジニアはネットワーク機器を設置・配線するイメージ。そのため物理的・論理的な仕組みや構成についての知識が必要。

次回は「サーバー」ついて解説
非同期通信を勘違いしていた問題

# 目次
[1.投稿ボタンを押しても無反応...](#1-投稿ボタンを押しても無反応)
[2.非同期通信という根本的なことを忘れていた](#2-非同期通信という根本的なことを忘れていた)

Laravel + Vue.js を使ったブログ開発にて。
ブログ投稿の際に、 Vue からコントローラへ投稿内容のデータを送る axios 通信でちょっとしたミスがあったのでアウトプットとして記事にしてみます。

# 1. 投稿ボタンを押しても無反応...

最終的に実装させたかったのは、
**投稿ボタンで発火させ、**
**Vue -> コントローラ -> DBに投稿データを保存し、投稿完了したらトップページへ自動遷移させる。**
という流れだったのですが

```vuejs:Create.Component.vue
<script>

axios
    .post("/posts", data)
    .then((res) => {
        console.log(res);
        this.posts = res.data.posts;
    })
    .catch((err) => {
        console.log(err);
        console.log(err.response.data);
    });
```

このように書いた結果、投稿ボタンを押しても画面はそのまま無反応でした。
結果から言うと、
**この処理では、投稿ボタンを押しても画面は何も変化しないのですが、投稿データ自体はコントローラに送られDBに保存されているため、変化がないからと投稿ボタンを何回も押しているとその分だけ同じ処理が走り同じ投稿がいくつもされてしまいます。**

# 2. 非同期通信という根本的なことを忘れていた

コントローラには、投稿完了と共にトップページへ自動遷移する処理を書いていましたが、axiosは非同期通信なので画面は遷移しません。
そのため、Vue 側にトップページ自動遷移処理を書く必要がありました。
というわけで修正後がこちら！！

```vuejs:Create.Component.vue

<script>

axios
    .post("/posts", data)
    .then((res) => {
        console.log(res);
        this.posts = res.data.posts;
        window.location = "/";
    })
    .catch((err) => {
        console.log(err);
        console.log(err.response.data);
    });
```

`window.location = "/";` を追加しました！
これで投稿完了とともにトップページへ画面が自動遷移してくれました。

非同期通信という根本的な部分を忘れていたおっちょこちょいミスでした...。
【Swift】フォント 液晶ディスプレイ風デジタル数字 7セグ

## 完成形
![スクリーンショット 2022-03-26 17.07.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/add34e02-2535-f2b3-4d31-f9c8f4a84824.png)


## 実装方法

### ① DSEG7 フォント(ttfファイル)をダウンロード
https://www.keshikan.net/fonts.html

### ② Xcode のプロジェクト に ttfファイル をポイっと置く
![Screen Shot 2022-03-26 at 17.00.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/1a7ee3ff-8d1c-8f8a-fea0-700988c20216.png)

### ③ Storyboard のインスペクターで Label の Font をDSEG7フォントを指定する
![Screen Shot 2022-03-26 at 16.56.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/6ee004d0-3af6-b6ef-ab3a-0d708e01ad8c.png)
【Swift】ハーフモーダルをライブラリなしで作る

### 実装方法
UIModalPresentationStyleを使う


### 遷移元のViewControllerからハーフモーダル用のViewControllerへ、Segueを繋ぐ
Kind は Present Modallyを選択する
![Screen Shot 2022-03-18 at 19.09.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/f74ef363-8773-b145-295b-ce688aa21bfc.png)


### 画面の上部の透過部分
ハーフモーダル用のViewControllerはViewのBackground を Clear Color とする
![Screen Shot 2022-03-18 at 19.08.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/217aa61b-b0a7-cea3-73fd-1cf2035772be.png)


### ハーフモーダル部分
HeightはSafeAreaに対して、0.65の比率を指定しました。
![Screen Shot 2022-03-18 at 19.07.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/e876bfce-f55f-2215-f494-82166ce6df2e.png)


これで、ハーフモーダルビューの完成。
【Swift】スプラッシュ画面をアニメーションさせる

## 手順

1. LaunchScreen.storyboardを設置する
2. LaunchScreen.storyboardと同じLabelを起動時に表示する
3. そのLabelをアニメーションさせる +α インジケーターを表示する

## ソースコード
```
    @IBOutlet weak var logoLabel: UILabel!        // LaunchScreenと同じロゴ
    @IBOutlet weak var logoImageView: UIView!     // LaunchScreenと同じView
```

```
    override func viewDidLoad() {

        // インジゲーターを開始
        showActivityIndicatorView()
        
　　　	// 好きな処理をする

        // インジケーターを終了
        finishActivityIndicatorView()
    }

    func showActivityIndicatorView() {
        if let logoImageView = logoImageView {
            logoImageView.isHidden = false
            // 表示位置を設定（画面中央）
            activityIndicatorView.center = CGPoint(x:view.center.x, y: view.center.y + 60)
            // インジケーターのスタイルを指定（白色＆大きいサイズ）
            activityIndicatorView.style = UIActivityIndicatorView.Style.large
            // インジケーターを View に追加
            view.addSubview(activityIndicatorView)
            // インジケーターを表示＆アニメーション開始
            activityIndicatorView.startAnimating()
        }
    }

  func finishActivityIndicatorView() {
        DispatchQueue.global(qos: .default).async {
            // 非同期処理などが終了したらメインスレッドでアニメーション終了
            DispatchQueue.main.async {
                // 非同期処理などを実行（今回は2秒間待つだけ）
                Thread.sleep(forTimeInterval: 2)
                // アニメーションをする
                self.showAnimation()
                // アニメーション終了
                self.activityIndicatorView.stopAnimating()
            }
        }
    }
    
    func showAnimation() {
        // 少し縮小するアニメーション
        if let logoLabel = self.logoLabel {
            UIView.animate(withDuration: 0.3,
                           delay: 0.5,
                           options: UIView.AnimationOptions.curveEaseOut,
                           animations: { () in
                logoLabel.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
            }, completion: { (Bool) in
                
            })
            
            // 拡大させて、消えるアニメーション
            UIView.animate(withDuration: 0.2,
                           delay: 0.8,
                           options: UIView.AnimationOptions.curveEaseOut,
                           animations: { () in
                self.logoLabel.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
                self.logoLabel.alpha = 0
            }, completion: { (Bool) in
                self.logoImageView.removeFromSuperview()
            })
        }
    }
```

### 参考

iOSのスプラッシュ画面実装における注意点と実装方法
https://qiita.com/kboy/items/7de88a834bf01a6e858f

[iOS]TwitterアプリのようにLaunch Screenがアニメーションするように見せる技
https://qiita.com/osamu1203/items/a7c78666b18eb499c94b
【Swift】UIButton 二重タップを防ぐ



# 概要

ボタンを連打することを防止する方法をまとめる。

#### 実装方法
ボタン押下されたタイミングでボタンを0.5秒間、選択状態(もしくは非活性)とする
```
　　// 入力ボタン
    @IBAction func Button_Input(_ sender: EMTNeumorphicButton) {
        // ボタンを0.5秒間、選択状態とする
        sender.isSelected = !sender.isSelected // もしくは.isEnabled 
　　　
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            sender.isSelected = !sender.isSelected
        }
```


# 参考

UIButtonの重複タップを回避する
https://qiita.com/shimizu6660/items/b4bb1b38bd3c639cc132
HDF5のAttribute（属性）の作成・読み取り by Python (h5py)

# 前置き
<font color="red">**HDF5のAttributeを読み取りたい**</font>と思って検索したが、日本語の文献は Cや fortranによる扱いばかりを説明したものばかりだった。[h5pyのドキュメント](https://docs.h5py.org/en/stable/high/attr.html)をさらっと見てもよくわからなかった（たぶん説明が書いてあったんだろうが、`初心者ゆえあまり理解できない部分が多かった.....`）。

**stackoverflowに良い質問と回答があったので（以下リンク）、ほとんどそれの翻訳みたいなことをしよう** と思って書かれたのが当記事です。

https://stackoverflow.com/questions/66146782/how-to-read-hdf5-attributes-metadata-with-python-and-h5py

# HDF5のAttributeの読み取り
手順は
1. `h5py` を `import`
1. (ファイルを開くときは with がより良いらしい)
1. GroupやDatasetに `.attrs` を付けることでその Attributeを辞書みたいな感じで取得できる
1. さらに `.keys()` を付ければ、Attributeの名前にアクセスできる
1. 3.によって得た Attributeに 4.で得た Attributeの名前を辞書キーのように指定すれば、Attributeの中身を配列として取り出せる。


```python
import h5py

with h5py.File("path/to/hdf5file", 'a') as f:
    # Attributeには .attrs でアクセスできる（手順３）
    attr_exmpl = f["path/to/Group_or_Dataset"].attrs
    print("読み込んだAttributeは:", attr_exmpl)
    ### 読み込んだAttributeは: <Attributes of HDF5 object at [数字]>
    # これに辞書のようにキーを付ければ中身を取り出せる。


    # Attributeのリストは辞書と同じように .keys() で得られる（手順４）
    print( attr_exmpl.keys() )
    ### <KeysViewHDF5 ['attr0', 'attr1', 'attr2', 'attr3', 'attr4']>


    # これを用いて、それぞれのAttributeの中身のデータを表示させる（手順５）
    for k in attr_exmpl.keys():
        print( f"{k} : {attr_exmpl[k]}" )
    #（テキトーな出力例↓）
    ### attr0 : 10
    ### attr1 : [0 1 2 3 4]
    ### attr2 : [[0 1 2]
    ###          [3 4 5]]
    ### attr3 : 0.
    ### attr4 : [1. 1. 1.] 
```

# Attributeの作成
Attributeは辞書みたいなものなので、作成するときも辞書と同様。
```Python
with h5py.File("path/to/hdf5file", 'a') as f:
    # Attributeには .attrs でアクセスできる
    attr_exmpl = f["path/to/Group_or_Dataset"].attrs

    # Attributeを追加（辞書と同じ書き方）
    attr_exmpl['new_attr'] = 5
```

# まとめ
`with h5py.File(filename, 'r') as f:`
　　`f['dataset'].attrs['name_of_attribute']` 
で Attributeの中身を見ることができる。
![attributeofhdf5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603341/b836e17a-9ce1-128e-5ff0-7d078939a61d.jpeg)

作成する際も上の画像と同じ形で書けばよい（辞書と同じ）。


# 追記（公式ドキュメントを見ればわかる話でした）
前置きでも言い訳したように、[公式ドキュメント](https://docs.h5py.org/en/stable/high/attr.html)を読んでも基礎知識の不足であまり理解できず、stackoverflowから具体的な操作を学び、それをこちらに日本語化したわけですが.....<br><br>



答えを知ったうえで公式ドキュメントを読み返すと、内容が理解できました。
こういうことは "初心者あるある" ではないでしょうか。
iPadOs15系 画面回転

### 概要
iPadOS15系で、画面を傾けても横画面が表示できず自動で縦画面となってしまう。
ランドスケープ機能の影響
iPadOS15でも従来の画面回転の挙動と同じにしたい。

### 対処方法
画面の回転処理を UIDeviceOrientation から UIInterfaceOrientation へ変更することで解決する。

|						|iOS6〜これまでの実装					|iPadOS15|
|:-----------------|------------------|------------------|
画面回転検知方法		|shouldAutorotate 					|viewWillTransitionToSize()
画面の回転処理			|UIDeviceOrientation				|UIInterfaceOrientation
端末の縦横状態		|UIDeviceOrientationIsLandscape	|UIInterfaceOrientationIsLandscape

※ viewWillTransitionToSize()とUIInterfaceOrientationの組み合わせは正確ではないので、UIInterfaceOrientationIsLandscapeの状態を反対に読む必要がある
※ iOS12では、ステータスバーが表示されてしまいステータスバーの高さ分が下へズレてしまう。表示を更新して非表示とする。(iOS15では表示されない。)
```
[self setNeedsStatusBarAppearanceUpdate];
```
画面回転処理で上記を実行することで、prefersStatusBarHddenで設定した値を反映することができる。
【Swift】HTMLからPDFを生成する

### 会計帳簿の帳票をHTMLでデザインしてPDFで出力する
* 帳票ページのコーディングしてHTML文字列を用意する
* PDFファイルをHTMLの文字列から生成
* 作成されたPDFデータを一時ファイルに保存


### HTML文字列からPDFファイルを作成
ここでは UIPrintPageRenderer , UIMarkupTextPrintFormatter, UIGraphics を使います
```
    /*
     この関数はHTML文字列を受け取り、PDFファイルを表す `NSData` オブジェクトを返します。
     */
    func getPDF(fromHTML: String) -> NSData {
        let renderer = UIPrintPageRenderer()
	    // まずレンダラーの設定を行い、希望の紙のサイズを指定します
        let paperFrame = CGRect(origin: .zero, size: paperSize)
        
        renderer.setValue(paperFrame, forKey: "paperRect")
        renderer.setValue(paperFrame, forKey: "printableRect")
        // HTML文字列をフォーマッターに入力します
        let formatter = UIMarkupTextPrintFormatter(markupText: fromHTML)
        renderer.addPrintFormatter(formatter, startingAtPageAt: 0)
        
        let pdfData = NSMutableData()
        // UIGraphics を使ってHTML文字列をPDFに変換します
        UIGraphicsBeginPDFContextToData(pdfData, paperFrame, [:])
        for pageI in 0..<renderer.numberOfPages {
            UIGraphicsBeginPDFPage()
            print(UIGraphicsGetPDFContextBounds())
            renderer.drawPage(at: pageI, in:paperFrame)
        }
        UIGraphicsEndPDFContext()
        return pdfData
    }
```
### 作成されたPDFデータを一時ファイルに保存
データをアプリの一時ストレージに保存する
```
    /*
     この関数は、特定の `data` をアプリのストレージに保存します。さらに、そのファイルが存在する場所のパスを返します。
     */
    func saveToTempDirectory(data: NSData) -> URL? {
        guard let documentDirectory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) else { return nil }
        let pDFsDirectory = documentDirectory.appendingPathComponent("PDFs", isDirectory: true)
        do {
            try FileManager.default.createDirectory(at: pDFsDirectory, withIntermediateDirectories: true, attributes: nil)
        }
        catch {
            print("失敗した")
        }
        let filePath = pDFsDirectory.appendingPathComponent("receipt-" + UUID().uuidString + ".pdf")
        do {
            try data.write(to: filePath)
            print(filePath)
            return filePath
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }
```
### 参考
iOSアプリのHTMLテンプレートに基づいてPDFを作成します（例えばレシート）
https://qiita.com/MaShunzhe/items/c64c510b7ed44157026a
AWSユーザのためのAzure入門②（権限関連）

# 内容
Azure環境で下記の様な権限設定を行います。
* ①AWSでいうIAMユーザ関連設定 ⇒ Azure Actve Directory関連設定
* ②AWSでいうIAMロール関連設定 ⇒ マネージドID関連設定

AWSの下記設定をAzureで行います。

![a2-azure-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/3cf1eb1b-7cfc-bbc1-3eec-5ab29dd6e88e.png)

* ①IAMユーザ関連設定
IAMグループを作成します。EC2読み取り専用のIAMポリシーをIAMグループに紐づけます。
AWSコンソールアクセス可能なIAMユーザを作成しIAMグループに所属させます。
IAMユーザはAWSコンソールからEC2に読み取りアクセスします。

* ②IAMロール関連設定
IAMロールにS3読み取りIAMポリシーを紐づけます。EC2にIAMロールを割り当てます。
IAMロールの情報がインスタンスプロファイルに渡されてS3にアクセス出来る様になります。

# 前提

* 細かい設定は全て割愛して基本的な設定のみ行います。
* ざっくりとした手順のみ記載します。
* 今回グループではなくユーザにAzureロールを割り当てます。
グループにAzureロールを割り当てるためには「Azure AD Premium P1 または P2 ライセンス」が必要となります。

https://docs.microsoft.com/ja-jp/azure/active-directory/roles/groups-assign-role

* 前回の記事（仮想マシン作成・監視・バックアップ設定など）は下記を参照下さい。

https://qiita.com/Toru_Kubota/items/6ff2101c3e72e2b43ff1

# Azure構成
下記の環境を作成します。

![a2-azure-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/a3769878-eb2f-955c-4e90-38c96c2c4a44.png)

* ①Azure Active Directory関連設定
AzureADにユーザを作成します。Azureではリソース管理が階層構造となっており、例えば上記「サブスクリプション」に権限を追加すると下位の「リソースグループ」、「リソース」に権限が継承されます。
今回は「リソースグループ」に「閲覧者権限のAzureロール」と作成した「AzureADユーザ」を紐づけます。
AzureADユーザから仮想マシンに読み取りアクセスが可能となります。
なお似たようなものにAzureADロールというものがありますが、下記の通りAzureロールとは別物になり今回は使用しません。

* Azureロール
仮想マシンの作成、削除などは「リソースを管理するもの」

* AzureADロール
AzureADユーザの作成、削除など「アクセス権を管理するもの」

* ②マネージドID関連設定
仮想マシンコンソール画面からシステムマネージドIDを払い出します。払い出したマネージドIDに「ストレージBlobデータ閲覧者用」のAzureロールを紐づけます。仮想マシンからBlobストレージにアクセス可能となります。

# Azure Active Directory関連手順

## AzureADにユーザ作成
* Azure Active Directoryに新規ユーザを作成します。（今回はグループ作成は省略します。）

![a2-azure-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/09c2169f-9601-65cc-015c-9a8f793bb601.png)

## Azureロールの割り当て
* リソースグループの管理画面から「アクセス制御（IAM）」を選択します。

![a2-azure-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/68e11803-e15c-80c7-e35e-89a822f828fc.png)

* 「ロールタブ」から「閲覧者」権限のロールを割り当てます。

![a2-azure-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/dc6a5e22-2f2f-8485-a980-ae6cdeb3008b.png)

* 「メンバータブ」から先ほど作成したユーザを割り当てます。

![a2-azure-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/94ec7e10-7bba-98e6-d738-38f738539dff.png)

## 権限割当確認
* 先ほど作成したユーザでログイン後、仮想マシンの情報を表示出来ることを確認します。また「閲覧者」ロールのため仮想マシンを停止出来ないことを確認します。
![a2-azure-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/ae3fbc9d-6366-18f2-3617-6ec0d554f4c2.png)

# マネージドID関連手順

## システムマネージドID払出
* 仮想マシンの管理画面から「ID」⇒「システム割り当て済み」を選択後、状態を「オン」にしてマネージドIDを払い出します。
![a2-azure-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/be5d4260-1f15-2781-d052-002815cc453f.png)

## Azureロールの割り当て
* 「Azureロールの割り当て」を選択し「ストレージBLOBデータ閲覧者」用のロールを割り当てます。
![a2-azure-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/a80242bc-d3bf-692a-e1f1-b871cb414608.png)
【Swift】オブザーバパターン イベント通知

## イベント通知
Swiftにおけるイベント通知のパターン
* デリゲートパターン
* クロージャ
* オブザーバーパターン


## オブザーバパターン
#### 実装方法
1. 通知を受けるオブジェクトにNotification型の値を引数に持つメソッドを実装する
2. NotificationCenterクラスに通知を受け取るオブジェクトを登録する
3. NotificationCenterクラスに通知を投稿する


#### ソースコード
```
    override func viewDidAppear(_ animated: Bool) {
        //ここでUIKeyboardWillShowという名前の通知のイベントをオブザーバー登録をしている
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
        //ここでUIKeyboardWillHideという名前の通知のイベントをオブザーバー登録をしている
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    // UIKeyboardWillShow通知を受けて、実行される関数
    @objc func keyboardWillShow(notification: NSNotification) {
    }
    // UIKeyboardWillShow通知を受けて、実行される関数
    @objc func keyboardWillHide(notification: NSNotification) {
    }
```
【Swift】キャプチャリスト

### キャプチャリスト

#### weakキーワード - メモリ解放を想定した弱参照
これをしていして変数や定数をキャプチャした場合、クロージャはOptional型の同名の変数を新たに定義し、キャプチャ対象となる変数や定数の値を代入します。キャプチャした変数や定数は、参照先に対して弱参照を持ちます。ということは、クロージャの実行時に参照先のインスタンスがすでに解放されている可能性があることを意味します。
その場合、キャプチャした変数や定数の値は自動的にnilとなる。そのため不正な変数や定数へのアクセスを心配する必要はない。
ローカルスコープ内で実行: オブジェクトは解放されていない
ローカルスコープ外で実行: オブジェクトは解放されている

#### unownedキーワード - メモリ解放を想定しない弱参照
weakキーワードと同様にクロージャは同名の新たな変数や定数を定義する。
弱参照を持つ
しかし、weakキーワードとは異なり、参照先のインスタンスがすでに解放されていた場合も、unownedキーワードを指定してキャプチャした変数や定数の値はnilになりません。参照先のインスタンスが解放されたあとにunownedキーワードが指定された変数にアクセスすると不正アクセスとなり、実行時エラーを招きます。

#### キャプチャリストの使い分け
常にweakキーワードを選択しておけば良いと思うかもしれません。しかし、実行中にnilになることがあり得ない箇所では、unownedキーワードを使用することで、nilになることはないという仕様を明確にできます。また、予期せぬ状態となった際には、実行エラーという形でバグを早期発見できます。
Processingでテクスチャ付きのOBJファイルを表示する

# はじめに
　Processingでは、外部ライブラリを使わず、OBJファイルを表示できる。OBJLoader.jarもいらないし、openGLも不要。
　Photogrametryした3Dデータを表示する手順をメモする。

# 準備
　objファイルとテクスチャファイルはpdeと同じか、dataフォルダにいれる。
トラブルの元なので、マテリアルファイルは捨て、obj内のmtllib関連の行もコメントアウト。

# コード
　要点はPShape.setTexture(PImage);
　ambientLightは255以上、認識しなかったので、2行書いたら、2倍の明るさになった。

```java:faceAngleRecognition.pde
PShape model;
PImage tex;

void setup() {
  size(512, 512, P3D);
  
  model = loadShape("face.obj");
  model.translate(0,300,0);
  model.scale(1);
  tex = loadImage("matFace.jpg");
  model.setTexture(tex);
}

void draw() {
  background(128);
  //lights();
  ambientLight(255, 255, 255);
  ambientLight(255, 255, 255);

  translate(width/2, height/2, 0);
  camera(0,0,300,
         0,0,0,
         0,1,0);
  rotateX(map(mouseY,0,width,0,2*PI));
  rotateY(map(mouseX,0,width,0,2*PI));
  rotateZ(0);
  shape(model);
}
```
【Swift】GCD

### 概要
アラート画面を表示する処理でエラーが発生していた。
対処方法を書く。

```
Modifications to the layout engine must not be performed from background thread after it has been accessed from the main thread
```
#### 問題のソースコード
```
URLSession.shared.dataTask() { [weak self] data, in
	// アラート画面を表示する処理
	self.showAlert() // この先でエラーが発生している
}
```
#### 修正後
```
URLSession.shared.dataTask() { [weak self] data, in
	DispatchQueue.main.async { // メインスレッドで処理を実行するように修正
		// アラート画面を表示する処理
		self.showAlert() 
	}
}
```
HTTP通信処理はバックグラウンドスレッドで行われ、
UI更新のDispatchQueue.main.async処理はメインスレッドでおこなわれる。


## GCD (Grand Central Dispatchの略)
非同期に処理を実行する技術
マルチタスク実行基盤API

#### 用法
スレッド管理をしなくても非同期処理を実行できる。直列処理と並列処理、非同期と同期といった組み合わせに対する専用APIも用意されており、複雑なタスク処理プロセスでも簡潔に記述できる。

#### Dispatch Queue
処理待ちタスクを追加するためのキュー。追加された順にタスクを処理側へ渡す役割を担う。

## タスクを渡す方式

##### 直列処理(SERIAL)
前タスク処理が終わるのを待って次タスクを渡す方式。常にひとつずつ順番通りに処理される。

##### 並列処理(CONCURRENT)
前タスクが終わっていなくても、CPUに余力があれば、次タスクを渡す方式。処理が分散されるので、個々のタスク完了の順番が入れ替わることがあるが、マルチコアCPUの性能を発揮して全体的に速く処理される。

- メインディスパッチキュー　直列処理タイプ。UI表示系タスクはここで行われないと動かない。
- グローバルディスパッチキュー　並列処理タイプ。
- プライベートディスパッチキュー
【Swift】構造体

### 構造体　値型のデータ構造

値型の一種であり、ストアドプロパティの組み合わせによってひとつの値を表します。
利用例は多岐にわたります。また、クラス、列挙型などと同様にメソッドを定義できるので、
振る舞いを実装することもできます。標準ライブラリで提供されている多くの型は構造体です。
構造体でないのは、列挙型であるOptional<Wrapped>型、型の組み合わせであるタプル型、プロトコルであるAny型です。

#### 定義方法
```
struct 構造体名 {
	定義
}
```
プロパティ、メソッド、イニシャライザなどの型を構成する要素は利用可能


#### ■　ストアドプロパティの変更による値の変更
構造体のストアドプロパティを変更することは、構造体を別の値に変更することであり、構造体が入っている変数や定数への再代入を必要とします。

##### 定数のストアドプロパティは変更できない
```
let constant = SomeStruct(id: 1)  // var 変数なら変更可能
constant.id = 2 // コンパイルエラー
```
##### メソッド内のストアドプロパティの変更にはmutatingキーワードが必要
構造体のストアドプロパティの変更は再代入を必要とするため、ストアドプロパティの変更を含むメソッドにはmutatingキーワードが必要です。付いていなければコンパイルエラー。
```
mutating func SomeMethod() {
	id = 4
}
```
#### ■　メンバーワイズイニシャライザー - デフォルトで用意されているイニシャライザ
型のインスタンスは初期化後に全てのプロパティが初期化されている必要がある
型が持っている各ストアドプロパティと同名の引数を取るイニシャライザです。

##### メンバーワイズイニシャライザのデフォルト引数
ストアドプロパティが初期化式とともに定義されている場合、そのプロパティに対応するメンバーワイズイニシャライザの引数はデフォルト引数を持ち、呼び出し時の引数の指定を省略できる。
【Swift】クラス

## クラス
参照型のデータ構造

## ■ 値の比較と参照の比較
参照先の値どうしの比較
==演算子


参照先自体の比較
===演算子

```
let a = SomeClass()
let b = SomeClass()
let c = a

// aとbは同じ値
a == b // true

// aとbの参照先は異なる
a === b // false

// aとcの参照先は同じ
a === c // true
```
【Swift】エラー処理

## エラー処理の使い分け

### Optional<Wrapped>型
エラーの詳細情報が不要で、結果の成否のみによってエラーを扱える場合

### Result<Success, Failure>型
非同期処理の場合

### do-catch文
同期処理の場合

### fatalError(_ :)関数
エラー発生時にプログラムの実行を終了したい場合

### アサーション
デバッグ時のみ、エラー発生時にプログラムの実行を終了したい場合

すべての方法に有効な方法はありません。エラーが発生したときにプログラムがどのように振る舞うべきか、ユーザーに対してどのうようにそれらのエラーを通知したいかを考慮し、目的に応じた方法を選択する必要がある。
【Swift】ジェネリクス

## ジェネリクス
ユーザーが定義した要件に応じて、指定したタイプで柔軟に動作する再利用可能な関数や型を指定できる機能

#### 汎用的な関数と型　
型をパラメータとして受け取ることで汎用的なプログラムを記述するための機能です。Swiftでは、ジェネリック関数とジェネリック型として提供されている。

### ジェネリクスの基本
#### ■ 定義方法
通常の定義に型引数を追加します。型引数は<>で囲み、複数ある場合は、区切りで<T,U>のように定義します。
```
func 関数名 <型引数>(引数名: 型引数) -> 戻り値型 {
	実行文
}
```

### ジェネリック関数
#### ■　定義方法
```
func 関数名 <型引数>(引数) -> 戻り値型 {
	実行文
}
```
型引数として受け取った型は、引数や戻り値型だけでなく、関数内の文でも使用できます。

#### ■　特殊化方法
ジェネリック関数の実行には、特殊化が必要となる。
引数から型推論によって型引数を決定する方法と、
戻り値から型推論によって型引数を決定する方法の二つが用意されています。

##### 引数から型推論によって特殊化
ジェネリック関数の引数のうち少なくともひとつの型が型引数となっている必要がある。型引数が複数の引数や戻り値で使用される場合、それらの実際の型は一致する必要がある。異なる型を与えた場合はコンパイルエラー。
```
func function<T>(_any: Any) -> T? {
	return any as? T
}
```
```
let a: String? = function(“abc”)
```
##### 戻り値から型推論による特殊化
ジェネリック関数の戻り値の方から型引数となっていて、かつ、戻り値の代入先の型が決まっている必要がある。
戻り値の代入先の型が決まっていない場合は、T型を決定する要因がないためコンパイルエラーとなる。

#### ■　型制約 - 型引数に対する制約
準拠すべきプロトコルやスーパークラスなど、型引数にはさまざまな制約を設けることができます。型制約を利用することで、ジェネリック関数やジェネリック型をより細かくコントロールできます。型制約がない型引数ではどのような型でも、受け取れるため、型の性質を利用した記述ができませんでした。型引数に必要十分な型制約を与えると、汎用性と型の性質を利用した具体的な処理とを両立できます。

##### スーパークラスや準拠するプロトコルに対する制約
```
func 関数名<型引数: プロトコル名やスーパークラス名>(引数) {
	実行文
}
```
##### 連想型のスーパークラスや準拠するプロトコルに対する制約
型引数にはwhere節を追加でき、where節では型引数の連想型についての型制約を定義できます。
```
func 関数名<型引数: プロトコル>(引数) -> 戻り値の型 where 連想型: プロトコルやスーパークラス {
	実行文
}
```
##### 型どうしの一致を要求する制約
型引数と連想型の一致や、連想型どうしの一致を要求する型制約を設けるためには、where節内で一致すべき型どうしを==演算子で結びます。
```
func 関数名<型引数1: プロトコル1, 型引数2: プロトコル2>(引数) -> 戻り値の型 where プロトコル1の連想型 == プロトコル2の連想型 {
	実行文
}
```

### ジェネリック型

型引数を持つクラス、構造体、列挙型のことです。
#### ■　定義方法
```
struct 構造体名<型引数> {
	構造体の定義
}
```
```
class クラス名<型引数> {
	クラス定義
}
```
```
enum 列挙型名<型引数> {
	列挙型の定義
}
```
#### ■　特殊化方法
ジェネリック型のインスタンス化やスタティックメソッドの実行には、特殊化が必要となる。

##### 型引数の指定による特殊化
```
let intContainer = Container<Int>(content: T)
```
##### 型推論による特殊化
```
let intContainer = Container(content: T)
```
#### ■　型制約
##### 型の定義で使用できる型制約
ジェネリック関数では、3種類の型制約を使用できました。ジェネリック型では、その3つのうち、型引数のスーパークラスや準拠するプロトコルに対する制約が使用できます。残り2つの型制約はジェネリック型の定義では使用できません。
```
struct 型名<型引数: プロトコル名やスーパークラス名> {
}
```
##### ジェネリック型の型制約付きエクステンション
型引数が特定の条件を満たす場合にのみ有効となるエクステンションを定義する。これを利用すると、型制約を満たす型が持つプロパティやメソッドを使った機能を汎用的に実装することができる。
```
extension ジェネリック型名 where 型制約 {
	制約を満たす場合に有効となるエクステンション
}
```
エクステンションではすべての種類の型制約が使用できます。

##### プロトコルへの条件付き準拠
```
extension ジェネリック型名: 条件付き準拠するプロトコル名 where 型制約 {
}
```
【Swift】FSCalendar


ライブラリ

https://github.com/WenchaoD/FSCalendar 

### カスタマイズ
```
	//ヘッダー
    fsCalendar.appearance.headerMinimumDissolvedAlpha = 0 //前月、翌月表示のアルファ量（0で非表示）
	// 水平方向（既定値）
    fsCalendar.scrollDirection = .horizontal
```
セルのデザイン
```
func calendar(_ calendar: FSCalendar, willDisplay cell: FSCalendarCell, for date: Date, at position: FSCalendarMonthPosition) {
    self.configure(cell: cell, for: date, at: position)
    // cellのデザインを変更
    // APIレスポンスの注文有効日とカレンダー上の日を比較して、同じであればセルを有効とする
}
```
前月、次月ボタン
```
    // value  前月: -1, 次月: 1 
    let date = currentCalendar.date(byAdding: .month, value: value, to:calendar.currentPage)!
    calendar.setCurrentPage(date, animated: true)
```
 今日ボタン
```
    // コードから日付を選択する
    fsCalendar.select(fsCalendar.today)
```
【Swift】UIをニューモーフィズムにする

# 概要

アプリのデザインをニューモーフィズム(Neumorphism)にする方法をまとめる。

#### ライブラリを使用する
https://github.com/hirokimu/EMTNeumorphicView


#### 実装方法
```
import EMTNeumorphicView
```
例　DatePickerの裏に配置したViewに修飾を加える場合
```
    let LIGHTSHADOWOPACITY: Float = 0.3 // 明るい影
    let DARKSHADOWOPACITY: Float = 0.5  // 暗い影
    let ELEMENTDEPTH: CGFloat = 6       // 影の深さ
    let edged = false                   // 縁取りをつけるかどうか

    @IBOutlet var datePickerView: EMTNeumorphicView!
    
    // UIパーツのデザインを指定する
    private func createButtons() {

        if let datePickerView = datePickerView {
            datePickerView.neumorphicLayer?.cornerRadius = 15
            datePickerView.neumorphicLayer?.lightShadowOpacity = LIGHTSHADOWOPACITY
            datePickerView.neumorphicLayer?.darkShadowOpacity = DARKSHADOWOPACITY
            datePickerView.neumorphicLayer?.edged = edged
            datePickerView.neumorphicLayer?.elementDepth = ELEMENTDEPTH
            datePickerView.neumorphicLayer?.elementBackgroundColor = UIColor.Background.cgColor
        }
```

#### 完成形

![IMG_7657.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413207/5044927d-ffd7-e8f9-7605-81a4d949f958.png)