OmniAICreator/Qiita-1.07M huggingface dataset:
CSSのみで、かわいいドロップダウンメニュー作ってみた。

CSSのみで、かわいいドロップダウンメニュー作ってみました。
JavaScript使わず、息抜きにやろうとしましたが、苦戦しました。

<a href="https://neptune.sakura.ne.jp/qiita/dropdown_menu001/">DEMOページ</a>

```html:index.html
<!DOCTYPE html>
<html lang="ja">

<head>
	<meta charset="utf-8" />
	<title>CSSのみで、かわいいドロップダウンメニュー作ってみた。</title>
	<link rel="stylesheet" href="style.css" type="text/css" />
</head>

<body>
	<div id="wrapper">
		<div id="nav">
			<ul>
				<li class="color-blue">
					<a href="#">ドリンク</a>
					<ul class="subs">
						<li><a href="test.html">コーヒー</a></li>
						<li><a href="test.html">ココア</a></li>
						<li><a href="test.html">紅茶</a></li>
					</ul>
				</li>
				<li class="color-red">
					<a href="#">スイーツ</a>
					<ul class="subs">
						<li><a href="test.html">チーズケーキ</a></li>
						<li><a href="test.html">ロールケーキ</a></li>
						<li><a href="test.html">スフレ</a></li>
					</ul>
				</li>
				<li class="color-yellow">
					<a href="#">和菓子</a>
					<ul class="subs">
						<li><a href="test.html">もち菓子</a></li>
						<li><a href="test.html">団子</a></li>
						<li><a href="test.html">八ツ橋</a></li>
					</ul>
				</li>
				<li class="color-green">
					<a href="#">スナック</a>
					<ul class="subs">
						<li><a href="test.html">キャラメル</a></li>
						<li><a href="test.html">ウェハース</a></li>
						<li><a href="test.html">クラッカー</a></li>
					</ul>
				</li>
			</ul>
		</div>
	</div>
</body>

</html>
```

```css:style.css
@charset "utf-8";

/* --- base --- */
body {
	background-color: #ECECEC;
	font-family: "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, Osaka, "ＭＳ Ｐゴシック", "MS PGothic", sans-serif;
	font-size: 12px;
	color: #465866;
}

body, div, ul, li {
	margin:0;
	padding:0;
}

img {
	border:0;
}

a {
	text-decoration: none;
	color: #465866;
}

/* --- wrapper --- */
#wrapper {
	width: 728px;
	margin: 50px auto;
}

/* --- nav --- */
#nav {
	width: 728px;
	background-color: #FFFFFF;
}

#nav li {
	list-style: none;
}

#nav > ul > li {
	position: relative;
	float: left;
	width: 180px;
	margin: 0 1px;
}

#nav > ul > li > a {
	display: block;
	height:55px;
	background-color: #FFFFFF;
	font-family: Helvetica, Verdana, Arial, sans-serif;
	font-size: 18px;
	line-height: 55px;
	text-align: center;
}

/* --- 子メニュー --- */
ul.subs {
	position: absolute;
	top: 100%;
	width: 180px;
	background-color: #FFFFFF;
	transition: all 0.5s ease;
	opacity: 0;
	visibility: hidden;
}

ul li:hover > ul {
	opacity: 1;
	visibility: visible;
}

ul.subs li a {
	display: block;
	height:40px;
	font-size: 12px;
	line-height: 40px;
	text-indent: 22px;
	transition-duration: 0.2s;
}

/* --- 色の指定 --- */
li.color-blue {
	border-top: 5px solid #ffb6b9;
}

li.color-red {
	border-top: 5px solid #fae3d9;
}

li.color-yellow {
	border-top: 5px solid #bbded6;
}

li.color-green {
	border-top: 5px solid #8ac6d1;
}

/* --- 子メニュー --- */
li.color-blue ul.subs li a:hover {
	background-color: #ffb6b9;
	color:#FFF;
}

li.color-red ul.subs li a:hover {
	background-color: #fae3d9;
	color:#FFF;
}

li.color-yellow ul.subs li a:hover {
	background-color: #bbded6;
	color:#FFF;
}

li.color-green ul.subs li a:hover {
	background-color: #8ac6d1;
	color:#FFF;
}
```
設計などついて学ぶ時に見てよかった動画

良書を読んで学習するのが一番なのかもしれませんが、YouTubeにもかなり良質な動画があるので、特によかったと感じたものをいくつかまとめます。

## 設計力を上げるバリエーションの見極め術
https://youtu.be/y0H05gl9dvg

コードの中に出現するバリエーション(変更されやすい部分)について、どう向き合うべきかが解説されています。

#### 重要なこと
- バリエーションとなりえる箇所がどこかを想像する
- バリエーションっぽいものが現れた時に、安易に条件分岐を書かずに一旦立ち止まって今後の変化パターンを想像する
- バリエーションとは、言い換えると処理が分岐するきっかけ。if...elseif...elseif...みたいに書いてしまいそうなら、その部分はバリエーションとして捉えるべきかも
- そこで一旦立ち止まって今後どういうバリエーションが増えそうかを考えることが大切
- ただし、その想像には業務知識が伴っていなければならない。業務知識が伴わない想像は妄想
- なぜならバリエーションが発生するきっかけは、ビジネスの変化であることが多いから(消費税とか元号とかそういうものももちろんあるが...)

## 開発現場で役立たせるための設計原則とパターン
https://youtu.be/qUKpgGFGHVo

設計について、単一責任の原則・オープン/クローズドの原則・凝集度と結合度 を用いて、今ある問題に対してどうコードを設計していくかが具体例を交えて解説されています。


#### 重要なこと
- 設計とは一塊りになった問題を分割して構造化すること。ただし闇雲に分割するのはよくない
- いろいろな設計方法やパターンがある中で、問題に対して最適な選択肢を選んで分割し構造化するといい
- 設計する際は、構造化する->設計原則にあてはめてレビューする...を繰り返す。一回構造をつくってそれで終わり、ではない
- 設計原則を知ることの何がいいのか -> コードの構造の良し悪しを根拠を持って判断する/言語化する助けになる
- 設計原則は大切だが、どこが変わりやすく、どこが変わりにくいのかを知らないと使えない。問題を捉え損ねたまま設計を考えるべきではない
- 問題に向き合い、それに対して適切な構造を与えることが大切
- 変わりやすい部分がわからない時は、現在わかっている範囲のみで極力シンプルにしておくべき

## SOLIDの原則ってどんなふうに使うの？オープン・クローズドの原則編
https://youtu.be/cUV1nXPfjFY

SOLIDのOに焦点を当てています。既存コードからバリエーションを判定する方法や、抽出したバリエーションの軸に沿ってリファクタリングする流れなどが、先輩後輩の対話形式で解説されています。

#### 重要なこと
- バリエーションには既知のバリエーション(考慮済み)、隠れたバリエーション(考慮されているが扱いが不完全)、未知のバリエーション(全く考慮されていない)などが存在する
- どのバリエーションが一番コードに対して影響を与えるかを考え、一番影響があるものを軸にするといい
- バリエーションの軸に沿ってコードをまとめ、拡張可能かつ修正不要の状態に持っていければ、OCPに準拠しているといえる

## Becoming a better developer by using the SOLID design principles
https://youtu.be/rtmFCcjEgEw

SOLID原則の各項目について、サンプルコードを使って網羅的に解説されています。
SOLIDについて調べ始めるにあたって、まずこの動画を見るのが一番わかりやすいんじゃないかと思いました
各項目の解説は動画に任せるとして、それ以外にもっと重要なことが話されていました↓

#### 重要なこと
- SOLIDは各原則がつながっているので、どれが欠けてもよくない
- ただし、あくまでSOLID "原則" であってルールではない
- SOLIDに準拠させようとした結果、コードが散らばってメンテや拡張がしにくいなら、それは何かが間違っているかもしれないので一度立ち止まったほうがいい。何を達成(解決)したいのかを考えるべき
- 道具であって、準拠させることがゴールではない

## 全体を通して言われていること

設計よりも先にまず問題(解決/達成したいこと = ゴール)についての理解を深めることが大切で、その問題に対するアプローチ方法を考える段階になって初めて設計方法が活用できる、ということがどの動画でも語られていました。
逆に、問題を正しく捉えないまま設計しようとすると、おかしなことになるということも解説されています。

## 思うこと
解決したい問題について正しい知識を得るには、コードを見ているだけでは足りないということを認識しました。
自分が今携わっているプロダクトはどういうふうに会社のビジネスに貢献しているのか、今実装している仕様はプロダクトが抱えるどんな問題を解決するのがゴールなのか...などビジネスサイドへの関心を持ち、ゴールは何なのかをしっかり対話することが重要なのだろうと思います。
Flutter TDD Clean Architecture Course その9 - Remote Data Source

- [こちらのチュートリアル](https://resocoder.com/2019/10/03/flutter-tdd-clean-architecture-course-9-remote-data-source/)の解説をします。
- チュートリアルを読むのが早いと思いますが、[概要をまとめた](https://qiita.com/maria_mari/items/8fdd92af13a36c663360)のでこちらもご参照ください。

---

# HTTP ClientのMock化
- httpパッケージを利用する

# getConcreteNumberTrivia
## APIのresponse
- 通常はplain textのResponseを受ける
- `application/json`ヘッダーを送りJSONのResponseを受ける方法は2通りある
    - [http://numbersapi.com/42?json]( http://numbersapi.com/42?json)のURLにアクセスする
    - `Content-Type: application/json` を送る

## 正常系TDD
- [チュートリアル](https://resocoder.com/2019/10/03/flutter-tdd-clean-architecture-course-9-remote-data-source/)参照

## 異常系
```test.dart
test(
  'should throw a ServerException when the response code is 404 or other',
  () async {
    // arrange
    when(mockHttpClient.get(any, headers: anyNamed('headers'))).thenAnswer(
      (_) async => http.Response('Something went wrong', 404),
    );
    // act
    final call = dataSource.getConcreteNumberTrivia;
    // assert
    expect(() => call(tNumber), throwsA(TypeMatcher<ServerException>()));
  },
);
```

```implementation.dart
@override
Future<NumberTriviaModel> getConcreteNumberTrivia(int number) async {
  final response = await client.get(
    'http://numbersapi.com/$number',
    headers: {'Content-Type': 'application/json'},
  );

  if (response.statusCode == 200) {
    return NumberTriviaModel.fromJson(json.decode(response.body));
  } else {
    throw ServerException();
  }
}
```

# getRandomNumberTrivia
- [チュートリアル](https://resocoder.com/2019/10/03/flutter-tdd-clean-architecture-course-9-remote-data-source/)参照

# 学んだこと
- 前回と同じでだが、外部との境界にあるDataSourceでExceptionを投げる
    - コントロール下にあるアプリの内側では、`Either<Failure, NumberTrivia>`が戻り値になる
TMS WebCOREを使っています

最近、Delphi10.4で、TMS WebCOREを使いはじめています、(ここからは、個人的な主観です)
####結論からいいますと、JavaScriptを今までの、Delphi IDEの使用方法で、作成できるので、個人的には、非常によい製品だと思っています。

***
すでに、ご存じの方も多いのかもしれませんが、<私は、今年はじめて、知りました..>TMS WebCOREは、エンバカさんで、今回、案内されている
https://blogs.embarcadero.com/ja/web-component-pack-campaign-ja/
Web Component PackソリューションでDelphiによるWeb開発を実現で、３つのソリューションの中から、選択できる、1製品です。

TMS Web Core  : https://www.tmssoftware.com/site/tmswebcore.asp
uniGUI        : http://www.unigui.com/
IntraWeb      : https://www.atozed.com/intraweb/

***
こちらで、使用するにあたって、今まで、２層クラサバの開発のみでしたので、３層Web開発を手に付けるにあたって、かなり頭の切り替えが必要でしたので(まぁ年齢のこともあるのだと思いますが..)

頭の切り替えが、必要だったこと、こちらで、途惑ったことなどをピックアップします。

  1.データベースデータのやりとりは、REST APIとなる。(クライアントでは従来のDBコンポーネントは使用しない、これが、よく理解できず、いままで、JSONの取り扱いなどは、避けて通っていたのが、悔やまれます、今年から使用しはじめたのですが、今ではデータの確認に、REST Debugger が、必須ツールとなりました、)
![restデバッガー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/a937e61e-12fc-8894-44d3-9b1630098009.png)


　こちらでは、WebCOREコンポーネントの、WebTabControlとWebHttpRequestを使用する用途が、多いように思っています。(データアクセスの結果に、Responseがあるのも、２層とは異なる感じでした)

  2.フォーム間での、データのやりとり(これは、手順が少々異なるようでしたが)
　サンプルコードのが参考になりました。
https://download.tmssoftware.com/tmsweb/demos/tmsweb_multiform/
https://download.tmssoftware.com/tmsweb/demos/tmsweb_formhosting/

  3.一時保存の方法(INIファイルが、つかえない)
　JavaScriptでは、LocalStrage、insdexdDBなどの手法があるようですが、少量なものなら、WebMemoゃWebStringGridでも、代用できる気がします。

  4.デバックが、ブラウザ上になる？(他の方法もあるのかもしれないですが、F12などを押して、IDEではなく、ブラウザで確認します)

  5.サーバー側のデータアクセス用APIは、TMS XData の作成する方法がありますが、Python(FastAPI) /Node.jsなどので作成する方法もあります。

6.いままで、見たことがないエラー(これは、一つずつ調べていくしかありません)
![パスワードを変更して1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/994413b7-7a41-bd6f-7135-b21687485c10.png)

***
https://www.tmssoftware.com/site/tmswebcoreintro.aspの下のほうに、他のサンプル画面も多数あります。

トライアル版をインストールすると、サンプル画面のコードがすべて、ダウンロードされますので、動作を確認しながらコード見ることで、理解しやすいと思います。
参考となるかは、わかりませんが、こちらて行った、トライアル版のインストール手順を書いています。
ご興味のある方は、ご覧ください。
http://a23.sblo.jp/article/187787348.html

***
画面構築などに関しては、従来通りな雰囲気で(たぶん、Intraweb と同じ感じ)なので、簡単です、コンポーネント名にWebつきますので、こんな感じです
Edit→WebEdit
Memo→WebMemo
Stringgrid→WebStringgrid
Form Unitなどの概念も、ほぼ従来通り(のように思います)
など、(Webプラウザー特有なことは多少は異なりますが)、従来のコンポーネントを使用する感じで、コードを記述していけます。
画面の細かい操作は、従来のｺｰﾄﾞ資産をお持ち方が、かなり有利となる気がします。
***

Windowsフォームの画面![webpc0731-0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/40e4739a-5b2a-12fb-b284-fc2bf3bbd8e8.png)
これを、こんなふうに、実現できそうです
![webpc0731-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/b60125a3-bd3b-b3e1-a011-ec09d66202f6.png)
実行すると、ブラウザで![webpc0731-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/852e38e4-24af-a871-6eeb-fa8a87fb7486.png)
となります。


コロナのご時世***発、Delphi言語+Web開発言語などで、開発されている方も多数おられると思いますので、是非、いろいろな情報をお聞きしたいものです。
***
#2021年は、国内で、WebCOREの入門者としては、DelphiとWebCOREのユーザーと情報が増えていくことを、すごく期待しております。
WEBアプリとネイティブアプリの違い

この記事はGlobal Mobility Serviceの社員による、[Global Mobility Service Advent Calendar 2020](https://qiita.com/advent-calendar/2020/global-mobility-service) 21日目の記事です。

#はじめに
未経験のAndroid向けアプリ開発を携わる事になった中で、Android専用のネイティブアプリが良いのか
WEBアプリでも良いのか気になった為、双方のメリット・デメリットを調査しました。

#なぜAndroid？
弊社はフィリピン・カンボジア・インドネシアの各国で、貧困層を救うといったビジネスを展開していますが
今回、韓国現地法人向けと言う事で使用割合を調べてみました。
![スクリーンショット 2020-12-20 11.19.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418460/ffc76d68-b225-075c-cfd8-4a64f1cc9d67.png)
2020年現在、韓国では8割弱がAndroidを使用しております。
またフィリピン・カンボジア・インドネシアでもAndroidが多くを占めています。
と言う事で今回はAndroid向けに開発を進めていきます。

ちなみに日本はというと、、、
![スクリーンショット 2020-12-20 11.20.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418460/4c7c5c22-225d-cd31-a08c-1202e1f1aa89.png)
iOSが6割以上を占めてますね〜


#アプリとは
アプリとはapplication software（アプリケーションソフトウェア）の略で、目的にあった作業をする応用ソフトウェア。

### ■WEBアプリ
楽天やAmazonなどの商品の購入やコメント・データの加工ができるインタラクティブなもので、
データのやり取りをするような仕組み。
参考：https://prog-8.com/docs/web-application

### ■ネイティブアプリ
LINEやゲーム、Excelなど直接端末へインストールして使えるソフトウェアで、
それぞれのOSに合わせて作られた仕組み。
参考：https://yapp.li/magazine/2897/

### ■ハイブリッドアプリ
WEBアプリとネイティブアプリの良いとこ取りしたアプリ。
”側”は「ネイティブアプリ」”中身”は「ウェブ」という代物で、クックパッドに使用されているらしい。
参考：https://yapp.li/magazine/3190/



#メリット・デメリット
|   |  WEBアプリ  |  ネイティブアプリ  |  ハイブリッドアプリ  |
| ---- | ---- | ---- | ---- |
|  動作速度  | ×　操作が遅く感じる  |  ◯　直感的なUI  | △　ネイティブアプリより遅く感じる |
|  デバイス機能  |  ×　デバイス固有の昨日は使えない  |  ◯　デバイス固有の機能が使える  | △　デバイス固有の機能が比較的使える |
|  インターネット環境  |  ×　必須 |  ◯　オフラインでも使用できる  | ◯　オフラインでも使用できる　 |
|  コスト  |  ◯　安い  |  ×　高い<br>OSに合わせて開発が必要  | ◯　比較的安価<br>クロスプラットフォームに対応しやすい　 |
|  保守  |  ◯　高い<br>OSに影響されない  |  ×　低い<br>OSに影響される  | △　高め<br>OSによる影響は受けづらい　 |
|  安全証明  |  △　SSL  |  ◯　公式ストアで配信可  |  ◯　公式ストアで配信可  |
|  検閲・審査  |  ◯　無い  |  ×　必要 <br>（iOS + アプリマーケットで配布時）  |  ×　必要 <br>（iOS + アプリマーケットで配布時）  |
|  導線  |  ×　ブラズザアクセス  |  ◯　アイコン型式  | ◯　アイコン型式 |

#まとめ
違いを調べてみて初めてハイブリッドアプリの存在を知りました。

今回の要件としては、
1) 社内ツール
2) スマホ・タブレット・PCで使用
3) ネットが繋がらない環境でも使用できる

と言う事でハイブリッドアプリにしていきますが、それぞれ一長一短があり状況や開発内容によってきちんと選定することが重要ですね。
Gmailで返信を除外してSlackにメール（スニペット形式）を通知する

# はじめに
ニジボックスという会社で新規事業支援などいつもお手伝いさせて貰っています。
最近、業務自動化にすごく興味があり、色々と勉強しながら身の回りを自動化しています。

今日はそんな中で起きた課題と対策を紹介させてくださいっ！

## 課題について
定型文の連絡が来た内容を通知したかったのですが、
課題が2つ起きました。

1. 文章が長いのでスニペット形式で通知したい
2. Gmailの返信を除外する条件が分からない

それぞれ解決方法が分かったので記載させてもらいます。

## **1. 文章が長いのでスニペット形式で通知したい**
スニペット形式で送るにはWebhook使ってファイルで送る必要があるなど分かったものの、
もっと簡単に出来る方法がないか調べました。

結果、Slackが提供してくれているメール送信機能を使うことで解決しました。

**参考ページ**
https://slack.com/intl/ja-jp/help/articles/206819278-Slack-%E3%81%AB%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B

以下のチャンネルにメールを送信するから設定出来ます。
![スクリーンショット 2020-12-21 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908755/4102cec8-7e7a-4bf1-baf4-afecc30887c2.png)

## **2. Gmailの返信を除外する条件が分からない**
Microsoft Outlookの方などとやり取りをすると、
「Re:◯◯◯◯◯◯」と、返信のやり取りになっていることが分かりますが、
Gmailではスレッド形式が**デフォルトで設定**されているため、分かりません。

以下のように、Gmailで「Re:」を含めないように検索すると除外されているはずです。

```
-Re:
```
![スクリーンショット 2020-12-21 1 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908755/77dffecc-e289-75dd-307b-94f55f0882d4.png)

スレッド形式を設定しない方法は以下で可能です。

**設定→全般→スレッド表示→オフ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908755/5e7e05f6-7169-8520-e06b-315e6038af9f.png)

スレッド表示をONのままだと、上記検索を行ってもスレッド内の内容もGmail上では出ますが、
オフにして確認すると含まれていない事が確認出来ます。
Amazon EC2 トラブルシューティング

## Permission denied (publickey).

ひたすらこのエラーが出て、IPアドレスを変えたり、PEMファイルの権限を変えたりしたが、結局はユーザー名がubuntuではなく、ec2-userとなっていただけだった

```
ssh -l ubuntu [IP Address] -i [PEM File Path]
```

サイトにはよくec2-userと書いているので注意
Photon×WebGL（6）日本語チャットの実装（英語チャット実装からのInputField改造）

やりたいこと

・日本語でのチャット機能の実装

--
<dl>
<dt>これも簡単そうなんだけど、、、</dt>
<dd>・WebGLは日本語入力を基本受け付けないので</dd>
<dd>・色々と試行錯誤</dd>
</dl>

--

##実装手順
<dl>

<dt>1）英語チャットテスト</dt>
<dd><strong>コピペしてみる</strong></dd>
<dd>　・戸惑い覚えるくらい簡単に出来てしまう</dd>
<dd>　　・Create Emptyでオブジェクト作成</dd>
<dd>　　・当該ブログよりスクリプトをお借り　<strong>※1</strong></dd>
<dd>　　　=>普通にチャット出来る。でも外人仕様、、、ローマ字でやりとりならできる。</dd>
</dl>

![キャプチャ01.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232643/88abb958-4dea-25ef-ea35-1947f6f176e3.jpeg)

<dl>
<br>
<dt>2）日本語チャットにする試行錯誤</dt>
<dd><strong>・フォント設定の変更を試す　※2</dd>
<dd>　これで全てが解決するはずだったNoto Sans CJK JP</dd>
<dd>　そうなんですよ、、、どこを日本語化するべきなのかって話なんですけど</dd>
<dd>　<strong>Noto Sans CJK JPは後で、効いてくるので必要なんだけど</dd>
<br>
<dd>　現時点では、GUIはよく分からないし、</dd>
<dd>　インスペクター画面にInRoomChatの設定はあるけどフォント設定出来ないし</dd>
<dd>　プログラムで生成されているので、設定する箇所がない（分からない）と、、、</dd>
</dl>
![03.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232643/b3c2d753-f5d9-1f8b-8241-83a79f000ef9.jpeg)


<dl>

<dd>　=>日本語化の目途立たず。</dd>
<br>
<dd>　下記2案が提示される、、、</dd>
<dd>　・GUIが対応するか調べる</dd>
<dd>　・InputField改造するか</dd>
<br>
<dd>　=>GUIよく分からないしInputFieldで！（適当）</dd>
<br>
<dd><strong>・通信箇所をInputFieldに変更</strong></dd>
<dd>　・InputFieldの使い方学ぶ<strong>　※3</strong></dd>
<dd>　　・ただ学ぶだけ</dd>
<dd>　　　--テキストの入力フォームという認識で問題ありませんと</dd>
<br>
<dd>　 <strike>・InputField改良（Unityネイティブプラグイン）<strong>※4</strong></strike></dd>
<dd>　　<strike>・予想以上の使いづらさ</strike></dd>
<br>
<dd>　・神サイト攻略（WebGLのIME入力プラグイン）<strong>※5</strong></dd>
<dd>　 　InputFieldにAdd ComponentでWebGLInputをつけるだけ、、↓こんな感じになる。
</dd>
</dl>
![04.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232643/81adc112-78a7-d89a-410c-de09ba0b2d30.jpeg)

<dl>
<br>
<dd><strong>・スクリプトの改変</strong></dd>
<br>
<dd>　<strike>・オリジナルスクリプトの調査</strike></dd>
<dd>　　<strike>・登場人物を調べる</strike></dd>
<br>
<dd>　・チャットスクリプトをInputField入力に対応させねば、、、</dd>
<dd>　　・どういう内容に変更する？</dd>
<dd>　　　・大雑把に</dd>
<dd>　　　　・InputField入力=>Sendボタン押下、、、public void OnSend関数の作成</dd>
<dd>　　　　・チャットスペースに表示させる、、、public void Chat関数の作成</dd>
</dl>


まとめにくくなったので、次回スクリプト更新＆バグをやっつける。


##参考サイト
[※1_オンラインゲーム制作 Photon Pun2 チャット導入辺](https://junyablog.site/post-2996/)
[※2_WebGLで日本語を表示する](https://qiita.com/tsubaki_t1/items/93e4b91b830729cd93a4)
[※3_入力したテキストを取得して文字を消す方法](https://squmarigames.com/2018/11/05/unity-programing-inputfield-text-delete/)
[※4_WebGLで日本語入力を行う](http://tsubakit1.hateblo.jp/entry/2016/06/02/233000)
[※5_WebGLのIME入力](https://kou-yeung.hatenablog.com/entry/2019/04/02/123542)
BooleanNotifierをToReactiveCommandしたときの挙動、が思っていたのと違う理由

# 概要
この記事は以下の記事へのアンサーというか、私なりの推測をしたものです。

[【WPF】BooleanNotifierをToReactiveCommandしたときの挙動について【ReactiveProperty7.5.1】](https://qiita.com/t13801206/items/c6093059aa7fd81ee3e5)

# BooleanNotifierの挙動が思っていたのと違う？

同じ初期値`false`を持つBooleanNotifierとReactivePropertyからReactiveCommandを生成すると`CanExcute`の値が異なります。

```csharp
var booleanNotifier= new BooleanNotifier(initialValue: false);
var reactiveProperty = new ReactiveProperty<bool>(initialValue: false);

BooleanNotifierButtonCommand = booleanNotifier.ToReactiveCommand();
ReactivePropertyButtonCommand = reactiveProperty.ToReactiveCommand();
//BooleanNotifierButtonCommand.CanExcute == true;
//ReactivePropertyButtonCommand.CanExcute == false;
```

# コード的原因

コード的には元記事でも述べられているように、以下のところがまさに原因です。

> （BooleanNotifierにはなく、ReactivePropertyでのみ）Subscribeの中でOnNext()が記述されている

# でもなんで？（本題）

ここからが記事の本題ですが、では何故BooleanNotifierはそうしないのか？という疑問があるかもしれません。

それは実は**SubscribeされたらOnNext**をするReactivePropertyのほうが、Rx的にもしくはObserverパターンとしては異質なことをしているから、です。

[Rx入門 (2) - オブザーバーパターン](https://blog.xin9le.net/entry/2011/12/10/153032)

Observerパターンの説明では通常、Observerが購読(`Subscribe`)した直後に値が流れて来ることはなく、Observableが通知(`OnNext`)して初めて値がObserverに来ます。

しかし、ReactivePropertyでは異なる動きをします。これはMVVMパターンの中で使われる上でそのほうが便利だからです。それは前述の`ToReactiveCommand()`でもそうですし、あるReactivePropertyから別のReadOnlyReactivePropertyに変換する場合もそうです。この動きはReactivePropertyの`Mode`で`RaiseLatestValueOnSubscribe`を無効にすれば無くすこともできます。

ただ、この判断には躊躇いもあったようで、途中で破壊的変更をして導入されています。

http://neue.cc/2011/11/20_354.html

> ReactivePropertyのデフォルトモードが DistinctUntilChanged|RaiseLatestValueOnSubscribe になりました。今まではRaise…が入ってなかったのですが、思うところあって変わりました。例えばCombineLatestは、全てが一度は発火していないと動き出しません。ReactiveCommandの条件に使うなどの場合にRaiseしてくれないと不都合極まりなく、かつ、Subscribeと同時にRaiseすることによる不都合なシーンは逆に少ない。ことを考えると、必然的にデフォルトをどちらに振るべきかは、分かりきった話でした。

というわけで、BooleanNotifierがReactivePropertyと違う挙動をするのは、ReactivePropertyがMVVMパターンを意識して本来のObserverパターンとは違う挙動をするようなクラスだから、です。

じゃあ、BooleanNotifierはどう使うか、というと本来のObserverパターンらしく何かの変更通知です。ロギングやバックアップ処理など、Viewに現在の状態を常に示す、という以外の用途ですね。

# 余談

実は同じNotifier系でもBusyNotifierは**SubscribeされたらOnNext**します。これは`ToReactiveCommand()`などで使われることが想定されたクラスだからです。
https://blog.okazuki.jp/entry/2016/04/09/005825
Python解説を覚え書き 5 - Lists

`# A list stores values inside of the array.
friends = ["Kevin", "Karen", "Jim"]`

`# How can we access individual elements
print(friends)`

`# Refer to elements by their index.
print(friends[0])
print(friends[-1])
print(friends[1:])`

`friends = ["Kevin", "Karen", "Jim", "Oscar", "Toby"]
print(friends[1:4])  # not including 4`

`friends[1] = "Mike"  # Modify a value inside the array.
print(friends[1])`
Lambdaから指定したS3に入出力するGlueを起動させる話

##背景
仕事の中でAWSのGlueを使う機会があり、その際に指定したS3からデータを読み込み、Glueでデータを加工して別の指定したS3バケットにデータを出力することを行ったので、その流れと方法をメモがてら残しておこうと思います。

##構築内容
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751681/3c2ceb64-10da-2da6-ccee-6f2531e32d49.png" width=70%>

##S3(Input)->Glue->S3(Output)
###引数(パラメータ)を取得

```python:
# パラメータを取得
args = getResolvedOptions(sys.argv, [
                          'JOB_NAME', 'source_path', 'out_path'])
# 各パラメータを変数におく
source_path = args['source_path']
out_path = args['out_path']
```
今回はLambdaから2つの引数の'source_path', 'out_path'を受け取る.

###S3からデータを受け取り
```python:
# 指定したS3のバケット配下のファイルをすべて読み込む
DataSource0 = glueContext.create_dynamic_frame_from_options(
    connection_type = "s3",
    connection_options = {'paths': source_path, 'recurse': True},
    format="json")
```
引数で受け取ったsource_pathを入れ、指定したバケットのパスの配下にあるファイルを全て読み込む

###別のS3バケットに出力する
```python
# 指定したS3のバケットにファイルを出力する
df.write.options(header=True, codec="gzip")\
    .mode('overwrite').csv(out_path)
```
指定したバケットのパスへcsvの形式でgzipに圧縮してから出力する

##Lambdaで引数をつけてGlueを起動する
```python:
from logging import getLogger, INFO
from datetime import datetime, timedelta, timezone
from app.libs.sns.sns_client import SnsClient
import boto3
import os
import json


logger = getLogger(__name__)
logger.setLevel(INFO)

# 起動するglueのジョブ名
# JOB_NAMEは環境変数
JOB_NAME = os.environ['JOB_NAME']
# エラー通知のSNSトピック
ERROR_PUBLISH_SNS_ARN = os.environ['ERROR_PUBLISH_SNS_ARN']


class TriggerJob:
    def __init__(self):
        self.sns = SnsClient()

    def handler(self, event):
        start_arg = {}
        try:
           
            # Glueのジョブを実行する
            start_arg = {
                '--out_path': "<指定のアウトプットするs3のパス>"
                '--source_path': "<指定のインプットするs3のパス>"
            }

            glue = boto3.client('glue')
            # glueJob起動
            response = glue.start_job_run(
                JobName=JOB_NAME,
                AllocatedCapacity=2,
                Arguments=start_arg)
            logger.info("response:{}".format(response))
            return response
        except Exception as err:
            logger.error("Glueジョブの起動でエラーが発生しました。err: {}".format(err))
```


##最後に
今回はlambdaでGlueを指定のS3から入力と出力をするコードを載せました。
実際は他の処理とかもあり、関係ない部分は削除しておりますが、不要なものがまだあるかもしれないですがご了承ください。
ご参考になれば幸いです。
Python解説を覚え書き 4 - Input

# Getting input
`name = input("Enter your name: ")
age = input("Enter your age: ")
print("Hello " + name + "! You are " + age)`

# Calc
`# Python is just going to convert it into a string by default.
num1 = input("Enter a number: ")
num2 = input("Enter another number: ")
result = float(num1) + float(num2)  # int = integer, float is for decimal number.`

`print(result)`

# Mad Libs (空欄補充のゲーム)
`# print("Roses are {color}")`
`# print("{plural noun} are blue")`
`# print("I love {celebrity}")`

`color = input("Enter a color: ")
plural_noun = input("Enter a Plural Noun: ")
celebrity = input("Enter a celebrity: ")`

`print("Roses are " + color)
print(plural_noun + " are blue")
print("I love " + celebrity)`
Herokuを寝かせないようにではなく指定時間に叩き起こすTips 【Heroku/enebular】


Herokuにデプロイしたアプリケーションは、 **30分アクセスが無いとスリープしてしまう**ことは有名です。ただ、24時間寝ないようにすると無料枠がすぐ無くなりませんか？

## 寝かせない運用は無料枠の1000時間がすぐに無くなってしまう

調べると定期的に自身にHTTPリクエストを行って寝かせないようにするなどの対処法が見つかります。

ただ、 **Herokuは無料枠の運用だと月間1000時間までしか利用できない**という制限があります。

寝かせない運用の場合、寝かせないので

24時間x30日=720時間

ということで、 **一つのアプリケーションだけで無料枠の7割をも使ってしまいます。**

## 基本寝かせておいて、指定したタイミングで叩き起こす

もちろん、24時間稼働が前提のアプリケーションではこれは厳しいですが、バッチ処理や定期的に発言するBOT、RPAツールなど常時稼働ではなく1日のうちに数回動けば良いといった仕様のアプリケーションならば24時間稼働をさせなくても良いはずです。

## Heroku Schedulerを利用

ここだけだと割と一般的です。Heroku SchedulerというHerokuアプリがスリープしてても指定時間にコマンドを実行してくれるツールです。

アプリケーション管理画面の`Resouces` > `Add-ons`からHeroku Scherdulerを追加します。

> ![](https://i.gyazo.com/48d2a0c4c689a16e22b3dbbf0f5aa6d4.png)

指定時間に指定コマンドを実行できるので

```bash
curl https://アプリ名.herokuapp.com
```

などを指定して定期的にリクエストを出すのが通常です。

## 1回のHTTPリクエストでは起動してくれないケースがある

これはNode-RED（enebular）のデプロイのケースだけなのかもしれないですが、 **1回のHTTPリクエストだけだとアプリケーションが起きるだけ、その次からのリクエストでやっと処理がされる**という事象がありました。

ということで **2回HTTPリクエストを出す**ようにしてみます。

## Sleep処理と2回のHTTPリクエスト

Heroku Schedulerで毎日指定時間に実行させようとすると、 **最短実施時間間隔が30分になっており、ただ2回実行しただけでは30分経過してしまいまた寝てしまいます。**

> ![スクリーンショット 2020-12-21 16.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/c8e767fd-b41d-119a-94e6-af8fb5523b93.png "スクリーンショット 2020-12-21 16.01.44.png")

これをSleep処理を挟めつつ、HTTPリクエストを2回行うことで回避できました。

以下は **12:30に処理を実行したい例です。** 

* STEP1. 12:00の実行

```
$ sleep 30 && curl https://hogehoge.herokuapp.com/ping
```

1回目のリクエストの前に、 **`sleep 30`で30秒待機してから、HTTPリクエスト**を行っています。

* STEP2. 12:30の実行

```
$ curl https://hogehoge.herokuapp.com/ping
```

これは通常通りです。STEP1の実行が12時00分30秒頃~となるのでSTEP2の実行時にギリギリ30分は経ってなく、sleepしません。

このsleep処理入れなくてももしかしたら起こす処理で時間がかかってSTEP2までの間が30分未満の場合もあると思いますが、確実なものにするためにsleepを入れた方が安心だと思います。

こんな感じで実行したいタイミングの30分前に一度HTTPリクエストを行って、起こしておきます。 

ちなみに、UTCになるのでマイナス9時間を指定すると日本時間になります。
**日本時間の12:30に実行したければ、ここの設定はAM03:30**ですね。

また、実際にはNode-REDでこんな感じでエンドポイントを用意してたりします。

> ![](https://i.gyazo.com/7ce2ed4cf26abddfce0fd7a05a20c39e.png)

## まとめ: 2回のリクエストで叩き起こす

まとめるとこんな感じで2回のリクエストを出し、1回目を遅延実行させることで2回目のリクエストで確実に処理が行われます。

> ![](https://i.gyazo.com/cd1d71c0673b28869b40bc14459abf1b.png)

一回のリクエストでは起きない（厳密には起きるだけで何もしてくれない）ので、 **2回のリクエストで叩き起こす**といった感じですね。
GatsbyでPWAを実装する

##マニュフェストファイルを追加する

```
yarn add gatsby-plugin-manifest 
```


gatsby-config.jsにプラグインの設定を追加する。
optionsではマニフェストのプロパティを指定します。

Name:アプリ名を指名
Short_name:アプリの短縮名を指定
Start_url:アプリを開始するURLを指定
Background_color:アプリの起動画面の背景色を指定
theme_color:テーマカラーを指定
display:アプリの表示モードを指定（standaloneを指定するとネイティブアプリと同じような表示を行う）
icon:アプリのアイコンを指定

```
{
resolve: `gatsby-plugin-manifest`,
options: {
  name:`アプリ名`,
  short_name:`アプリの短縮名`,
  start_url:`アプリを開始するURL`,
  background_color:`アプリの起動画面の背景を指定`,
  theme_color:`テーマカラーを指定`,
  display:`アプリの表示モードを指定`,
  icon:`アプリのアイコンを指定`,
　},
},
```

##オフラインに対応する

```
yarn add gatsby-plugin-offline
```

gatsby-config.js内にgatsby-plugin-offlineの設定をgatsby-plugin-manifestの後に記述する
（生成されたmanifest.webmanifestをキャッシュできるようにするため）


```
`gatsby-plugin-offline`
```

##動作確認
・アイコンの表示
・アプリとしての表示
・オフライン表示
を確かめて、正常に動作するか確認します


参考文献：
Webサイト高速化のための静的サイトジェネレーター活用入門　GatsbyJSで実現する高速＆実用的なサイト構築
UINavgationControllerの NavigationBar の色が変わらない時の処方箋

NavgationController の NavigationBar の色を変えるのは以下の通りですが、
**ViewDidLoad で呼ぶと変わらないことがあるので、 ViewWillAppear で呼ぶと変わります**。

```swift
navigationController?.navigationBar.barTintColor = .black // 背景色
navigationController?.navigationBar.tintColor = .white // 戻るボタンなど
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white] // タイトル

 // ViewWillAppear で呼びましょう🐥
```
🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
追加したい新しい項目にWindowsフォームが無い場合の解決方法

# はじめに
本稿は、私がWindowsフォームアプリを開発時にあったことを戒めとしてメモしたものです。
私が解決に至るまで少なくない時間が掛かったのため、同じ問題で躓いた人の参考になれば幸いです。

# 環境
OS：Windows10
IDE：Visual Studio Community 2019
言語：C#
プロジェクトの種類：Windowsフォームアプリケーション

# 問題
Windowsフォームアプリケーションに2つ目以降の画面を追加しようと[右クリック]>[追加]>[新しい項目]>[インストール済み]>[Visual C#アイテム]>[Windows Forms]を選択したがWindowsフォームのファイルが選択肢にありませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390453/61998222-e792-f8c3-4a56-21828942b0c8.png "新しい項目の追加")

# 原因
Visual Studio Installerで[インストール済み]>[Visual Studio Community 2019]>[変更]>[ワークロード]>[デスクトップとモバイル]>[.NET デスクトップ開発]に関連するコンポーネントをインストールし忘れていました。
初めてVisual Studio Community 2019をインストールした時はXamarinでの開発が目当てだったので[.NET デスクトップ開発]に関連するコンポーネントは完全にスルーしてた結果ですね…。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390453/902e2727-643f-8a7e-0875-930b84bee1c5.png)

# 解決方法
この後に[.NET デスクトップ開発]関連のコンポーネントをインストールしたので新しい項目にてWindowsフォームのファイルが無事に選択できるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390453/6942391c-95de-dd1e-7fd8-e5d942152527.png)

# 終わりに
そもそもPCの容量に余裕があるなら最初のインストール時に一般的によく使われるコンポーネントは全部入れなさい！って事でしたね…。
開発環境によってはPCの容量に余裕が無いので必要最低限のコンポーネントだけで～…といった選択肢も取れる必要な機能ですので、皆さんは私のような失敗を防げることをお祈りします(´・ω・`)
UITabbarController 配下の UINavigationController をモーダル表示する

tabBarController デリゲートメソッドの shouldSelect viewController　内でNavigationController をインスタンス化してプレゼントします。

StoryBoard から TabBarItem に タグをつけることをお忘れなく。

```swift
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
    guard viewController is UINavigationController else { return true }
    if tabBarController.selectedIndex == 1 {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let popupViewController = storyboard.instantiateViewController(withIdentifier: "NavigationController") as! UINavigationController
        popupViewController.modalPresentationStyle = .fullScreen
        tabBarController.present(popupViewController, animated: true, completion: nil)
        return false
    } else {
        return true
    }
}
```

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
Python解説を覚え書き 3 - Numbers

`print(-2.0987)
print(3 + 4.5)
print(3 * (4 + 5))`
`# modulates operator?  Modulo operator: returns the remainder of a division.
print(10 % 3)  # 10 divided by 3. that's going to be 3 with a remainder of 1.`

`# variable containers
my_num = 5
print(my_num)
print(str(my_num) + " is my favorite number.")`

`#  abs == absolute value of a number
my_num = -5
print(abs(my_num))`

`#  pow
print(pow(3, 2))  # 3^2  3 raised to the power of 2. It should be 3 squared.`

`#  max, min
print(max(6, 4))
print("The minimum number is " + str(min(6, 4)))`

`# round
print(round(3.2))
print(round(3.7))`

`from math import *  # math module gives us more math function
print("floor 3.7 is " + str(floor(3.7)))
print("ceil 3.7 is " + str(ceil(3.7)))`

`# square root
print(sqrt(36))`
enebularでウルトラソウルに洗脳されたlinebotをサクッと作ってみた

#ハローenebular！
この記事は[enebular Advent Calendar 2020](https://qiita.com/advent-calendar/2020/enebular)の21日目の記事になります。
先日人生初LTということで「[ゆるふわマシンラーニングvol.5](https://enebular.connpass.com/event/188257/)」にて登壇させていただきました。
今回は、そこで学んだenebularとSunabaをハンズオンしてみました。

その際に登壇されていた方が[同様の記事](https://qiita.com/kawazu255/items/14df737887ff5e360488)をすでに書かれていたので参考にさせていただきました。
かなり丁寧に手順を書いてくれているので、是非是非一度ご覧になってくださいね。

#完成デモ
##クソbotの爆誕
今回作ったのはline bot「__ウルトラソウるbot__」。
アイコンからただならぬクソbot感がしますね。
以前[こんな記事](https://qiita.com/canonno/items/964b9ff613ced1b217c2)を書いて以来、ウルトラソウル基準で考えるようになってしまいました。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/8951bc16-088a-2150-d20d-f1802739fa8d.png">

##何言ってもウルトラソウルを絡めてくる
このbotは__何でもかんでもウルトラソウルに絡めてくるbot__です。
「ウ」「ル」「ト」「ラ」「ソ」のどれかで終わる言葉を言うと、全部ｿｳﾙにして返してきます。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/a1ee90f7-83e0-b7b1-f9c3-43f6a95aa290.png">
それ以外の言葉を言うと煽ってきます。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/9cb3a0d3-a707-bc15-29da-cdccc9b871d2.png">

#実装こまごま
##Enebular・SUNABA・Line Messaging APIの設定など
設定面は全面的に[こちらの記事](https://qiita.com/kawazu255/items/14df737887ff5e360488)を参考にさせていただきました。
丁寧に解説していただいているおかげで、初心者でも1時間半ぐらいでクソbotを実装できました。
躓いたところも後述のSUNABAの実装だけで、Enebularはほとんどハマらずに使えました。
Enebularのnodeも種類が豊富だったので色々使い倒してみたいところです。

##SUNABAの実装
ここがあまり資料が無かったので備忘録的に書いておきます。
今回はユーザ入力の言葉の最後の文字を取り出して、それを返す必要がありました。
全体像はこのような感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/ad47637b-78e5-5204-41f9-b393da02da15.png)

ノードの設定はこのような感じです。
正規表現が使えたので、$を使って判定ロジックを作りました。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/d27e7d38-e976-479e-b47d-ceb749f6f97d.png"><img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/8843132c-8c62-058f-ce35-46a62c1030e8.png">



返答側のノードはこちら。
ユーザ発話全体がultraに代入されるので、それを取り出すだけですね。
入力条件タブは「ここ何か入れないとダメなのかな・・・？」となってしばらくハマったので、「何も入れなくていいよ」ということを示すために念のため添付しています。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/c5fbad84-2a7d-2633-83bb-d0d28e526988.png"><img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/9f9f220a-2bfb-4615-06b4-94f768c228a2.png">

#最後に
JSON形式でAPIへPOSTする際に色んなお作法を間違えてハマってしまうことがよくありました。
そんなところを線をつなぐだけでbot一つ簡単に作れちゃうなんてすごいですよね。
Enebular、色々試してみたいと思います・・・！
Python解説を覚え書き 2 - Strings

`print("Giraffe\nAcademy")  # new line
print("Giraffe\"Academy")  # escape sequence
print("Giraffe\\Academy")`

`phrase = "Giraffe Academy"
print("\n\n" + phrase)  # appending another strings is concatenation (+)`

`#  function
print(phrase.lower())
print(phrase.upper())
print(phrase.isupper())`

`#  function in combination
print(phrase.upper().isupper())`

`#  length function
print(len(phrase))`

`#  index of the character
print(phrase[0])`

`#  passing a parameter
print(phrase.index("a"))
print(phrase.index("Acad"))`

`# In here I can actually give this two parameters so I can give this replace function two values that it can use.
print(phrase.replace("Giraffe", "Elephant"))`
アナログ回路 その19

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# レベルシフター回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a64340ed-0c0c-d5c8-90a5-d1cbfd395e64.jpeg)


# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/57407ebb-6232-ce42-9fab-2b6faa65bfbe.jpeg)


# 説明

arduinoとラズパイの動作電圧を合わせる回路
3.3V出力、5V入力です。
トランジスタを2個使います。

# 成果物

https://embed.plnkr.co/plunk/fFIzb56xRY5ULgnq


以上。
railsのバリデーションのまとめ（自分用）

#はじめに
今回Railsのテストコードを実装する上で詰まったバリデーションをまとめる。

#バリデーションとは
一般的には検証、実証などの妥当性を判断する上で使われる英単語である。
ITでは文法などが適切に記述されているかどうかを検証する意味で使われる。

# よく使われるRailsのバリデーション
###:presence
 　空ではない事を検証する際に使用する。
#####使い方
```
validates :item presence: true
```
こうする事で仮に新しくitemを投稿する際に、空欄のままでは投稿する事はできなくなる。
#####エラーメッセージ
:presenceの場合デフォルトで ["〇〇　can`t be blank"]と設定されている。

###numericality
   カラムの型をintegerに設定した時に使う事が多い。
   数値のみの指定で使う。
#####使い方
```
validates :price, numericality: true
```
presenceと使い方は主に同じ。

###length
   長さを制限することができるバリデーション
#####使い方
```
validate :price, presence: true, length: {maximum: 7}
```
こうすることで長さを制限できる。maximum,minimumなどのオプションと一緒に使う事が多い。

まだまだあるが今回使ったのはこの３つ

#参考にした記事
[Railsドキュメント](https://railsdoc.com/validation)

#最後に
初めての投稿になる。これからも続けていきたい。
GASでスプレッドシートの特定チェックボックス変更検知のコツ

# 想定状況
スプレッドシートのチェックボックスがチェックされた瞬間に外部APIを叩くなどの状況

# 直感的だがスマートでない実装方法
>別のセルに前後の状態を保存しておかなければ
>特定のチェックボックスセルでチェックがついた/外れた瞬間に操作を実行するのは不可能

と思っていませんか？必ずしもそうする必要はありませんし、そうすればシートが複雑になります。

# 僕なりのスマートな解決策
チェックボックスの場合は前後の値がTRUE/FALSEのみに限定されるので
シート変更の変更トリガーでアクティブセルとその値を確認すれば所望の操作が実現できます。


```js:main.gs
//トリガーを手動で設定しなくともシートの変更時にトリガーされる
function onEdit(e){
  const sheet = SpreadsheetApp.getActiveSheet()

  // 例として2行3列のチェックボックスセルを監視したいとする
  const target={
    row:2,
    col:3
  }

  listenForCheckBoxChange(sheet,target)
}



//チェックボックスセルの変更を確認
function listenForCheckBoxChange(sheet,target){
  //監視するチェックボックスセル上が選択されている i.e. アクティブになっている
  //なお、これがtrueの場合、シートに変更があり、
  //アクティブセルから変更はチェックボックス上で直前に行われた と判断できます
  const isTargetCellActive= (sheet.getActiveCell().getRow()==target.row)
                            &&(sheet.getActiveCell().getCol()==target.col)
  if(isTargetCellActive){
    //そのセルがチェックされているかどうか i.e. TRUEになっているかどうか
    //監視するチェックボックスの値が変更され、かつ直後にTRUEになっている場合は
    //FALSE->TRUEと変化したと考えて差し支えありません。
    //ちなみにチェックボックスの値を取得したときはJavaScriptのboolean value (true/false)が返されます
    const isTargetChecked=sheet.getActiveCell().getValue()
    if(isTargetChecked){
      Logger.log("監視しているチェックボックスの値が変更され、かつチェックはtrueに変化しました。")
      // 監視チェックボックスがチェックされた時に行いたい処理
      // ...
    }else{
      Logger.log("監視しているチェックボックスの値が変更され、かつチェックはfalseに変化しました。")
      // 監視チェックボックスがチェック解除された時に行いたい処理
      // ...
    }
  }
}

```

## チェックボックス以外のセルには応用できない
ただしチェックボックスでない通常のセルでは同様に前後をトラックして、
それに応じて処理を分岐するのは難しく、別のセルなどに状態を保存する仕組みを作る必要があります。

### コメント
実際にGASと外部APIを連携させる業務で利用する際に思いつきました。
Qiitaリンク集

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# Qiitaリンク一覧

1.  [qiitaリンク集](https://qiita.com/kensugita/private/b8d47b3d04f7c52ccff1)



------
 - **source** ~/grad_members_20f/members/kensugita/README.org
HiltでMediaBrowserServiceCompatに依存関係を注入する

`MediaBrowserServiceCompat` へ `@AndroidEntryPoint` を使って依存関係を注入しようとすると、以下のエラーがでてしまいます。

```
エラー: MediaBrowserServiceCompatにアクセスできません
  androidx.media.MediaBrowserServiceCompatのクラス・ファイルが見つかりません
```

これを解決するために、新たに `EntryPoint` を定義します。

```kotlin
@EntryPoint
@InstallIn(ApplicationComponent::class)
internal interface MediaBrowserServiceCompatInterface {
    fun getHoge(): Hoge
}
```

そして、 `MediaBrowserServiceCompat` 内でこれを使って注入します。

```kotlin
    EntryPoints.get(applicationContext, MediaBrowserServiceCompatInterface::class.java).also {
        this.hoge = it.getHoge()
    }
```

[Entry Points - Hilt](https://dagger.dev/hilt/entry-points) のBestPracticeにはクラス内にInterfaceを定義し、それを使うことが推奨されていますが、 `MediaBrowserServiceCompat` の場合はうまく動きません。おとなしく別ファイルに書くしかないようです。


MediaBrowserServiceCompatはServiceを継承しているので、AndroidEntryPointでかけそうなものですがなにがだめなのでしょうか。。。もし、なにかいい方法をご存じの方がおられたら、コメントで教えていただけると嬉しいです！
Swifterを使ったapi認証の実装について


個人開発でswiftを使ったtwitterのアプリを作成中。
開発進めたらこの記事を少しずつ更新していく予定です。

事前準備として、twitterのapi利用の申請は済んでいる状態とします。

##Swifterとは
公式サイト
https://github.com/mattdonnelly/Swifter
Swift言語で作成されたTwitterフレームワーク。

##Swifterを入れる

作成したプロジェクトを選択し、「Swift Package」のタブより「Packages」の＋を選択する
![スクリーンショット 2020-12-20 15.56.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/9a78a5b8-4c30-0087-c737-d95fe68ce928.png)

SwifterのgithubURLを入力する
![スクリーンショット 2020-12-20 15.56.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/4f687dfe-0a44-4727-dc90-eb60d6218188.png)

masterBranchを選択
![スクリーンショット 2020-12-20 15.56.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/ce733146-1916-4a20-0bec-f759096fa29d.png)

Add to Targetがプロジェクト名になっているかを確認し、Finishする
![スクリーンショット 2020-12-20 15.57.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/43e3dd00-4a41-ad2b-2690-e64dc6ff530f.png)


##api接続
swifter公式サイトのExample Requestsを参考に作成します。

```
ViewController.swift
@IBAction func login_button(_ sender: Any) {
        let swifter = Swifter(
            consumerKey: "Twitter_consumerKey",
            consumerSecret: "Twitter_consumerSecret"
        )
        swifter.authorize(
            withCallback: URL(string: "CallbackURL")!,
            presentingFrom: self,
            success: { accessToken, response in
                self.fetchTwitterHomeStream()
        }, failure: { error in
        })
    }
}
```



##画面操作
ビルドします。

![Simulator Screen Shot - iPod touch (7th generation) - 2020-12-21 at 16.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/de060f13-e502-ce77-af70-59a1cdd827fe.png)
Main.storyboardが表示されている状態です。
ログインのボタンを設置し、ViewControllerのlogin_buttonに紐づけています。


![Simulator Screen Shot - iPod touch (7th generation) - 2020-12-21 at 16.44.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/ead275d7-bb88-a9e7-fd28-d3d03ff169f4.png)
ログインボタンを押してログイン画面に遷移。



![Simulator Screen Shot - iPod touch (7th generation) - 2020-12-21 at 16.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922099/beb332e3-e9ed-5270-9c64-16acd3d8cded.png)
成功するとリダイレクト画面を表示して戻ります。
JavaScript Array.reduce()の使い方

# 概要
Array.prototype.reduceは引数で与えられたreducer関数を配列要素一つ一つに実行し、単一の出力値を作る。

```javascript
hogeArray.reduce(reducer, initialValue)
```

## reducer関数
reducer関数は4つの引数を取る。そのうちアキュムレーターと現在値は必須。

1. アキュムレーター(accumulator)
reducer関数の返り値を溜めていく変数のようなもの
2. 現在値(currentValue)
今回ってきている配列の要素
3. 現在の添字(index)
今回ってきている配列のインデックス
4. 元の配列(array)
reduceが呼び出された配列(上記例で言うとhogeArray)

```javascript
function reducer(accumlator, currentValue, index, array) {
	return ???
}
```

## InitialValue
InitialValueはreducer関数の最初の呼び出しの最初の引数として使用する値。
例えばInitialValueに0を指定した場合、アキュムレーターの最初の値は0になる。

# 使い方の例と処理の内容
配列内の値の合計値を出すような処理を作る際にはスマートに記述する事ができる。

```javascript
const array = [1, 3, 5];
return array.reduce(function (acc, cur) {
	return acc + cur;
}, 0)
// 出力結果：9
```

reduceは配列の内容を一つずつ網羅し、それについての計算をしていく。
0番地の配列に入っているのは1なので、最初の計算は下記のようになる。

```jsx
0(アキュムレーター) + 1(現在値) = 1
```

次の1番地に回ると、0番地の計算で返された1がアキュムレーターに入っており、それに1番地の3が足されている事が見て取れる。

```jsx
1(アキュムレーター) + 3(現在値) = 4
```

最後の2番地も同様の動作になる。配列の最後に到達したら、現在アキュムレーターに格納されている内容がreduceの返り値となる。

```jsx
4(アキュムレーター) + 5(現在値) = 9
```

他の引数による動作の変化は[MDNのリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)を見てみてください。

# まとめ

余計な変数を用意しなくても計算結果をアキュムレーターに突っ込んでいく事ができるメソッド、reduce。配列操作する際は使っていきましょう。
Laravelのmail送信の宛先を指定したぃぃ！！

##laravelのmailの宛先を指定の名前に変えたい！

今回は、Laravelでのmail送信の宛先について、投稿します！
簡単すぎてかわかりませんが、あまり宛先についての記事がなかったように思ったので、残しておこうと思います。

##環境
-windows10
-laravel6
-php(7.4.6)

※今回はgmailのsmtpを使用します。
mailの設定は省きます。ちなみに筆者は２段階認証後アプリパスワードを指定し、設定しました。
[メール設定参考](https://qiita.com/koru1893/items/e30d19ac97eac59b1e19)


##やったこと

今回はmailableクラスを使っています。

```cmd.
php artisan make:mail ContactMail
```

コマンドで作成し、mailableクラスを作成し、それを編集しています。


```ContactMail.php

public function build()
{
 return $this->subject('*****について')     //件名
         ->from('*****@gmail.com')     //送り元
         ->text('*****')     //メール内容（直接記載もできるが、bladeの指定もできる。）
         ->to('*****@gmail.com')      //送り先
         ->with('*****');     //view等に引き継ぎたい値を指定します。
}
```

このあとコントローラーでMail::toを使用し、送信します。
すると、

![mail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764103/83de6769-4263-90ed-d696-f5840970636c.png)

すみません、消していますが宛先がgmail表記になっていることがわかると思います。
これを指定の名前にしたいのです。

##結果

```ContactMail.php

public function build()
{
 return $this->subject('*****について')     //件名
         ->from('*****@gmail.com','ここに指定したい名前')     //送り元
         ->text('*****')      //メール内容（直接記載もできるが、bladeの指定もできる。）
         ->to('*****@gmail.com')     //送り先
         ->with('*****');      //view等に引き継ぎたい値を指定します。
}
```

結果としては、第2引数引数に値を持たして、値を引き継いだら名前を指定できます。
だーん！！！
![gmail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764103/c9629b43-8e73-56c5-674b-575dbab99c0e.png)
Ruby で gRPC を使ってみる

# はじめに

Ruby を使って簡単なアプリを作りながら gRPC を練習してみたいと思います。

今回作成するのは計算機のCLIアプリです。

ターミナル上で 1 + 2 などと入力するとクライアントが"1 + 2"の文字列をサーバーへ送信し サーバー側が答えを計算しレスポンスとして返してくれるというものです。
これをgRPCで実装します。

## 準備

grpc と grpc-tools の gem をインストールします。

~~~
$ gem install grpc
$ gem install grpc-tools
~~~

アプリ用のディレクトリを作成します。
名前はなんでも良いですがとりあえず grpc_calc とします。

~~~
$ mkdir grpc_calc
$ cd grpc_calc
~~~

## 実装

### Protocol Buffers を定義する

proto ファイルを作成していきます。

~~~
grpc_calc $ mkdir protos
grpc_calc $ vi protos/calc.proto
~~~


~~~calc.proto
// この proto ファイルは proto3 の文法で作成します。
syntax = "proto3";

// example というパッケージ名で作ります。(※名前はなんでも良いです。)
package example;

// 計算機のサービスを定義します。
service Calc {
  // solve というメソッドを定義します。
  // Input を引数に渡すとOutput を返します。
  rpc Solve (Input) returns (Output) {}
}

// クライアントから渡す計算式です。
message Input {
  // question という名前で文字列を定義します。 タグは1とします。
  string question = 1;
}

// サーバー側が返す答えです。
message Output {
  // answer という名前で数値を定義します。 タグは1とします。
  int32 answer = 1;
}

~~~

lib ディレクトリを作ります。

~~~
grpc_calc $ mkdir lib
~~~

protps/calc.proto をコンパイルし lib 以下に出力します。

~~~
grpc_calc $ grpc_tools_ruby_protoc -I protos --ruby_out=lib --grpc_out=lib protos/calc.proto
~~~

すると lib以下に　calc_pb.rb と calc_services_pb.rb ができていると思います。

### サービスの実装

サーバー側から実装していきます。

~~~calc_server.rb
require 'grpc'
require_relative 'lib/calc_services_pb.rb'


class CalcServer < Example::Calc::Service
  def solve(input, _unused_call)
    answer = eval(input.question)

    return Example::Output.new(answer: answer)
  end
end

def main
  s = GRPC::RpcServer.new
  s.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
  s.handle(CalcServer)
  s.run_till_terminated_or_interrupted([1, 'int', 'SIGQUIT'])
end

main
~~~

クライアント側も実装していきます。

~~~calc_client.rb
require 'grpc'
require_relative 'lib/calc_services_pb.rb'

def main(input)
  stub = Example::Calc::Stub.new('localhost:50051', :this_channel_is_insecure)
  output = stub.solve(Example::Input.new(question: input))
  p "答えは #{output.answer}"
end

p "計算式を書いてください"
input = gets.chomp

main(input)
~~~

これで実装は終了です。


## 実際に動かしてみる
サーバー起動

~~~
grpc_calc $ ruby calc_server.rb
~~~

クライアント実行

~~~
grpc_calc $ ruby calc_client.rb
"計算式を書いてください"
10 + 20 + 30
"答えは 60"
~~~

上記のようになれば成功です!
アナログ回路 その18

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# レベルシフター回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/4e89e403-de16-e8c0-2fee-1ed43b9dc175.jpeg)


# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/c040c419-d85f-ea29-f0a0-bdfa75e5c580.jpeg)


# 説明

arduinoとラズパイの動作電圧を合わせる回路
５V出力、３．３V入力です。
抵抗で分圧します。


# 成果物

https://embed.plnkr.co/plunk/4CRLNj5BiErMwGXg


以上。
Kotlinのnull安全とは？

##概要
はじめてkotlinで実装する機会が訪れ、今までjavaしか触ったことのなかった私は少し苫だった点がありました...。

それは、kotlinは基本的にnullを許容しないということです。
全体的な実装方法はjavaと似ているので、慣れると実装はしやすいなと感じました。
逆に、javaと似ていながらも少し違うことで小さなエラーに悩まされることがありました。

初心者ですので、すべて正しいわけではないと思いますが、自分が理解した範囲でメモ程度にまとめておきたいと思います。

今回は、vue.jsのrouterを使用します。

#####null許容とnull許容ではないパターン
```kotlin:example.kt
val nonNullable: String = null //NG
val nullable: String? = null //OK
```
null許容にさせたい場合は型の後に"?"を加えます。
そうすることで、この変数はString型とnullを許容するということを定義できます。


#####null許容の変数には呼び出し方にも注意！
メソッド間でのnull許容の変数の受け渡しには注意が必要です。

```kotlin:User.kt
// null許容の変数なのでIntに"?"をつける必要がある
fun getAge(age: Int?) Int?{
    age = 20
return age
}
```

```kotlin:Name.kt
val user: User = User

// null許容の変数
var age: Int = null

// null許容ではない変数
var userAge: Int = 0

// Userクラスから年齢を取得
var userAge = user.getName(age) // userAgeはnull許容ではないため、コンパイルエラーが起きる！
```

↓　そのため↑のUserクラスから年齢を取得する場合は
下記のようにif文やエルビス関数などを使用してnullチェックを行う必要がある。

```kotlin:Name.kt
// if文
if(!getName(age)){
    var userAge = user.getName(age)
}

// エルビス関数
user.getName(age)?.let{
    // getName(age)の戻り値がnullではない場合の処理
    var userAge = user.getName(age)
}?: user.getName(age) //nullであった場合ここの処理が実行される
```

null許容である変数とnull許容ではない変数をうまく使い分ける必要がある。
下記のように無理やりnull許容の変数を「nullではないです！」と宣言することもできる
しかし、安全とは言えないのであまり使わない方が良いそう...

```kotlin:example.kt
var userAge = user.getName(age)!! //"!!"をつけることでnullで非nullであることを無理やり宣言
```
OpenCV(Java)のことはじめ

# はじめに
コマンドでの実行が苦労したときのメモ書きしたものになります。

実行環境: Windows10、Java15、OpenCV-4.5.0
# OpenCVのインストール
1. [公式ホームページ](https://opencv.org/releases/)から最新バージョン(4.5.0)を入れる。(Windowsボタンを押すとインストールが始まります。
ダウンロード先のファイルの指定の所では、c:\にしておくと後で探しやすいと思います。

2. 解凍したフォルダに移動します

3.  "*****\opencv\build\java"の中opencv-450.jarとx64という名前のフォルダの中にopencv_java450.dllがあることを確認してください。



# サンプルコードとコンパイルの仕方
Sample.javaを作成します(コードは以下をコピペしてください)。
このプログラムと同じディレクトリに"lib"という名前のフォルダを作成し、
opencv-450.jarとopencv_java450.dllのコピーを入れます。

```java:Sample.java
import java.io.File;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

public class Sample {
    public static void main(String[] args) {
        // OpenCVが使えるためのおまじない
        // 環境によってcan't load libraryのエラーが出る可能性がある
        // <解決策>
        // lib_pathに"opencv_java450.dll"を入れたフォルダの
        // 絶対パスを調べて、lib_folder.getAbsolutePath()の代わりに書きます
        // 例: String lib_path = "C:\\Users\\username\\workspace\\lib";
        File lib_folder = new File("lib");
        String lib_path = lib_folder.getAbsolutePath();
        System.load(lib_path + "\\" + Core.NATIVE_LIBRARY_NAME + ".dll");
        // OpenCVの画像の型は"Mat"になります。
        // Matは行列の形をしています。
        // ここではOpenCVが実際に動くか確かめるために
        // 3×3の対角行列を試しに作ってみます。
        Mat mat = Mat.eye(3,3,CvType.CV_8UC1);
        // 作った行列の中身を確認します。
        System.out.println("mat = " + mat.dump());
    }
}
```
それでは、コンパイルをしてみましょう。

```
javac -classpath .;lib\opencv-450.jar Sample.java

```
実行します。

```
java -classpath .;lib\opencv-450.jar Sample

```
出力結果が以下のようになっていればopenCVが使えていることが確認できます。

```
mat = [  1,   0,   0;
   0,   1,   0;
   0,   0,   1]
```
# 終わりに
今度Macでも確認する。-Djava.library.pathでdllのパス指定するのは面倒だったのでこうした。元も子もないけど、IDE使うのが楽そう。
コマンドで連続した数字を含む複数ファイル作成

# 結論
## 入力
```bash
touch report-{1..3}.cpp
```
## 結果
```
以下のファイルが作成される:
report-1.cpp
report-2.cpp
report-3.cpp
```

# ありがたみ
わざわざnodeやpythonでosをimportしてループ回してファイル作成するのは面倒ですよね😒
コマンドラインから慣れ親しんだtouchコマンドと共に所望の処理ができるので楽チンです😂

# ユースケース
情報系の学生はいまだにこんな連番ファイル名で課題のソースコード作成を強いられています。
授業支援システムは既に提出フォームと評価システムが統合されてるのに、
石器時代のようなファイル名設定や、複数ファイル提出できるのに謎にzipでの提出を求められるなど
アカデミアの世界はまだ石器時代のような風習が蔓延っています。
「東京都新型コロナ対策サイトのアクセシビリティ改善を語る」を語る

サイオステクノロジーの伊藤です。金融システムのUI設計などを専門にしています。
こちらは、[CivicTechテック好き Advent Calendar 2020](https://qiita.com/advent-calendar/2020/civictech_tech)の21日目の記事です。

今年は新型コロナの影響で年初予定していたことが出来なかったり、想定外のことが多くありましたが、そんな中でも、様々なアクセシビリティ関連の活動や発表が活発に行われ、事業会社でも次々に専門チームが立ち上がったり、アクセシビリティー・ガイドラインや強力そうなアクセシビリティ検証ツールが発表されたり、様々な実践が形になりつつあるのを感じます。

その中でも、[Code for Japan Summit 2020](https://summit2020.code4japan.org/)でも発表された「東京都新型コロナ対策サイトのアクセシビリティ改善」は今年だけではなく、日本のアクセシビリティ関連の活動の中でも、大きなエポックとなった出来事ではなかったかと考えています。

そのエッセンスが詰め込まれた資料と講演の動画が公開されていますのでぜひご覧ください。
（「テック好き」というお題的にはアクセシビリティの自動検査ツールまわりの話が興味深いかと。）

発表資料：[東京都新型コロナ対策サイトのアクセシビリティ改善を語る](https://docs.google.com/presentation/d/1J85Tjx8Yorpg1D7eXgTeqgxLVMhGjKEoQOmiMGGN8dc/)
講演動画：[2020 Day2 Track2 4 東京都新型コロナ対策サイトのアクセシビリティ改善を語る](https://www.youtube.com/watch?v=b5DsjUa54Gc)

発表資料から引用
> - 約2ヶ月で数十件のアクセシビリティIssueが提案され、高速で反映され、ユーザーフィードバックが寄せられる現場は前代未聞！
> - たいてい「どうしたらアクセシビリティ向上を始められるか？」からの議論になるのに、この現場では最初からフルアクセルだった
> - 障害当事者ユーザーも協力し、現実的なラインを議論しながらもどんどん改善されていく様子は、圧倒的なRe:DESIGN感を感じた
> - なぜそれができたのか？どのように進んでいったのか？それを共有することで他の現場でもRe:DESIGNを起こしたい

ふだん様々な界隈で活躍するアクセシビリティのスペシャリストが次々に議論や作業に加わり、それに多くのデザイナーやエンジニアが応えていく様は、参加していてもとても胸が熱くなりました。

受託の中の人なのでふだんあまり人目に触れるアウトプットがない人間ですし、シビックテックの活動に参加するのもこれが初めてではありましたが、とても刺激を受けました。また、今後機会があればより積極的にかかわっていきたいとも思うようになりました。

ふだん仕事と家庭の両立だけでアップアップしてはいるのですが『シビックテックとアクセシビリティはズッ友』ということなので、また来年も何か地道なところからでもやっていこうと思います。

![段ボールに張り付けたNVDAチートシートで地道なテスト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2827/d8feaa1b-5653-e749-8603-2dcfacfce555.png)

それから感謝状ありがとうございました。ちょい家族に面目が立ちました。
![東京都新型コロナ対策サイトのコントリビューター感謝祭でもらった感謝状](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2827/53b6e823-c5b9-8eab-a512-a34532116042.png)

あ、今見るとshunitoがshuitoになってる。