OmniAICreator/Qiita-1.07M huggingface dataset:
AtCoderわからん日記_3　ABC149C,D

#はじめに
　[ABC149](https://atcoder.jp/contests/abc149)も参加してきました。Unratedになっちゃったけど。
　愚かなのでA問題で問題文を読み違えてミスしちゃったりしました。あと、B問題で結果を得るのではなく文字通りの操作をやろうとして、計算量のことを思い出して慌てて方向性の調整をしたりして、前回前々回やったことが少しだけ生きている……気がします。
　Qiita、この日記をテンプレート化したいんだけどどうしたらいいんだろう。それこそプログラミングでなにがしかのコードを組めばいいのか。わざわざエディタ開いてなんかするよりメモ帳に貼ってコピペしたほうが早いんじゃないかな。こうやって楽しようとしてよりめんどくさいことをする人、プログラマに多い気がする。偏見です。

# C - Next Prime
X以上の素数のうち、最小のものを求めよ。

## 考えたこと
①素数の間隔がどのぐらいあるのか（平均で10ちょっとらしい）
②もう地道に割っていくしかないんじゃないか
③TLEこわい
この問題文シンプルでいいですね。
ルジャンドル予想とか使えないかなと思ったけど別にいらなかった。

###1回目
1回目というか通ったので1回しかない

```py
import math
n=int(input())
#ループを奇数から始める
if n % 2 == 0 and n != 2:
        n += 1
#余裕を持って20回試行
while n <= n + 20:
    i=3
    #平方根より小さい奇数のiで割り続ける
    while i <= math.sqrt(n):
        #割れたら次のn
        if n % i == 0:
            break
        #割れなかったら次のi
        else:
            i += 2
    #全部割れなかったらそれが答えなので終わる
    if i >= math.sqrt(n):
        print(n)
        break
    else:
        n+=2
```
通りました。う～ん。もっといいやり方があるとは思うけれども……。

```py
if i >= math.sqrt(n):
```
しかし、やりかたというか、これすごくダサい気がする。ループをbreakせずにやり遂げた時の判定をどうしたらいいのかと思ってこうしたんだけれど、同じことをやるにしてもなんかもっといい方法がある気がする……。
それと、素数について、10<sup>5</sup>レベルならだいたい20もあれば十分だろう、という仮定で20回のループにしたけど、こういうのっていいのかなあ……。


強人（つよびと）の解答
---
 - 平方根、math入れなくても**0.5でいい
 - 地道に1ずつ増やしながら割っていくだけ

　意外と普通の総当たり作業だった。
　そもそもそんなに多くない回数で終わることがわかっているのでwhile文によるiの大きさの定義っていらないし、for文のほうを使うべきだったな。同様にwhile二回も使わなくてよかったな。
　前回前々回でTLEになりまくったこともあり、負荷をかけないように奇数だけで割るとか工夫したけれど、意外となくてもいけるんだなと思いました。このへんの計算量のおおよそな予想ができると加減がわかるんだろうな。しかし、それのおかげかわからないけれど実行時間は速かったです。また、割る範囲を平方根にしている人があまりいなかったな。しかし、競技プログラミングはいかに速くコードを書くかのところが強いから、そこまで計算量が多くなければなくてもいいのだけれど。でもだいぶ減るんじゃないかな、どうかな。

　みんなの提出を見ているといいコードってなんなのかなあと考えます。もちろんわかりやすくて早くて短いのがいいんだろうけれど、それらのバランスが難しいですね。一行で終わってるコード書いても可読性は低いし、早くてもこんな冗長なコードはよくないし。

忘れないうちにDも書こう。

# D - Prediction and Restriction

高橋君は、ゲームセンターで「じゃんけんバトル」というゲームをプレイすることにしました。このゲームのルールは以下の通りです。

 - プレイヤーは筐体とN回じゃんけんを行う (あいこの場合も1回のジャンケンと数える)。
 - プレイヤーがじゃんけんで勝った場合、プレイヤーは出した手に応じて以下のスコアを得る (あいこや負けは0点)。
    - グーで勝った場合、R点
    - チョキで勝った場合、S点
    - パーで勝った場合、P点

ただし、ちょうどK回前のじゃんけんで出した手と同じ手を出すことはできない。(K回目までのじゃんけんでは好きな手を出せる。)
筐体は、各回のジャンケンで出す手をゲーム開始前に決定します。能力者である高橋君は、ゲーム開始前にこれをすべて読み取りました。
高橋君が読み取った情報は文字列Tとして与えられます。Tの i(1≤i≤N)文字目がrのときはi回目のじゃんけんで筐体がグーを出すことを、sのときはチョキを出すことを、pのときはパーを出すことを表します。
高橋君がN回のじゃんけんで出す手を最適に選んだとき、ゲーム終了までに最大で合計何点を得られるでしょうか。


## 考えたこと
①k回後に被るときはあいこか負けなのでカウントしない
②カウントしない文字を置換して、最後に有効なじゃんけんの数を数える
AtCorderには能力者が多いね。全員集めてバトルさせたいな。

###1回目
```python
n,k = map(int,input().split())
r,s,p = map(int,input().split())
st = input()
for i in range(len(st)-k):
    if st[i] == st[i + k]:
        st = st[:i + k]+ 'no' + st[i + k + 1:]
win = r*st.count('s') + s*st.count('p') + p*st.count('r')
print(win)
```
通りました。文字列って置換できないからスライスで切ってつないだんだけど、う～む。つかlen(st)て。nあるじゃん。

強人（つよびと）の解答
---
 - 普通にリストで受け取って置換すればよい

 ほかはだいたい同じでした。文字列にしたせいか実行時間がむっちゃ長い。試しにリストでやったら598msが47msになりました。愚かなり。
良くないところもあるけどD意外とできたな。時間内には出来てないけど。これからも頑張っていきたいです。
Android9でNotificationが表示されない～ので対応



Androidアプリ開発で、つまずいた所があったのでメモ。

#転載元
当記事は以下ブログからの転載です。
[TECH BACK](https://techback.info/android8-notification/)

# はじめに
リマインドのために、ステータスバーに通知を定期的に表示してるんですが、Android9で表示できず。。。

[こちら](https://amzn.to/2tI2Q5d)の本を参考に、通知機能を実装しました。

通知機能自体も、こちらの本のコードを参考に構築しました。


Androidアプリ開発は、この手の事象は多く発生するだろうな～これからも。

#Androidのバージョン一覧

先におさらいをしておくと、

下記の表のように**Androidバージョン**があるんですが、それぞれ**APIレベル**と**コードネーム**があります。

皆さんも困ったときにググって、それを参考に対応することもあるかと思いますが、**Androidバージョン**で語っていたり、**APIレベル**・**コードネーム**だったり、まちまちなんですよね。そんな時は、この表を思い出してください。

今回は、Android9で動かなかったので、Android9 API28 に対応していく必要があります。

|Android|	API|	コードネーム|
|:-----------------|------------------:|:------------------:|
|Android 4.4	|19	|KITKAT|
|Android 5	|21	|LOLLIPOP|
|Android 6	|23	|MARSHMALLOW|
|Android 7	|24	|NOUGAT|
|Android 8	|26	|OREO|
|Android 9	|28	|PIE|
|Android 10	|29	|Q|

#やはり公式ドキュメント

今回対応したい、通知に関する公式ドキュメントは、こちらですね。

「Android 8.0以上では、、、」と、数カ所記載があります。

Android 8.0以上とそれ以前のバージョンで、大きな違いがあるようです。

気になる記載としては、

>Android 8.0 以上では、**通知を送信する前に通知チャネルを作成する必要がある**ため、**アプリが起動したらすぐにこのコードを実行する必要があります。**
既存の通知チャネルを作成してもオペレーションは実行されないので、これを繰り返し呼び出しても問題ありません。

多分これじゃないでしょうか。

# 対応内容

公式ドキュメントにあるとおり、

>「通知チャンネルを作成する必要がある」

ってことですね。作りましょう！

## 実装コード

これは、公式ドキュメントにそのままのものがあるので、それを既存コードに追記していくことになります。

nameとdescriptionTextは、取得しているコードになっていますが、私はリテラルで指定してしまいました。

```kotlin
private fun createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = getString(R.string.channel_name)
        val descriptionText = getString(R.string.channel_description)
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
                description = descriptionText
        }
        // Register the channel with the system
        val notificationManager: NotificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
        }
    }
```

## 実装する場所

Activityを継承しているClassだったら、どれでも大丈夫かと思うんですが、

>「アプリが起動したらすぐにこのコードを実行する必要があります。」

なんて記載がありますので、**MainActivity**で実装しておけばOK。

そして、createNotificationChannel を onStart()で呼び出しました。
基本情報11週目(12/30週)

# 目標と結果
### 目標
- 参考書をみる。
- [基本情報技術者試験ドットコム](https://www.fe-siken.com/)を使う。
- 午後で通用する様に内容を理解する。
    - アルゴリズムとプログラミングの勉強をする。
    - 午後問題で重視する分野を見つける。
- 1月の予定を立てる。
- 記事のステータスを公開にする。

### 結果
- 正月はじっくりと休みました。

# 振り返り
### Keep
- 道場は継続。

### Problem
- 特に無し。

### Try
- 1月の予定を立てる。
console.logで色付き表示をするメモ

## コンソールログの出力に `色`をつけたかった
どうやら調べていたら `console.log()` の出力の際に色々とスタイルを当てられるということらしい

結果的にまず調べたら
`console.log('%c色を変更する', 'color: red');` //こうすると全部文字色が赤

`console.log('色を変更%cする', 'color: red');` //こうすると `する` の部分のみ色が赤


`%c` これをスタイルの当てたい前後で適用すればいける

が複数の場合は？
調べたところ次のようになった

## コンソールログで複数のスタイルを当てたい場合
```
//関数を作ってもできる
  const consoleStyle = (moji) => {
    const styles =
        `font-size: 100px;
         color: red;
         line-height: 2;
         padding: 10px;`;
         
    console.log('%c' + moji, styles);
  };

 consoleStyle('test'); 

//実行すると testと赤文字、フォントサイズ１００pxなどを指定した上のスタイルが適用されている

```

```
///関数じゃなくても当然（メモなので）

const styles =
  `font-size: 100px;
   color: red;
   line-height: 2;
   padding: 10px;`;

const moji = 'test';
  
console.log('%c' + moji, styles);
```

### まとめ
軽く調べたらコンソールログを変更できるスタイルには限りがあるらしいが
とりあえず複数できるようなので非常にすばらしい

メモとして記録
MATLABによるポケモンのデータ解析

こんにちは

watawatavoltageです．

# はじめに

最近，ポケモンのデータを使った機械学習の記事が増えてきている風に思えます．私も，アイコンをガラル地方に住んでいるワンパチにするくらいポケモン好きでございます．そこで，ポケモンのデータを使ってなにかできないかなと思い私もポケモンデータ解析の世界に参戦いたします．

ポケモンの世界を考えたときに，思うのがどのタイプのポケモンがどれくらいいるのかという情報です．感覚的には，わかるけれども，果たしてデータでみるとどうなのか知りたいですよね．

ということで，さっそくデータ解析したいと思います．今回，使うデータセットは[このサイト](https://www.kaggle.com/abcsds/pokemon)からダウンロードできます（kaggleアカウントが必要）．本データセットには，カントー地方からアローラ地方のポケモンの情報がつまっています．今回の解析は細かい分類を無視しています（フォルムチェンジやメガシンカも１個体としてカウント，タイプが２つあるポケモンも重複してカウント）．データ解析には，MATLABを用いています．Pythonユーザーの方ごめんなさい．

# ソースコード
以下にMATLABのソースコードを示します．読みにくいソースコードで申し訳ございません．

```MATLAB:pokemon_datamining.m
%% 変数やグラフの消去

clear all
close all

%% ポケモンのデータの読み込み．カレントディレクトリにPokemon.csvを置く．
%ダウンロード元"https://www.kaggle.com/abcsds/pokemon"

Pokemon_data = readtable('Pokemon.csv', 'delimiter', ',');

%% 各タイプに対するポケモンの分布

%１つ目のタイプを抽出
Pokemon_type1 = groupsummary(Pokemon_data,'Type1')

%２つ目のタイプがあれば抽出
Pokemon_istype2 = Pokemon_data(~ismissing(Pokemon_data.Type2),:)
Pokemon_type2   = groupsummary(Pokemon_istype2,'Type2')

%１つ目のタイプと２つ目のタイプの数を統合
Pokemon_Type_TotalCount = Pokemon_type1.GroupCount + Pokemon_type2.GroupCount

%テーブルの再構成
Pokemon_type = table(Pokemon_type1.Type1,Pokemon_Type_TotalCount,'VariableNames',{'Type','GroupCount'})

%% グラフの表示

bar(categorical(Pokemon_type.Type),Pokemon_type.GroupCount)
title("タイプ別ポケモンの数")
ylabel("ポケモンの数[匹]")
```

# 結果

結果として次のようなグラフが得られました．
![pokemon_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328296/edf4054c-f02f-a6c4-1344-1ede7fb7bf0d.png)

この結果からわかることは，まず水タイプが多いことですね．マナフィの映画のときにたくさんの水タイプポケモンが海を泳いでいたのは記憶に新しいです．私は，ミロカロスが好きですが．．．

次に，ノーマルタイプポケモンが多いですかね．ノーマルは無難なタイプですね．ガルーラ大暴れしたのも記憶に新しいですね．最近では，ドラパルトやミミッキュたちの猛攻をノーマルタイプポケモンで防ぐ戦略も人気？ですよね．カビゴンに期待します．

あとは，ひこうタイプポケモンですかね．確かに，人気ポケモンが固まっている（リザードン，サンダー，フリーザー，にらみつけるさん，ボルトロスなど）の序盤鳥ポケモンは必然的にひこうですよね．さらにノーマルと抱合せがほぼほぼ．ひこう単体はいなかったような（実際はトルネロス，最近だとココガラとかが該当）．

逆に，あまりいないタイプのポケモンはこおりタイプポケモンですね．最近だと，波平ペンギンことコオリッポが人気ですね．あと，ウルガモスのこおり版であるモスノウがきてますね．こおり，むしタイプなので，あいかわらずいわタイプに４倍弱点をもっています．こおりタイプは終盤に出てくるイメージが強いです．カントー地方だと，終盤のふたごじま（ジュゴン，フリーザーなど）．ジョウト地方だと，こおりのぬけみち（ウリムー，ニューラなど）．ホウエン地方だと，あさせのほらあな（タマザラシ，ユキワラシ？など）．

ほかは，フェアリータイプですね．このタイプは最近増えたタイプなので，仕方ないですかね．昔からいたポケモンの一部にフェアリータイプをつけてある程度増えている印象ですかね．フェアリータイプの代表格といえば，ミミッキュですね．おそろしい．最近では，オーロンゲとか伝説ポケモンのザシアンとかが該当しますね．ドラゴン無効はやっぱり強いですわ．ポケモンバトルの神ガブ・リアスもいなくなりましたね．

ゴーストタイプですね．またミミッキュですか．よく出てきますね．ピカチュウさんよりもこの記事に多く出てきているじゃないですか？．ミミッキュ旋風はいつ終わることやら．気長に待ちましょう．最近だと，ギラティナと同じタイプをもつドラパルトが人気ですね．いやーギラティナかっこよかったね．あの映画は良かった．時代的にはコイル事件のあたり．シェエーイミですよ．あいつてんめぐエアスラ使えますよ．キッスさんも顔負けですわ．

とこんなもんですかね．

# おわりに
今回は，簡単ですが，ポケモンのデータ解析をやってみました．しょうもない雑談が長くなりましたが，やはりポケモンは最高ですね．いつかポケモンの専門記事を書きたいですね．全く懐古厨ですわ．またアップしてほしい記事とか，ソースコードが間違えているとか，コメント等あればよろしくお願いいたします．
GitBucketのWikiのページ強制削除

# GitBucketのWikiのページ強制削除

本稿は、GitBucket 4.23.0で、Wikiのページを強制削除する必要が発生し、
ページを無理やり削除した時のメモ。

尚、まっとうなやり方とは思えないので、真似して実施する場合は自己責任でお願いします。

## 削除が必要になった訳

GitBucketのWikiのタイトルに「+」を指定して保存したところ、
ページは表示できるが、編集画面が開けなくなった。
具体的には、編集画面を開こうとするとURLの「+」部分が半角ブランクのURLエンコードされた %20 に置換され、
別のタイトルの編集画面が開かれた。
試しに「+」をURLエンコードしたURLを入力してみたが、それでも意図した画面の編集画面は開けず結局物理削除を行った。

上記がバグならそのうち解決されるだろうが、他の理由で同手順が必要になる可能性もあるので念の為やったことをメモに残す。

## やったこと

以下のようなリポジトリのWikiを消す場合、

```
https://xxxxxxxxxxxx/git/hoge.git
```

リポジトリ名の後に.wikiをつけたリポジトリを取得する。

```shell-session
$ git clone https://xxxxxxxxxxxx/git/hoge.wiki.git
```

リポジトリの中にはページ名.mdのようなファイルがあるので、gitコマンドでrmとcommitを行い、
pushを行えばWeb画面に表示されなくなった。
(他にもどこかに情報あるかもしれないが、そこまで探す気はなかった)

尚非公開プロジェクトのクローンや、Wikiのpushは実施できるユーザでやらなければダメなようだった。
tensorflowのインストール

#tensorflowのインストール
tensorflowのインストールはpythonのバージョンとtensorflowのバージョンが適合することが必要になる。
（anacondaを使用すると楽だが、ここでは直で入れる場合とする）

今回Ubuntu18.04.3にpython3.6.9が入っていた。

https://qiita.com/yasushi00/items/3e5a299b0a6a808e4af3
このサイトによると、python3.6.9に適合するtensorflowのバージョンは2.0.0とあったので、以下を実行。

```
pip3 install tensorflow==2.0.0
```
※pipではなくpip3でやらないとダメだった。
すると下記のようなメッセージが出た。

Collecting tensorflow==2.0.0
  Could not find a version that satisfies the requirement tensorflow==2.0.0 (from versions: 0.12.1, 1.0.0, 1.0.1, 1.1.0rc0, 1.1.0rc1, 1.1.0rc2, 1.1.0, 1.2.0rc0, 1.2.0rc1, 1.2.0rc2, 1.2.0, 1.2.1, 1.3.0rc0, 1.3.0rc1, 1.3.0rc2, 1.3.0, 1.4.0rc0, 1.4.0rc1, 1.4.0, 1.4.1, 1.5.0rc0, 1.5.0rc1, 1.5.0, 1.5.1, 1.6.0rc0, 1.6.0rc1, 1.6.0, 1.7.0rc0, 1.7.0rc1, 1.7.0, 1.7.1, 1.8.0rc0, 1.8.0rc1, 1.8.0, 1.9.0rc0, 1.9.0rc1, 1.9.0rc2, 1.9.0, 1.10.0rc0, 1.10.0rc1, 1.10.0, 1.10.1, 1.11.0rc0, 1.11.0rc1, 1.11.0rc2, 1.11.0, 1.12.0rc0, 1.12.0rc1, 1.12.0rc2, 1.12.0, 1.12.2, 1.12.3, 1.13.0rc0, 1.13.0rc1, 1.13.0rc2, 1.13.1, 1.13.2, 1.14.0rc0, 1.14.0rc1, 1.14.0, 2.0.0a0, 2.0.0b0, 2.0.0b1)
No matching distribution found for tensorflow==2.0.0

そのため、下記を実行

```
pip3 install tensorflow==2.0.0a0
```
インストールが実行された。

```
pip3 list
```
でバージョンを確認すると
tensorflow (2.0.0a0)
と表示されたのでこれでOK。
３人子育て中の助産師がプログラミングを学習して２ヶ月半を振り返る

少し更新が遅くなりました。
インフルエンザにかかっていました。
詳細は後日[ブログ](https://www.55mfmfmf55.com)に挙げますが、一言で言うとマジできつかったし自分の老を感じました。

プログラミング学習をして２ヶ月半が経過しました。
学校のカリキュラム的にもここが一区切りなので、今日は少し振り返りたいと思います。
似たようなコトを[ここ](https://www.55mfmfmf55.com/bootcamp/)にも記載しています。

#最初に感想
最初に結論を言ってしまうと、自分なりに結構頑張って**全力疾走**した２ヶ月だったと思います。
他の人に比べるとプログラミングにかけられる時間は相当限られていた中でも、なんとか自分なりに常に試行錯誤をして時間を絞り出しながら、最大限コードと向き合えたと思っています。
**これ以上は出来なかった**と言い切れるくらい自分の中では走り切れたと思っています。

#とりあえず書いて動かした２ヶ月半
毎週課題提出がほぼ容赦無く火曜と木曜にあります。
ちなみにプログラミングの授業は火、水、木で金曜日は別の講義。
木曜に出た課題は金、土、日、月と日数があるように見えますが、私にとって土日は子ども達との時間のため、プログラミングに充てられる時間はほぼなし、よって実質火曜の課題も木曜の課題も同じくらい大変でした。
とりあえずイメージしたのを、どんどん書いて動かしてみる。わからんければググってとりあえず書いて動かしてみる。
ひたすらこの繰り返しをし続けた２ヶ月半でした。
１回でうまくいく事の方が少なく、大体「なんで動かんの？」「思ってたのと違う」が多かったのですが、それでも諦めず自分で決めた最低ラインまでは動かせるように何度も調べては書いて動かしてみるをひたすら繰り返しました。
それ程大した事ない機能つけるのに２時間かかったり、すごい遠回りをして実装したりというのもありました。もしかしたらすごく無駄な時間とか効率が悪い方法もたくさんあったと思いますが、それも全て含めてその過程があったからこそ今があるのではないかと思っています。
よってこの２ヶ月半のコードを書いたりぐぐったり感んが得たりした時間全てを無駄だとは全く思わないし、むしろとても良い経験だったと今は思っています。（その時は苦しかったが・・・笑）

#常に時間とのやりくり
全ての時間を自分だけのために費やせるのであれば、もっと出来たと思いますが私の場合5,4,1歳児の子育てをしながらの学習です。
ブログの中で[何回](https://www.55mfmfmf55.com/greatest-performance/)も[何回](https://www.55mfmfmf55.com/how-to-use-the-time/)も書いていますが、一番大変だったのは時間のやりくりです。
家でコード書ける時間は子ども達がいないもしくは寝ている時間だけです。
その時間を最大限コードに充てられるように、自分の起床時間を３時にしたり、家事時短や家事の効率化を心がけたりと常に時間を意識しながら家事と育児をこなしてきました。
正直これが本当に一番大変でした。
常に自分の導線や家事育児のto do listを頭の中で整理しながら行動する、全てはプログラミングの時間を捻出するために。
子育てしながらプログラミングは今後もずっと続くのでとても良いトレーニングになったと思っているし、今後もここは常に意識しながら日々改善していきたいと思っています。

#家族に大感謝
私がここまで２ヶ月半、プログラミング学習に全力疾走できたのは言うまでもなく家族のおかげです。
子ども達はそれ程大きな体調不良はなく、ほぼ毎日幼稚園や保育園に朝から晩まで嫌がらずに通ってくれたからです。
夫が子ども達の送り迎え含めた育児や家事の一部を担ってくれたからです。
それがないと私はここまでプログラミングに時間を費やせなかったし、こんなに全力疾走できませんでした。
もっと技術を身につけて家族に何らかの形で恩返しが出来る様になりたいなと強く思っています。

#プログラミングはとても大変だが、とても楽しい
やっとプログラミングのプの字くらいはわかってきたような気がします。
年末年始は自分の中で作戦会議をして、来年は新しい言語やフレームワークにもチャレンジして、引き続き自分が作りたいのをどんどん作っていきたいと思います。
７６５プロの誰に似てるか判別してくれるアプリつくた

#前置き
最近、転職を機にAWSを触る機会が増えたので勉強がてらにAWS Rekogniteを使ったWebアプリを作ってみました。
ついでにJavascriptもやってみたかったので、Node.jsとかいうのを使ってみました。
今は慣れているものを使うべきだったと反省しています。

#作ったもの
なんとなく似たようなものは既にありそうな気がしますが、アイマス（765プロ）の顔と自分の顔を比較して、
誰が一番似ているのか類推してくれるアプリを作りました。
比較対象の顔画像はミリシタから収集しています。

http://takosan-winnner.com:3000/

サンプルは僕の好きな雨宮天さんですが、ひなたに似ているらしいですね。
![サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498626/e1b208f6-03b8-2373-24bd-562b15cb5e03.png)

~~雨宮天はパ●パンだった！？~~

#遊び方
適当に画像ファイルを選択します。
診断を押すと似てるTOP５が表示されます。それだけ。

当然、あんまり納得感はないので、はえーってやるだけです。

#概要
アーキは下図のような感じです。
![AWS Networking (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498626/c5029f98-dd8c-a9a9-9faf-9047d4a126ef.png)

やってることとしては、
1.S3に画像をアップロード
2.上記をトリガーにLambdaで画像をRekogniteのコレクションへ登録（Lambda）
3.クライアントから画像をS3へアップロード
4.S3上の画像とコレクションの中身を比較し、類似度を算出
5.S3から画像ファイルを削除

#ソース
Github:
https://github.com/takochanWinner/idol-faces

先人たちの知恵により、成り立ちました。
みんな、Thank you!

#感想
AWSのSecretKeyをGithubにあげちゃったり、非同期処理ではまったり、色々と勉強になりました。
仕事でやる前で良かった:sunglasses:

今回は遊びがてらにRekognitionを使いましたが、アニメキャラと３次元キャラだと当然特徴のとらえ方が違うので、
あんまり納得するような感じにはなりませんでした。

でもAWSを使ってアプリ公開までやれたので、今回は満足です。

おわりだよー。
virtualboxで仮想マシンを起動するとUSB接続のHDDが強制イジェクトされる

MacBookAirを外付けSSDから起動できるようになったので、virtualBoxを再び使えるように、この数日作業していました。

その中で、Windows8.1の仮想マシンが中断のままでしたので、スタートさせてみました。
すると、何故か、勝手にUSB接続しているハードディスクを取り出してしまうのです。
仮想マシンがあるドライブも、強制的に不正に取り出されてしまいます。
仮想マシンのUSBの設定を変えても、変化が無かったです。

そのため、新しく仮想マシンを作り、ハードディスクを今まで使っていた仮想のハードディスクを選択して起動してみました。

そしたら、無事に起動できました。

自分自身の備忘録も兼ねて、記録します。
EmacsでHTMLの補完機能をつける

EmacsでHTMLの補完機能をつけてみました。

## パッケージのインストール

まずは、パッケージのインストール

```
M-x package-install
Install-package: web-mode
```
これでパッケージのインストールは完了です。

## web-mode.elの編集

次に、web-mode.elの編集をします。
/.emacs.d/init.elファイルに、コードを書いていきます。
web-modeの[公式サイト](http://web-mode.org/)を参考に、自由にカスタマイズしていきます。

```elisp:init.el
(requere 'web-mode)
(add-to-list auto-mode-alist '("¥¥.html?¥¥'" . web-mode))

(defun my-web-mode-hook ()
  "Hooks for Web mode."

  ;; インデント設定
  (setq web-mode-markup-indent-offset 4)
  (setq web-mode-css-indent-offset 4)
  (setq web-mode-code-indent-offset 4)

  ;; 要素のハイライト
  (setq web-mode-enable-current-element-highlight t)

  ;; フォントの配色
  (set-face-attribute 'web-mode-doctype-face nil :foreground "Pink3")
  (set-face-attribute 'web-mode-html-tag-face nil :foreground "Green")
  (set-face-attribute 'web-mode-html-attr-value-face nil :foreground "Yellow")
  (set-face-attribute 'web-mode-html-attr-name-face nil :foreground "#0FF")

  ;; タグを自動で閉じる
  (setq web-mode-enable-auto-pairing t)
  (setq web-mode-enable-auto-closing t)
)
(add-hook 'web-mode-hook 'my-web-mode-hook)
```

とりあえず今回はここまで。
またCSSやJSなどについてもやってみようと思います。
ジェネレーティブデザインの荷重方向を変えて結果を比較してみた

# えっ！！ゼロ円でジェネレーティブデザインを！？！
できらぁ。
Autodesk さんが、年末まで[ジェネレーティブデザイン使い放題キャンペーン](https://www.autodesk.co.jp/campaigns/generative-design/free)を実施されていますね！
通常なら生成一回につき25クレジット（4,200円相当）、生成結果のダウンロード一件当たり100クレジット（17,000円相当）が完全無料とは太っ腹にもほどがあります。

せっかくですのでこの機会にしかできないような、設定の比較及び結果を共有し、このキャンペーンに貢献したく思います。

# デザイン対象
対象は、普段使っているバッファローのキーボードの裏側にあるキーボードに傾斜をつける部品が割れてしまったので、これの代替品を作ることにしました。と、文章では伝わりづらいかと思うので、完成品写真を以下に掲載します。
![P_20191225_185357_vHDR_Auto_HaP.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110181/62045e77-ebec-04de-0401-00e3ade02b73.jpeg)
元の部品はキーボードを収納する姿勢にもできるように可動できるようになっていましたが、今回は割り切って可動部分無しのシンプルな構造を3Dプリントで生成して、両面テープ留めしています。

# 比較内容
元となるボディは以下の形状です。画面内で選択している青い面がキーボード本体に両面テープ留めされる個所、空中に浮いている円柱が、机等に接する面を想定しています。
![素体.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110181/6710f92f-e45e-d4e8-cd80-23a287d810e4.png)
（※　なお、ジェネレーティブデザイン計算の際は自身の重量も計算条件に含まれるため、計算時の姿勢と実際の運用時の姿勢は同じ姿勢であるべきです。つまり本例では『上下逆転した』姿勢で実施してしまっています。。）

こちらの素体に対して以下表の３条件でジェネレーティブデザインを実施してみました。
基本的な設定は同じで、荷重ケースのみ変えています。

|スタディ|マテリアル|製造方法|安全率|荷重|荷重ケース|
|:--|:--|:--|:--|:--|:--|
|スタディ1|熱可塑性樹脂|制約なし＆アダプティブ|2.0|10 [N]（1.02 [kgf]）|真上方向からのみ（合計1方向）|
|スタディ2|熱可塑性樹脂|制約なし＆アダプティブ|2.0|各10 [N]（1.02 [kgf]）|スタディ1に加え、前後±20度方向から（合計2方向）|
|スタディ4|熱可塑性樹脂|制約なし＆アダプティブ|2.0|各10 [N]（1.02 [kgf]）|スタディ2に加え、左右±20度方向から（合計5方向）|
（スタディ3は条件を変えてしまって単純比較できなくなってしまったので、省略しています）
ちなみに既に設定したスタディを改変して新たにスタディを作成するときは、スタディで右クリックし「スタディをクローン化」とすると楽です。

![スタディ124.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110181/12e24c9c-cb46-3282-c382-7a2501bf35ef.png)
青い矢印が荷重ケースですが、‥潰れて見にくいですね。上表の通りスタディが増えるごとに、荷重ケースが増えていることに注目いただければと思います。なお、実際の画面上では上図のように荷重ケースを重ねて表示はできません。（画像処理をしています）

複数の荷重を想定する場飯の注意点として、同一の荷重ケース内で複数の荷重を設定するのではなく、荷重ケースを「新しい荷重ケース」なり「荷重ケースをクローン化」で増やして、その中で別の設定を作成することが必要です。もし荷重ケース内で複数の荷重を設定してしまった場合、それぞれが合成され単一の荷重として計算されるそうです。

なお、製造方法の項目についてはよく分かっていません‥。

# 結果
## スタディ１
![上から10N.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110181/510efa66-fc06-25fc-c627-6938609f76de.png)
## スタディ2
![上、斜めから10N.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110181/6adbba4f-638b-8833-5230-dafc62a54f75.png)
## スタディ4
![上、左右斜めから10N.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110181/3bb8a976-364c-45d8-c445-fe6ad4e92d95.png)

※　荷重条件が増えると「完了」が増えている（「収束」していない）ことに注意してください。

# 所感
全てのケースで収束している右端の「アダプティブ（Z+）」などが比較しやすいでしょうか。

スタディ1実施の時点で、出来上がったデザインは（垂直真上からしか荷重を与えていないので当然なのですが）前後方向の揺さぶりに脆そうに見受けられました。良くも悪くもシミュレーション条件通りの結果といった塩梅です。
そこで前後方向からの揺さぶりに強くする目的で前後方向からの荷重を与えると、スタディ2のデザインが出来上がりました。確かに前後方向の荷重への耐性が上がってそうです。
さらにこれに左右方向からの荷重を与えるとスタディ4が出来上がりました。スタディ2の構造に加え、接合部で枝分かれし、左右からの耐性もあるよう見受けられます。
これらの比較により荷重条件により結果の形状が大きく変わることが見て取れます。ジェネレーティブデザイン実施時の荷重設定の重要さが感じられます。


# 余談
結局スタディ4の右端形状が3Dプリントした形状です。画像の方向にプリントアウトしましたが、左右に出っ張っている部分にサポート材がつかず、オーバーハングでの印刷となり、本来水平であるべき接地面が波打ったように印刷されてしまいました。
いくらシミュレーションをしっかりしたとしても、製造がその通りとはいかないものですね。
ドライヤーで温め、柔らかくした後平面に押し付けることにより、ことなきをえました。
django.db.utils.OperationalError: table "t" already existsが出てmigrateできない

## 課題
`python manage.py migrate`を実行したところ、表題のエラーが発生しました。
> django.db.utils.OperationalError: table "t" already existsが出てmigrateできない

・エラー発生なし
`python manage.py makemigrations`

・エラー発生あり
`python manage.py migrate`

## 背景
DB(model)とmigrationFilesは以下のようなになっていた。
（テーブルの例として、食べ物の名前テーブルを使用）

### データベース(`models.py`)
- ***作成済***テーブル
    - `Apple` 
    - `Banana` 
- ***未作成***テーブル
    - `Chocolate`

### migrationの最新ファイル(`000X_auto_20XXXXXX.py`)
- `AlterField`(作成する旨の記述***なし***)
    - `Apple`
- `CreateModel`(作成する旨の記述***あり***)
    - `Banana`  ←あれ、***作成済***テーブルのはずだが:frowning2:
    - `Chocolate`

```python:000X_auto_20XXXXXX.py

( 略 )

        migrations.CreateModel(
            name='Banana',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=1000)),
            ],
        ),
        migrations.CreateModel(
            name='Chocolate',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=1000)),
            ],
        ),
        migrations.AlterField(
            model_name='Apple',
            name='id',
            field=models.UUIDField(default=uuid.UUID('13a6d974-aeba-4faf-b501-fad036c92a0e'), primary_key=True, serialize=False),
        )

( 略 )
```
`python manage.py migrate`するが、`table already exists`のエラーが発生した。

## 原因
`Chocolate`だけ作成したいのに、`Banana`も作成することになっている。
DB内には`Banana`が既に存在するので、`already exists`エラーで落ちてしまう。
そのため、`migrate`できない。
Modelで履歴と実データに差異が出ている状況だった。


## 対処法
***CreateModelの記述を前回の`000X_auto_20XXXXXX.py`に移動することで対処。***
前回のmigrationファイルは適応済みの判定であるため、参照されない。


```python:000X_auto_20XXXXXX.py
( 略 )
        # BananaのCreateModelは前回の'000X_auto_20XXXXXX.py'ファイルに移動

        migrations.CreateModel(
            name='Chocolate',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=1000)),
            ],
        ),
        migrations.AlterField(
            model_name='Apple',
            name='id',
            field=models.UUIDField(default=uuid.UUID('13a6d974-aeba-4faf-b501-fad036c92a0e'), primary_key=True, serialize=False),
        )

( 略 )
```

`000X_auto_20XXXXXX.py`の中身を書き換えるという発想がなかった。
普段自動でやってくれるので、手動で書き換えるとは思わなかった。
なぜこのような不整合が起こってしまったのかは謎。:cry:
GoogleAppsScriptでぐるなびAPIから取得した駅周辺のお店をスプレッドシートに書き出す

# 経緯
googleアカウントのマイマップを作ろうと思って手作業でやるのは手間なので、上手くできないかなと思って調べてみました。

参考にさせていただいた記事はコチラになります。
https://qiita.com/ymk1102_1t/items/c7802205f6a54c88ba74

#やること
ぐるなびのAPIを利用して駅周辺のスタバの情報を取得してきます。

## 使用するAPI

### ぐるなびAPI
今回メインで使用するAPIです。利用のためには利用アカウントを作成する必要がありますが、今回は個人の趣味で利用するので一番登録内容が少ないが期間限定のアカウントを取得しました。

>https://api.gnavi.co.jp/api/manual/restsearch/
ぐるなびWebサービスは、ぐるなびが所有する豊富な飲食店情報を提供する、無料のAPIです。
ぐるなびWebサービスは、新たなコンテンツを制作する開発者をサポートします。

### 駅情報取得API
直接ぐるなびAPIを叩いてもいいんですが、上手く絞り込みが出来なかったので、駅情報から緯度経度を取得するために利用しました。
>http://express.heartrails.com/api.html
「HeartRails Express」 は、路線／駅名データ等の地理情報を、XML、JSON(P) 形式の API により無料でご提供させていただくサービスです。この API をご利用になることにより、お客様側ではサーバーサイドの処理を実装することなく、サンプルのようなアプリケーションを簡単に開発することができます。

# 作業手順

1. ぐるなびAPIにて利用アカウントを登録し、取得したアクセスキーを確認
2. GASのスクリプトエディタを開く ※1
3. 以下記載のソースを記載し、実行！！ ※2

※1 詳細なやり方はコチラを参照（https://tonari-it.com/gas-script-editor/）
※2 1で取得したアクセスキーだけ自分で取得した値に変更する


```javascript
function myFunction() {
  
  // 対象の駅
  var stationName = '新宿';
  
  // 駅名から緯度経度を取得
  var arrPosition = getPosition(stationName);
  var parPosition = '&latitude=' + arrPosition[0] + '&longitude=' + arrPosition[1] + '&range=3';
  
  var gurunaviAPI = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';//取得したアクセスキー
  var url = 'https://api.gnavi.co.jp/RestSearchAPI/v3/?';
  url = url + 'keyid='+ gurunaviAPI;

  // リクエストパラメータ
  url = url + '&name=スターバックス';
  url = url + '&hit_per_page=100';// 表示件数を限定
  url = url + '&pref=PREF13';// 東京都の都道府県コードで絞り込み
  url = url + parPosition //位置情報を付与する

  var response = UrlFetchApp.fetch(url);
  var json=JSON.parse(response.getContentText());

  var jsonLength = Object.keys(json.rest).length;//ヒットした件数を取得する
  var arrArea = [];//出力する値を入れるための配列

  if(jsonLength < 1){
    return;
  }

  for (var i=0;i<jsonLength;i++){
    // 出力したい情報を配列に入れていく
    arrArea.push([json.rest[i].name,
                  json.rest[i].address.slice(10),
                  json.rest[i].tel,
                  json.rest[i].opentime,
                  json.rest[i].holiday,
                  json.rest[i].access.station
                 ]);
  } 

  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet1 = sheet.getSheetByName('シート1');
  var rows = arrArea.length;
  var cols = arrArea[0].length;
  sheet1.getRange(3,2,rows,cols).setValues(arrArea);//スプレッドシートに書き込む
}


function getPosition(name){
  // 駅情報取得 API
  var url = 'http://express.heartrails.com/api/json?method=getStations&';//

  // リクエストパラメータ
  url = url + '&name=' + name;
    
  var response = UrlFetchApp.fetch(url);
  var json=JSON.parse(response.getContentText());
  
  var arrpin = [];
  arrpin[0]=json.response.station[0].y;
  arrpin[1]=json.response.station[0].x;

  return arrpin;
}
```
MacでSambaをマウントしようとしてハマった

MacでSambaをマウントしようとしてハマったので、備忘録として残す。


# まずは普通にマウントしようとして失敗
ずっと前からFinderからマウントしようすると「接続できませんでした」と失敗していたが、
この度、コマンドで試してみることに。

```bash:Terminal
$ mount -t smbfs //user@192.168.1.10/dir /Volume/dir
Password for 192.168.1.10:
```

パスワードを入力すると、

```bash:Terminal
$ mount_smbfs: server connection failed: No such file or directory
```

なんでや！あるし！
ということで、怒られた文言をそのままググってみるとヒットした。

# sambaに接続できない理由？
以下がヒットしたサイト。
[Mac mini can't connect to my corporate SMB server. Was working some days ago](https://apple.stackexchange.com/questions/257836/mac-mini-cant-connect-to-my-corporate-smb-server-was-working-some-days-ago/262136#262136?newreg=d83d3569497d4d40aa594a6cafa12de0)

このサイトによると、
> Sierra SMB subsystem and HAXM are apparently unrelated pieces of software, but it seems they are somehow incompatible between them. In case you have SMB problems you'll have to decide which of the two you really need more

とのこと。
ハードウェアアクセラレーションを有効にするkextを入れているとどうもsambaが正常に機能しないらしい。

# kextをアンインストールする
そこでサイトに有る通りkextをアンインストールする。
まずアンインストール対象がインストールされているか確認。

```bash:Terminal
$ kextstat | grep -iv apple | grep intelhaxm
   92    0 0xffffff7f8269e000 0x14000    0x14000    com.intel.kext.intelhaxm (6.0.1) 8FF2C637-0A5E-367E-B007-5B08655B1E8A <8 6 5 3 1>
```
こいつが犯人。ささっとアンインストールしてやる。
これのインストール時にアンインストーラも格納されるので、まずそれがあるか確認。

```bash:Terminal
$ ls /Library/Extensions/intelhaxm.kext/Contents/Resources/uninstall.sh
/Library/Extensions/intelhaxm.kext/Contents/Resources/uninstall.sh
```
あるからこれを実行。
ディレクトリごと消されるみたいなので、ここ配下に移動して実行するとシェルがエラーで止まっちゃうので気をつけて←これやって焦った。

```bash:Terminal
$ sudo /Library/Extensions/intelhaxm.kext/Contents/Resources/uninstall.sh
```

エラー終了しちゃってどう出るかわからないけど、完了するとリブートを促されるらしいのでする。
(エラー終了してもリブートしたらうまくいった)

# もっかいSambaマウント
…できた。
Finderからサーバへ接続でできた。
けどこれの副作用として(当然だけど)ハードウェアアクセラレーションが使えなくなってるから
必要なら再インストールみたい。
根本的な解決方法はどうすれば…。
　
　
　

おわり。
GitHubとBitBucketとGitLab

個人開発の成果をアピールしたいならGitHub
無料でソースを非公開に管理したいならGitLab
ソースを非公開に管理しつつUIもいい感じのやつ使いたいならBitBucket

って感じでしょうかね。

# 参考
https://www.geeksforgeeks.org/bitbucket-vs-github-vs-gitlab/
https://qiita.com/hiroponz/items/c1ed4d6c10484233bf88
TwitterのDeveloperアカウント申請方法

TwitterのAPIを使って開発をしようとしたが、アカウント申請に手間がかかったので備忘録としてメモ

https://developer.twitter.com/
から登録

左上のDeveloperからメニューを開いてApplyから申請に進む
![スクリーンショット 2019-12-30 0.34.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/2ae9fa3e-159b-9749-4fbc-3edc437241fe.png)


![screencapture-developer-twitter-en-apply-for-access-2019-12-30-00_13_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/4ae7637e-5e7e-710d-b95f-9c5acdb3ebb8.png)
=> Apply for a developer account から作成

![screencapture-developer-twitter-en-application-use-case-2019-12-29-23_52_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/8ebf5537-4b55-e071-6f76-61ea964c1ffa.png)
=> よくわからないのでExploring the API を選択

![screencapture-developer-twitter-en-application-intent-2019-12-29-23_55_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/1f1efc4c-b9d9-fcd9-a8d8-42a01b9b8e90.png)

下記だけYesにして回答
- In English, please describe how you plan to use Twitter data and/or APIs. The more detailed the response, the easier it is to review and approve.（Response must be at least 200 characters）
- Will your app use Tweet, Retweet, like, follow, or Direct Message functionality?（Response must be at least 100 characters
）

![スクリーンショット 2019-12-29 23.45.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/b5074073-25c6-3c2f-64ac-f49aeac7d906.png)

![スクリーンショット 2019-12-30 0.23.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/2f400856-56ad-cbbc-9ec5-8d6a2ecd6132.png)

![スクリーンショット 2019-12-29 23.47.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26860/a21795c1-3f28-2d6e-015e-728da65c6802.png)
プログラミング初心者がRailsでサービスを作ってみる

# まえがき
プログラミング初心者がRuby on Railsで何か一つサービスを作ってみる。
※職場のエンジニアの方の協力を得つつ…

## □前提
▼プログラミングスキル

- ProgateでRilasを1周している。
- 「いきなりはじめるPHP入門」で少しだけPHPをやったことがある。


▼ステータス

- Ruby on Railsで書かれているサービスのプロダクトマネージャーをやっている。
- 開発ディレクションっぽいことをやっている（けど、コードとかに関する知識がなく、もやもやしている。）

## □目標（ゆるく）
- 自分でサービスを作ってみることで、ディレクションスキルを上げる。
    - 企画〜リリースまでの手順を、実体験をもとに把握する。
    - なんとなくコードが読める。工数がわかる。
    
## □計画（ゆるく）
- 12月からはじめて4月くらいでリリースできるといいな。
    - 12月
        - ドットインストール見る。
        - Progateやる。
        - チュートリアル見る。


## □つまずいたところたち※随時更新
▼12/29
**Railsが立ち上がらない。**
ActiveRecord::ConnectionNotEstablished　No connection pool with ‘primary’ found.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559050/ab135321-62e1-f06c-6e80-57ebcf07352d.png)
→これを参考に解決。[Railsを始めてsqlite3まわりのエラーで躓いている人たちへ](https://qiita.com/Kta-M/items/254a1ba141827a989cb7)。このコマンドも叩いた。「$ rails db:create」

▼12/30
**初期画面以降のプレビュー画面の開き方がわからない。**
Progateの教材をCloud9でやろうとした。プレビュー画面の開き方がわからなかった。
→Cloud9でPreview Runing Applicationを選択。開いたページのURLの末尾に/Top/homeなど自分の作ったページのURLを指定して解決。

## □ログ※随時更新
サーバーにアップしたCSSファイルが反映されない時の解決法

#はじめに
以前Xserver(レンタルサーバー)に自作サービスをアップしたのですが、CSSファイルを修正して再度アップしてサービスにアクセスしてブラウザで表示したところ・・・

**CSSが反映されない！！！！**

ということでこの現象の解決方法について調べて試した結果、無事解決することができたので記事として残しておきます。

同じ現象で悩んでいる方の参考にされば幸いです。

#対処法

僕が調べた限りでは、下記の通り3つの解決法があります。
(他の方法をご存知の方がいらっしゃいましたら是非コメント欄でコメントをお願いしますm(__)m)

1.ブラウザ側のキャッシュを削除する
2.サーバー側のキャッシュを削除する
3.Disable cacheにチェックを付けてリロードする

では1つずつ説明して行きます。

ちなみに僕は**3.Disable cacheにチェックを付けてリロードする**で解決しました。

##そもそもキャッシュって？
キャッシュについてはサルワカさんのブログで以下の通り解説されています。
>キャッシュとはパソコンやスマホに一時的にウェブページのデータを保存しておいて、次に同じページを開いたときに素早く表示させる仕組み。

サルワカさんのブログ[「キャッシュとは？IT初心者でもわかるように解説」](https://saruwakakun.com/it/web/cache)

##1.ブラウザ側のキャッシュを削除する
これはご存知の方が多いと思います。

方法の順序としては、

**①GoogleChromeのデベロッパーツールを開く**

GoogleChrome上で表示された画面で**option+⌘command+Iを押す**もしくは**画面上で右クリック→検証をクリック**することでデベロッパーツールを起動できます。
(ご存知ですよね・・・)

![スクリーンショット 2019-12-29 21.35.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/da9b1ae7-d7ef-0732-2f39-be4be3b894ee.png)

**②リロードボタンを右クリックして**キャッシュの消去とハードの再読み込み**をクリック**

画面左上のリロードボタン（矢印が輪っか状になっているボタン)を右クリックして**キャッシュの消去とハードの再読み込み**をクリックします。

![スクリーンショット 2019-12-29 21.35.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/8c9f9542-6de2-e505-7a9f-fd30d99528a1.png)

ちなみに、PHPファイルをブラウザだけで表示している場合に修正箇所が反映されないことがよくあるのですが、この方法で解決します。

##2.サーバー側のキャッシュを削除する
これは僕は今回の現象が起こるまで**1.ブラウザ側のキャッシュを削除する**しか方法を知らなかったのですが、解決しなかったので調べて新しく知った方法です。

サーバーに公開しているサイト・サービスの場合はブラウザ側だけでなくサーバー側にキャッシュが残っている場合があるみたいなのでこれを削除する方法です。

僕はレンタルサーバーとしてXserverを使用しているのでここではXserverでのサーバー側のキャッシュを削除方法を説明します。

**①Xserverのサーバーパネルにログインする**
ここはXserverを触ったことのある方ならわかると思いますので割愛させていただきます。

**②サーバーキャッシュ設定をクリックする**
![スクリーンショット 2019-12-29 22.12.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/648fda9f-b6b4-c58c-9ffd-4c4e5c028441.png)

**③修正したいサイトのドメイン名を選択する**
![スクリーンショット 2019-12-29 22.14.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/6e1f6a65-a3fc-7131-d976-6ad9bb8e3f25.png)

**④キャッシュを削除する**
![スクリーンショット 2019-12-29 22.14.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/afa7be06-92b4-3d02-ec26-50e3dde6713d.png)

これでサーバー側のキャッシュを削除することができます。
この方法で解決できる場合もあるみたいです。

##3.Disable cacheにチェックを付けてリロードする
こちらも新しく知った方法です。
僕は今回はこちらの方法でCSSの反映に成功しました。では手順です。

**①デベロッパーツールを起動する**

先ほど説明したのと同じやり方でデベロッパーツールを起動します。

**②NetWorkタブを選択してDisable cacheにチェックを入れる**
![スクリーンショット 2019-12-30 0.26.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/1346a7e9-692c-3bb2-1783-8db5b07355b6.png)

**③ページをリロード**
画面左上のリロードボタン（矢印が輪っか状になっているボタン)をクリックしてページをリロードします。
このとき、**デベロッパーツールは閉じてはいけません！**

この方法はキャッシュを削除するというよりは「キャッシュの使用を禁止する」という意味みたいです。
Disable cacheにチェックを入れた状態でページを再読み込みすると、**キャッシュは使用せず、サーバーからファイルやデータを読み込む**ようになります。
よって、新しいCSSファイルの内容を読み込むことができたようです。
この機能はデベロッパーツールを起動させている間のみ有効です。

#最後に
この記事では**サーバーにアップしたCSSファイルが反映されない時の解決法**について紹介して行きました。

手順自体は簡単なので、比較的覚えやすいかなと思います。
同じような現象でお困りの方の参考になれば幸いです。
Unityの新規プロジェクト作成時にやるべきことメモ

# 自分の開発開発環境にバシッとあてはまる記事があったのでこれ通りにやればよさそう
https://qiita.com/cs1000/items/07368892a599b2b7b836

# 要するに以下のことをやってる
- Unityプロジェクトを新規作成
- Version ControlのModeをVisible Meta Filesに(メニュー>Edit>ProjectSettings>Editor)
  - 外部バージョン管理システム(SVNやGit)のサポートを有効化する設定。
  - UnityはAssetsディレクトリ内の各ディレクトリ、ファイル対する.metaファイルを自動的に作成しているが、これは**各ディレクトリ、ファイルの参照情報が含まれている(metaファイル内に各ディレクトリ、ファイルのID情報が記録されている。)。Assets内のディレクトリ、ファイルの名前を変更したり、場所を移動させたりすると、.metaファイル内の情報も更新される。****例えばスクリプトファイルに対するmetaファイルを削除した場合、そのスクリプトを割り当てられたゲームオブジェクトやプレハブは、スクリプトへの参照が切られてしまうため、機能を失ってしまう**。これを修正するには、これらのオブジェクトに手動でスクリプトを再割り当てしなければならない。**だから、metaファイルは絶対にバージョン管理する必要がある**のだ。
- Asset SerializationのModeをForce Textに(メニュー>Edit>ProjectSettings>Editor)
  - 効果は、Assetsに**Prefab、sceneといったデフォルトでバイナリファイルのものがテキストデータとして保存される**、というもの。これにより**バージョン管理で差分が見やすくなる**
- プロジェクトは以下の.gitignoreをcommitしてpush
  - https://github.com/github/gitignore/blob/master/Unity.gitignore
  - 最低限のものだけ登録する。最低限のものでUnityによって自動生成され、プロジェクトの状態が復元されるものは不要ってこと。

# 参考
- [Unity で外部のバージョン管理システムを使用](https://docs.unity3d.com/ja/2017.4/Manual/ExternalVersionControlSystemSupport.html)
- [アセットの内部処理](https://docs.unity3d.com/jp/current/Manual/BehindtheScenes.html)
- [UnityプロジェクトをGitで管理](https://qiita.com/cs1000/items/07368892a599b2b7b836)
kubeadm, vagrantを使ってsingle node k8s clusterを構築した際のメモ

# なぜまとめたか
**想定読者: Kuberneteクラスタの構築を手元のマシンでお金をかけずに試す方法を知りたい人**

Kubernetesを用意する方法は、マネージドのものを使ったり、minikubeやkindなどの簡易なものを使ったり、Kubernetes Hardwayを実施してみたりと様々な方法がある。
ただ、マネージドやminikube, kindなどは比較的簡単にk8sクラスタを用意できる反面、どのようにk8sクラスタが作られているかなどを実感することができない。
また、[kelseyによるKubernetes Hardway](https://github.com/kelseyhightower/kubernetes-the-hard-way)は、GCPを使い切ったものにとっては少しお財布が心配になるため敬遠している。




基本的には下記のマニュアルを参考にすれば良いが、「スワップをオフにする」等と言われても具体的なコマンドの説明は割愛されているのでメモとして残すことにした。
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl

# コードだけ見たいんだ、という人向け
下記リポジトリに同様の内容を簡潔にまとめています

<a href="https://github.com/iaoiui/single_node_k8s_with_vagrant"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/iaoiui/single_node_k8s_with_vagrant.png" width="460px"></a>


# 観測したエラーと回避策

## swap復活する問題
swapoff -aコマンドでスワップを無効化するが、/etc/fstab内にswapfile使う設定が記載されていたためVMの再起動ごとにkubeletが落ちるという現象に見舞われた
vagrantでcentos7を作成した場合には、/swapfileにスワップファイルが作成されているため、fstabからこの行を削除し、swapfileファイルの実体も削除することで対応した。


## kubelet動かない問題
kubeletが下記のようなエラーで正しく動作しないことがあった。

```
failed to load Kubelet config file /var/lib/kubelet/config.yaml, error failed to read kubelet config 
```

上記のエラーが出てkubeletがうまく動いていない場合、下記コマンドでkubeletが正常に起動する

```
kubeadm init
```

この事象と回避策は下記のIssueで報告されている

https://github.com/kubernetes/kubernetes/issues/65863

確認していないがkubeadm initすることで諸々の設定をし直す必要がありそう
下記のあたりの再設定が必要か(未検証)


```
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

calicoの再デプロイも必要？

```
kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml
```

taintの設定も再度必要？

```
kubectl taint nodes --all node-role.kubernetes.io/master-
```


# 補足
vagrant upで作成したマシンを削除

```
vagrant destroy -f
```

普通のsshコマンドでVMにアクセスするための設定
ansibleとかでvagrant sshでなく素のssh使いたい時に便利
```
vagrant ssh-config >> ~/.ssh/config
```
java フレームワーク

今日は疎かになっていた
javaフレームワークについて投稿します。

# 選び方
前提としてどう選んでいくかというと

* 何を作るか
* 開発スケジュール
* 技術者の人数および技術力
* 保守性

などが挙げられますが
以下２点は抑えておきたいものです。

## 必要な機能を備えているか
例えば
Spring Frameworkは汎用性が高く、機能が充実していますが
Play Frameworkは軽量で機能が絞り込まれているという違いがあります。
したがって、大規模開発のために機能重視でフレームワークを選ぶ場合は
Spring Frameworkを採用することも1つの考え方です。

## 実績あるフレームワークであるか
次々と新しいフレームワークが生まれていますが
マイナーなフレームワークを選んでしまうと、対応できるエンジニアが少なく
学習コストや開発コスト、メンテナンスコストが余計にかかります。
そのため実績あるフレームワークを選ぶことをおすすめします。
有名なフレームワークであれば、開発コミュニティや日本語ドキュメントが充実してお
情報を入手しやすいというメリットもあります。

# フレームワーク一覧

* Spring Framework
* Java EE
* Apache Struts
* Play Framework
* Spark Framework

他にもありますが、有名どころのこれらを紹介して行きます。

## Spring Framework

オープンソースフレームワークで、単にSpringと呼ばれることもあります。
データベースへのアクセスやトランザクション処理などをサポートするフレームワークをはじめ
多数のフレームワークの集合体です。

##  Java EE

Java標準仕様のフレームワーク。
かつてはJ2EE（Java 2 Platform, Enterprise Edition）と呼ばれていました。
大規模システムに採用されています

##  Apache Struts

Apache Software Foundation が提供する、2001年ごろから使われているフレームワークです。
Struts 1は既にサポート終了、Struts2が別バージョンでリリースされています。

##  Play Framework

Javaと、Javaとの連携が容易なプログラミング言語Scalaで書かれたオープンソースのフレームワーク。
Rubyのフレームワーク「Ruby on Rails」、pythonのフレームワーク「Django」の思想に大きく影響を受けています。

##  Spark Framework

シンプルな構成・軽量のマイクロフレームワーク。Rubyのフレームワーク「Sinatora」に影響を受けています。
p5jsでPokémon GOっぽいUIを作る(5)

さて、5回目です。これまで`createCanvas(600,600,WEBGL)`と画面サイズを決め打ちしてましたが、スマートフォンの画像サイズを取得してキャンバスサイズを指定するのと、`touchMoved`を使って、画面をスワイプすると地図が動くようにします。

まず、今回からJavaScriptが長くなるのでhtmlから分離します。また、キャンバスの上と左に余計なマージンができるので、CSSで`padding:0; margin:0`にしています。

```html
<!-- index.html -->
<!doctype html>
<html lang="ja">
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, viewport-fit=cover" />
<title>Pokanpo Here</title>
<style>
*{
  padding: 0;
  margin: 0;
  background: black;
}

canvas{
  display:block;
}
</style>
<script src="p5.min.js"></script>
<script src="p5.geolocation.js"></script>
<script src="here.js"></script>
</head>
<body>
</body>
</html>
```

次にJavaScript。スマートフォン上でスワイプしたときにスクロールされてしまわないため`setup()`の中で`addEventListner()`を呼び出してます。このあたりの黒魔術、下記のサイトが充実してます。

[p5.jsとスマートフォンでインタラクティブアートを作る - WGGの活動log](http://wgg.hatenablog.jp/entry/20181225/1545703427)

今回のキモは`touchEvent()`で、スワイプした距離を取得して、`draw()`の中で角度を指定しているところ。これをスワイプする都度、呼び出すことで、ヌルヌルと地図を回転できます。縦にも横にも回転できるようにしてみましたが、グラグラしてます。そういえばPokémon GOは横方向だけスワイプで、縦方向はダブルタップしないと変えられないようにしてますね。

```js
let rotX = 1.0;
let rotZ = 0.0;

let img;
let locationData;

function preload() {
    locationData =  getCurrentPosition();
    notoSans = loadFont('NotoSans-Regular.ttf');
}

function setup() {
    let lat = locationData.latitude;
    let lon = locationData.longitude;
    let url = 'https://example.com/getmap.php'
    url = url +'?lat='+lat+'&lon='+lon;
    img = loadImage(url);

    window.addEventListener("touchstart", function (event) { event.preventDefault(); }, { passive: false });
    window.addEventListener("touchmove", function (event) { event.preventDefault(); }, { passive: false });

    createCanvas(windowWidth, windowHeight, WEBGL);
    textSize(12);
    textAlign(CENTER, CENTER);
    textFont(notoSans);
}

function draw() {
    background(0);

    rotateX(rotX);
    rotateZ(rotZ);

    push();
    texture(img);
    plane(1000, 1000);
    pop();
}

function touchMoved(){
    let dx = pmouseX - mouseX;
    let dy = pmouseY - mouseY;
    rotX = rotX + dy * 0.01
    rotZ = rotZ + dx * 0.01
}
```
Django2.2でPyMySQLが使えずmysqlclientを使った話


# 過程
ゲームの大会を開けるようなWebアプリを作りたいな〜
→時代はPythonでしょ❗

ってことでDjangoを用いて環境構築をはじめました


# 環境
- Python:3.7
- Django:2.2

# 何が起きたか
https://qiita.com/aeas44/items/90c867aa2d02f9047ef0
を参考にPyMySQLをインストール。DB設定を行い


    python manage.py migrate

を叩いた。

すると

    raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)
    django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.

なぜかMigrateできない。

#原因

### ①Django2.2ではPyMySQLが非対応
Django2.1のバージョンであれば問題なく動作するとのこと

### ②そもそも公式の推奨ドライバーはmysqlclient

しかし公式ドキュメントを覗いてみると

>mysqlclient is a native driver. It’s the recommended choice.
>https://docs.djangoproject.com/en/2.2/ref/databases/

mysqlclient使えよって書いてる

ということでせっかくなのでコチラで試してみることに

    pip install mysqlclient

でインストール。環境の設定は変えなくて大丈夫そう

    python manage.py migrate

無事migrateできました❗
Railsの新規プロジェクトを指定のRubyバージョンで作成する。

# はじめに
久しぶりにRailsの新しいプロジェクトを作成するに当たり、Rubyバージョンを最新のものを利用しようとしてつまずいたので、今後の自分のためにも記事として残しておく。
## 環境
・rbenvはすでにインストールされているものとする。
https://qiita.com/Alex_mht_code/items/d2db2eba17830e36a5f1
・macOS
 Catalina
# 1. プロジェクトを運用するディレクトリを作成する。

```
$ mkdir app_name
$ cd app_name
```

# 2. Rubyのバージョンを最新にする。
現在使用しているバージョンを確認する

```
$ rbenv versions

  system
  2.5.1
* 2.6.5
```

以下のコマンドでインストール可能なバージョンリストが表示される。

```
$ rbenv -l
```

インストールしたいバージョンがない場合は以下のコマンドでアップデート
(2019/12/29時点では安定の最新バージョンは2.7.0)

```
$ brew update
```

```
$ rbenv install 2.7.0
```

インストールが完了すると以下のように表示が増える

```
$ rbenv versions

  system
  2.5.1
* 2.6.5
  2.7.0
```

現在はバージョン2.6.5が指定されているので、2.7.0を指定する。
このときコマンドが以下の２パターンあるので使い分けてください。

```
$ rbenv local 2.7.0 これは現在のディレクトリのプロジェクトのみに適用。
$ rbenv global 2.7.0　その他のプロジェクトのバージョンも全てに適用。
```

僕は別のアプリを2.6.5で作っているのでlocalで実行。

# 3. Railsのプロジェクトを作成する。

```
$ bundle init
```

Gemfileが生成される。
開いて以下のように編集

```
# gem rails  →　gem rails (コメントアウトを外して保存)
```

```
$ bundle install
```

ここでオプションを付けるかどうかも議論はありますが、プロジェクトが多くなってきてスキルが上がってきたときに考えたほうが理解できると思います。
ざっくりとした説明としてはオプションを付けたほうが容量を節約した運用ができるよということ。


以下のコマンドでプロジェクトを作成。DBの選択などオプションはありますが、シンプルに作っていきます。

```
rails new .
```

Gemfileを上書きするか聞かれるのでyを入力し、return。

今回は以下のメッセージが出たので対応。

```
Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/
```

こちらを参考に。
https://qiita.com/libertyu/items/1eb74adc817ab8971100
以下のコマンドを実行。

```
$ brew install yarn
```

続いて

```
$ rails webpacker:install
```

これで準備OK!　以下で起動！

```
$ rails s
```

以下にアクセスして起動を確認。
http://localhost:3000/

<img width="823" alt="スクリーンショット 2019-12-30 0.02.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246652/3fb65af4-f25c-895b-3786-7f1792e21a4a.png">

# まとめ
一つ一つのコマンドの意味を理解してくことは、とても大切です。
一方で、完璧に理解して進むことは時間がいくらあっても足りません。
今回はコマンド入力しただけで進んだ、次回はそのうちの一つのコマンドについて調べて理解が進んだ状態で進んだというように
毎回毎回少しずつ学習していくことがいいのではないかと考えています。

もし、上記のコマンドでうまく行かなかった際はつまずいた箇所を指摘していただけると幸いです。
共に頑張っていきましょう！
【Carthage】failed with exit code 128: fatal: could not read Username for 'https://github.com': terminal prompts disabled

# 概要
Carthageでレポジトリを指定して、

```shell
carthage update --platform ios
```

を実行すると

```shell
A shell task (/usr/bin/env git fetch --prune --quiet https://github.com/Qiuck/Nimble.git refs/tags/*:refs/tags/* +refs/heads/*:refs/heads/* 
(launched in /Users/[user_name]/Library/Caches/org.carthage.CarthageKit/dependencies/Nimble)) failed with exit code 128:
fatal: could not read Username for 'https://github.com': terminal prompts disabled
```

というエラーが出た。

# 解決策

解決策ってほどのものでもなく、 **Cartfileのレポジトリ名がtypoってた** だけでした。

もうちょっと分かりやすいエラーメッセージにしてもらえませんかね...。
2020年02月02日について ※Pythonの記事です。

# はじめに

## 2019年某日

ある素晴らしい記事に出会いました。

[2013年4月5日について ※Rubyの記事です。 | TECHSCORE BLOG](https://www.techscore.com/blog/2013/01/04/2013%E5%B9%B44%E6%9C%885%E6%97%A5%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-%E2%80%BBruby%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%A7%E3%81%99%E3%80%82/)

以下は内容を要約したものです。

- 2013年4月5日を構成する数字に重複がない。すごい！
- 前回はいつ？次回はいつ？Rubyのプログラムによって調査！
- 前回は「○○○○年○○月○○日」で次回は「××××年××月××日」でした！

個人的に興味深く読ませていただき、楽しませていただきました。（ぜひ、みなさまもご覧ください！）プログラミングを使うことでサクッと色々なことが調べられるのは良いですねー。「すごい切り口だな～来年（2020年）は年だけでもすでに2も0も2回ずつ使われているな～」と思っていました。そんなとき、あることに気が付きました。

## 2020年02月02日とは

「アレ……2020年02月02日は0と2の2つの数字しか使われていない……？」

この日は……なんと……“0”と“2”のみで構成されています！！

2013年4月5日とは異なる観点で、この日もレアな日なのでは……？と思いました。というわけで、このような2つ以下の数字で構成されている年月日を調べてみます。元ネタの記事ではRubyを使っていますが、今回はPythonを使います。実行環境はGoogle Colaboratory[^Google Colaboratory]です。

[^Google Colaboratory]: https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja

# 調査

## 制約

今回、年を4桁、月と日を2桁とします。それゆえ、桁が足りない年月日はゼロ（0）によって埋めます。（例：「1年」→「0001年」、「1月」→「01月」）また、対象とする年月日を0001年01月01日～9999年12月31日とします。

## プログラム

```python:該当年月日の調査
import datetime
from collections import Counter

# 定数
START_DAY = datetime.datetime(1, 1, 1)
END_DAY = datetime.datetime(9999, 12, 31)
BORDER = 2

# 対象年月日を辞書に格納（0001年01月01日～9999年12月31日）
target_days = {}
today = START_DAY
while True:
    target_days[today] = today
    if (today == END_DAY):
        break;
    today = today + datetime.timedelta(days=1)

# 対象日数
print(len(days))

# 2つ以下の数字によって構成されるという条件に該当する年月日を辞書ansに格納
ans_days = {}
for today in target_days:
    if (len(Counter(today.strftime("%Y%m%d"))) <= BORDER):
        ans_days[today] = today

# 該当日数
print (len(ans_days))

# 該当率
print (len(ans_days)/len(target_days))
```

## 結果

今回の対象日数は0001年01月01日～9999年12月31日の`3652059`日間でした。その中で、`2020年02月02日`の様に2つ以下の数字で構成されている年月日は`928`日でした。全体に対するその確率は、`0.0002541032332719707`、つまり3935日に1回でした。なかなか、レアじゃないでしょうか。（かなりムラはありますが、10年に1度ペースですね。）ちなみに、以下の年月日が該当しました。（省略、抜粋しています。）

```python:該当年月日の算出
for today in ans_days:
    print(ans_days[today].strftime("%Y/%m/%d"))
```

```console:実行結果
0001年01月01日
0001年01月10日
0001年01月11日
（略）
2002年02月02日
2002年02月20日
2002年02月22日
2020年02月02日
2020年02月20日
2020年02月22日
2022年02月02日
2022年02月20日
2022年02月22日
2111年11月11日
2111年11月12日
2111年11月21日
（略）
9999年09月09日
9999年11月11日
9999年11月19日
```

前回は`2002年02月22日`、18年前ですね。2020年には`2020年02月02日`を含めて、3回あるようで、2022年にも3回あるようですね。その次は2111年……なかなか先ですね……

# おわりに

本記事では、2020年02月02日のように、2つの数字のみで構成されている年月日を調査しました。2020年02月20日や2020年02月22日と近い日がありましたが、確率からいうと10年に1度程度と、レアでしたね。

というわけで（？）、2019年はありがとうございました。:bow:
2020年もよろしくお願いいたします。:bow:

（2019年1月2日追記）
以下の記事に掲載していただきました！ありがとうございます！

- [【Python】Qiita 週間ストック数ランキング【自動更新】（2020年1月1日 13時00分更新 ）](https://qiita.com/kou_pg_0131/items/01127f188250a2d68dbf#_reference-a37ab4270185f4e88e2b)
SATySFiのパッケージを作る

これは「[SATySFi Advent Calendar 2019](https://adventar.org/calendars/3929)」の24日目の記事です。

23日目は[bd_gfngfnさん]()でした。25日目は[puripuri2100]()です。


# はじめに

SATySFiで機能を拡張したり新たな機能を追加したりするときに用いるのが「パッケージ」です。

実態としては`let-inline`や`let-block`で定義されたコマンド、`let`や`let-rec`で定義された関数などです。

利用者側がパッケージを`@require`や`@import`で読み込むだけで、そこで定義されているコマンドや関数を使えるようになるという便利機能で、SATySFiを使っている人間ほぼ全員がお世話になっていることでしょう。

さて、このパッケージはとても簡単に作ることができるのでここで解説してみようと思います。

コマンドや関数をパッケージ化することでメンテナンスしやすくなったり、便利機能を使いまわすことができたり、車輪の再発明を防いだりすることができるので、良いコマンドや関数を作ったらパッケージ化していくようにしましょう。

パッケージの配布方法についてはこのアドベントカレンダーの「[素敵なライブラリをSatyrographosで配布しよう！](https://qiita.com/na4zagin3/items/b392f5d522f9bcc0493b)」をお読みください。


# ファイルを分ける

まず、機能が似ている関数やコマンド、目的が同じ関数やコマンドを別のファイルに分けましょう。これだけでもパッケージになります。

基本としてはそのままコピペするだけですが、注意点として依存する他のパッケージがある場合はそれを読み込む必要がありますし、元の文書のプリアンブルなどに依存する関数などが書いてある場合はそれもすべてコピペする必要があるということです。

ここで定義された関数などは、パッケージを読み込んだだけですぐに使えるようになります。
便利ですね。

しかし、これには欠点があります。
内部で関数などを定義するときだけに使われるものがトップレベルで定義されてしまい、場合によっては他のパッケージの関数などを覆い隠してしまい、衝突してしまうかもしれないのです。

ここで使う機能がモジュールです。


# モジュールを使う

定義する関数などに名前空間を付ける機能がモジュールです。

モジュールは

```
module 〈名前〉 = struct

  関数やコマンドの定義

end
```

という形で使います。
コンストラク名は大文字のアルファベットから始まるアルファベットと数字の組み合わせのものです（正規表現なら`[A-Z][a-zA-Z0-9]*`となります）。

ここで定義された関数は`〈モジュール名〉.〈関数名〉`のようにして使います。
たとえばこんな感じです。

```

module Module0 = struct

  let hoge = 1

end

let fuga = Module0.hoge
```

一々モジュール名を書くのが面倒な時は`open 〈モジュール名〉`とすることで省略できるようになります。

効果を局所的にしたいときは`open 〈モジュール名〉 in`とするか`〈モジュール名〉.(式)`とするかします。


# シグネチャを使う

モジュールを使うと名前空間によって関数などが衝突するのを防げますが、内部で使うだけの関数も公開されてしまいます。

そこで、シグネチャという機能を使うことで後悔する関数やコマンドを限定することができます。

使い方は

```
module 〈名前〉:sig 

  公開する関数などの名前と型

end = struct

  関数やコマンドの定義

end
```

です。関数は`val f : 型`の形で、型は`type t`か`type t = 定義`の形で公開できます。

コマンドは`val cmd : 型のリスト inline-cmdかblock-cmdの指定`か`direct cmd : 型 inline-cmdかblock-cmdの指定`でできます。`direct`を使うと、トップレベルで定義したのと同じように、モジュール名を付けなくてもコマンドを使うことができるようになります。


例えばこんな感じです。

```
@require: stdja

module Module1 :sig

  val hoge : int
  direct \test : [string] inline-cmd
  direct +test : [string] block-cmd

end = struct

  let hoge = 1

  let fuga = 2 %公開されない

  let-inline \test str = embed-string str

  let-block +test str = <+p{\test(str);}>

end

```

# おわりに

短い記事なりましたが、モジュール機能やシグネチャを使って素敵なパッケージをたくさん作ってみてください。