OmniAICreator/Qiita-1.07M huggingface dataset:
Xcode の不要ファイルを消す shell script

今までは PC の容量がなくなるたびに「Xcode ファイル 削除」とかでググって以下の記事を参考にしてファイルを消してたけど、それを shell script にしておくとコマンド一発で全部消せて便利。

* 参考
    * [\[Xcode 8\.2\] 年末なので Xcode まわりの不要ファイルを一掃してみた ｜ Developers\.IO](https://dev.classmethod.jp/smartphone/remove-xcode8-related-unnecessary-files/)
    * [~/Library/Developer/Xcode/というゴミ屋敷を新年前に大掃除してみた \- Qiita](https://qiita.com/sintario/items/6d993f3ccdb3212509ae)
    * [xcode \- Can I delete data from iOS DeviceSupport? \- Stack Overflow](https://stackoverflow.com/questions/29930198/can-i-delete-data-from-ios-devicesupport/29931912)

```bash
#!/bin/sh -x

rm -rf ~/Library/Developer/Xcode/DerivedData
rm -rf ~/Library/Developer/Xcode/Archives
rm -rf ~/Library/Developer/Xcode/DeveloperPortal*
rm -rf ~/Library/Developer/Xcode/DocumentationCache
rm -rf ~/Library/Developer/Xcode/Products
rm -rf '~/Library/Developer/Xcode/iOS DeviceSupport'
rm -rf ~/Library/Developer/XCPGDevices
rm -rf ~/Library/Developer/Shared/Documentation/DocSets
rm -rf '~/Library/Developer/Xcode/iOS Device Logs'
xcrun simctl erase all

rm -rf ~/Library/Caches/com.apple.dt.Xcode
```

実行権限を付与して実行。

```bash
$ chmod 755 xcode_cleanup.sh
$ ./xcode_cleanup.sh
```

実際にこの shell 動かすと 40GB くらい削除できた。
そのあと Xcode 立ち上げてビルドも問題なし。 (キャッシュが消えたので初回ビルドは時間かかる)
rubyの記法チートシート

# この記事の目的

いくつかの言語を勉強しているとrubyのときは配列どうだったっけ？とか迷うことがあるのでそれらをすぐに思い出すためのシート

# 命名

* クラス名、モジュール名・・・単語のはじめを大文字で始める（パスカルケース）
* メソッド名・・・単語は小文字ではじめ単語の間は_を用いる（スネークケース）
* 変数名・・・単語は小文字ではじめ単語の間は_を用いる
* 真偽を表すメソッド名・・・真偽値を返すメソッド名は?で終わる
* 定数・・・アルファベット大文字のみで書く（スクリーミングスネークケース）
* 破壊的メソッド・・・破壊的でない同名のメソッドがある場合，破壊的メソッド名は!で終わる

# 出力

```ruby:例
puts

# 引数を標準出力。出力の後に改行される。

print

# 引数を標準出力。改行はされない！

p

# 引数の内容を詳しく標準出力。改行される。文字列であれば””で囲まれていて、数値はそのまま出力される。

pp

# pと同様の標準出力。出力される内容が、適切なインデントと改行で整形されている。pだと、改行などがないから見にくくなる。
```

# %()記法

「Rubyで%記法（パーセント記法）を使う」
https://qiita.com/mogulla3/items/46bb876391be07921743

# コードブロック

rubyでは

* do...end
* {...}

でブロックを区切る。

# 改行

基本的にはrubyは式と式を改行で区切ります。しかし、;で1行で表すこともできます。

```ruby:test
name = 'ruby';puts(name.updase)
```

# コメントアウト

```ruby:rei
# コメント

# --1行コメントは「#」のあとに書く

=begin 
コメント
=end

# -- 「=begin」から「=end」の間がコメントになる

__END__

# -- この行以降すべてがコメントになる

# 変数

```ruby:例
rei = "例"
```

=でつなぐだけ。変数を展開する場合は下記のように書く

```ruby
word = "world"
puts "hello,#{word}"
```

## ローカル変数

上記の変数で下記の場合のみ効く非常に狭い範囲の変数。

* ブロック
* メソッド定義
* クラス/モジュール定義
* トップレベル

## グローバル変数

```ruby:例
$rei = "例"
```
$を変数名の先頭につけるとどこからでも参照できるようになる。

## 定数

```ruby:例
REI = "例"
```

全部大文字で書くと定数になり、一度しか代入できなくなります。つまり値を変更したくないときに使うものです。

# 多重代入

```ruby
a,b = 1,2
a => 1
b => 2

# 余った場合は無視
a,b = 1,2,3
a => 1
b => 2

# 配列の代入
a,*b = [1,2,3]
a => 1
b => [2,3]
```

# メソッド

```ruby
def say(name)
  puts "Hi #{name}"
end
say("tarou")
```

詳しくは
https://qiita.com/you88/items/a3a6e972d6f3b87edbcb

# 条件分岐

## if文

```ruby
if n = 1
 puts "nは1です"
else
 puts "nは1じゃないです"
end

unless n = 1
 puts "nは1じゃないです"
else
 puts "nは1です"
end
```

unlessはelsifを使えない。

## case文

```ruby
case signal
when "red"
  puts "stop"
when "green","blue"
  puts "go"
else
  puts "go"
end
```

詳しくはこちら
https://qiita.com/you88/items/5744a26eb2db8839a644

# 配列（Array）

```ruby
colors = ["red","white"]
puts colors[1]
=> "white"

# 配列の追加

animals = ["dog", "cat", "mouse"]
animals << "pig"
p animals

=> ["dog", "cat", "mouse", "pig"]
```

詳しくは
https://qiita.com/you88/items/83d694d223461df7a068

# ハッシュ（連想配列）の書き方

```ruby:例
# キーが文字列の場合の配列

users = {"name" => "yohei","age" => 20}

# キーをシンボルにする

users = {:name => "yohei",:age => 20}

# シンボルの省略形

users = {name: "yohei", age: 20}

```

詳しくは
https://qiita.com/you88/items/0c78a310c836741c3c93

# each

```ruby

オブジェクト.each do |変数|

end

オブジェクト.each {|変数|

}
```

# classの継承

```ruby
class Parent
end

class Child < Parent
 def ababa
 end
end
```

# その他の豆知識

```ruby:その他
a ||= true
# 左辺が未定義、もしくはfalseなら代入。||はorの意味なのでもしくは代入の意味。

  def logged_in?
    !!session[:user_id]
  end
# !!はメソッドの返り値をtrue,falseに変える。今回はsessionがあるかないかを聞くメソッドであればtrue、なければfalseを返す

```
Jupyterでデータ分析を全力で楽しむ！（2）最小二乗法

　お疲れ様です。
　今回は第2弾、データセットを使って簡単なデータ分析をしてみたいと思います。

#最小二乗法とは
>測定で得られた数値の組を、適当なモデルから想定される1次関数、対数曲線など特定の関数を用いて近似するときに、想定する関数が測定値に対してよい近似となるように、残差の二乗和を最小とするような係数を決定する方法、あるいはそのような方法によって近似を行うことである。
>(Wikipedia:https://ja.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%97%E6%B3%95)

# ライブラリを読み込む

　まずはデータの読み込みや分析、グラフに必要なライブラリを読み込みます。
　基本的なライブラリは下記のURLを参考にしてきましたので、今回もこれらのライブラリをまず読み込みます。
　https://logics-of-blue.com/python-state-space-models/

　他にライブラリが必要になってきた場合は、今回は適宜読み込むようにします。

```
# 基本のライブラリを読み込む
import numpy as np
import pandas as pd
from scipy import stats
from pandas.core import datetools

# グラフ描画
from matplotlib import pylab as plt
import seaborn as sns
%matplotlib inline

# グラフを横長にする
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 15, 6

# 統計モデル
import statsmodels.api as sm
```

# データセットを読み込む

　今回は、機械学習用ライブラリsckit-learnのデータセットである、Boston house-prices(ボストン市の住宅価格)を使って、簡単なデータ分析をしていきたいと思います。

```
#Boston house-prices (ボストン市の住宅価格)のデータセットを読み込む
from sklearn.datasets import load_boston
boston = load_boston()

#データの内容を表示する
pd.DataFrame(boston.data, columns=boston.feature_names)
```

　これで実行すると、次のように出力されました。
　今回使うデータセットの内容です。

![jupyter005.png](https://qiita-image-store.s3.amazonaws.com/0/213134/26dd1f73-d633-e6c8-b430-e5e9ee88cb1f.png)

　ここで記載されている各カラムの意味を記載しておきます。
　下記から引用しました。
　http://pythondatascience.plavox.info/scikit-learn/scikit-learn%E3%81%AB%E4%BB%98%E5%B1%9E%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%83%E3%83%88

|WORD|意味|
|:-----------------|:------------------|
|CRIM|人口 1 人当たりの犯罪発生数|
|ZN|25,000 平方フィート以上の住居区画の占める割合|
|INDUS|小売業以外の商業が占める面積の割合|
|CHAS|チャールズ川によるダミー変数 (1: 川の周辺, 0: それ以外)|
|NOX|$NO_{x}$の濃度|
|RM|住居の平均部屋数|
|AGE|1940 年より前に建てられた物件の割合|
|DIS|5 つのボストン市の雇用施設からの距離 (重み付け済)|
|RAD|環状高速道路へのアクセスしやすさ|
|TAX|$10,000 ドルあたりの不動産税率の総計|
|PTRATIO|町毎の児童と教師の比率|
|B|町毎の黒人 ($Bk$) の比率を次の式で表したもの。$1000(Bk – 0.63)^{2}$|
|LSTAT|給与の低い職業に従事する人口の割合 (%)|

# 関係性をグラフにプロットする

　今回は犯罪発生数（CRIM)と家の価格の関係性を調べてみようと思います。
　まずは生データの関係性をプロットしてみます。

```
#犯罪発生数CRIMを取り出す
crime=boston.data[:,0]

#家の値段を取り出す
prices=boston.target

#犯罪発生率と家の値段の関係性をプロットする。
plt.scatter(prices,crime)
```

　プロットした結果が下になります。
　$x$軸が家の値段、$y$軸が犯罪発生数ですね、なんだか反比例の傾向が見えそうですね。

![jupyter006.png](https://qiita-image-store.s3.amazonaws.com/0/213134/5a5ed323-5575-d75c-6336-33bbaf91df1e.png)

#最小二乗法を使って関係性を出してみよう

　まずは簡単な最小二乗法を使って、線形的な関係性を出してみます。

```
# 最小二乗法で誤差が最も少なくなる直線を得る
x = np.array([[v,1] for v in prices])
y = crime
(slope,bias), total_error, _, _ = np.linalg.lstsq(x, y)
```

　この結果、得られた直線をプロットしてみます。

```
# グラフを表示する
plt.scatter(prices,crime,color='r')
plt.plot(x[:, 0], slope * x[:, 0] + bias)
plt.xlabel('crime')
plt.ylabel('price')
plt.grid()
plt.show()
```

![jupyter007.png](https://qiita-image-store.s3.amazonaws.com/0/213134/41d30cb2-beb1-5043-0d4c-a4e5870e846d.png)

　おお、犯罪発生数の増加とともに家の価格が下がるのが表現できてます。
　これは直感と合致してますね。

　ただ、線形で表現するにはここまでが限界っぽいですね、
　反比例で表現するにはどうしたらいいのかな…？

　今回はここまで。
RDSのMySQLでGRANT文が通らない

### やりたかったこと
RDSのMySQLで、全DBへの権限を付与したユーザの作成

### 最終的に成功したSQL
```
grant all on `%`.* to '{ユーザ名}'@'%' identified by '{パスワード}';
```

### 苦労話
恐らく、通常のMySQLであれば以下のSQLで全DBへの権限を付与したユーザ作成になるはず
`grant all on *.* to '{ユーザ名}'@'%' identified by '{パスワード}';`

しかし、RDSのMySQLに対しては、rootユーザで上記のSQLを実行しても以下のエラーメッセージが出てしまう
`Access denied for user 'root'@'%' (using password: YES)`

ググって色々やり方変えて試しても上手く行きませんでしたが、最終的には以下の記事にたどり着きました。

##### 参考URL
https://www.flydata.com/blog/access-denied-issue-amazon-rds/
http://www.fidian.com/problems-only-tyler-has/using-grant-all-with-amazons-mysql-rds

しかし、参考URLの1つ目のリンク先にある、
`GRANT ALL ON '%'.* TO 'admin_sync'@'%';`
上記のSQLを参考にしてもシンタックスエラーが出てしまいます。

**'%'.\*ではなく\`%\`.\*でないとだめ**みたいです。
SQL*Loaderに改行コードが含まれたCSVファイルの取り込み

# はじめに
自社開発のアプリケーションで、ExcelファイルのデータをCSVに変換後に内部でSQL*LoaderによりOracleの指定テーブルに登録する処理があります。登録したテーブルのデータを使用する別のアプリケーション側でエラーになったことから調査の依頼がありました。

# 調査
登録されたテーブルのデータを調べると、改行コードが含まれていました。テーブルのデータを条件により抽出してJSONに格納しているため、改行コードが含まれていると別の行としておかしなデータになってしまうことでエラーになることが分かりました。

このテストを行うにあたり、Excelファイルの改行コードを含めてSQL*LoaderにOracleの指定テーブルに登録しようとすると、そもそもSQL*Loader側でエラーになり登録できません。でも、現実的には改行コードが含まれて登録することができています。

# 先頭行の改行コード
一体何が違うのか調べてみると、先頭行に改行コードがあるとエラーになり、先頭行に改行コードが無ければ2行目以降に改行コードがあっても登録できることが分かりました。

先頭行に改行コードが無いダミーデータを登録して、後でダミーデータを削除するといいかも知れません。

# 最後に
UTF-8で登録しているなど他と異なるので参考になるかは分かりませんが、実体験としてあったので備忘録として書いてみました。

``` test.bat
SQLLDR fuga/fuga@hoge control=test.ctl errors=9999
```
``` test.ctl
LOAD DATA
CHARACTERSET AL32UTF8
INFILE 'test.csv'
APPEND
INTO TABLE TEST
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(AA,AB,AC,AD)
```
改行コードが含まれているデータは2重引用符で囲んでいます。

``` test.csv
01,K,T,1
02,"K
","T
",2
```

# 参照
* [文字列に改行を含むCSVのロード（１／２）](https://www.mtu-accelerates.jp/load_csv_string_contains_lf1/)
* [SQL*Loader 改行コードを含む文字列をロードする方法 oracle 10g](http://blog.livedoor.jp/heihachiwin/archives/51095868.html)
* [9章　SQL*Loader 12cのエクスプレスモード](http://www.soldoutdb.com/silver/silver9.html)
pythonでpython (とR) スクリプト内の不要なコメントを消す

## 悩み

こういうやり辛そうな文字列から，不要なコメントのみを削除したい．
が，この場合，ハッシュ記号 (#) の全てを消すとまずい (引用符内にあるハッシュを削除しないようにしなくてはならない…)．

```py3
cmd = """
# これは消さなきゃダメ
x <- 3  # これは消さなきゃダメ

paste('# これは消しちゃダメ')
paste('''
    # これは消しちゃダメ
''')
paste('"# これは" 消しちゃダメ')
"""
```

## 方法

ハッシュの位置 (`hash_ids`) を取得した後，さらに絞り込みをかけ，コメントを示すハッシュの位置 (`comment_ids`) を取得する．

```py3
from typing import List
from copy import copy
import numpy as np


def count_quote_marks(x: str) -> List[int]:
    """各種引用符の数を数える"""
    n_tquotes = x.count('\'\'\'')
    n_tdquotes = x.count('\"\"\"')
    n_quotes = x.count('\'') - 3 * n_tquotes
    n_dquotes = x.count('\"') - 3 * n_tdquotes
    return [n_quotes, n_dquotes, n_tquotes, n_tdquotes]


def get_comment_ids(cmd: str) -> List[int]:
    """「コメントを示す」ハッシュのインデックスを取得"""
    # quotes, double quotes, triple quotes, triple double quotesの数を保持するリスト
    quotes_counts = np.zeros(4, dtype=int)

    # ハッシュ (#) の位置を返すジェネレーター
    hash_ids = (i for i, elem in enumerate(cmd) if '#' in elem)

    # hash_idsのうち，引用符内に無いハッシュのインデックスをcomment_idsとする
    prev_i = 0
    comment_ids = []
    for i in hash_ids:
        sliced = cmd[prev_i: i]
        quotes_counts += np.array(count_quote_marks(sliced))

        # 全quotes_countsが偶数 <=> 引用符外にあるハッシュ
        if np.sum((quotes_counts) % 2) == 0:
            comment_ids.append(i)

        prev_i = i

    return comment_ids


def get_return_ids(cmd: str) -> List[int]:
    """改行記号\nを取得"""
    return [i for i in range(len(cmd)) if cmd[i: i + 1] == '\n']


def delete_useless_comments(cmd: str) -> str:
    """不要なコメントを削除する"""
    cmd = copy(cmd)

    comment_ids = get_comment_ids(cmd)
    return_ids = get_return_ids(cmd + '\n')

    next_return_ids = []  # ハッシュ直後の改行コードを取得
    for index in comment_ids:
        next_return_ids.append([i for i in return_ids if i > index][0])

    # 後ろからcmdを削っていかないとインデックス指定が面倒なので
    for i, j in zip(reversed(comment_ids), reversed(next_return_ids)):
        cmd = cmd[:i] + cmd[j:]
    return cmd
```

## 結果

いけた．

```py3
print(cmd, end='\n' + '=' * 50 + '\n')
print(delete_useless_comments(cmd))
```

```
# これは消さなきゃダメ
x <- 3  # これは消さなきゃダメ

paste('# これは消しちゃダメ')
paste('''
    # これは消しちゃダメ
''')
paste('"# これは" 消しちゃダメ')

==================================================


x <- 3  

paste('# これは消しちゃダメ')
paste('''
    # これは消しちゃダメ
''')
paste('"# これは" 消しちゃダメ')
```

## 余談

「pypeRに引き渡すコマンドにコメント#が含まれているとpypeRがフリーズする」という悩みがきっかけだったので，cmdがRのスクリプトになっている…
RubyでECを作ろうとしている

# 言いたいこと
* 既存のECのプラットフォームが微妙。
* 自分で作ったほうがコスト安そう
 * というよりMagento2とか学習コスト高い
 * あとからくる人間に学ばせるのも大変
* せっかくだからいろいろ思うところを実装したい
* 作りたいから作る(使ってないけどActiveRecordとかでできるってことは聞かない
* https://github.com/S2/ec で作っているけれどリポジトリ名とか適当で変わることあり。


# 動機
既存のECプラットフォームは割と微妙。
対象に考えているのは
* Magento2
* EC-CUBE
の二つ。
嫌な点は、いろいろだけども、それらのプロダクトがダメということだけでなく、もともと立て付けの起因するものも多い。
EC-Cubeはあんまり使ってないので不当なFUDになりそうなので控えて、Magento2の嫌なところを書いていきたい

## 立て付けもあって仕方ないかなと思うところ
* PHP
* EAVの絡みで大変バックアップがとりづらい。EAVテーブルの主キーをキー名ではなく、AUTO_INCREMENTな数値で持っているため、本体のデプロイを変更する(例えばモジュールの読み込み順を変える)などしたときに、EAVのIDが変わって大変なことになる。
* 画像類のバックアップ、移行などが大変 
* DDL書くのにPHPで書かされる。全体的にSQLを知らない人を対象にしている風がある。

## プロダクトの問題
* プロダクト全体が大きい
 * デザインパターンとかを駆使して、コードの統一をしようとしているのはわかる。
 * 実際のクエリがどこで作られてどんなものが実行されているか、などが隠蔽されていて追いづらい
 * XMLも同様に何が読まれていて、今どのXML要素が実行されているのかわかりづらい
 * DIは便利ではある。遅いけど。
* XMLで書くのが煩雑な上にXMLで書かれたものの解釈が狭く自由度が低い
* 1+n問題が置きまくっていて重い。管理画面もフロントも。
* アプリケーションレイヤーで重い問題を改善しないでVarnishを推奨してくる
* eav_attributeっていうアンチパターンの権化みたいなやつが幅を利かせてる
* テーブル定義にまとまりがない。外部キーが貼ってあったりなかったり、あとカラム名にも統一感がない。
* XMLとかEAVとかプロダクトの大きさとかで学習コストがすごく高い。それなりにできるエンジニアで一月くらいはかかりそう(てきとう

といったところ。

# 新しく作るものと要件
EC、コア部分は本来小さく作れる感触がある。
商品、顧客、カート、受注管理、配送管理などを作れればよいかと思う。
速度的なチューニング類は売り上げに直結するので行いたいところ。
アプリケーション側ではある程度適切なクエリを書くようにしておく。
それ以上のチューニングはNginxとかCroudfrontで行えるのではないかと思う。

# 取り入れたい機構
* Rubyで作る
 * 書いてたら楽しくなった
 * 割と読み書きできる人が多いし平易
 * 本当はClojureとかでやりたかったけどハードル高い…
* テーブル定義を書いたら大体アプリケーションサーバは出来上がってほしい
* テーブル定義だけでは例えばバリデーションルールとか、列の和名などは作れないのでそういうテーブルは作る必要はありそう
* 設定類は変にYAMLとかに出すよりDB持たせる方針
 * フロント側を書いていないけど、YAMLとかになる感じもちょっとある
* サーバサイドレンダリングとフロントJSを合わせて頑張る、という方針よりも、JS、CSS、HTMLを統合的に扱えるのでフロントに任せたほうがシンプルになりそう
* SPAではないので各種ページは必要。

# テーブル定義からアプリケーションサーバ
構想の域はまだ出ていないが、考えはある。
いわゆるモデル的な層のみを考えている。
またDBに起因しないモデルみたいなもの、Redis等のRDBMS以外のDBは想定していない。

## テーブル定義上のパターンについて
RDBMSなのでテーブル間の関係性というものを考える必要があるが、それらはいくつかのパターンに分けられるかと思う。
ここで書く内容は、自分のテーブルが他のテーブルに依存しているか、ということに焦点を当てて書いていて、依存されているかどうかは考えていない。

* 単独のテーブル
* 一つのテーブルを親に持ち、親にたいして複数のレコードを持ち、列ごとに固有のIDを持つテーブル(一般的な1:多かと思う)
* 一つのテーブルを親に持ち、親にたいして複数のレコードを持ち、列ごとに固有のIDを持たないテーブル(1:多なのだけども、個々の列を操作しない、ということ)
* 一つのテーブルを親に持ち、親にたいしてふくすう単数のレコードを持ち、親への外部キーがPrimaryKeyになる(1:0もしくは1:1)
* 複数のテーブルを親に持ち、そのうちのいくつか一つ以上の親テーブルのくみあわせでPrimaryKeyになるテーブル
* 複数のテーブルを親に持ち、独自にAUTO_INCREMENTなPrimaryKeyに持つテーブル

親への依存についてはこの程度のパターンではないかと思う。まあ増えればその際にまた処理を書けばよい。

## 入力処理
思うに単独のテーブルへの入力のみで足りることはないかと思う。
例えば顧客と複数ある顧客の配送住所、みたいなものを考えたときに、

* 顧客情報のみを入力して、配送住所は入れない
* 顧客情報を入力して、合わせて配送住所も入力する
* 顧客情報は入っているので、配送住所のみを入れる
といったパターンが考えられる。
一番目と三番目はそれぞれのテーブルへのINSERT文を実行すればよいが、二番目はセットで処理が行われないといけない。
その処理は

* 顧客テーブルへINSERT
* 顧客テーブルの主キーを取得して、それを持たせた状態で子テーブルのINSERT処理を実行させる
といった形になる。
このあたりを抽象化すると、それぞれのテーブルへの適切な入力ルール(これは上記のテーブルパターンによって決まる)を作ることと、親テーブルは子テーブルへの参照を保持する必要があるということになる。
子のテーブルは孫への参照を保持しておけばよくて、再帰構造で作れば問題なく実装できるイメージがある。

## 出力
上記で子テーブル、孫テーブルへの方向は再帰的に持っているので、問題なさそう。要はSELECT文を発行して、子方向にも同様に発行させて、結果を決まったフォーマットでオブジェクト化すればよい。

## 更新
そのうち書く。

## 削除
ログとかではなくて、子になる要素はそこまで多くはならないはずなのでON DELETE CASCADEで対応しておけば良さそう。
問題になってから考えよう。

# フロントよりの話
ディスパッチャは面倒なのでもう決まった処理をさせて、あとはフロントで頑張る方針。まだ手も付けていないのでその辺は追々…
PHP でメールの受信

PHP で imap  サーバーからメールを受信する方法です。

```php:imap_get.php
#! /usr/bin/php
<?php
// --------------------------------------------------------------------
/*

	imap_get.php

					Nov/26/2017


*/
// --------------------------------------------------------------------
fputs (STDERR,"*** 開始 ***\n");

$server = 'imap.mail.yahoo.co.jp';
$port = 993;
$user = 'xxxxxxx';
$password = 'yyyyyy';

$mailBox = imap_open('{' . $server . ':' . $port . '/novalidate-cert/imap/ssl}' . "INBOX", $user, $password);
if (!$mailBox) {
	echo "接続失敗\n";
}

$messageIds = imap_search($mailBox, 'ALL');

print_r($messageIds);

foreach($messageIds as $messageId) {
	$header = imap_headerinfo($mailBox, $messageId);

	$subject = mb_decode_mimeheader($header->subject);

	echo "Subject: " . $subject . "\n";

	$body = imap_fetchbody($mailBox, $messageId, 1, FT_INTERNAL);
	$body = trim($body);

	echo "Body: " . $body . "\n";
}

fputs (STDERR,"*** 終了 ***\n");
// --------------------------------------------------------------------
?>
```

Arch Linux でのライブラリーのインストール方法

```bash
sudo pacman -S php-imap
```

設定ファイルのコメントアウト

```text:/etc/php/php.ini
（省略）
extension=imap
（省略）
```

Ubuntu でのライブラリーのインストール方法

```bash
sudo apt install php-imap
```



次の環境で動作を確認しました。

```text
$ uname -a
Linux iwata 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

$ php --version
PHP 7.4.3 (cli) (built: May 26 2020 12:24:22) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
```
HPE ProLiant MicroServer Gen10でFreeNASを起動する

[HPE ProLaint MicroServer Gen10](https://www.hpe.com/jp/ja/product-catalog/servers/proliant-servers/pip.hpe-proliant-microserver-gen10.1009955118.html)はコンパクトかつ省エネ、HDDが4台入るという非常にNAS向きのサーバです。
是非NASとして使いたいサーバですが、NAS用OSである[FreeNAS](http://www.freenas.org/)はそのままでは立ち上がりません。
この記事ではMicroServer Gen10でFreeNASをUSBメモリから起動し、使用する方法を解説します。

#### 必要な物

* [HPE ProLaint MicroServer Gen10](https://www.hpe.com/jp/ja/product-catalog/servers/proliant-servers/pip.hpe-proliant-microserver-gen10.1009955118.html)
* [FreeNASのインストールイメージ](http://www.freenas.org/download-freenas-release/)(FreeNAS 10.0-U4)
* MicroServerとは別のUEFIをサポートしたPC

# 手順

## インストール

MicroServer以外のPCを用意し、[FreeNASのドキュメント](https://doc.freenas.org/11/install.html)に従いUSBメモリなどにFreeNASをインストールします。
この際、Boot Modeは **Boot via UEFI** にしてください。Boot via BIOSにするとMicroServerでFreeNASが立ち上がりません。

![Boot via UEFIを選ぶ](https://qiita-image-store.s3.amazonaws.com/0/67657/d49dda4d-46fe-d87f-9c9f-93f06e2a77b5.png)

## FreeNASの起動と設定

FreeNASのインストールに使ったPCにFreeNASをインストールしたUSBメモリを指し、FreeNASを起動します。
FreeNASが起動しない場合はPCのUEFI画面のBoot MenuからFreeNASをUSBメモリを選択して起動してください。

FreeNASが起動したら、ブラウザで立ち上げたFreeNASにアクセスします。

**root**でログインし

![rootでログイン](https://qiita-image-store.s3.amazonaws.com/0/67657/cff1891b-20c7-fe7e-9160-ca105b935987.png)

**System > Tunables**を選択し、**Add Tunable**をクリック

![Tunables画面へ](https://qiita-image-store.s3.amazonaws.com/0/67657/de80af7f-5c73-8139-8e12-acaf64538ae2.png)

下記の値を設定します。
* Variable: **hw.pci.realloc_bars**
* Value: **1**
* Type: **Loader**
* Comment: 適当に(必須ではない)
* Enabled: **✓**

![3.png](https://qiita-image-store.s3.amazonaws.com/0/67657/cd08c497-bb01-b12c-3531-ee10ee6ee15b.png)

**OK** を押し、PCをシャットダウンします。

## MicroServerでの起動

FreeNASをインストールしたUSBメモリを、MicroServer Gen10に刺し起動します。
FreeNASがMicroServer上で無事起動します。
FreeNASが起動しない場合はMicroServerのUEFI画面(起動画面でF2/Deleteを押す)からBootを選択し、FreeNASの入ったUSBメモリの優先度を上げてみてください。

# その他

HDDの振動がMicroserverの筐体と共振してうるさいので、HDDとケースの間に100均で買った防振ジェルをHDDとケースの間に挟んでみました。
これだけで共振しなくなったので静かになりました。

![IMG_3475.jpg](https://qiita-image-store.s3.amazonaws.com/0/67657/777b7ae8-a150-4c7b-6893-f198cc05a166.jpeg)


# 参考文献

* [Installation stops after a few seconds on a Microserver Gen10 | Page 2 | FreeNAS Community](https://forums.freenas.org/index.php?threads/installation-stops-after-a-few-seconds-on-a-microserver-gen10.56809/page-2)
umbrella.jsを（少し）使ってみた

# umbrella.jsを（少し）使ってみた

## 動機

- パフォーマンス優先
- 開発効率も落としたくない
- jQueryはできれば使いたくない（重量、将来性）
- ajaxは必須

## umbrella.js

  https://umbrellajs.com/

- ドキュメント日本語訳　http://tr.you84815.space/umbrella/

## 有利性

- 軽い

  必要最低限のAPIのみで構成されているためかなり軽量。（jQuery 3.2.1 : 90kb, umbrella.js 2.8.0: 9.5kb）

- jQueryと似ている

  使用方法やAPIをjQueryに（意図的に）近似させているため、jQuery経験者であれば学習・調査コストをかけず、jQuery同等の開発生産性も得られることが期待できる。

  ざっくり言うとjQueryの`$`が`u`に変わるだけなので、殆どjQueryを使っているような感覚で書ける。

### example

- `.addClass()`

      - jQuery: 
      ```
      $('#foo').addClass('bar');
      ```

      - umbrella.js: 
      ```
      u('#foo').addClass('bar');
      ```

## 不利性

- 使用できるAPI（関数）が少ない

  これはそのように意図して設計されているため不利性というより必然だがjQueryで使えるAPIの全てが使える訳ではない。
  APIは`DOM操作`と`Ajax`と`イベントハンドリング`に限定されている。
  その他の、`animate`系や、`deffered`などユーティリティ系のAPIが必要な場合は、別途ライブラリを導入するか、スクラッチで書く必要がある。


- 情報が（まだ）少ない

  比較的新しいライブラリのため、日本語の情報は当然だが、stackoverflow等でも有用な情報が見つけにくい。
  jQueryであれば、詰まった時やconsoleエラー、「あれこれなんだったっけ？」という時はGoogle検索ですぐに回答が（大量に）出てくるが、umbrella.jsについては、まだあまり情報が蓄積されていない印象。
  詰まった時はGoogle検索、ではなく内部デバッグ（中身を見る意味での）が必要となる。（というかその方が早い気がする）

  例えば、jQueryでも頻繁に使用する`.val()`がなかったので、input要素のvalueを取りたい場合どうするのか、Googleでは回答は見つからないためconsole.log等でオブジェクトの内部を確認してvalueをどこに保持しているかを探す。
  結局`.val()`に相当する（便利な）書き方はなさそうなので下記のように取得するしかなかった。（他によい方法があれば教えてくださいm(__)m）

  ```javascript
  /**
   * ボタンクリックでinput要素のキーワードを取得してajaxリクエストを投げる
   */
  u('button').on('click', (e) => {

    e.preventDefault();

    // input要素のvalueを取得する
    let keyword = u('input[name=keyword]').nodes[0].value; // TODO: もっと良い方法はないか

    ajax(action, options, after, before);

  });
  ```

- 対応ブラウザ

  githubページには以下の記載がある。

  > Support: IE11+

  https://github.com/franciscop/umbrella

  jQueryの代替である以上、モダンブラウザ向であることは推測できるが Android、iOS の対応バージョンについては記載が見当たらなかった。
  ただ、`.addClass`のドキュメント内に以下の記載があるため、Android 4.3 以上には対応している（ように意図している）と推測することはできるか。いずれにしろ、android、iOSについては個別に検証が必要かもしれない。

> However, there are also some advantages of using Umbrella's methods instead of native methods. For example, with .addClass() vs native classList.add():
> 
> - cross-browser: the classList.add() with multiple elements is not compatible with IE10-11 & Android 4.3-

## 所感

DOM操作、ajax、イベントハンドリングについてはumbrella.jsで必要十分という印象。
その他のAPIが必要であれば個別に導入すればよいかな。
amimate系であれば`velocity.js`などのより優れたライブラリはあるし、`Deferred`は既に`Promise`や`async/await`が使える環境であれば不要かも。
レガシーブラウザへの対応が不要であれば「取り敢えずjQueryを使う」という選択肢の代替には十分なり得る印象。
Siv3DでのJSONファイル使い方サンプル

# Siv3DでのJSONファイル使い方サンプル

JSON,INI,CSVの特徴

### INI
余り使ったことが無いけど構成ファイルに使える。  
JSONと違ってコメントを入れられる。  

config.iniファイルを作って、ウィンドウサイズやキー設定を入れておくと便利。  

### CSV
複数ユニットの挙動を列挙するのに便利。  
簡単に扱えるので初心者向け？  
JSONの方が出来ることが多いので自分はもう使っていません。

### JSON
一番便利。  
ユニットのデータをまとめるのによく使います。  
例外的なユニットも記述できる汎用性の高さが魅力的。
コメント機能がないのが残念（裏技的な方法は検索すれば出てきますが、、、）

## 具体例

``` JSON:data.json
[
    {
        "name":"ザリガニ",
        "color":"(255, 0, 0)",
        "size":100,
        "speed":1.0
    },
    {
        "name":"カタツムリ",
        "color":"(255, 128, 0)",
        "size":50,
        "speed":0.1
    },
]

```

``` C++:Main.cpp
#include<Siv3D.hpp>

struct UData
{
	String	name;
	Color	color;
	int		size;
	double	speed;

	UData(JSONValue j)
		: name(j[L"name"].get<String>())
		, color(j[L"color"].get<Color>())
		, size(j[L"size"].get<int>())
		, speed(j[L"speed"].get<double>())
	{}
};

struct Unit
{
	UData*	uData;
	Vec2	pos;
	
	Unit(UData* _uData)
		: uData(_uData)
		, pos(RandomVec2(Window::ClientRect()))
	{}

	void	update()
	{
		Circle(pos, uData->size).draw(uData->color);
	}
};

void Main()
{
	Array<UData> uData;
	JSONReader json(L"data.json");
	for (auto j : json.root().getArray()) uData.emplace_back(j);

	Array<Unit>	units;
	for (auto& ud : uData) units.emplace_back(&ud);

	while (System::Update())
	{
		for (auto& u : units) u.update();
	}
}
```
3GIM > GPS > 3GIMの電源確保の方法考察



これは以下の記事で書いた事を実現するにあたり、どうやったらGPSリアルタイムトラッキングが可能かを最初に考察した記録です。

#### **[3GIMでGPS リアルタイムトラッキング](https://qiita.com/sugasaki/items/450845e8a5285a1bf6ab)**


# 3GIMの電源をどのような方法で供給するか？

## 電源の悩み

さて、クラウドへデータを送る目処があらからついたが、
電源をどう確保するかの悩みが新たに発生した。

動作環境は3日間山の中である。
当然電源は無い。

3GIMへ接続する電源としては、リチウムイオン電池 26650、もしくは18650が良いとの事である。

まったくの素人に26650がどんなものか想像も付かなかったが、調べていくうちにリチウム電池の規格番号というのが分かってきた。

26650と18650は長さが共に65mmで、直径が違うようだ。
26650は26mm、18650は18mm

![image.png](https://qiita-image-store.s3.amazonaws.com/0/49910/4bb4fd98-cf3a-ed4e-52d5-9072ed7ab74f.png)![image.png](https://qiita-image-store.s3.amazonaws.com/0/49910/cc46c678-363a-46e1-d32c-d2ea3ce731ce.png)


### で、どちらを選べばいいのだ？
リチウムイオンポリマーはどうなのだ？
容量は？

悩みは尽きないが、試すことにした。
ひとまず、26650、18650、リチウムイオンポリマー400を買う

## 電源BOXの悩み

電池の種類はなんとなく分かった。
じゃ、電池とIoTabとどうやって接続すればいいのだ？
まだ実物が目の前にないので想像するしか無い。

イメージとしては↓たぶんこんな物に入れてPHコネクタに繋げばOKだろうと思う。
<img src="https://qiita-image-store.s3.amazonaws.com/0/49910/c117624a-b1a3-989e-c5e8-e4f505663509.png" width=200px>

と思って秋月電子の電池ケースを見ても売ってない。
[パーツ一般/電池ｹｰｽ\(電池ﾎﾞｯｸｽ/電池ﾎﾙﾀﾞｰ\)/単3×4本用 秋月電子通商 電子部品 ネット通販](http://akizukidenshi.com/catalog/c/c3x4box/)

他を探してみてもリチウム用の電池ケースがなかなか売ってない。
Amazonでは見つけたが、評価がかなり別れているし、中国から発送するようで到着まで10日～15日かかるようだ。

<img src="https://qiita-image-store.s3.amazonaws.com/0/49910/df8acf0f-1c89-91ef-c80f-417cbe8bba6a.png" width=200px>


さんざん探してここで1個見つけた。209円！
[蓄電システム：バッテリーホルダーケース（26650×1本）](http://www.chikuden-sys.com/category/iron-battery.asp?id=7026&c2id=212)
[蓄電システム：バッテリーホルダーケース（18650×1本）](http://www.chikuden-sys.com/category/iron-battery.asp?id=2957&c2id=212")



電池が入るのかも問合せたところ、規格の65mmは入るが、
Keeppewerは過放電、過充電保護機能付きで69mmの為、入らないとの事である。
しかも送料が700円

### 振り出しに戻るである。

その後、
[【共立エレショップ】>> 18650用電池ケース1本用 リード線付](http://eleshop.jp/shop/g/gE2R121/)

[【共立エレショップ】>> リチウムイオン18650×1本用電池ケース リード線付:](http://eleshop.jp/shop/g/gF2H126/#)

<img src="https://qiita-image-store.s3.amazonaws.com/0/49910/661762e2-85f0-ee98-af96-4bc1a458bee4.png" width=200px><img src="https://qiita-image-store.s3.amazonaws.com/0/49910/808922a5-05b4-a240-3f77-321d0b4cd7cd.png" width=200px>

写真でみる限りは69mmの電池も入るか入らないかギリギリな感じがする。

### 秋月にもありました。

１８６５０用なのに１８６５１という商品名でした。そらひっかかないわ。

[電池ボックス　ＢＨ－１８６５０１－Ａ: パーツ一般 秋月電子通商 電子部品 ネット通販](http://akizukidenshi.com/catalog/g/gP-08407/)

<img src="https://qiita-image-store.s3.amazonaws.com/0/49910/293e7159-d8ae-35fb-4a43-0dc25b994077.png" width=200px>

サイズも70mmが入りそうです。


## 結果

ひとまず電池ケース全部注文してみました。
1個200円くらいのに送料700円くらいかかりました。
九州まで届くのにあと2日かかります。
JISキーボードMacbookのWindows(VirtualBox)でも`かな`キーと`英数`キーでIME on/off する

## 方針
- Sierra以降に対応した`Karabiner-Elements`で設定する
- `英数`キーを CTRL+¥ に割り当てる（`かな`キーはデフォルト`全角/半角`のまま）

## 方法
#### 1. `Karabiner-Elements`がなければインストールして起動しておく
#### 2. 設定ファイルを作成する  

```sh
$ vim ~/.config/karabiner/assets/complex_modifications/FromEisuuToCtrlYen.json
```

この内容で  

```json:FromEisuuToCtrlYen.json
   {
  "title": "VirtualBoxのWindowsで`英数`キーをCTRL+Yenに",
  "rules": [
    {
      "description": "VirtualBoxのWindowsで`かな`キーも`英数`キーも`全角/半角`なので、`英数`キーをCTRL+Yenにして区別可能にする",
      "manipulators": [
        {
          "type": "basic",
          "from": { "key_code": "japanese_eisuu", "modifiers": { "optional": [ "any" ] } },
          "to": [ { "key_code": "international3" , "modifiers" : [ "left_control" ] } ],
          "conditions": [ { "type": "frontmost_application_if", "bundle_identifiers": [ "^org\\.virtualbox\\.app\\.VirtualBoxVM$" ] } ]
        }
      ]
    }
  ]
}
```

#### 3. `Karabiner-Elements` アイコンクリック > `Preferences...` を開いて
1. `Complex Modifications` の `Add rule` ボタンから
<img width="1112" alt="スクリーンショット" src="https://qiita-image-store.s3.amazonaws.com/0/51686/31c5f99d-a111-a3f8-1ea6-efc9f926f61d.png">
2. 作成した定義「VirtualBoxのWindowsで...」の `Enable` ボタンを選んで追加する
<img width="1112" alt="スクリーンショット" src="https://qiita-image-store.s3.amazonaws.com/0/51686/3561b4c1-51c3-2dd6-4556-0bb4cecbe499.png">

#### 4. これで「VirtualBoxのWindows」で以下の通り変換される
| Macキー | Windows（on VirtualBox)キー |
| --- | --- |
| `英数`キー | CTRL+¥ |
| `かな`キー | `全角/半角`キー |

#### 5. 「VirtualBoxのWindows」で使ってるIMEにたいして、それぞれのキーへ、`onのみ`/`offのみ`を設定して完了

## 課題
本当は、以下の通りににしたかったけど、力不足で実現できず(`japanese_pc_xfer`？)

| Macキー | Windows（on VirtualBox)キー |
| --- | --- |
| `英数`キー | `変換`キー |
| `かな`キー | `無変換`キー |

## 環境
- macOS Sierra
- Karabiner-Elements 11.3.0

## 参考
- [Windows on VirtualBox on Macのかな切り替えの方法](https://qiita.com/shouta-dev/items/6b12b32501fa147a4512)
for for ∞ for python

C言語とかは`for(;;)`とかで無限ループできるらしいですが、pythonのfor文でも出来ます。気をつけて下さい。動作確認はpython3でやってますが、python2とかでも起きるはずです。
あと、普通に無限ループしたい場合は`while True:`を使ってください。

# 方法
for文が参照しているリストをループ内で増やす。

サンプルコード

```py3
from time import pause # これなしで無限ループを試す度胸ないです

# 参照するリストの初期化
loop = [0]

# 無限ループ
for i in loop:
    print(i)
    pause(0.5)
    loop.append(i+1)
```

適当なあたりで切り上げて下さい。

# 対策
ただループするつもりが、無限ループになっちゃった！というのはとても怖いので、対策をお伝えしておきます。

リストをコピーした上でfor文に渡して下さい。

```py3
# 有限ループ
for i in loop[:]:
    print(i)
    pause(0.5)
    loop.append(i+1)
```

## 注意：対策になってそうでなってない奴

```py3
loop2 = loop

# 無限ループ
for i in loop2:
    print(i)
    pause(0.5)
    loop.append(i+1)
```

これ、一旦`loop2`にコピーしているので問題なさそうに見えますが、`loop`に要素を追加すると、`loop2`にも追加されます。
代入はオブジェクトをコピーせず、オブジェクトを共有します。
下のは問題ありません。`[:]`をつけるとシャローコピーしてくれるので。

```py3
loop2 = loop[:]

# 有限ループ
for i in loop2:
    print(i)
    pause(0.5)
    loop.append(i+1)
```


# リストのコピーについて
コメントを受けて調べ直したところ、`[:]`はシャローコピーとは違うことがわかりました。
4種類のリストのコピーとその違いを紹介します。

```py3
before = [[1,2,3], [4,5,6]]
```

以下の四つです。

 - そのまま代入
 - スライス(`[:]`)を使う
 - `list()`を使う
 - `copy.deepcopy`を使う

## そのまま代入

```py3
after_eq = before
```

ここで、`after_eq`と`before`の`id`を調べてみましょう

```py3
id(after_eq) == id(before)
# => True
```

これはどういうことかというと、リストはコピーされず、**ひとつのリストを二つの変数から扱える**状態です。
それが嬉しいかはわかりません。

## スライス(`[:]`)や`list()`を使う
この二つは結果が同じです。

```py3
after_sl = before[:]
id(after_sl) == id(before)
# => False

after_ls = list(before)
id(after_sl) == id(before)
# => False
```

このように、スライスや`list()`を使うと全く別のリストがコピー出来たように思います。しかし、

```py3
id(after_sl[0]) == id(before[0])
# => True

id(after_ls[0]) == id(before[0])
# => True
```

となります。つまり、**一階層だけコピーするシャローコピー**と言うことです。
これがどういう意味かは、以下の例も参考にして考えてみて下さい。

```py3
zero = [[0]]
zeros = zero*3
print(zeros)
# => [[0], [0], [0]]
zeros[0][0] = '0'
print(zeros)
# =>[['0'], ['0'], ['0']]
```

## `copy.deepcopy`を使う
1番安全なのは、標準ライブラリ内の`copy.deepcopy`を使うことだと思います。

```py3
import copy

after_dc = copy.deepcopy(before)

id(after_dc) == id(before)
# => False

id(after_dc[0]) == id(before[0])
# => False
```

これこそが**ディープコピー**というものです。
python でメールの受信

Python3 で、imap サーバーからメールを受信する方法です。
Yahoo Mail で確認しました。

```py:imap_get.py
#! /usr/bin/python
#
#   imap_get.py
#
#					   Jun/26/2023
#
# --------------------------------------------------------------------
import os
import sys
import ssl
import imaplib
import email
from email.header import decode_header, make_header
from dotenv import load_dotenv
# --------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
dotenv_path = '.env'
load_dotenv(dotenv_path)
#
server= os.environ.get("SERVER")
usr= os.environ.get("USR")
password= os.environ.get("PASSWORD")
try:
	context = ssl.create_default_context()
#	context = ssl._create_unverified_context()
	imapclient = imaplib.IMAP4_SSL(server, 993, ssl_context=context)
#   sys.stderr.write("*** usr = %s ***\n" % usr)
#   sys.stderr.write("*** password = %s ***\n" % password)
	imapclient.login(usr,password)
	imapclient.select()
	typ, data = imapclient.search(None, 'ALL')
	icount = 0
	for num in data[0].split():
		typ, data = imapclient.fetch(num, '(RFC822)')
		email_message = email.message_from_bytes(data[0][1])
#
		email_from = str(make_header(decode_header(email_message['From'])))
		print(email_from)
		subject = str(make_header(decode_header(email_message['Subject'])))
		print(subject)
		sys.stderr.write(subject + "\n")
		

#		msg_encoding = 'iso-2022-jp'
		msg_encoding = 'utf-8'

		if email_message.is_multipart() == False: # シングルパート
			sys.stderr.write("*** eeee ***\n")
			byt  = bytearray(email_message.get_payload(), msg_encoding)
			body = byt.decode(encoding=msg_encoding)
		else:   # マルチパート
			sys.stderr.write("*** multi part ***\n")
			prt  = email_message.get_payload()[0]
			byt  = prt.get_payload(decode=True)
			try:
#				body = byt.decode(encoding=msg_encoding)
				body = byt.decode("utf-8")
			except Exception as ee:
				sys.stderr.write("*** error *** byt.decode\n")
				sys.stderr.write(str(ee) + '\n')
			sys.stderr.write("*** hhhh ***\n")
#
		print(body)
#
		icount += 1
		if (2 < icount):
			break
	imapclient.close()
	imapclient.logout()
except Exception as ee:
	sys.stderr.write("*** error ***\n")
	sys.stderr.write(str(ee) + '\n')

sys.stderr.write("*** 終了 ***\n")
# --------------------------------------------------------------------
```

```text:.env
SERVER = 'imap.mail.yahoo.co.jp'
USR = '*****@yahoo.co.jp'
PASSWORD = '*********'
```

## 確認したバージョン

```text
$ python --version
Python 3.11.3
```

Yahoo 以外のサイトで、次のようなエラーが出る時の対策

```text
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for
```

```py
#       context = ssl.create_default_context()
       context = ssl._create_unverified_context()
```
ブラウザで非同期処理を同期的に処理する fetch(Promise) + async/await

## 目的
Webアプリケーションを作成する際に、一旦サーバ上の設定ファイルやレンダリング用のモデルデータを事前に読み込んでおきたい場合に、どうしてもシーケンシャル（同時にアクセスしたくない場合）がある。jQueryのDeferredでも同じことができるが、fetch、async/awaitを用いることでもっと単純に処理ができるので、備忘として記載する。同じことを示した記事はいろいろとあるけど、どれもsetTimeoutやjQueryのDeferred、generatorなどの経緯も込みで書いてあるので、それはそちらにまかせて、ここではfetch + async/awaitのみを書く。

## fetch + async/await
これでOK

```js
getConfig = async() => {
    var conf1 = await (await fetch("/conf/conf1.yml?_="+(new Date()).getDate())).text();
    console.log(conf1);
    var conf2 = await (await fetch("/conf/conf2.yml?_="+(new Date()).getDate())).text();
    console.log(conf2);
}

window.onload = function(){
    getConfig();
}
```
fetchやfetchの text() / json() / blob() などはPromiseを返却するので、以下のように書くと理屈がわかりやすい。

```js
getConfig = async() => {
    var promise1 = await fetch("/conf/conf1.yml?_="+(new Date()).getDate());
    var conf1 = await promise1.text();
    console.log(conf1);
    var promise2 = await fetch("/conf/conf2.yml?_="+(new Date()).getDate());
    var conf2 = await promise2.text();
    console.log(conf2);
}

window.onload = function(){
    getConfig();
}
```

fetchの代わりに、Promiseを返却する関数を指定しても同じことができる。
また、fetchは4xx系、5xx系のエラーコードが返却されても、正常処理としてしまうので、try catchが使えない。※ネットワーク系のエラーの場合のみcatchが使える。4xx、5xx系はstatusを見て判断しろという事らしい。
そのため、エラーハンドリングをしたい場合は以下のようにすることができる。

```js
getConfig = async() => {
    var conf1 = await (await fetch("/conf/conf1.yml?_="+(new Date()).getDate())
                    .then(handler)
                    .catch(error)
                ).text();
    console.log(conf1);
    var conf2 = await (await fetch("/conf/conf2.yml?_="+(new Date()).getDate())
                    .then(handler)
                    .catch(error)
                ).text();
    console.log(conf2);
}

function handler(response){
    if(!response.ok){
        throw Error(response.statusText);
    }
    return response;
}

function error(e){
    console.log(e);
}

window.onload = function(){
    getConfig();
}
```

## まとめ
* fetch は Promise を返却する
* await は async なメソッドの中でのみ実行可能
* await は Promise を待つ
* 上記のコードは、getConfig() 自体が同期になるわけではない。
* 上記のコードは ```python -m SimpleHTTPServer 80``` では動かないので注意
* トランスパイルなんてしたくない！！古いブラウザは捨てたい！！<br>大企業の古いブラウザバージョンいつまでもケアは頭がおかしい。

## 添付
* async/await対応状況 https://caniuse.com/#search=async%20functions
* fetch対応状況 https://caniuse.com/#feat=fetch
fish 2.7.0 で追加された cdh コマンドが便利

fish 2.7.0 で `cdh` というコマンドが追加されました。

これはディレクトリの履歴から `cd` するディレクトリを選択できるものです。fish だとこれまで `pushd` / `popd` とか `z` とかを使ってディレクトリの移動はやりくりするしかなかったので、このコマンドの追加はかなりありがたいと感じています。zsh の `cd -` や `cdr` をご存知の方であれば、そういったユーザーフレンドリーなディレクトリ移動をサポートするものと思ってもらえればよいです。

まあ一回使ってみれば使い方はすぐわかるのでわざわざ紹介するまでもないのですが、どうせお前らリリースノートとか読んでないだろうからな！

## 使いかた

```shell-session
$ cdh
```

とだけ入力すると

```shell-session
$ cdh
 d  4)  ~/ghq/github.com/xxxxx
 c  3)  ~
 b  2)  ~/Desktop
 a  1)  /Library
```

とこんな感じで最近訪問したディレクトリがリストアップされますので、文字 (`a...`) か数字 (`1...`) で移動したいディレクトリを選択します。

ちなみに、`cdh` にディレクトリを引数として渡すと `cd` と同じ働きになるようです。つまりそのディレクトリに単純に移動します。

また、試していないのですが、`man cdh` によると、ディレクトリ履歴は `$dirprev` と `$dirnext` という変数に格納されるため、それらの変数を universal variable にするとセッションを跨いで履歴を共有することができるようです。
MATLABとMatplotlib 3dの座標系 | viewの違い > view(azimuth=0) > MATLAB:xaxisが横軸 | Matplotlib:yaxisが横軸 > MatplotlibとMATLABで同じ表示にするには

```txt:動作環境
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.2.1
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
scipy v0.19.1
geopandas v0.3.0
MATLAB R2017b (Home Edition)
```

[pySpherepts > Jupyter > 結果の座標を球面上に表示する実装 v0.2 > 奥の点排除 > 同じものが得られた](https://qiita.com/7of9/items/af4827dc6c56366f6112)
にて同じazimuthとelevationとした時に結果が異なるのが気になった。

## 座標系

座標系を調べた。

MATLAB
http://math.loyola.edu/~loberbro/matlab/html/PlotChangeCoordinates.html

Matplotlib 3d
https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html

~~Yの方向(正負)が異なる。~~


MATLABは「右手系」
https://jp.mathworks.com/matlabcentral/answers/80671-does-matlab-use-a-left-handed-or-right-handed-coordinate-system-for-the-plot3-command

~~Matplotlibは「左手系」なのだろう。~~

x軸とz軸を基準に見ると、両者が同じように見えてきた。
view()で見える対象が異なるのだろうか。
(azimuthの定義の違い?)

## viewの違い

### APIの比較

Matplotlibのview_init()
https://matplotlib.org/mpl_toolkits/mplot3d/api.html
> view_init(elev=None, azim=None)

MATLABのview()
https://jp.mathworks.com/help/matlab/ref/view.html
> view(az,el)

elevationとazimuthを同じにして、軸ラベルを追加してみた。

MATLAB
![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/4a044ae2-8e2f-cdaf-d762-ed82a7c53cf2.png)

Matplotlib
![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/2217dec7-bd6f-ecb8-3602-9c958bd9270e.png)

azimuthが0の時

- MATLAB: xaxisが横軸になる
- Matplotlib: yaxisが横軸になる
- 手前と奥の軸の正負も異なる
    - MATLAB: yaxis
    - Matplotlib: xaxis

### 同じ表示にするには

Matplotlibで`ax.view_init(elev=0, azim=0)`に対する
MATLABの設定は`view(90,0)`にすれば同じ見た目になる。
(90: azimuthに90を足す)

この場合、横軸はy軸になる。
Matplotlib 
![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/93328c94-9389-555b-31c5-e3bad5b988b5.png)

MATLAB
![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/55b4fa98-4917-67d1-8d6b-26a8247264ae.png)
GitHub Markdown + TeX記法で筆算を書きたい

GitHub Markdown + $\TeX$ 記法で数式を書く際に調べた事について覚書き
# 筆算を書きたい

[コードブロックの言語指定に "math" を指定](http://qiita.com/Qiita/items/c686397e4a0f4f11683d#%E6%95%B0%E5%BC%8F%E3%81%AE%E6%8C%BF%E5%85%A5)することで合わせることができた.

> \`\`\`math
\begin{array}{rr}
& 12345\\
+&6789\\
\hline
&13023
\end{array}
> \`\`\`



```math
\begin{array}{rr}
& 12345\\
+&6789\\
\hline
&19134
\end{array}
```

***
よりスマートな方法があれば教えていただけると嬉しいです.
pySpherepts > Jupyter > 結果の座標を球面上に表示する実装 v0.2 > 奥の点排除 > 同じものが得られた

```txt:動作環境
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.2.1
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
scipy v0.19.1
geopandas v0.3.0
MATLAB R2017b (Home Edition)
```

### 処理

[pySpherepts > Jupyter > 結果の座標を球面上に表示する実装 v0.1 > 余分な点が見える (奥側の点のようだ)](https://qiita.com/7of9/items/d7d3c810b9ffdef52585)
上記の問題点は「奥側の点が隠面処理されずに見えている」ことだろう。

プロットするデータから排除するようにした。

排除を容易にするため一つの座標のquadrant(象限)を排除することにした。
加えて、view設定を変更することで、残った点が正面に見えるようにする。

### code v0.2


```py:plotSphNodes_171126.ipynb
import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from pylab import rcParams
from matplotlib.colors import LightSource

# https://stackoverflow.com/questions/31768031/plotting-points-on-the-surface-of-a-sphere-in-pythons-matplotlib

rcParams['figure.figsize'] = 10,10
rcParams['figure.dpi'] = 130

# Create a sphere
r = 1
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0.0:pi:100j, 0.0:2.0*pi:100j]
x = r*sin(phi)*cos(theta)
y = r*sin(phi)*sin(theta)
z = r*cos(phi)

#Import data
data = np.genfromtxt('res_IcodsNodes_4_0_171126.txt')
data = data * 1.0005
xx, yy, zz = np.hsplit(data, 3) 

xs, ys, zs = [], [], []
for ax, ay, az in zip(xx, yy, zz):
    if (ay > 0):
        xs += [ax]
        ys += [ay]
        zs += [az]
xx, yy, zz = xs, ys, zs

#Set colours and render
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

ax.plot_surface(
    x, y, z,  rstride=1, cstride=1, color='y', alpha=1.0, linewidth=0, shade=False)

ax.scatter(xx,yy,zz,color="k",s=15)

ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
ax.set_aspect("equal")
plt.tight_layout()
ax.view_init(0, 90)
plt.show()
```


![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/7b6aec14-323f-c901-6698-2f07b2e976fe.png)

### MATLABの結果

MATLABでsphereptsを実行した結果は以下。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/8c3d2dfb-63ea-2e24-8020-124cca9c3f91.png)

上記は下記にて得られた (spherepts使用)。

```matlab
>> [x0,tri0] = getIcosNodes_log(4,0);
>> plotSphNodes(x0)
>> view(0,0)
```

### APIの比較

Matplotlibのview_init()
https://matplotlib.org/mpl_toolkits/mplot3d/api.html
> view_init(elev=None, azim=None)

MATLABのview()
https://jp.mathworks.com/help/matlab/ref/view.html
> view(az,el)

view(90,0)にすると配置が異なる。
~~座標系(xyzとxzyなど)が二つのプラットフォームで異なるのかも。~~
azimuthの定義が異なっていた。
fish 2.7.0 にアップデートしたら iTerm2 で "Looks like paste bracketing was left on..." というワーニングが出るようになった

fish 2.7.0 にアップデートしたら iTerm2 で 

```
Looks like paste bracketing was left on when an ssh session ended unexpectedly or an app misbehaved. Turn it off? (Yes/Always/Never)
```

というワーニングが出るようになった。

また、ここでどの選択肢を選んでもまた再起動するとワーニングが再現してしまう。

## 対策

まず、issue があがっていてまだ現在進行形で続いているので、あくまでこれは現時点で「ひとまずワーニングを黙らせたい」場合の回避策となる。

https://github.com/fish-shell/fish-shell/issues/4521

1. iTerm2 の `Shell Integration` 機能を無効にする
2. その後、ワーニングへの対応で `Never` を選択する

自分の場合は `Shell Integration` を全く使っていないのでこれで別に問題ないが、活用している人は、今後根本対策の情報があるかもしれないので issue をウォッチしておくとよいと思う。

### iTerm2 の `Shell Integration` 機能を無効にする

<img width="1049" alt="Screen_Shot_2017-11-26_at_10_38_33.png" src="https://qiita-image-store.s3.amazonaws.com/0/29846/9633a547-8fe8-8b6e-67d3-95754e19ccf4.png">

### その後、ワーニングへの対応で `Never` を選択する

<img width="173" alt="Screen_Shot_2017-11-26_at_10_38_59.png" src="https://qiita-image-store.s3.amazonaws.com/0/29846/e157c9c9-997e-ef2d-440f-2a935b5f8697.png">
Google Data Studioを使用してBigQueryのデータを可視化する

#初めに

##何故、Google Data Studioを使用するか。
自宅でセンシングしたデータをサーバレスでWEBから表示出来るようにしたかったため。

##目標
BigQueryにあるデータをレポート化するところまでやってみます。

#前提

2017年11月時点の情報です。

##データソースにするテーブル定義
以下のテーブルをBigQuery上に作成しています。

```json
[
    {
        "mode": "REQUIRED",
        "name": "ID",
        "type": "INTEGER"
    },
    {
        "mode": "REQUIRED",
        "name": "LOCATION_LOGI",
        "type": "FLOAT"
    },
    {
        "mode": "REQUIRED",
        "name": "LOCATION_LATI",
        "type": "FLOAT"
    },
    {
        "mode": "REQUIRED",
        "name": "DEVICE_DATETIME",
        "type": "DATETIME"
    },
    {
        "mode": "REQUIRED",
        "name": "TEMPERATURE",
        "type": "FLOAT"
    },
    {
        "mode": "REQUIRED",
        "name": "PRESSURE",
        "type": "FLOAT"
    },
    {
        "mode": "REQUIRED",
        "name": "HUMIDITY",
        "type": "FLOAT"
    },
    {
        "mode": "NULLABLE",
        "name": "TIMESTAMP",
        "type": "TIMESTAMP"
    }
]
```

#手順
##1.DataStudioを起動する
[こちら](https://cloud.google.com/data-studio/)のサイトを開いてDATA STUDIOを起動するを押します。

##2.データソースを設定する
1. すべてのタブでデータソースを押して、右下の＋ボタンを押します。利用規約の同意が出てきた場合は同意して進めます。
2. コネクタの一覧からBiqQueryを選択し、プロジェクトにアクセス権を付与しろと言われるので承認を押して許可を押します。
3. GCPのプロジェクト一覧が出てくるので、対象となるプロジェクトを選択しデータセットの選択、テーブルの選択を行います。
4. 最後に右上の接続を押してデータセットの設定は完了です。

##3.集計方法の設定をする
集計方法は以下の通りに設定します。

| フィールド      | タイプ | 集計方法 |
|:----------------:|:-----------------:|:------------------:|
| ID             |              テキスト |   なし        |
| LOCATION_LOGI           |            数値 |   なし      |
| LOCATION_LATI             |              数値 |   なし        |
| DEVICE_DATEHOUR(BigQueryのカラムから名前を変えています)             |              日付時 |         なし         |
| TEMPERATURE             |             数値 |      平均       |
| PRESSURE          |           数値 |      平均       |
| HUMIDITY          |           数値 |      平均      |
| TIMESTAMP          |           日付時|      なし      |

最後に右上のレポートを作成を押します。


##4.レポートを作成する
「このレポートにデータソースを追加しようとしています」と確認をしてくるのでレポートに追加するを押します。GoogleDriveへのアクセス許可と承認をもとめられるので承認します。

レポート作成画面で、期間とポップアップされるこのボタン![WS000025.JPG](https://qiita-image-store.s3.amazonaws.com/0/168941/d8056682-51fb-fa00-76f8-32feac816810.jpeg)を押します。
レポートのどの位置にグラフを配置するか決めると、グラフが出ます。
![WS000027.JPG](https://qiita-image-store.s3.amazonaws.com/0/168941/1620b3f2-405b-e4c8-8143-4ba26c2ebf55.jpeg)
この指標のところを変えると色々なグラフが作成できます。色などを変更したい場合はスタイルタブを押せば編集が可能です。

こんな感じで作成が可能です。
![WS000029.JPG](https://qiita-image-store.s3.amazonaws.com/0/168941/76fe47c4-3ab0-c6bd-c1cf-da568730cdd4.jpeg)


##5.レポートを共有する（おまけ）
右上の人にプラスがついたマークを押すと人と共有が可能です。Googleアカウントでの認証も可能です。

#最後に
とても簡単にレポートを作成することが出来ました。
GCPのサービスと比べると比較的毛色の違うものに思えます。データソースの集計のところにさえ慣れてしまえば問題なく使えるのではないでしょうか。
これでセンシングしたデータを見せるところまでできました。気になるのは料金ですね。
無駄な部分も多いので、調整していきたいと思います。
重い PDF を Pythonista で軽量・分割した話

この記事は [Pythonista Advent Calendar 2017](https://qiita.com/advent-calendar/2017/pythonista) の9日目の記事です。

Pythonista でライフハックするための、小ネタを紹介します。

## 概要
![P1030456.jpg](https://qiita-image-store.s3.amazonaws.com/0/48607/54ded407-c20b-b2f5-33b8-6ff72a033146.jpeg)


iPhone と Pythonista があれば、いつでもどこでもプログラミングが出来ます。
とは言えフリック入力で Python Syntaxを打ち続けるのは、エディタ支援があっても流石につらいので、

1. Bluetoothキーボード
2. バンカーリング

という最小限のギアを組み合わせて、ライフハックしています。


## 📱 実際にやってみると？
iPhone でプログラミングしてみて感じることは、

1. 検索する時にiPhoneを手に持つと、Bluetoothペアリング状態でソフトウェアキーボードが隠れてつらい
2. 画面サイズに限界のあるiPhoneで、ドキュメントを見ながらアプリを行ったり来たりするのはつらい 

でした。iPad ProとSplitViewを使えば上記の問題を解決できますが、iPad Proは外に持ち出しません...

いろいろ試行錯誤して、眼を通したいページやドキュメントを PDF にして紙の資料にすれば、
解決できるのでは？と考えました。


## 📃 紙の資料にプリントする
iPhoneからPDFをプリントするアプリはいくつかありますが、
私は自宅にプリンターを所持していないので、コンビニでプリント出来るアプリをよく使っています。

ただ、そのアプリに送信出来るPDFのファイルサイズが6MBまでという制約があり、対処に困りました。
そのためだけにPDF分割のアプリをダウンロードしたり、Macでリサイズしてもう一度iPhoneに戻すのは、
あまりスマートではありません。

...

前置きが長くなりました。
この問題に対処するためにPythonistaを使って、PDFのファイルサイズを6MBまでに抑えて分割します。

## 🐍 Python で解決
```python
# -*- coding: utf-8 -*-

import os
import appex

from PIL import Image
from PyPDF2 import PdfFileWriter, PdfFileReader

div = 6

def imageWriter(page0):
	xObject = page0['/Resources']['/XObject'].getObject()
	for obj in xObject:
		if xObject[obj]['/Subtype'] == '/Image':
			size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
			data = xObject[obj].getData()
			if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
				mode = "RGB"
			else:
				mode = "P"
			if xObject[obj]['/Filter'] == '/FlateDecode':
				img = Image.frombytes(mode, size, data)
				img.save(obj[1:] + ".png")
			elif xObject[obj]['/Filter'] == '/DCTDecode':
				with open(obj[1:] + ".jpg", "wb") as img:
					img.write(data)
			elif xObject[obj]['/Filter'] == '/JPXDecode':
				with open(obj[1:] + ".jp2", "wb") as img:
					img.write(data)

def main():
	src = appex.get_file_path()	
	src = PdfFileReader(src, 'rb')
	items = [range(i, min(i + div, src.numPages)) for i in range(0, src.numPages, div)]
	
	if not os.path.exists('pdf'): 
		os.mkdir('pdf')
		
	for i, lst in enumerate(items):
		dst = PdfFileWriter()
		for j in lst:
			dst.addPage(src.getPage(j))
			with open('pdf/%03d.pdf' % i, 'wb') as out:
				dst.removeLinks()
				dst.write(out)

if __name__ == '__main__':
	main()
```
https://gist.github.com/sho7noka/44415e24adc19d92248baf2e5e74bad4

*PyPDF2* 内で余計なメタデータを削除・ページ数を分割することで、１ファイルあたりのサイズを6MBまで
軽量化しています。Pythonista Documents 内の pdf フォルダに書き出されます。

*PIL* と *PyPDF2* はPythonista built-in モジュールなので、別途 *pip* インストールする
必要がありません。*appex* モジュールはPythonista用モジュールなので、他の環境では
os.path モジュールなどに読み替える必要があります。

## まとめ
ポケットに収まるサイズ感でモバイルハック出来るのがPythonista最大のメリットなので、
工夫次第でなんでも出来そうです。カフェの小さなテーブルでも邪魔にならないサイズ感です☕

日常の小さな問題を解決する手段としての、Pythonの小ネタの紹介でした。
pySpherepts > Jupyter > 結果の座標を球面上に表示する実装 v0.1 > 余分な点が見える (奥側の点のようだ)

```txt:動作環境
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.2.1
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
scipy v0.19.1
geopandas v0.3.0
MATLAB R2017b (Home Edition)
```

[pySpherepts > sphereptsのNumpy、Scipy実装 > 結果: sphereptsと同じものが得られた](https://qiita.com/7of9/items/9006941f4a9ae76e4670)
にてNumpy+Scipyでの処理結果をJupyterで表示したい。

### 参考

https://stackoverflow.com/questions/31768031/plotting-points-on-the-surface-of-a-sphere-in-pythons-matplotlib

### データ例

読込むデータはpySphereptsで生成した座標データ。

```bash
$ head res_trisectTri_171126.txt 
[[-0.98302355 -0.18347941  0.        ]
 [-0.98302355  0.18347941  0.        ]
 [-0.93417236  0.         -0.35682209]
 [-0.93417236  0.          0.35682209]
 [-0.85198102 -0.39551069 -0.34307382]
 [-0.85198102 -0.39551069  0.34307382]
 [-0.85198102  0.39551069 -0.34307382]
 [-0.85198102  0.39551069  0.34307382]
 [-0.85065081 -0.52573111  0.        ]
 [-0.85065081  0.52573111  0.        ]
```

### code

上記のリンク先コードから以下などを変更した。

- 点の位置をradial direction外側に移動
- 下地の球の色を変更
- figsize変更

```py:plotSphNodes_171126.ipynb
import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from pylab import rcParams

# https://stackoverflow.com/questions/31768031/plotting-points-on-the-surface-of-a-sphere-in-pythons-matplotlib

rcParams['figure.figsize'] = 10,10

# Create a sphere
r = 1
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0.0:pi:100j, 0.0:2.0*pi:100j]
x = r*sin(phi)*cos(theta)
y = r*sin(phi)*sin(theta)
z = r*cos(phi)

#Import data
data = np.genfromtxt('res_IcodsNodes_4_0_171126.txt')
data = data * 1.0005
xx, yy, zz = np.hsplit(data, 3) 


#Set colours and render
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

ax.plot_surface(
    x, y, z,  rstride=1, cstride=1, color='y', alpha=1.0, linewidth=0)

ax.scatter(xx,yy,zz,color="k",s=15)

ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
ax.set_aspect("equal")
plt.tight_layout()
plt.show()
```

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/cda61b0d-2968-6c02-5c28-f4710e07fabf.png)

下の図(MATLAB上でsphereptsのplotSphNodes使用)と比べて見栄えが良くない。分布の感じがつかみにくい。
~~本来見えない奥側の点も見えているようだ。~~
~~点の影が映っているのかもしれない。~~
中央の球を消した時と消さない場合で同じ点が見えているため、奥側の点が見えているのかもしれない。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/2f974e21-9f5e-111c-ee95-fe0cac3b7984.png)