OmniAICreator/Qiita-1.07M huggingface dataset:
Mapbox GL JS で右下の緯度経度を取得する

先日、Mapbox GL JSで表示中の地図をPNGでダウンロードするためのボタンを設置するプラグインを作りました。

https://github.com/tilecloud/mbgl-export-control

デモは以下にあります。

https://tilecloud.github.io/mbgl-export-control/#5/35.69/139.69

その中で、ハマった小ネタを紹介します。

## 地図の右下の緯度経度を取得したい

Mapbox GL JS で表示されている地図の右下の緯度経度を取得する必要があって、ささっとドキュメントを調べて、一度以下のように実装しました。

```javascript
const bottomRight = map.getBounds().getSouthEast()
```

`getBounds()` についてはドキュメントには以下のような記述があります。

> Returns the map's geographical bounds. When the bearing or pitch is non-zero, the visible region is not an axis-aligned rectangle, and the result is the smallest bounds that encompasses the visible region.

後半がよくわかんないけど、まあなんとかなりそうかなとおもたのですが、結論からいうとこれではダメでした。

Mapbox GL JS はベクトルタイルなので地図が傾いていることがありえるのですよね。

![Untitled.png](https://qiita-image-store.s3.amazonaws.com/0/32458/03fa26ad-bdfc-33cc-2b8c-a8e8c6886be7.png)

上の画像のように地図が傾いている場合、`getBounds()`で取得している位置は赤い矢印のところでした。

## 地図の右下の緯度経度を取得するための正しい方法

というわけで最終的に以下のような方法で実装しました。

```javascript
const width = map.getContainer().offsetWidth
const height = map.getContainer().offsetHeight
const bottomRight = map.unproject([width, height])
```

`unproject()` という関数は、ピクセルでの位置を緯度経度に変換してくれる関数です。逆に緯度経度からピクセルに変換したいときは `project()` です。

この関数の名前ちょっとわかりにくいですよね。笑

## なにがしたかったのか

今回作った画像としてエクスポートするプラグインは、`<canvas />` を PNG に変換してエクスポートしています。

最初、できたできたと喜んでいたのですが、`© OpenStreetMap Contributors` が入ってないとまずいなと思いまして、それを入れたいと思ったのです。

ところが、Mapbox GL JS で表示されている Attribution は、Canvas ではなく 普通の HTML テキストを上のレイヤーにのっけてるだけなので、画像にはいってこなかったのですよね。

なので、Attribution 用の文字列を Canvas に放り込むという処理を行いました。

そのために動的に GeoJSON をつくって地物として挿入するという処理をおこなっていて、それで右下の緯度経度を知りたかったのです。

やってみたらなんでもない処理でしたが、「どうせ画像としてだすだけだから、一時的に地物として放り込んでしまえ」というアイディアにたどりつくまでに半日程かかってしまいました。。。

（半日は Canvas を直に操作しようと頑張ってた。。。ｗ）
aiohttp で TypeError: _request() got an unexpected keyword argument 'json' が発生したときの解決方法

ラズパイで下記のコードを実行するとなぜか`TypeError: _request() got an unexpected keyword argument 'json'`とエラーが出てしまう問題に遭遇したので，解決方法を記録しておきます．

```
requests.post(url, json=data)
		async with aiohttp.ClientSession() as session:
			await session.post(url, json=data)
```

#原因
非常に単純な問題でした．aiohttpのバージョンが低かったのが原因です．

#解決法
```
pip3 uninstall aiohttp
sudo pip3 install -U aiohttp
```

#説明
なぜこんなにバージョンが低いものが入っていたのかは分かりませんが，わたしのラズパイに入っていた aiohttp は v1.0.5 でした．
何度か `sudo pip3 uninstall aiohttp` `sudo pip3 install aiohttp` 等を行ったのですが，これは Debian の場合は `/usr/local/lib/python3.5/` 直下にあるパッケージのみを編集し，ユーザーのホームディレクトリにあるパッケージには触りません．
ホームディレクトリに入っていた aiohttp のバージョンが低かったため，ホームディレクトリにあるパッケージが`/usr/local/lib/python3.5/`にあるパッケージよりも優先して使用されてしまい，`sudo pip3 install -U aiohttp` を行ったにも関わらず問題が解決しませんでした．
`sudo`なしで`pip3`を実行するとホームディレクトリのパッケージが編集されるため，`pip3 uninstall aiohttp`を実行することで問題が解消されました．
attrの属性の使い方

#attr()とは
attrとはhtml要素の属性の取得をしたり、設定することができるメソッド

```<a class= "link" href="##">これはリンクです</a>
```

##attr属性の利用
attr属性を活用することで、属性の取得、変更を行うことができる
【対象要素attr(属性,(変更する値))】
###属性の取得
```
<body>
<p id = "sample">こんにちは</p>
<script>
var result = $('p').attr('id');

cosole.log(result);
</script>
</body>

=>sample
```
###属性の変更
```
<body>
<p id="samle">こんにちは</p>
<script>
var result = $("p").attr('id', 'text');

cosole.log(result[0]);
</script>
</body>

=><p id="text">こんにちは</p>
phpファイルをcrontabで実行できなかったけど解決した(Extension [実行ファイル] not present.)

# 前書き
こんにちは。@mashiです。

皆さんはスケジューラ使っていらっしゃいますか。

【決まった日時に実行させる】ことは便利ですし、特に業務関連のアプリでは使うものではないでしょうか。

今回は私が泥沼に嵌った(半日使ってしまいました)ことを共有させていただき、被害者を減らせたらと思います。

# 何が起きたのか
crontabからphpファイルを実行すると、「Extension '[実行ファイル]' not present.」と表示されていました。

パスは間違っていないし、ファイルは存在するし権限回りは大丈夫だし、そもそも動いているサーバからFTPで持ってきた物だったので動かない原因が全く分かりませんでした。

「Extension not present」等の検索をしてもなかなか欲しい情報がなく困り果ててしまいました。

# 確認したこと
- 権限
 - 実行権限
 - 所有者
- ファイルの存在
- パスの間違い

# 解決したこと
とあるサイト( https://ameblo.jp/j-field/entry-11046927335.html )にサラッと下記のような記載がありました。
<pre>
補足
WindowsではCR+LFの改行コードを使用しているのに、UNIXではLFだけで改行コードとみなされ、
プログラムなどでは余ったCRのせいで誤動作を起こす場合がある。
</pre>

FTPで、元の置いてあったサーバ→Windowsのローカル→新たに置くサーバ　というように移動したので、その際におかしくなったのかなと。
なので、vimで新たなファイルを作成し、元のコードをコピペするだけでしたとさ。
ホントに無為な時間を過ごしてしまった・・・。
Eloquent を単体で使うスニペット

諸般の事情により Laravel に入門したので、Eloquent で素振りというか試し切りをするために単体で使えるようにするためのスニペット。普通にやろうとすると Application クラスやらが必要だったりめんどくさいので PDO のインスタンスから雑に使う方法。

---

`illuminate/database` をインストールします。

```sh
composer require illuminate/database
```

Connection を作成して Model にセットします。

```php
<?php
require __DIR__ . '/vendor/autoload.php';

use Illuminate\Database\MySqlConnection;
use Illuminate\Database\ConnectionResolver;
use Illuminate\Database\Eloquent\Model;

$host = '192.168.99.100';
$port = 3306;
$database = 'test';
$username = 'root';
$password = '';

$pdo = new PDO("mysql:host=$host;port=$port;dbname=$database", $username, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => 0,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$conn = new MySqlConnection($pdo);

$resolver = new ConnectionResolver([$conn]);
$resolver->setDefaultConnection(0);
Model::setConnectionResolver($resolver);
```

データベースを準備します。

```php
<?php
$sql = <<<SQL
drop table if exists users;
drop table if exists groups;

create table groups (
    id int not null primary key auto_increment,
    name varchar (100)
);

create table users (
    id int not null primary key auto_increment,
    group_id int not null,
    name varchar (100)
);

insert into groups values
    (100, 'A'),
    (200, 'B'),
    (300, 'C');

insert into users (group_id, name) values
    (100, 'ore'),
    (100, 'are'),
    (200, 'sore'),
    (200, 'dore'),
    (300, 'kore'),
    (300, 'more');
SQL;
Model::getConnectionResolver()->connection()->unprepared($sql);
```

モデルクラスを定義して使ってみます。

```php
<?php
class User extends Model
{
    public $timestamps = false;

    public function group()
    {
        return $this->belongsTo(Group::class);
    }
}

class Group extends Model
{
    public $timestamps = false;

    public function users()
    {
        return $this->hasMany(User::class);
    }
}

var_dump(User::query()->first()->group->toArray());
//=> [ 'id' => 100, 'name' => 'A' ]
```
Linux—ファイル閲覧するなら view コマンドを使えば良いじゃない ( Vim の閲覧専用モード )

## 結論

```
alias view="view -M"
```

## 思っていたこと

ファイルを読むのにどのコマンドを使っているだろう。

- less
- cat
- more

自分は `cat` 派。

「vimをファイル閲覧に使いたいけど、ミスって編集するのが嫌だな」と思っていた。

## 閲覧モードがあるじゃない

`view` コマンドを使ってみよう。
vim の閲覧専用モード ( `vim -R` ) がコマンド化されているもののようだ。 

vim の検索とか、キーストロークとか、全部使えていい感じ。

## 挙動

実はテキスト編集自体は出来てしまう。


![image](https://user-images.githubusercontent.com/13635059/44139422-fdd5e8e8-a0b1-11e8-97a3-83c3d2af834f.png)

保存ができない仕様。 ( `:w` )

![image](https://user-images.githubusercontent.com/13635059/44139437-0dac953c-a0b2-11e8-9922-b16150e6565e.png)

Vimを抜けるには強制脱出する。 ( `:q!` )

## 追記

`$ vim -M`

だと編集も出来なくなるようだ。

![image](https://user-images.githubusercontent.com/13635059/44236306-7c50fd80-a1e7-11e8-851c-ba0acfac1e61.png)


```
$ vim --help | grep \\-M
   -M			Modifications in text not allowed
```

エイリアス登録しておくと便利かもしれない。

```
alias view="view -M"
```

## 途中でやっぱり編集したくなった場合


```
:set write modifiable
```

を実行


```
:set write ma
```

でも良い ( `ma` は `modifiable` の短縮名 )

- [readonly - How can I exit from read-only mode in Vim? - Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/71109/how-can-i-exit-from-read-only-mode-in-vim)

## Links

- [Gist](https://gist.github.com/YumaInaura/4991cf0b5bbe434ba8a1a55698bfc86d)
- [Medium—imported](https://medium.com/supersonic-generation/linux-i-recommend-view-command-to-read-file-in-console-readonly-mode-vim-aad4bdaa2a7a)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
【ティラノスクリプト】選択済みの選択肢にマーク【glink】

選択肢ごとにいちいち[if]～[endif]と書くのが面倒だったからCSSとjsでどうにかするバージョン
[button]タグの場合は知らん

## CSS記述
まずは`tyrano.css`にこんな感じで記述
別のCSSファイルに記述して`[loadcss]`で読み込んでもいいです

```css:tyrano.css
/* 選択済みの選択肢にマーク */
.glink_button.checked::after{
    content: url("../data/image/button/glink_check.png");
    position: absolute;
    top: -10px;
    left: 90%;
}
```

`checked`っていうのが選択済みの選択肢に与えるクラスです。

## マクロ記述
次に選択肢ボタン用のマクロを記述
この中で選択済みの選択肢（＝通過済みのラベル）の場合は事前にCSSで記述しておいた選択済み選択肢用のクラスを追加する

```:macro.ks
[macro name="glink_ad"]
[iscript]
tf.label = "trail_" + mp.storage.replace(".ks", "").replace(/\u002f/g, "").replace(/:/g, "").replace(/\./g, "")
tf.label = tf.label + "_" + mp.target.replace("*", "")
tf.name = null
if(TYRANO.kag.variable.sf.record[tf.label] === undefined){
    tf.name = mp.name
}else{
    tf.name = mp.name + ",checked"
}
[endscript]
[glink * color="bk-image" name="&tf.name" clickse="button_click.ogg" enterse="button_hover.ogg"]
[endmacro]
```

基本的には通常の`[glink]`と指定できる属性等同じですが、マクロ内で呼び出し元のシナリオファイル名を取得する方法がわからなかったので`storage`指定は必須です。

## ロード時の処理
これだけだと、選択肢部分でセーブ、その後ロードしたときに表示される選択肢が選択済みのときにマークが反映されないので`make.ks`にこんな感じに記述

```:make.ks
[iscript]
var el = $(".glink_button")
for(var i = 0; i < el.length; i++){
    var glink = JSON.parse($(el[i]).attr("data-event-pm"))
    var label = "trail_" + glink.storage.replace(".ks", "").replace(/\u002f/g, "").replace(/:/g, "").replace(/\./g, "")
    label = label + "_" + glink.target.replace("*", "")
    name = null
    if(TYRANO.kag.variable.sf.record[label] === undefined){
    }else{
        $(el[i]).addClass("checked")
    }
}
[endscript]
```

cssをアレンジすればマークの追加以外にも色を変えたりいろいろできるはず
難点はラベルの通過を選択肢を選択したかの判断基準にしているので、選択肢は選択したけど次のラベルまで到達してない場合にマークがつかないこと　まあその辺はダミーのラベル通過させるとかすればよろし

何かの参考になれば幸いです
よくつかうかもしれないCSSアニメーション

###ゆっくり点滅２回

```css
.hoge-blink{
    animation: anime1 2s ease -2s 3;
    -webkit-animation:anime1 2s ease -2s 3;
}
@keyframes anime1 {
    0% {opacity:0;}
    100% {opacity:1;}
}
@-webkit-keyframes anime1 {
    0% {opacity:0;}
    100% {opacity:1;}
}

```

###要素を真ん中に表示
参考：http://hail2u.net/pub/test/631-2.html

```css
.hoge-box {
    bottom: 50%;
    display: inline;
    position: absolute;
    right: 50%;
    -webkit-transform: translate(50%, 50%);
    transform: translate(50%, 50%);
    vertical-align: top;
}
```


###ローディングくるくるずっと

```css
.hoge-img {
    display: block;
    -webkit-animation: spin 0.5s linear infinite;
    animation: spin 0.5s linear infinite;
}
@-webkit-keyframes spin {
    0% {-webkit-transform: rotate(0deg);}
    100% {-webkit-transform: rotate(360deg);}
}
@keyframes spin {
    0% {transform: rotate(0deg);}
    100% {transform: rotate(360deg);}
}
```
Flutter Android でもスワイプで戻る機能を有効にする

より新しい方法は https://qiita.com/najeira/items/dfa20d0104bd4457bc9a を参照

----

「iOSにおけるスワイプで戻る」をAndroidでも提供するために、CARTUNEでは画面遷移に`CupertinoPageRoute`を使っています。これはFlutterが提供しているクラスです。

- [CupertinoPageRoute](https://docs.flutter.io/flutter/cupertino/CupertinoPageRoute-class.html)

このPageRouteは、通常の画面遷移は横方向のスライド、ダイアログ（`fullscreenDialog: false`時）の場合は縦方向のスライドと、画面遷移のトランジションもiOS標準のものと同じようになっています。

この画面遷移の仕方はAndroidユーザーにとっても分かりやすいと思い、これでiOS/Androidともに統一しています。

ちなみに、画面遷移のたびに `CupertinoPageRoute` を書くのは手間なので、以下のような関数を用意して使っています。

```dart
Future<T> pushPage<T>(BuildContext context, WidgetBuilder builder, {String name}) {
  return Navigator.push<T>(
    context,
    new CupertinoPageRoute<T>(
      builder: builder,
      settings: new RouteSettings(name: name),
    ),
  );
}

Future<T> pushDialog<T>(BuildContext context, WidgetBuilder builder, {String name}) {
  final nav = Navigator.of(context, rootNavigator: true);
  return nav.push<T>(
    new CupertinoPageRoute<T>(
      builder: builder,
      settings: new RouteSettings(name: name),
      fullscreenDialog: true,
    ),
  );
}
```

使う側はこんな感じ:

```dart
// 結果のやりとりがない画面遷移
pushPage<void>(
  context,
  (BuildContext context) {
    return new YourPage();
  },
  name: "/foo/bar",
);
```

```dart
// 何らかの画面を表示し、その画面から結果を受け取るような処理
final future = pushDialog<int>(
  context,
  (BuildContext context) {
    return new YourDialog();
  },
);

// pop時に渡した値が入ってくる
final result = await future;
```

※サンプルコードのライセンスは MIT とします。

※CARTUNEの実際のコードでは、歴史的経緯などにより`MaterialPageRoute`を継承した`MyPageRoute`を定義し、その内部から`CupertinoPageRoute`を使っていますが、記事のように直接`CupertinoPageRoute`を使っても大丈夫なはずです。

※歴史的経緯とは、以前のFlutterでは`MaterialPageRoute`を前提としたコードがあったことです。ただ、[このコミット](https://github.com/flutter/flutter/pull/15643) により直っているので、いまは`CupertinoPageRoute`直でいいはず。
LetsEncryptを導入

* 環境
    * Ubuntu 16.04.3 LTS (Xenial Xerus)
    * Apache/2.4.18


## Lets'sencryptの設定

letsEncryptのリポジトリをcloneしてきたら、以下を実行します。
よくわからなくてもとりあえず、実行します。


`./letsencrypt-auto --apache -d (ドメイン)`

そして、ssl.confに以下が追記されていること、同時にそれぞれのディレクトリに　ファイルが配置されていることを確認します。


```sh
ServerAlias (ドメイン)
SSLCertificateFile /etc/letsencrypt/live/(ドメイン)/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/(ドメイン)/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
```

以下のコマンドで、SSLの更新します。crontabに設定しておくといいかもしれません。

`/opt/letsencrypt/certbot-auto renew -n`

## ファイアウォールの設定


以下のコマンドで、SSLの更新

* `sudo ufw allow 443`←ポートを開放
* `sudo ufw reload`←ファイアウォールを再起動
* `sudo ufw status`←ファイアウォールの確認

以上のコマンドで、ファイアウォールが有効かを確認します。


## ページを更新して確認

自分のページをリロードして確認します。


## 参考URL

以下、参考URLです。

[Let’s Encrypt](https://letsencrypt.org/)
[プログラマー備忘録](https://sankame.github.io/blog/2015-12-07-letsencrypt_setup/)
[同期は考える](https://doukigayameta.com/archives/282)
yaml_vaultとRailsとconfigまわり

# 背景

* Rails5.2でencrypted secretsが導入されたが取り回しがしにくい
* [yaml_vault](https://github.com/joker1007/yaml_vault) は便利
* Rails5.2でconfig/secrets.ymlを置いても ```Rails.application.secrets``` にロードしてくれない
* 自前で任意のyamlをロードするようにしてもよいが、[config](https://github.com/railsconfig/config) を使うと規定できて楽

configとyaml_vaultの詳細についてはそれぞれのドキュメントを参照

# 整備

## セットアップ

```rb:Gemfile
# ...
gem 'config'
gem 'aws-sdk-kms'
gem 'yaml_vault'
```

```bash
$ bin/rails g config:install 
```

```text:.gitignore
config/settings.yml
config/settings.local.yml
config/settings/*.yml
```

gitignoreはデフォルトだとlocal系のみになっているのですべて対象にする。

## rakeタスク追加

```rb:yaml_vault.rake
YAML_VAULT_ARGS = '--cryptor=aws-kms --aws-kms-key-id=your-key-id'

namespace :yaml_vault do
  desc 'encrypt'
  task :encrypt do
    target_files = ['config/settings.yml'] + Dir.glob('config/settings/*')
    target_files.each do |target|
      dst = target.sub('config/', 'config/encrypted/')
      FileUtils.mkdir_p(File.dirname(dst))
      `bundle exec yaml_vault encrypt #{target} -o #{dst} #{YAML_VAULT_ARGS}`
    end
  end

  task :decrypt do
    Dir.glob('config/encrypted/**/*').each do |encrypted_file|
      next if FileTest.directory?(encrypted_file)
      dst = encrypted_file.sub('config/encrypted/', 'config/')
      FileUtils.mkdir_p(File.dirname(dst))
      `bundle exec yaml_vault decrypt #{encrypted_file} -o #{dst} #{YAML_VAULT_ARGS}`
    end
  end
end
```

上記例ではaws-kmsを使っているが、YAML_VAULT_ARGSを適宜書き換える。
暗号化したファイルはconfig/encrypted以下に出力している。

## capistrano統合

```rb:deploy.rb
namespace :deploy do
  task :decrypt_secrets do
    on roles(:app) do
      within release_path do
        execute :bundle, :exec, :rake, 'yaml_vault:decrypt'
      end
    end
  end

  before :updated, :decrypt_secrets
end
```

capistranoのhookタイミングとしてはupdatedがよさそう。
pyenvでPythonのバージョンを切り替えられない場合の対処法＋

`Python 3.5`を使う必要があり、[pyenv] (https://github.com/pyenv/pyenv)で設定を行なったのですが、Pythonのバージョンを切り替えられない問題にぶつかったので初投稿です。


# 想定読者
下記の記事を読んでも、この問題を**解決できなかった方**を想定しています。

- [pyenvのインストール、使い方、pythonのバージョン切り替えできない時の対処法] (https://qiita.com/koooooo/items/b21d87ffe2b56d0c589b)
- [pythonのバージョンが切り替わらない] (https://qiita.com/mckyhrs/items/94a2db3506287df0420e)
- [Mac OS Xで複数バージョンのPythonを利用する（１）複数Verインストール編] (https://qiita.com/_rdtr/items/3927e042b2ca18f03b8c)


# 環境情報
- OS : macOS High Sierra 10.13.6（17G65）
- Shell : bash


# [前提] 問題にぶつかるまで
アクション開始前の状況です。

```
$ python --version
Python 2.7.10
```
<br>

https://github.com/pyenv/pyenv#homebrew-on-mac-os-x を参考に、Homebrewを使用して`pyenv`をインストール。

```
$ brew update
$ brew install pyenv
```
<br>

`pyenv`を使用して、`Python 3.5.6`をインストール。

```
$ pyenv install 3.5.6
```
<br>

バージョンを切り替える前。

```
$ pyenv versions
* system
  3.5.6 (set by $HOME/.pyenv/version)
```

バージョンを切り替え。

```
$ pyenv global 3.5.6
```

バージョンを切り替えた後。

```
$ pyenv versions
  system
* 3.5.6 (set by $HOME/.pyenv/version)
```
<br>

Pythonのバージョンを確認してみると…

```
$ python --version
Python 2.7.10
```
orz
<br>
各コマンドの参照先は以下の通り。

```
$ which python
/usr/bin/python
```

```
$ which pyenv
/usr/local/bin/pyenv
```
<br />

`~/.bash_profile`の`$PATH`に`$HOME/.pyenv/shims`を追加してみたものの…


```
$ python --version
Python 2.7.10
```

`/etc/paths`を確認。この設定でも、`/usr/bin/python`が優先実行されてしまう。

```
/usr/bin/python
/usr/local/bin/pyenv
```


# 解決方法
https://github.com/pyenv/pyenv#homebrew-on-mac-os-x を読み直してみたら、「`pyenv init`を使うように！」とあったので、早速実行。

```
$ pyenv init
# Load pyenv automatically by appending
# the following to ~/.bash_profile:

eval "$(pyenv init -)"
```

指示通り、`~/.bash_profile`に`eval "$(pyenv init -)"`を追記して、`source ~/.bash_profile`を実行したところ…

```
$ python -V
Python 3.5.6
```
<br>

解決！
ドキュメントはきちんと読めということですね（反省）
jQuery UIを使用した連動セレクトボックスでハマったこと

#コピペプログラマーメモ
##jQuery UIを使用した連動セレクトボックス、selectmenuの仕様でハマった
###概要
連動セレクトボックスをjQueryを使用して実装していた。
デザイン会社さんからの上がってきたデザインにも、同じように実装したら、まずchangeイベントが発火しない。
イベントが発火しても、連動した選択肢が切り替わらなかった
####changeイベント発火方法
通常
`$('.parent').change(function () {`
jQuery UI selectmenu
`$('.parent').on('selectmenuchange', function() {`

コピペサイト
- http://sengokuzidaiprogram.seesaa.net/article/438406581.html
- https://teratail.com/questions/30485

####選択肢切り替え
>実際に表示されるコンポーネントも、ボタンのように選択された項目が表示されている状態のものと、クリックして画面に表示される、選択項目がずらりと並ぶリストの２つから構成されていることが分かります。

>ただ操作するだけではいけません。これだけでは、jQuery Mobileのセレクトリストの項目は変化しません。なぜなら、<option>タグや<select>タグを操作しても、セレクトメニューの表示が変わるわけではないからです。

html側とjQuery UI側的な?html側をいくら変えても、jQuery UIも変えてやらないと画面上での表示が切り替わらない。
処理の最後に`$('.children').selectmenu('refresh');`としてあげることで解決

コピペサイト
- https://www.tuyano.com/index3?id=643002&page=3
- http://lifelog.main.jp/wordpress/?p=2676
Linux—実行権限のないファイルに対してコマンド補完が効かない

Linuxが良い意味で驚かせてくれた。

## 確認

実行ファイルを作る。

```
touch example.sh
```

コマンド補完で実行しようとするが、なぜか補完できない。なぜだ？

```
./exa
```


## 答え

実行権限をつけていないから。

```
chmod +x example.sh
```

`chmod` すれば補完が有効になる。

```
./example.sh
```

すごいねLinux!


## Versions

- Docker version 18.03.1-ce, build 9ee9f40
  - `$ docker run --interactive --tty ubuntu /bin/bash`

## Links

- [Linux—Command completion does not work when try to execute no extension file](https://gist.github.com/YumaInaura/c2f6a97047e42a2c19da7673551cd11b)
- [Medium imported](https://medium.com/supersonic-generation/linux-command-completion-does-not-work-when-try-to-execute-current-directory-file-directly-no-42fb98ad341)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Watson STT（Speech to Text）におけるCustom Modelについて

音声認識ド素人のため、Watson STTのリファレンスだけ読んでも、"Custom XXX Model"がなんなのかさーっぱり分からなかったので、自分用メモがてらまとめておく。

※注意※
原文載せても意味ないので、自分なりの解釈をして載せています。
誤った捉え方をしていて、不適切な記載をしている可能性がありますので、
予めご了承ください。
（精通されている方で、お気づきのことがあればコメントにてご指摘いただけますと幸いです。）

# 目次
1. 音声認識における「音響モデル」と「言語モデル」
2. STTにおける「音響モデル」のカスタマイズ
3. STTにおける「言語モデル」のカスタマイズ
4. まとめ

# 音声認識における「音響モデル」と「言語モデル」
## 音声認識の手法
一言で音声認識と言っても、その手法は様々。
昨今主流となっているのが「統計的手法」で、入力された音声の特徴を抽出し、蓄積されたデータから抽出された特徴と比較して、最も近いものを認識結果とするもの。
## 音響モデル
音響的特徴を定義したもの。それぞれの音素がどういう周波数を持っているのか、という特徴を定義することで、入力データから抽出された特徴と照合し、音素を特定する。
## 言語モデル
音素の並びから単語や文章を定義したもの。音素の並びや、文脈的特徴などから、単語や文章を定義することで、音素を文章に変換する。
## 音声認識のフロー
音声認識は以下のプロセスを踏み、音⇒テキストへの変換を実現している。

|#|プロセス|説明|
|:-:|:--|:--|
|1|音響処理|デジタル化された音声信号から「音響」として認識可能なデータへ変換する。ノイズや周波数の歪みを調整することも。 |
|2|音響モデルの適用|入力されたデータの周波数から近い音響モデルを適用し、「音素」を特定する。音声を全て平仮名で文字列表記できるところまで特定するイメージ。|
|3|言語モデルの適用|特定された「音素」を意味のある「言語」にしていく。音素の並びに対して言語モデルを適用し単語、文章にする。平仮名⇒漢字を交えた文章にしていくイメージ。|

## 音響モデル・言語モデルの考察
音響モデルは「方言」の適用なんかで重要になってくるかと思う。
私の出身地でもある茨城では、「か⇒が」などのように濁音化して発音されることが多い。
> ここの先は危ないよ

例えば上記のような文章を方言の強いうちのばあちゃんが読んだ場合、
茨城モデルが適用されていないと、、、
> 午後の詐欺は危ないよ

などと認識されてしまう。
（極端ではあるが）

一方で言語モデルは割とイメージしやすく、例えば専門用語なんかは
言語モデルとして登録していないと正しく認識されないだろう。

一般的に教師データが多いほどAIの認識・分析精度が高くなる、と言うのは、この音響モデルと言語モデルがより高度でかつ対象とする領域に近いモデルに改善するためだろう。

# STTにおける「音響モデル」のカスタマイズ
ちょっとこっちまで手を出している余裕が今ないため、
いったん塩に漬ける。

# STTにおける「言語モデル」のカスタマイズ
STTにおいて、言語モデルをカスタマイズするには、Custom Language Modelを登録し、
それをWatsonに学習させることで精度が変化してくるそう。
何も登録しなくても、デフォルトで「ベースモデル」が登録されているので、それっぽい音声認識はできるが、例えば業界特有の会話や専門用語などは個別にモデルを作成しWatsonに勉強してもらう必要がある。
## Custom Language Modelの登録
まずは、新たなモデルを登録する。
この時点では空っぽのモデルだが、これに後述するコーパスなりワードなりを登録していくことでWatsonの学習するモデルとして仕立てていく。
## コーパスの登録
作成したモデルに対して「コーパス」を登録する。
コーパスとはWatsonが学習する際に使う「読み物」というイメージ。専門分野の論文や本、またはニュース記事など、プレーンテキストファイルの形式でコーパスとして登録していく。
これにより、Watsonが与えられた文章を分析し、個々の単語が使われている文脈・前後関係を学習する。
音声認識の精度を上げるためには、このコーパスをできるだけたくさん登録してWatsonに学習させてあげる必要があるそう。（後述するワードよりもこっちの方が影響度はでかいらしい）
辞書よりもたくさん本を読ませたほうが、頭がよくなるようだ。
## ワードの登録
こちらも作成したモデルに対して、個々の単語を登録する。
コーパスとは違い、個々の単語をJSON形式のデータとして定義してモデルに登録する。専門用語などWatsonが言語として知らない単語は、ワードとして登録しないといけない。
## モデルの学習
モデルを作成しただけでは、まだ教材を作成しただけに過ぎないため、この教材を使ってWatsonに学習してもらう必要があるのでお忘れなく。
この際に、モデルの重みを設定でき、このモデルをどれだけ影響させることができるか調節出来るらしい。「ここテストにでるぞー」と言ってからプリント配るのと、「時間ある時にさらっと読んでおけー」とプリントを配るのとの違いみたい。

# まとめ
STTで操作できるパラメータ（モデル）を調べることで、音声認識の一般的な流れと、モデルについて知ることができ、STTのパラメータの意味も理解することができた。
まずは言語モデルをカスタマイズしてみて、認識精度がどう変わっていくか試してみようと思う。

# 参考
https://ja.wikipedia.org/wiki/%E9%9F%B3%E5%A3%B0%E8%AA%8D%E8%AD%98#%E8%AA%8D%E8%AD%98%E6%8A%80%E8%A1%93
http://www.i.ci.ritsumei.ac.jp/~shirai/media-up2.pdf
https://www.ibm.com/watson/developercloud/speech-to-text/api/v1/node.html?node
https://console.bluemix.net/docs/services/speech-to-text/language-resource.html

最初のWikipediaの記事は分かりやすかったです。
iphoneの戻るリンクのメモ

## 現象
Backboneで作られたSPAのある画面に戻るリンクがあって、それをclickイベントハンドラーで、`Backbone.history.history.back();`によって全画面に戻ります。
しかし、iPHoneSE実機で確認するときに、戻るリンクをクリックしても、画面遷移は発生しません。

```
<a class=".backHoge" href="#">戻る</a>
```

### 原因推測
iPhoneの場合、クリックすると、`window.location+"#"`のような画面遷移が先に発生してしまい、その後、既存画面に戻してしまうので、実質、画面遷移が発生しなくなるではないかと推測します。


### 対応案
- 案１
  hrefを空白""に変更
  うまく戻れるが、もうリンクではなくなる

- 案2
　　　　aタグをやめて、pまたはbuttonに変更する
MongoDBをバージョン4.0にアップグレード in Docker

[MongoDB4.0がリリース](https://docs.mongodb.com/manual/release-notes/4.0/)され、ついにMongoにもトランザクションが導入されました。

トランザクションは是非とも利用したいので現在稼働しているMongoを3.4から4.0にアップグレードしようと思います。

MongoはDocker上で１コンテナとして起動しています。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
d06abb0b764a        mongo               "docker-entrypoint.s…"   2 months ago        Up 13 minutes       27017/tcp                mongo
```

バージョンは3.4

```
$ docker exec -it mongo bin/bash
root@d06abb0b764a:/# mongo --version
MongoDB shell version v3.4.16
```

Mongo公式に沿ってアップグレードを進めていきます。
https://docs.mongodb.com/manual/release-notes/4.0-upgrade-standalone/



ただ、3.4からアップグレードを試みると、以下のように失敗します。

```
db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } )
{
	"ok" : 0,
	"errmsg" : "Invalid command argument. Expected '3.6' or '3.4', found 4.0 in: { setFeatureCompatibilityVersion: \"4.0\", $db: \"admin\" }. See http://dochub.mongodb.org/core/3.6-feature-compatibility.",
	"code" : 2,
	"codeName" : "BadValue"
}
```

ということで、まずは3.6へのアップグレード
https://docs.mongodb.com/manual/release-notes/3.6-upgrade-standalone/

## 3.4 →　3.6

まずは、Mongo3.6のイメージをpull

```
docker pull mongo:3.6
```

docker-composeを利用している方は、`docker-compose.yml`のimageを3.6にして、`docker-compose up -d`

``` docker-compose.yml
  mongo:
    image: mongo:3.6
```

で、mongo3.6で起動したコンテナ内でFCVを3.6にする

```
> db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
{ "ok" : 1 }
```

これだけ！

## いざ4.0へ


### DockerHubから最新バージョンをインストール

DockerHubにあるMongoを確認すると、すでに4.0がlatestバージョンになっていました。

```
docker pull mongo:latest
```

コンテナをlatestにして再起動

```
  mongo:
    image: mongo
```

```
docker-compose up -d mongo
```

### FCVを4.0にする

```
> db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } )
{ "ok" : 1 }
```


お疲れ様でした。これでアップグレード完了となります。

## 悲報

すでにお気づきの方いらっしゃるかもしれませんが、トランザクションはレプリカセットの場合のみ対応してます。。。
そう、この手順スタンドアローンなんです。mongo1台で運用してるんです。。。

ということで、次はレプリカセットの設定をしていきます。

今回はここまで。
RaspberryPiへのUSBカメラと純正カメラモジュールの接続

（この記事は2018/8/15に作成しています）
 
# 概要
RaspberryPiの用途は様々ですが、一般的で用途も広いセンサであるカメラを取り付けてみます。

まずはRaspberryPiのカメラを有効にします。

```ssh

$ sudo raspi-config
```

"5 Interfacing Options" → "P1 Camera"と進み、カメラを有効にしてください。有効にしたら再起動します。

<img width="566" alt="スクリーンショット 2018-08-15 13.55.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/227728/69cd56d4-f103-ce93-8aaa-4ba83ead0239.png">

## 純正のカメラモジュールの場合
純正のカメラモジュールにはいくつかの種類があり、赤外線カメラや広角レンズも存在するようです。今回は、"Piカメラ Official V2 for 3/2/1/0"を使用します。専用のスロットにしっかりと取り付けてから電源を接続します。

まずは認識されているか確認します。

```
$ vcgencmd get_camera
```
suppoted=1 detected=1 となっていれば、カメラの準備ができています。


早速撮影テストをしてみます。下記のコマンドを入力すれば撮影されます。

```:写真の撮影
$ raspistill -o photo.jpg
```
photo.jpgを変更すれば保存名を変更することが可能です。拡張子は.jpgから変更しないようにしてください。

続いて動画も撮影します。コマンドは以下の通りです。

```:動画の撮影
$ raspivid -o video.mp4 -t 10000
```

このとき、ファイル名は "video.h264" となります。 -t 以下には動画の撮影時間を指定することができます。 10000なら10,000ミリ秒、すなわち10秒です。

この状態では.h264形式で保存されています。使いやすいようにmp4形式に変換します。変換には "gpac" をインストールしてから、以下の通りコマンドを実行します。


```:gpacのインストール
$ sudo apt-get install gpac -y
```


```:動画の変換
$ MP4Box -fps 30 -add video.h264 video.mp4
```

また、動画ファイルをダブルクリックで再生するためには、ファイル形式とアプリケーションの関連付けが必要です。GUIから右クリック→ファイルのプロパティ→開くアプリケーション→カスタマイズから、以下の通り設定することで、ダブルクリックで再生されるようになります。

<img width="404" alt="スクリーンショット 2018-08-15 14.44.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/227728/d44d48ef-a12e-06c2-f8c5-38283c60044a.png">

・実行するコマンドライン
/usr/bin/omxplayer -b -o alsa

・端末エミュレータで実行する
チェックを入れる

・アプリケーションの名前
Omxplayerと入力

なお、VNC接続、ssh接続ではカメラに映る画面や動画ファイルを確認することはできません。

## 市販のUSBカメラの場合

USBカメラをRaspberryPiに接続します。RaspberryPiに認識されているかどうか、以下のコマンドを入力して確認してください。

```:認識の確認
$ lsusb
$ ls /dev/video*
```

USBスロットにカメラが接続されていることと、デバイスドライバがインストールされているかを確認してください。

USBカメラの表示には、guvcviewを使用します。下記コマンドからインストールしてください。

```:guvcviewインストール
$ sudo apt-get install guvcview
```

インストール完了のあと、GUIからguvcviewをダブルクリックなどで実行すれば、撮影画面が表示されます。スタートメニュー→サウンドとビデオ　に追加されています。


（追記）
luvcviewを使用してもRaspberryPiのプレビュー画面が見られることがあるようです。
luvcviewはコマンドラインから起動します。

```:luvcviewインストールと実行
$ sudo apt-get install luvcview
$ luvcview
```

（おわり）
visualstudioで作ったc#アプリからのスクリーンショットがずれた時の対処

c#で有るタイミングでスクショをとって暗号化して保存するやつを作っていたときにはまった部分。
**app.manifestを書きかえることでHighDPIに対応する**
visualstudioの
プロジェクト>新しい項目の追加>アプリケーションマニフェストファイル
を選択し追加。

```
  <!-- アプリケーションが DPI 対応であり、それ以上の DPI で Windows によって自動的にスケーリングされないことを
       示します。Windows Presentation Foundation (WPF) アプリケーションは自動的に DPI に対応し、オプトインする必要は
       ありません。さらに、この設定にオプトインする .NET Framework 4.6 を対象とする Windows Forms アプリケーションは、
       app.config ファイルで 'EnableWindowsFormsHighDpiAutoResizing' 設定を 'true' に設定する必要があります。-->
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>
```
この部分のコードのところのコメントを外す。
あとは心おきなくCopyFromScreen等をやる。
「Let's Encrypt」で無料HTTPS

# **実行環境**
- CentOS6
- apache 2.2

## **Step1**
## **certbotのインストール**
「certbot」とは？
Let’s Encryptが提供しているクライアントソフトウェアです。
これを使えば楽々に証明書を取得して更新できるようになります。

```bash
//インストール
$ sudo curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto

//権限付与
$ sudo chmod 700 /usr/bin/certbot-auto
```

## **Step2**
## **certbot-autoで証明書を発行**
certbotのインストールができたら、
証明書を発行していきます。

```bash
//発行
$ certbot-auto certonly --webroot -w /var/www/hoge -d hoge.com --email hoge@hoge.com

// certbot-autoコマンドの詳細
certbot-auto certonly            // 証明書の作成
    --webroot                    // 既存のウェブサーバを使うモードを選択
    -w /var/www/hoge             // ドキュメント・ルートのパス
    -d hoge.com                  // 認証するドメイン名
    --email <メール>@<アドレス>     // メールアドレス登録 (証明書期限切れの通知用)
```

hogeは利用するドメインに合わせて変えましょう。

以下のようなメッセージが出たら発行成功です。

```
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/hoge/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/hoge/privkey.pem
   Your cert will expire on 2017-12-23. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:
```

## **Step3**
## **apacheに証明書を設定する**

発行された証明書の確認をします。

```bash
$sudo ls /etc/letsencrypt/live

//ドメイン別でディレクトリが生成されます。
drwxr-xr-x 2 root root 4096 Aug 15 14:48 hoge.com

$sudo ls /etc/letsencrypt/live/hoge.com

//中にシンボリックリングが貼られています。
total 4
-rw-r--r-- 1 root root 543 Mar 24 00:59 README
lrwxrwxrwx 1 root root  34 Aug 15 14:48 cert.pem -> ../../archive/hoge.com/cert3.pem
lrwxrwxrwx 1 root root  35 Aug 15 14:48 chain.pem -> ../../archive/hoge.com/chain3.pem
lrwxrwxrwx 1 root root  39 Aug 15 14:48 fullchain.pem -> ../../archive/hoge.com/fullchain3.pem
lrwxrwxrwx 1 root root  37 Aug 15 14:48 privkey.pem -> ../../archive/hoge.com/privkey3.pem
```

こいつらをapacheに読み込ませていきます。

```bash:/etc/httpd/conf/httpd.conf
<VirtualHost *:443>
        SSLEngine on
        SSLCertificateFile /etc/letsencrypt/live/hoge.com/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/hoge.com/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/hoge.com/chain.pem

        ServerAdmin hoge@hoge.com
        DocumentRoot /var/www/hoge
        ServerName hoge.com
</VirtualHost>
```

設定が終わったら、apacheを再起動します。

```bash
service httpd restart
```

## **LastStep**
## **自動更新の設定**

Let'sEncryptを利用する上で気をつけたい点があります。
**証明書の有効期限は90日で切れます。**
なので、証明書を自動で更新するようにしましょう。

```bash
$sudo crontab -e

//毎週火曜の16時にrenewが起動する。
/usr/bin/certbot-auto renew --post-hook "sudo service httpd restart"
```

## **最後に**

SSLの設定が終わったら
HTTP→HTTPSへのリダイレクトなど行うのが普通ですが
それはまたの機会に...
論理学って何を扱うの？論理学入門

## 記事の内容

「論理」

数学やコンピュータサイエンスの基礎に位置付けられるものが論理です。

そして、「論理そのもの」を学問するのが論理学です。

そこで、この記事では論理学の初歩を確認します。
* 論理学とは、いったい何を対象にする学問なのか？
* 論理学とは、どのような方法をとる学問なのか？

### 参考文献　野矢茂樹の『論理学』
野矢先生の本からまとめさせていただきます！
[野矢茂樹　論理学](https://www.amazon.co.jp/exec/obidos/ASIN/4130120530/hatena-blog-22/)

本書は序文にて、こんな言葉からスタートします。
>「論理的に正しい」とはどういうことなのだろうか。そしてそれは何と対比された概念なのだろうか。

気になりますね。それでは、論理学の入口について整理していきましょう。

## 言葉と論理

論理という言葉は、「その言い方は論理的じゃないよね」など、日常でもよく使います。それなら、論理学であつかう「論理」も同じようなものなのでしょうか。「論理」とは厳密には何なのでしょう。

一般的には、論理的であるかどうかは言葉の意味に依存します。そのため、言語使用一般について、言葉の意味という観点から、「正しい正しくない」という意味が論理と関係していそうです。

それでは、「論理」を説明してみるとどうなるか。


「論理的」ということを「言葉使いの正しさ」だけで説明しようとする。ところが、「言葉遣いの正しさ」は、再び「論理的」ということで説明されてしまう。

**循環だ。**

これは、「論理的」ということと、「言葉使いの正しさ」とが不可分だということを意味する。

うーん、なるほど。

しかし、まだ考える範囲が広すぎます。

だから、論理学という学問では、「言葉使いの正しさ」の中でも、ある要素だけを取り上げます。

それは、「推論」です。


## 命題論理があつかう対象

論理学が対象とする領域とはなんでしょう。ここでは、論理学の基礎となる命題論理という分野について考えます。

命題論理という分野は、言語使用一般の論理を扱うわけではありません。言語をまるっと全て扱おうとすることは不可能です。あらゆる学問は対象を持ちます。限定が必要です。

 
命題論理の対象とは**推論形式**です。


形式の例
>PならばQではない

>Q

>それゆえ、Pではない


ある形式を満たす推論を正しい推論である、と定義するのです。
ゆえに、推論に関わる、 **「ではない」「ならば」** という言葉の意味もポイントになります。

命題論理では、推論形式に関与する「ではない」「ならば」などの、否定詞と接続詞のみに注目するのです。


**「命題論理」とは、否定詞と接続詞の論理学**、と一言で表せます。

そして、最も有名な推論こそ、三段論法でしょう。

    AならばB 
    A
    よって、B

この形式の推論を正しい推論と定義するから、三段論法は正しい推論なのです。

 
命題論理という学問は、言葉という広大な海の中で何を対象とするのか、どう構築しているのか。この基礎部分の考え方はとても大事です。日常言語の実践と、命題論理との間のギャップについて理解が深まりました。


## 様々な切り出し方がある
命題論理という方法は、あくまでも日常言語の使用から一部を切り出したものに過ぎません。つまり、切り出し方は他にも色々とあるのです。

**命題論理が唯一絶対なものではない。**

なので、基本的な概念の使い方や、それにともなう論理法則の決め方により、様々な「論理学」が研究されています。

## 論理と計算の行き着く先には
個人的に、論理学と計算論の関係が気になっています。

* 論理と計算の行き着く先がどうなるのか？
* 数学と論理の関係はどうなっているのか？

いくつかのリンクをまとめておきます。どれも、最高に**知的にスリリング**な話題です。興味がある方はぜひ。

https://www.buchinuku.work/entry/2019/7/28

https://www.buchinuku.work/entry/2019/12/11

https://www.buchinuku.work/entry/2019/11/1
pandas.DataFrameの型を変えたいけど例外レコードがあってastypeできない時の対処法

pandas.DataFrameにおけるString型列をfloatやint形式に直したい時がある。欠損値がある場合でも、`astype(float)`をすることによりfloat形式に変換することは可能だ。しかし、実データを扱う際には例外レコード（数値が入っているはずなのに記号が入っているなど）が紛れ込んでいることも多く、`astype`変換ではできないことがある。

そんな時には`pandas.to_numeric`を使おう。

```python
df["数値変更したい列"] = pd.to_numeric(df["数値変更したい列"], errors='coerce')
```

errosに対応するパラメータには３種類存在し、それぞれ以下の役割を持つ。

- `raise`：例外データがあることを表示し、エラーを返す
- `coerce`：例外データ部分をNaNで返し、他の行は数値変換する
- `ignore`：例外データがある場合には数値変換はせず、inputのDataFrameをそのまま返す


詳しくは公式のレファレンスを参照。
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.to_numeric.html

なお、`convert_objects`による数値変換も存在するようだが、現在では非推奨になっている模様。
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.convert_objects.html
will_paginate to kaminari 

# 概要
- will_paginateとkaminariが混在しているのでkaminariに寄せたい

# 対応
## will_paginateの`.paginate`が使われている部分をkaminariの`.page`や`.per`などに書き換える

```rb
Hoge.paginate(page: params[:page], per_page: PER_PAGE)

# ↓

Hoge.paginate.page(params[:page]).per(PER_PAGE)
```
SSH 鍵作成手順

今更ながら。。。

**作成した秘密鍵は厳重に管理すること!**


## Tera Term の場合

1. **設定 - SSH 鍵生成** をクリックする。
   - *TTSSH: 鍵生成* ウィンドウが表示される。
1. 以下の通り設定し, **生成** ボタンを押下する。
   - 鍵の種類: **ED25519**
   - ラウンド数: (初期値)
1. **公開鍵の保存** ボタン, 及び, **秘密鍵の保存** ボタンを押下し, それぞれの鍵を保存する。
   - *鍵のパスフレーズ,* 及び, *パスフレーズの確認* は, それぞれ空欄のままとする。


## CentOS 7 の場合

1. SSH 鍵を生成する。
   - `$ ssh-keygen -q -t ed25519 -N "" -f ~/id_ed25519`
1. 以下のファイルが生成されるので, SFTP で回収する。
   - `~/id_ed25519` (秘密鍵)
   - `~/id_ed25519.pub` (公開鍵)


どっとはらい。
Python list.sorted() における NaN値の扱い

Pythonのlist.sorted()は、比較要素にNaN値が含まれると正しくソートできない。比較要素内にNaN値がある場合は、それらを適当な値に置き換える必要がある。

### サンプルコード
    import numpy as np

    a1 = [1, 2, 9, 3, 2, np.nan, np.nan] # 例題 a1
    a2 = [1, np.nan, 2, 9, 3, 2, np.nan] # 例題 a2

    # 単純なSortの実行
    ng1 = sorted(a1, key=lambda x: x)
    ng2 = sorted(a2, key=lambda x: x)

    # NaN値を置き換えてのSortの実行
    ok1 = sorted(a1, key=lambda x: np.inf if np.isnan(x) else x)
    ok2 = sorted(a2, key=lambda x: np.inf if np.isnan(x) else x)

    print("NG:", ng1, ng2) # 例題 a2 を正しくソートできない
    print("OK:", ok1, ok2) # 両例題とも正しくソートできる

### 実行結果
    NG: [1, 2, 2, 3, 9, nan, nan] [1, nan, 2, 2, 3, 9, nan]
    OK: [1, 2, 2, 3, 9, nan, nan] [1, 2, 2, 3, 9, nan, nan]
VNC 利用手順まとめ

Windows 上の Tera Term より CentOS に SSH 接続し, VNC Server を起動させた際の手順まとめ。


## 参考: VNC の SSH ポート転送番号

途中で SSH のポート転送に使用する番号は, IANA のプライベートポートと, CentOS のローカルポートレンジの重複区間としている。

- [Service Name and Transport Protocol Port Number Registry](https://www.iana.org/assignments/service-names-port-numbers/)

   - *the Dynamic and/or Private Ports (49152-65535)*

- ```
  $ cat /proc/sys/net/ipv4/ip_local_port_range
  32768   60999
  ```

そのため, SSH ポート転送番号は 49152 から 60999 までの間であれば, 不具合が少ないと考えられる。


## VNC Viewer ダウンロード

1. Web ブラウザーを開き, [TigerVNC](http://tigervnc.org/) にアクセスする。
   - RHEL (CentOS) が採用している VNC は TigerVNC のため, クライアントも合わせる。
1. 画面上部の **Releases** をクリックする。
   - GitHub の Releases ページに遷移する。
1. 画面を少しスクロールし, 最新バージョンの **Binaries are available from bintray:** の後に記載されているリンクをクリックする。
1. 使用している Windows のビット数に応じて, バイナリーをダウンロードする。
   - 64 ビット: **vncviewer64-x.x.x.exe**
   - 32 ビット: **vncviewer-x.x.x.exe**
      - なお, `> mklink /H vncviewer.exe vncviewer64-x.x.x.exe` などでリンクを作ってからショートカットを作成すると, アップデート時のショートカット作り直しの手間が少し省ける。


## VNC Server 起動

1. VNC Server を起動する。
   - `$ vncserver`
      - 大きめのウィンドウにする場合は, -geometry オプションで調整する: `$ vncserver -geometry 1280x1024`
   - 途中で VNC 接続用のパスワードを入力する。
   - view-only password は不要 **(n)** とする。

        ```
        You will require a password to access your desktops.

        Password:
        Verify:
        Would you like to enter a view-only password (y/n)? n
        A view-only password is not used
        xauth:  file /home/ryo-sato/.Xauthority does not exist

        New 'test91:1 (ryo-sato)' desktop is test91:1

        Creating default startup script /home/ryo-sato/.vnc/xstartup
        Creating default config /home/ryo-sato/.vnc/config
        Starting applications specified in /home/ryo-sato/.vnc/xstartup
        Log file is /home/ryo-sato/.vnc/test91:1.log
        ```

   - ホスト名の右に表示される番号がディスプレイ番号となる。
      - 5900 足すと, VNC Server が LISTEN しているポート番号になる。

## VNC 接続

1. Tera Term を以下の通り設定し, SSH ポート転送を有効化する。
   1. **設定 - SSH 転送** をクリックする。
      - *SSH ポート転送* ウィンドウが表示される。
   1. **追加** ボタンをクリックする。
      - *ポート転送を行う向きの選択:* と表示されたウィンドウが表示される。
   1. 以下の通りに入力し, **OK** ボタンを押下する。
      - ローカルのポート: **55901** (49152 から 60999 までの間であれば OK. 今回は VNC のポート番号に 50000 足しただけ。)
      - リッスン: (空欄)
      - リモート側ホスト: **127.0.0.1**
      - ポート: **5901**
   1. *SSH ポート転送* ウィンドウに戻るので, そのまま **OK** ボタンを押下する。
1. VNC Viewer を起動し, 以下の通りに入力, **Connect** ボタンを押下する。
   - VNC server: **127.0.0.1:55901**
1. *VNC authentication* 画面が表示されるので, パスワードを入力し, **OK** ボタンを押下する。
   - X Window System が表示される。


## アプリケーション起動例: Firefox の場合

- Tera Term の場合: `DISPLAY` 環境変数を付与してコマンドを入力する。
   - `$ DISPLAY=':1' firefox &`
- X Window System の xterm の場合
   - `$ firefox &`


## VNC Server 終了

1. VNC Server をシャットダウンする。
   - `$ vncserver -kill :1`


どっとはらい。
iTerm2でCtrl+Shift+Jで日本語変換したときに文字が入力されるのをなんとかする

HHKBやUS配列のキーボードなどを使っていて、IMEの切り替えをCtrl+Shift+JやCtrl+Shift+;で行っている人向けです。

iTermの初期設定だとIME切り替えのキーバインドを入力したときに文字や改行が入力されてしまいます。
元々はターミナルで特殊文字を打ち込むためのキーの組み合わせだったらしいですが、今回は困るだけなのでこれを無効化します。

![スクリーンショット 2018-08-15 15.41.01.png](https://qiita-image-store.s3.amazonaws.com/0/152713/fc58f2ab-32d5-dc2f-ee31-72d76a79d0cf.png)

1. iTermの環境設定を開く
2. KeysタブのKey Mappingsの下のプラスを押し、Ctrl+Shift+JなどのIME切り替えに必要なキーを入力する
3. "Do Not Remap Modifiers" を選択
4. 使うショートカットキーの数だけ繰り返す(筆者はCtrl+Shift+J, Ctrl+Shift+;の2つを設定しています)

![スクリーンショット 2018-08-15 15.49.04.png](https://qiita-image-store.s3.amazonaws.com/0/152713/6e70f2e9-3773-1b8c-74a2-9a807e4d13de.png)

英字キーボード使いに多幸あれ！
お名前メール（お名前.com）契約時のDNS設定方法/HEROKUアプリのSSL対応

# お名前メールのサーバーのDNS設定
お名前.comでドメインを取得し、メールサーバーもお名前メールを使っている場合、通常のお名前.comのDNS関連機能設定のところからではDNSの設定ができなくて手間取ったので備忘録として。

1. お名前.comのメニューの「メール」から、DNSを変更したいドメインにログイン。
2. 「サービス設定」から「独自ドメイン設定」を選択。
3. 変更したいドメイン名の「DNS設定」 を押す。
4. 以下のような感じで設定する。
![スクリーンショット 2018-08-13 12.01.45のコピー.png](https://qiita-image-store.s3.amazonaws.com/0/31687/74a9502f-564e-7220-9ca0-49894fa43b93.png "スクリーンショット 2018-08-13 12.01.45のコピー.png")


# HerokuアプリをSSL対応する
基本的な流れはこちらの記事の流れが参考になります。
参考：[お名前.comで購入したドメインをHerokuに設定する](https://qiita.com/ozin/items/62bc7ef1dd3c827177fb)
上記記事のページのお名前.com側の設定の部分を、本記事 **お名前メールのサーバーのDNS設定** の流れに置き換えればOKです。赤のマスク部分をHEROKUアプリの *Settings* 内の *Domains and certificates* にあるDNSターゲットの通りに設定します。
![スクリーンショット 2018-08-13 12.04.26のコピー.png](https://qiita-image-store.s3.amazonaws.com/0/31687/dff06ab7-5262-79ba-0ce3-00742ad0c49d.png "スクリーンショット 2018-08-13 12.04.26のコピー.png")


wwwつきのドメインだけならこれでOK。

ルートドメインも同じようにSSL対応しようとすると少し大変になるようです。
今回はやらなかったのでここでは割愛。ルートドメインもやりたい方は以下など参考に。
参考：[Heroku + お名前.com で SSL 通信を行う
](https://medium.com/indies-band/heroku-%E3%81%8A%E5%90%8D%E5%89%8D-com-%E3%81%A7-ssl-%E9%80%9A%E4%BF%A1%E3%82%92%E8%A1%8C%E3%81%86-1d08a94c3c00)


# httpからhttpsにリダイレクトする
サイト上のすべてのページでhttpからhttpsにリダイレクトさせるため、configのforce_sslをtrueに。デフォルトではコメントアウトされています。

```ruby: config/environments/production.rb
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
```
参考：[railsアプリケーションをhttpsでアクセスできるようにするまでのこと。](https://qiita.com/acairojuni/items/29ed22a128c16a113b0d)


何らかの事情でコントローラー、アクション単位でリダイレクトしたいとかならこんな感じで。

```ruby: application_controller.rb
class ApplicationController < ActionController::Base
	before_action :redirect_to_https
	
	def redirect_to_https
		return unless /http:\/\/www.hogehoge.com/ =~ request.host
	end
end
```

参考：[【Rails】herokuapp.comから独自ドメインに301リダイレクトを行う方法](https://pg-happy.jp/rails-heroku-domain-301redirect.html)

# cookie情報の漏洩を防ぐ
こちらに関しては以下の記事が詳しいです。
参考：[Railsエンジニアが安心して新年を迎える方法](https://qiita.com/masarakki/items/e498d257a2105d055281)

```ruby: config/initializer/session_store.rb
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_hogehoge_session', secure: Rails.env.production?

```

# httpsに対応したのに「このサイトへの接続は完全に保護されていません」と出る場合
画像等を置いているAWS等のサーバーへのリンク、JavaScriptやCSSのCDNのリンク先にhttpがあるとchromeで「！」マークが出ます。
リンク先がhttpかどうかも確認しましょう。
AWS EC2インスタンス上に Docker/Docker Compose 環境を用意する

# 事前準備
- AWS EC2 インスタンスを作成し、インスタンスに接続しておくこと

# Docker
1. インストール済みのパッケージとパッケージキャッシュを更新   
```
$ sudo yum update -y
```
2. 最新の Docker Community Edition パッケージをインストール  
```
$ sudo yum install -y docker
```
3. Docker サービスを開始  
```
$ sudo service docker start
```
4. ec2-user を docker group に追加すると、sudo を付けずに docker コマンドを実行可能  
```
$ sudo usermod -a -G docker ec2-user
```
5. ターミナルを一度閉じ、再度EC2インスタンスに接続（docker group アクセス権限取得のため）
6. docker コマンドが実行できることを確認  
```
$ docker -v
```

※2018/08/15時点では、以下のバージョンがインストールされました。
Version : `Docker version 18.03.1-ce, build 3dfb8343b139d6342acfd9975d7f1068b5b1c3d3`

# Docker Compose
1. Docker Compose のインストール  
```
$ sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
```
2. 実行権限の追加  
```
$ sudo chmod +x /usr/local/bin/docker-compose
```
3. docker-compose コマンドが実行できることを確認  
```
$ docker-compose --version
```

※2018/08/15時点では、以下のバージョンがインストールされました。
Version : `docker-compose version 1.22.0, build f46880fe`

# 参考
- Docker インストール方法   
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html
- Docker Compose インストール方法   
https://docs.docker.com/compose/install/#install-compose
- Docker / Docker Compose 自身のバージョン更新方法   
https://qiita.com/n11sh1/items/e11bb30adf276a9fa774

# さいごに
個人ブログにオリジナル（日本語＆英語）をUPしています。
この記事が良いと感じた方は、そちらにもリアクション頂けると嬉しいです:relaxed:
https://blog.n11sh1.com
[GNU] screen コマンド早見表



# 注意書き
screen のバージョン

```
$ screen -v
Screen version 4.01.00devel (GNU) 2-May-06
```

デフォルトではキーバインドが Ctrl-a から始まりますが個人的に Ctrl-a は他で使いたいので Ctrl-t に割り当てて使ってます。
Ctrl-t の部分は Ctrl-a に読み替えていただければと思います。

# セッション関連
## 新規セッション作成
`screen`

## デタッチ
`Ctrl-t, d`

## スクリーンの状態確認
`screen -ls`

## アタッチ
`screen -r`

## 名前 or id を指定してアタッチ
`screen -r {名前 or id}`

## 名前を付けてセッション作成
`screen -S {名前}`

# スクリーン内
## 新規 window 作成(create)
`Ctrl-t, c`

## window 名前設定
`Ctrl-t, A`

## window 順送り(next)
`Ctrl-t, n`
`Ctrl-t, space`

## window 逆送り(previous)
`Ctrl-t, p`
`Ctrl-t, backspace`

## window を一つ前のものに戻る
`Ctrl-t, Ctrl-t`

## window の名前を変更
`Ctrl-t, A`

## 画面分割(水平)
`Ctrl-t, S`

## 画面分割(垂直)
`Ctrl-t, |`

## 分割した画面の移動
`Ctrl-t, tab`

# その他
## コピーモード
`Ctrl-t, [`

## コピー
`space` で始点を選択、もう一度 `space` で終点を選択

## 貼り付け
`Ctrl-t, ]`

## コマンドモード
`Ctrl-t, :`

## help
`Ctrl-t, ?`


# 参考
http://aperiodic.net/screen/quick_reference
pythonのスクレイピングで躓いたところをメモ

Pythonをそもそも初めて使ったのですが、
その時に苦労したことをメモ書き

# 環境
python3.7
Django2
pydrive
selenium
chromedriver
CentOS7.0

# OSがCentOS6だとchromedriverが動かない
CentOS7にあげる

# ローカルだと動くのに, Webから動かすとバグが出た
エラーを記録するのを忘れたのだが
python3.5の標準機能のバグでした。
python3.7にupgradeするとうまくいきました.  
日本語の情報がなかったので


# pydrive crontabで実行するとエラー
エラー内容

``` 
 File "/home/XXXX/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pydrive/auth.py", line 388, in LoadClientConfigFile
    raise InvalidConfigError('Invalid client secrets file %s' % error)
pydrive.settings.InvalidConfigError: Invalid client secrets file ('Error opening
 file', 'client_secrets.json', 'No such file or directory', 2)
```


修正箇所

```
# Google Drive 認証を行う
google_auth = GoogleAuth()
credential_path = os.path.join(DIR_PATH,'credentials.json')
# DIR_PATHは自身の絶対PATH
store = Storage(credential_path)
credentials = store.get()
google_auth.credentials = credentials

# ここを追加するとcrontabで動かしても大丈夫になりました
google_auth.LoadClientConfigFile(DIR_PATH + 'client_secrets.json')
# client_secrets.json も絶対PATHで指定

drive = GoogleDrive(google_auth)
```

これ解消するのにめっちゃ時間かかった.



# 外部ファイルimport(Djangoとローカルで動きが違う)
python3からimportの挙動が変わったようだ.

importされる側 のファイルをaa.pyとすると

エラー内容(Djangoでは動くが,ローカルで動かそうとしたとき)

```
Traceback (most recent call last):
  File "importする側.py", line 38, in <module>
    from . import aa
ImportError: cannot import name 'aa' from '__main__' (importする側.py)

```

修正

``` importする側.py
if __name__ == '__main__':
   # こちらローカルで動かすとき
   import aa
   main()
else:
  # こちらDjangoで動かすとき
  from . import aa
  main()
```

これでとりあえずは大丈夫

# Chromeの開き過ぎのエラー

```
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: chrome not reachable
  (Session info: headless chrome=68.0.3440.84)
  (Driver info: chromedriver=2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb),platform=Linux 3.10.0-862.9.1.el7.x86_64 x86_64)
```

```python:scraping.py
# pythonからシェルコマンドを動かす
import subprocess

def scraping:
  try:
    for i in range(100) :
      # とりあえずたくさん開く
      driver.get(url) # urlは実際のURLを入れてください

  finally:
    driver.quit() # これだけだとバグが出るケースがある。
    # 下を追加
    subprocess.call("killall chrome",shell=True)
    subprocess.call("killall chromedriver",shell=True)

```

シェルでkillallさせる。とりあえずこれで動く。 

```bash

ps aux|grep chrome
```
これで消えているか確認する

だいぶ走り書きをしてしまったが、今度清書するかもしないかも
com.google.api.client.util.DateTime

com.google.api.client.util.DateTime.parseRfc3339(String)

の引数に渡す文字列のフォーマットって、こんなんなんですね～。
```
  /** Regular expression for parsing RFC3339 date/times. */
  private static final Pattern RFC3339_PATTERN = Pattern.compile(
      "^(\\d{4})-(\\d{2})-(\\d{2})" // yyyy-MM-dd
      + "([Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?)?" // 'T'HH:mm:ss.milliseconds
      + "([Zz]|([+-])(\\d{2}):(\\d{2}))?"); // 'Z' or time zone shift HH:mm following '+' or '-'
```

ここに渡したいインプットに秒がない時に無理やりくっつけないとLocalTimeに０秒渡しても
Stringにしたときに出力してくれないから面倒だった．．．
【備忘録】App Storeから"gambling apps"と判断され削除されたiOSアプリの対策 (Metadata編)

## はじめに

先日，ギャンブルに関係する個人アプリがApp Storeから一斉削除されました。

* [【速報】Appストアからギャンブル系アプリが大量削除](http://blogos.com/article/316890/)
* [Apple、政府の要請により個人によるギャンブルアプリをApp Storeより追放。無関係のアプリは異議申し立てで復活可能の模様](http://www.gamecast-blog.com/archives/65924288.html)

対応したバイナリをアップロードしたものの再び Reject されてしまいました。どうやら，Rating に Gambling を設定していたためのようです(すっかり忘れていました)。
無駄なAppleとのやり取りを避け，適切な審査のために時間を費やせるように備忘録としてここに残します。

## 方法

早速方法です。

1 . [App Store Connect](https://appstoreconnect.apple.com/) (旧: iTunes Connect) へログイン
2 . iOS APPを選択
3 . Rating の右にある Edit (画像参照) を選択

![ss_2018-08-15_at_14_32_50.png](https://qiita-image-store.s3.amazonaws.com/0/195913/faf31a61-4da1-f5f5-a713-1fba3008207c.png)

4 . `Simulated Gambling` `Gambling and Contests` に関する項目を `None` にして Save

![ss_2018-08-15_at_14_29_12.png](https://qiita-image-store.s3.amazonaws.com/0/195913/99d7642d-a2b4-2fd2-48da-cf44123026ec.png)

5 . 新しいバイナリを選択し，Submit for Review

## 結語

もちろんギャンブルに関する機能は削除した上で申請しましょう。

## 参考

* [【速報】Appストアからギャンブル系アプリが大量削除](http://blogos.com/article/316890/)
* [Apple、政府の要請により個人によるギャンブルアプリをApp Storeより追放。無関係のアプリは異議申し立てで復活可能の模様](http://www.gamecast-blog.com/archives/65924288.html)
【RxSwift】flatMapでunwrapしたい

# やりかた

```swift:flatMap.swift
flatMap { Observable.from(optional: $0) }
```

Observable.from(optional:)の説明
> Converts a optional to an observable sequence.

# 解説

↓このissueの下の方に書いてありました
https://github.com/ReactiveX/RxSwift/issues/450#issuecomment-314296626


ストリームで流れてくる値をUnwrapしたい！って時は上記のように書けば良いらしい。
windowsにreact-native環境を構築する

#windowsにreact-native環境を構築する
##はじめに
react-native環境をwindows上に構築したのですが、ちょっと手こずったところを備忘録的に書きたいと思います。

##node.jsをwindowsにインストール
下記の記事がすごくわかりやすかったです。
**Node.js / npmをインストールする（for Windows）**
https://qiita.com/taiponrock/items/9001ae194571feb63a5e

##react-native-windowsのインストール
node.js command promptを開いて、以下のページを参考にコマンドを入力していきます。
https://github.com/Microsoft/react-native-windows/blob/HEAD/docs/GettingStarted.md

> npm install -g react-native-cli
> react-native init SampleProject --version 0.55.0

2018/8/15現在、--version 0.55.0 でバージョン指定しないと、後々react-native windowsコマンドを実行したときに以下のように怒られてしまいます。

![01.png](https://qiita-image-store.s3.amazonaws.com/0/88747/0bedd923-f64e-8542-227d-349dc357aba6.png)

あとはGetting Startedの通りに

> cd SampleProject
> npm install --save-dev rnpm-plugin-windows
> react-native windows

ここまでいくとSampleProjectの下に「windows」フォルダができ、さらにその中に「SampleProject.sln」ができています。
【CakePHP3】ORMのgetメソッドにid以外の検索条件をつける

DBのカラムにdelete_flagをつけて論理削除することはよくあると思います。
findメソッドだとconditionsやwhereで検索条件としてdelete_flat=0をつけることが出来ますが、
findの場合データが無くても例外は出ません。
例外を出したい場合は、getにカスタムFinderを指定することが出来ます。

```php
// カスタムFinder定義
class ExampleTable extends Table
{
  // メソッド名はfindXxxの形
  public function findNotDelete(Query $query): Query
      {
          return $query->where([
              'delete_flag' => 0
          ]);
      }
}

// getの引数にfinderを指定
$tableName->get($id, ['finder', 'notDelete']);
```

以上。
AWSサービスについてのメモ

#AWSサービスについてのメモ(超意訳含む）

##これだけは覚えておきたい
- **EC2(Elastic Compute Cloud)**
    - **仮想サーバー**
    - Elasticとは「拡張できる」の意味。よって、「拡張可能なクラウド上コンピュータの意と解釈
        - CPU数追加、メモリ追加、スペック追加が可能
        - 最小1vCPU 0.5GBメモリから最大128vCPU 約4TBメモリまで
        - 但し、データ保存領域となるストレージを持っていないので、後述するEBSサービスの申し込みが必須
    - AWS利用時に契約必須となるサービス
    - 1秒毎の従量課金
    - Windows、Linux等の多数のOSをサポート、ライセンス費用込みで従量課金
    - 自由にソフトウェアのインストールが可能
    - スケールアップ/ダウン、アウト/インが可能
    - 情報処理試験で見覚えが有るかもしれませんが、Saas(Software as a Service)、PaaS(Platform as a Service)、IaaS(Infrastructure as a Service)の内のIaaSです。
- **EBS(Elastic Block Store)**
    - 拡張可能なブロック**ストレージサービス**
    - EC2の仮想サーバー上に展開するストレージを指す
    - 1つのEBSは最大16TB、最大32,000IOPSまで性能を確保可能
    - RAID1での冗長化は不要（内部的に冗長化済み）
    - サイズ変更可能
    - スナップショット機能で後述するS3に差分バックアップ可能
- **S3(Simple Storage Service)**
    - シンプルなクラウド上の**ストレージサービス**
    - EC2の仮想サーバー上に展開するストレージを指す
    - バックアップ用途。
    - 容量無制限
    - 従量課金。1GB辺り月間$0.019~
- **AMI(Amazon Machine Image)**
    - **仮想OSイメージのベースとなるもの**
    - EC2の仮想サーバー上に保存した仮想OSのイメージを指定して起動できる。
    - EC2上で、仮想OSを「開発チーム用」「検証チーム用」、「リリース用」といった用途に応じて、仮想OSを起動する事が出来る。