OmniAICreator/Qiita-1.07M huggingface dataset:
conohaのオブジェクトストレージをopenstackでPHPから使う（2019年）

はい、S３使ったら苦労はないということはわかってます、ただ、転送量無料は正義です。
リファレンスも少しわかりにくかったので、メモ。

$optionsの内容についてはconohaの管理画面にある。

使ってるopenstackは▽
https://github.com/php-opencloud/openstack/blob/master/doc/index.rst

まずは、composerで入れてね。

```bash
$ composer require php-opencloud/openstack
```


```php

use OpenStack\OpenStack;
use Guzzle\Http\Exception\ClientErrorResponseException;
use GuzzleHttp\Psr7\Stream;

       $options = [
            'authUrl' => env('CONOHA_AUTH_URL'),  // APIの認証URL
            'username' => env('CONOHA_USERNAME'),  // API ユーザーのユーザー名
            'password' => env('CONOHA_PASSWORD'),      // API ユーザーのパスワード
            'tenantName' => env('CONOHA_TENANT_NAME'),  // テナント情報のテナント名
        ];

        try {
            $client = new OpenStack($options);
            $identityService = $client->identityV2();

            $service = $client->objectStoreV1([
                'identityService' => $identityService,
                'catalogName' => 'Object Storage Service',
            ]);

            //コンテナの存在確認
            //ここはもしかすると作成だけでも良いかもしれない
            if ($service->containerExists('test')) {
                $container = $service->getContainer('test');
            }else{
                //コンテナが存在しない場合はコンテナを作成する
                $container_name = array(
                    'name' => 'test',
                    'readAccess' => '.r:*' //パブリックアクセスにする
                );
                $container = $service->createContainer($container_name);
            }

            //gazelleでアップするファイルを読み込み
            $stream = new Stream(fopen('/var/www/html/app/webroot/img/unko.png', 'r'));

            $file_option = [
                'name'   => 'unko.png',  //オブジェクトストレージ保存するファイル名
                'stream' => $stream,     //これはファイルの本体データ
            ];

            //ファイル（オブジェクトをアップする）
            $container->createObject($file_option);

            // コンテナ内のオブジェクト一覧の取得
            $objects = $container->listObjects();

            // コンテナの中のオブジェクトのパブリックURLを取得する
            foreach ($objects as $object) {
                $images_url[] = $object->getPublicUri();
            }
```

続いて、ACL関係も調査予定。
AWS CLIでecsを構築する手順

aws cliでecsを操作するコマンドは２パターンあります。（aws ecsからecs-cli）
どっちを使ってもいいんですが、一つに統一してほうがいいかも知りません。
今回はecs-cliを使おうとします。

## 大まかな手順
- AWS環境設定(configuration)
awsに繋ぐためのprofileを登録する必要があります。今回はOregonリージョン(us-west2)に環境を構築します。

- configuration

```
ecs-cli configure profile --profile-name west2-profile --access-key "XXXXXXXXXXXXXX" --secret-key "XXXXXXXXXXXXXXXXXXXXXXX"

ecs-cli configure --cluster [CLUSTER_NAME] --default-launch-type EC2 --region us-west-2 --config-name west2-config
```

結果は「.ecs/credentials」、「.ecs/config」に記録されます。


- cluster作成

SSHでecsのホスト・インスタンスにログインするためにssh keyを作成します。
AWSコンソールからEC2 Dashboardに入り、「Key Pairs」で「Create Key Pair」をクリックします。
名前を入力して（今回はwest2-keyにします）、「Create」を押します。すぐダウンロードが始まりますが、~/.sshに入れときましょう。

```
ecs-cli up --keypair west2-key --capability-iam --size 1 --instance-type t2.small --cluster-config west2-config
```

- task/service実行

```
ecs-cli compose --project-name [PROJECT_NAME] --ecs-profile west2-profile --cluster-config west2-config service up
```

task実行のみ：service up -> up
project-nameはservice名、task名、task definition名になります。

このまま実行するとSSMにアクセスを拒否されたと怒られます。

```
Fetching secret data from SSM Parameter Store in [REGION]: AccessDeniedException: User: arn:aws:sts::[ACCOUNT-ID]:assumed-role/ecsTaskExcutionRole/XXXXX is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:[REGION]:[ACCOUNT-ID]:parameter/[パラメータ] status code: 400, request id: XXXXXXXXXX
```

対策としては、ecsTaskExcutionRoleに次のpolicyを与える。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
        {
            "Effect": "Allow",
            "Action": "ssm:GetParameters",
            "Resource": "*"
        }
    ]
}
```

- コンテナーがちゃんと立ち上がったのか確認する

```
ecs-cli ps --ecs-profile west2-profile --cluster-config west2-config
```

- コンテナーからpaprameterが読み取れたのかを確認する。（SSHでECSホストにLOGINする必要がある）

```
docker exec -it `CONTAINER ID` env
```

- サービスを削除する

```
ecs-cli compose --project-name [PROJECT_NAME] --ecs-profile west2-profile --cluster-config west2-config service down
```

- クラスター（及び関連リソース）を削除する

```
ecs-cli down --ecs-profile west2-profile --cluster-config west2-config
Are you sure you want to delete your cluster? [y/N]
```
確認メッセージが出るので[y]を入力して確定します。


## 参考
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_CLI_reference.html
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cmd-ecs-cli-compose-ecsparams.html
https://medium.com/@felipgomesilva/using-secrets-in-aws-ecs-dc43c37ce4a1
https://dev.classmethod.jp/cloud/aws/ecs-secrets/
sqlalchemyメモ

## 設定ファイルを環境変数に設定する
```
export FLASK_CONFIG_FILE=./local.cfg 
```

## model変更をもとにrevisionファイル生成する
```
python manage.py db migrate
```

## revisionファイルを持ってデータベースを更新する
```
python manage.py db upgrade
```

## 手動で編集するrevisionファイル作成する場合
```
python manage.py db revision
```
upgrade, downgradeのないrevisionファイルを作られる


## 現在のrevison情報を表示する； revison履歴を表示する
```
python manage.py db show 
python manage.py db history
```

## 全revisionのsql scriptsを生成する
```
python manage.py db upgrade --sql > ../sql/`date "+%y%m%d%H%M"`.sql
```
【WPF】簡単に特定のコントロールのプロパティ(Width,Heightなど)に、値を一括設定する。

XAMLの小ネタテクニック。
例えば、Textboxが下記のように列挙していて同じような幅(Width)を設定した場合に有効です。

```xml:
<StackPanel>
    <StackPanel HorizontalAlignment="Left">
        <TextBlock Width="100" HorizontalAlignment="Left">性</TextBlock>
        <TextBox Width="200"></TextBox>
    </StackPanel>
    <StackPanel HorizontalAlignment="Left">
        <TextBlock Width="100" HorizontalAlignment="Left">名</TextBlock>
        <TextBox Width="200"></TextBox>
    </StackPanel>
</StackPanel>
```

ResourcesプロパティにTextBlockとTextBoxのWidthを設定するようにします。
こうすることで、StackPanel配下のTextBlockおよびTextBoxのWidthプロパティを一括で設定することができます。

```xml:
<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Width" Value="100"></Setter>
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="Width" Value="200"></Setter>
        </Style>
    </StackPanel.Resources>
    <StackPanel HorizontalAlignment="Left">
        <TextBlock HorizontalAlignment="Left">性</TextBlock>
        <TextBox ></TextBox>
    </StackPanel>
    <StackPanel HorizontalAlignment="Left">
        <TextBlock HorizontalAlignment="Left">名</TextBlock>
        <TextBox ></TextBox>
    </StackPanel>
</StackPanel>
```

適応範囲をWindow全体にしたい場合は、Window.Resourcesに定義を書けばOK。

```xml:
<Window ... 省略...>
    <Window.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Width" Value="100"></Setter>
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="Width" Value="200"></Setter>
        </Style>
    </Window.Resources>
```

同じページ内のコントロールの幅などはそろえることが多いですし、特定範囲にさくっと適用したい場合に有効です。
Railsで「CarrierWave＋fog」を使ってAWSのS3へアップロード

#はじめに
Railsアプリを外部サービスと連携させてみようと思い、AWSが提供するS3へ画像や動画をアップロードしてみた過程をまとめていきます。
今回はCarrierWaveで単純にアップロード機能を利用し、fogでクラウド上のs3へ簡易的にアップロードできるようにしています。

#AWS上での設定
S３の詳しい利用法の要点をまとめます。

①AWSアカウントの取得
　AWSのアカウントを取得。原則としてクレジットカードの登録が必要になります。アカウント作成から12か月間は無料枠(最大5GB)としてS3が利用できます。

②IAMユーザーの作成
　続いてIAMユーザーを作成します。IAMとはAWS上のサービスを操作するユーザーと、ユーザーアクセス権限を管理するものです。
IAMがなかった場合、フルアクセスのAWSアカウントをみんなで共有することになります。
ユーザーがアクセスするための認証情報（アクセスキー、ポリシーの設定）を取得しS3へアクセスします。

※ここで取得したアクセスキーIDとシークレットアクセスキーは絶対に控える＆定期的に更新する

③バケットの作成
　バケットとは、ファイルなどのオブジェクトを格納するための入れ物です。ここでバケット名を決めるのですが、注意が必要です。AWSバケット名の命名規則に従った名前を付けてください。https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/BucketRestrictions.html
自分の場合、バケット名に不適切な文字を記述してしまい、原因がわからずS3にいつまでたってもアクセスできない事態に見舞われました。

続いてバケットのリージョンを設定します。リージョンとはS3のサービスが提供されている場所を意味します。「アジア・パシフィック（東京）」の場合、使用する資格情報は「ap-northeast-1」となります。

#CarrierWaveの導入
```/Gemfile
gem 'carrierwave'
gem 'fog'
```

アップロードファイルの作成
```$ rails g uploader file```
app/uploaders/file_uploader.rbが生成されます。

```file_uploader.rb
class FileUploader < CarrierWave::Base
  require 'streamio-ffmpeg'

  if Rails.env.production?
    storage :fog
  else
    storage :file 
  end

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def extension_white_list
    %w(jpg jpeg gif mp4 MOV wmv)
  end

  version :screenshot do
    process :screenshot
    def full_filename (for_file = model.logo.file)
      "screenshot.jpg"
    end
  end

  def screenshot
    tmpfile = File.join(File.dirname(current_path), "tmpfile")

    File.rename(current_path, tmpfile)

    movie = FFMPEG::Movie.new(tmpfile)
    movie.screenshot(current_path + ".jpg", { resolution: '500x600' },preserve_aspect_ratio: :width)
    File.rename(current_path + ".jpg", current_path)

    File.delete(tmpfile)
  end
end
```
サムネイル用にffmpegを使用しています。
今回はアップロードされたファイルが画像でも動画でも、一旦tmpフォルダーにjpgファイルとして格納し、最終保存先を開発環境時はローカルに、本番環境時はfogに設定しています。

続いてcarrierwave.rbを作成します。

```carrierwave.rb
require 'carrierwave/storeage/fog'

CarrierWave.configure do |config|

  config.fog_provider = 'fog/aws'

  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: 'アクセスキー',
    aws_secret_access_key: 'シークレットアクセスキー',
    region: 'リージョン',
  }
  
  config.fog_directory = 'バケット名'
  #日本語ファイル名の設定
  CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
  config.cache_dir = "#{Rails.root}/tmp/uploads"
end
```

モデルにuploaderを紐づけます。

```gallery.rb
class Gallery < ApplicationRecord
  mount_uploader :file, FileUploader
```

viewの実装は今回は割愛します。
これで本番環境時にS3にアップロードすることができました。
   
#おわり
特に基盤となってくるuploaderとcarrierwaveの設定はまだ完全に理解していないし、不十分なところもあると思うので今後さらに深堀していきたいです。

#参考
・https://qiita.com/junara/items/1899f23c091bcee3b058
・http://vdeep.net/rubyonrails-carrierwave-s3
・https://qiita.com/yukiyukimiyaiwa/items/a9e0103c8342b81f6ac1
・https://stackoverflow.com/questions/15717368/uploading-image-to-s3-using-carrierwave-and-fogs-bad-uri
eclipseのショートカットキーが効かない問題

# 環境
CentOS7
eclipse4.6(日本語化あり)

# 問題
eclipseのショートカットキーの一部効かないことがあったときの対処方法です。
実際に起きた問題としてはCtrl + s は使えるがCtrl + / は使えないなど。

ウィンドウ->設定->一般->キー
の順に移動

ここのデフォルトの復元を押下（キーの設定を変更している場合はその設定も消えるので注意）
適応を押下

最後にeclipseを再起動で直りました。

# ちなみに…
CSVのエクスポートというボタンがありますが、
インポートのボタンはありません。
この機能は正直よく分かりませんがコマンドをCSVで一覧出来るということなのでしょうか。

実際にキーの設定をExportするのは、
ファイル->エクスポート->一般->設定->キー設定
の順に移動し、
.epfでExport出来ます。

インポートするときは、
ファイル->インポート->一般->設定->キー設定
でソース設定ファイルからExportしたファイルを参照し、
キーの設定にチェックを入れて、完了を押下で出来ました。
【elasticsearch6.6.0】scroll APIで大量の検索結果を取得する

Elasticsearchで何か検索した時、特にオプションで何も指定しなければ10件までしか取得されない。
オプションでsizeを指定するとこれを大きくできるのだが、このsizeにも上限があり、10,000件までだ。

10,000件を超えるデータを取得する際は、scroll APIで何回かに分けて取得する事になる。
（10,000件以下でもscrollで複数に分けて取得することも可能）

scroll APIは、実行時点でのスナップショットを保存して、取得しきれなかった分を辿っていくことができる。

```shell
$ curl -H "Content-Type: application/json" -XGET 'http://localhost:9200/index名/type名/_search?scroll=1m&size=1000&pretty=true' -d '
{
  "query": {
    "match": {
      "field名": "検索したい文字列"
    }
  }
}'

# 実行結果
#1000件取得できる。
  "_scroll_id" : "DnF1ZXJ5..........",
  "took" : ,
  "timed_out" : false,
  "_shards" : {
    "total" : ,
    "successful" : ,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : ,
    "max_score" : ,
    "hits" : [
      {
        "_index" : "index名",
        "_type" : "type名",
        "_id" : "8x0a6......",
        "_score" : ,
        "_source" : {
          "field" : "文字列"
        }
      },
...........
...........
......
```

`1m` は、スナップショットを保持する期間。
`size=1000` は、検索した時に取得する件数。

以降は、以下のコマンドで残りのデータを取得できる。
`size=1000` なので、10,000件のデータなら、以下のコマンドを10回実行すれば全ての検索結果を取得できる。
スナップショットは1mしか保持されないので、時間を超えると、４０４エラーになる。

```shell
#_scroll_idを指定して実行。
curl -H "Content-Type: application/json" -XGET 'localhost:9200/_search/scroll'  -d'
{
    "scroll_id" : "DnF1ZXJ5.........." 
}'
```

使わなくなったら、scroll_idを削除すると行儀が良い。

```shell

curl -H "Content-Type: application/json" -XDELETE  'localhost:9200/_search/scroll' -d '
{
    "scroll_id" : "DnF1ZXJ5.........."
}'
```

##参考

[Elasticsearch でつまづいた話 (3)](https://tkrtkhsh.hatenablog.com/entry/2017/12/06/232208)
[ElasticsearchのScroll APIをためしてみた](https://blog.soushi.me/entry/2016/12/23/162825)
円周率は3.05以上であることを示す。

有名な東大入試の問題の解き方を紹介します。

紙と鉛筆でも解けますが、プログラムを組んだ方がよりスムーズに解くことができます。
なぜなら正十二角形を使うからです。
正十二角形は手書きで書くと大変なのでプログラムで書いた方が楽です。

![正12角形のプログラム.png](https://qiita-image-store.s3.amazonaws.com/0/387778/edca108c-06f4-7890-1a08-e88c226dbeab.png)
図1:JavaScriptで描いた正十二角形

それでは早速、今回解いていく問題を確認しましょう。
![問題画像.png](https://qiita-image-store.s3.amazonaws.com/0/387778/c69a32d5-3b13-32d3-2bd5-93823f27bb33.png)
図2:今回扱う問題

1.円周率って何？
そもそも円周率って何でしょうか？
率という数字が示すように「何か」と「何か」の割合のことです。
例えば「勝率」という言葉は「勝ち数」÷「試合数」で求められます。
10試合して３勝している場合勝率は3÷10で0.3になります。

円周率の場合は、「円周の長さ」÷「直径」で求められます。

![円周率.png](https://qiita-image-store.s3.amazonaws.com/0/387778/60b70c65-03f2-ee71-13cf-67190688653b.png)
図3:円周率を求める式

ということで「円周の長さ」÷「直径」の式を活用すると良さそうです。

2.正十二角形を活用した解き方
![円周と正十二角形の長さ.png](https://qiita-image-store.s3.amazonaws.com/0/387778/f9e16d4c-5595-feef-251a-e5d13b1d44e1.png)
図4:円と正十二角形

余弦定理を活用して解きます。
余弦定理が分からない場合はGoogleで「余弦定理　とは」と検索しましょう。
（分からない単語が出てきたら検索する癖をつけましょう）

![計算式.png](https://qiita-image-store.s3.amazonaws.com/0/387778/5d120172-14f9-09aa-49fe-656e4808de55.png)


参考：Pythonによるプログラム
出展：https://qiita.com/redmeteor777/items/4b4aebd9da8db825b10d

```
import math
# [π > 3.05 を証明せよ]
while True:
    target_input = input("円周率がいくつより大きいことを証明しますか？")
    try: #入力値チェック
        target = float(target_input)
    except ValueError:
        print("数値を入力してください。")
    else:
        # 入力値が円周率より大きいと無限ループするため入力値をチェック
        if target <= math.pi:
            break
        else:
            print("円周率より小さい値を入力してください。")
print("円周率が{}より大きいことを証明する".format(target))
print("")
#正ｎ角形の頂点の初期値を3にセット
n = 3
# breakするまでループさせる
while True:
    # 等辺の長さ1、頂角360/nの二等辺三角形の底辺の長さを求める
    kakudo = 360 / n
    # math関数の三角関数計算ではラジアンを用いるので度→ラジアンの変換が必要
    radian_kakudo = math.radians( kakudo )
    # 余弦定理から、底辺 x の長さは[x ^ 2 = 1 ^ 2 + 1 ^ 2 + 2 * 1 * 1 * cos(360 / n)]
    x = ( 1*1 + 1*1 - 2*1*1*math.cos( radian_kakudo ) ) ** 0.5
    # 底辺の長さ * ｎを円周の近似値 y とする
    y = x * n
    print("正{0}角形のとき、辺の長さの合計は{1}".format(n , y))
    if y / 2 > target: #目標値より大きくなったらブレイクして終了処理へ
        break
    # 頂点を1つ増やす
    n = n + 1

print("")
print("円周率 = 円周 / 直径")
print("")
print("{0} / 2 = {1} > {2}".format(y , y / 2 , target))
print("")
print("よって円周率は{}より大きい".format(target))
```
macで標準shellをzshにする方法

この度、shellをzshにして、作業効率アップアップ(?)したので、備忘録
 
```bash:bash

# zshの場所を確認
$ which zsh
>> /bin/zsh

# 以下のコマンドを実行
$ chsh -s /bin/zsh 
$ export SHELL=/bin/zsh
$ exec $SHELL -l
```

変えたら、標準がpython2になったり、pipでインストールしたパッケージ類が使えなくなるので、以下を実行.
zshにも同じpathを指定すれば使えます。

```zsh:zsh
# .zsh_profileを作成して編集
$ vi ~/.zsh_profile
```
```sh:.zsh_profile
# 以下を追加
if [ -d $HOME/.anyenv ] ; then
    export PATH="$HOME/.anyenv/bin:$PATH"
    eval "$(anyenv init -)"
fi
export PATH="$HOME/.pyenv/shims:$PATH"
```
```zsh:zsh
# 更新する
$ source ~/.zsh_profile
```

# 追記
.zshrc に`source ~/.zsh_profile`を追加しないと、ターミナルを起動する度、毎回このコードを入力する羽目になる.
Railsチュートリアル　第2章

#学習内容
[Railsチュートリアル](https://railstutorial.jp/)　　1周目
# 環境
pc:MacBook Air
IDE:AWSCloud9
Rilsバージョン：5.1.6
Rubyバージョン：2.6.0
##2.1 アプリケーションの計画
```$ bundle install --without production```
エラー
<img width="563" alt="スクリーンショット 2019-04-04 16.04.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/27064b76-e09a-7a2d-34a7-72dd770f77e2.png">

```$ bundle update```を実行後、
```$ bundle install --without production```でOK
```$ heroku create```すると　"command not fond"となってしまった
```$ heroku --version```を試すも"command not fond"。
herokuがインストールされていない…（一回インストールしたはずなんだけどな…？）おそらく、新しいアプリを作るときはその都度しないといけないのかな？もう一度インストール。
```$ source <(curl -sL https://cdn.learnenough.com/heroku_install)```
でインストールOK

ここではtwitterのようなアプリを作成する。
ユーザのためのモデルと、マイクロポスト(ツイート)を行うためのモデルを作成する。
##2.1.1 ユーザーのモデル設計
ユーザーモデル↓
<img width="238" alt="スクリーンショット 2019-04-04 16.24.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/00ef27e1-7f4d-9d13-2e0f-51f43d5bc04a.png">
テーブル名は"**users**"
##2.2 Usersリソース
```$ rails generate scaffold User name:string email:string```でusersテーブルの作成
```$ rails db:migrate```でマイグレーションを反映
2.2.1 ユーザーページを探検する
<img width="556" alt="スクリーンショット 2019-04-04 17.25.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/cb0824e3-903e-b4b4-2287-1400d1ef64a7.png">
できなかった…
<img width="292" alt="スクリーンショット 2019-04-04 18.36.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/63bec338-4316-24cd-d7c3-db1a368f9dc4.png">
cloud9上の設定適当にいじってたら、なぜかできた(^_^;)
でもheroku上でひらけない…

<img width="552" alt="スクリーンショット 2019-04-04 19.25.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/db30f459-1d61-c7f3-a832-fc9c83eef6d1.png">


<img width="469" alt="スクリーンショット 2019-04-04 19.22.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/4925a0d8-7861-9601-637f-3c2359c13561.png">
できたー！！[参考](https://qiita.com/ryosuketter/items/f7997be31f079c96f66e)

##2.3.2 マイクロポストをマイクロにする
<img width="260" alt="スクリーンショット 2019-04-05 13.42.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/390288/7fdf4c7c-8ce1-aafe-d724-86dfa40c301a.png">

このページにたどり着くまでにも少し時間を要したので、メモ。

このページを表示するために、モデルの変更やルートファイルを書き換えた
↓
herokuのページで URL /microposts/new　の接続を試みるも失敗。
↓
cloud9上のプレビューでは正しく表示されることを確認
↓
herokuの設定がうまくできていないのかな？
↓
第1章の　git add,push,commit,create,の流れでコマンドを打ったら成功！[参考](https://qiita.com/megu_ma/items/03388e1979b3fc0539f7)


結局、第1章の流れを理解していなかったことがうまくいかなかった原因でした(^_^;)
【Blockchain】修飾子modifierとpayable

前回では、[初めてのSmart Contractsを作ってみた](https://qiita.com/toshiok/items/f65ccd8f7609abe83954)のですが、 いかがでしたでしょうか？
その際に、 `view` と言う関数を作るときに追加する `修飾子` が出てきました。
これは 「この関数を呼ぶのは読み込みONLYで `GAS` がいらないですよ、タダですよ」と言う意味であることを説明しました。
今回は、別の修飾子 `modifier` と `payable` を説明します。

## modifier
前頭の処理が複数の関数で繰り返し同じコードを利用したいときに `modifier` 修飾子を利用します。

```javascript
function setMessage(string newMessage) public isOwner {
    message = newMessage;
}

modifier isOwner() {
    require(owner == msg.sender);
    _;
}
```

上記のサンプルでは、 `isOwner` と言うmodifierを作りました。
これは、実行しようとするアカウントがこのSmart Contractのオーナーかを確認するものです。
使い方は、`setMessage` 関数の宣言に `isOwner` を追記することで完了です。
気をつけることは、modifierを作成するときに、コードの最後に `_;` を書くことです。
これは、「ここで対象の関数の処理をします」を意味します。

これで、関数setMessageは、オーナーしか使えない関数であることになります。

## payable
payable修飾子を関数につけると、その関数にのみ `ether` (お金)を送ることができるようになります。

```javascript
function setMessage(string newMessage) public payable {
    require(msg.value == 3 ether);
    message = newMessage;
}
```

上記のサンプルでは、 `setMessage` に `ether` を送れるように `payable` を追加しました。
そして、その額が `3 ether` ちょうどでなければいけないようになっています。
もし、最低 `3 ether` とかにしたい場合は、 `==` を `>=` に入れ替えてください。

`ether` を送るには、下のようにRemix開発環境の `Run` > `Value` にその額を入力します。

![IMG-01.png](https://qiita-image-store.s3.amazonaws.com/0/273166/94a333af-ad65-94cc-8485-587a512dc789.png)
BoostnoteにAdd(再リンク)できない時にどうすればいいか

## はじまり
Dropbox上でBoostnoteを管理していたら、データが消えました…

正確にはアプリから参照できなくなったですね。
[boostnoteでdropboxデータの復元を試みる](https://qiita.com/Hibiki86002300/items/4520815a1af4249c0d98)に記載されている内容と類似した以下のような現象が起きました。

* データはDropbox上に存在
* Boostnote mobileからは確認可能
* 再リンクが不可

## 環境
* MacOS Sierra 10.12.6
* Boostnote 10.11.15
* Boostnote mobileとDropbox連携(ios 12.1.4)
* python3.6

## 原因
[Boostnoteアップデート後CSONファイルが存在するにも関わらずストレージ設定が消えてフォルダとドキュメントが表示されない障害原因と解消法](https://qiita.com/ma2wit/items/e1c607180facd41c9fbf)がわかりやすくて助かりました。

結論的には、既存のcsonファイルにおいてcontentが空だと、読み込みがエラーになるようです。
同様の問題かどうかは、`View > Toggle Developer Tools`を参照するとわかります。

## 解消方法
やるべきことはcontentが空のファイルを見つけて、削除することです。

順番にノートの中身を確認するにはいかんせんノートの数が多かったので、以下のpythonスクリプトを`Boostnote/notes`ディレクトリにて行うことで探索しました。

```python
import cson
from pathlib import Path
p = Path.cwd()
for path in p.iterdir():
    with open(path) as f:
        c = cson.load(f)
        if len(c['content']) < 1:
            print(path.name)
```

内容はカレントディレクトリにおけるcsonファイルのcontentが1文字より小さいものを探して、ファイル名を標準出力です。
一応、中身を確認してから表示されたファイルを削除することをお勧めします。

これで再リンクできない問題は解決されるはずです。

## 同時に起きていた、別の問題について
Boostnoteを再起動するたびにリンクが解除され、再リンクが必要となる問題も発生していたのですが、そちらは`$HOME/Library/Application Support/Boostnote`を削除して、Boostnoteをインストールし直して強引に解決しました。
もっといい解決法がありそうですが、サボってしまいましたね…

## 参照元
* [boostnoteでdropboxデータの復元を試みる](https://qiita.com/Hibiki86002300/items/4520815a1af4249c0d98)
* [Boostnoteアップデート後CSONファイルが存在するにも関わらずストレージ設定が消えてフォルダとドキュメントが表示されない障害原因と解消法](https://qiita.com/ma2wit/items/e1c607180facd41c9fbf)
今年の言語はRust その2


Rustを学びます

勉強ページは日本語ドキュメント

[プログラミング言語Rust](https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/)

目次は6つ

- はじめる - Rust開発へ向けた環境構築です。
- Rustを学ぶ - 小さなプロジェクトを通してRustについて学びます。
- シンタックスとセマンティクス - Rustについて一歩ずつ、小さく分割しながらやっていきます。
- Effective Rust - 良いRustのコードを書くための高レベルな概念です。
- Nightly Rust - 安定版のRustでは使えないRustの最前線の機能です。
- 用語集 - 本書で使われる用語の参考です。
- 関係書目 - Rustへ影響を与えたもの、Rustに関する論文です。

前記事の続きデス。


## 4. シンタックスとセマンティクス

## 4.2 束縛変数 - Variable Binding

```rust
fn main() {
    // Variable Binding
    let x = 5;
    
    // Patterns
    let (x, y) = (1, 2);
    
    // Type annotations
    let x: i32 = 5;

    // Mutability
    let mut x = 5;
    
    // Initializing bindings
    let z: i32;
        z = 0;


}

```


スコープとシャドーイング


```rust
fn main() {

    let x: i32 = 17;
    
    {
        let y: i32 = 3;
        println!("The value of x is {} and value of y is {}", x, y);
    }
    
    println!("The value of x is {} and value of y is {}", x, y); // <-- エラー! yがスコープ外
}



$ cargo run
   Compiling ex4 v0.1.0 (/home/ec2-user/environment/ex4)
error[E0425]: cannot find value `y` in this scope
  --> src/main.rs:24:62
   |
24 |     println!("The value of x is {} and value of y is {}", x, y);
   |                                                              ^ help: a local variable with a similar name exists: `x`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0425`.
error: Could not compile `ex4`.

To learn more, run the command again with --verbose.

```



```rust
fn main() {

    let x: i32 = 8;
    
    {
        // シャドーイング
        println!("{}", x); //8
        let x = 12;
        println!("{}", x); //12
        
    }

    println!("{}", x); //8
    let x = 42;
    println!("{}", x); //42
    
    
}

```

特に特筆すべきはありませんでした。

次回は関数です。
Wordpress でメールアドレスなしでユーザー登録したい（プラグインなし）

※注意：
Wordpressビギナーの記事（備忘録）です。
鵜呑みにしたら想定外のことが起こるかもしれないので気をつけてください。セキュリティ的なことも考慮していません。（気づきがあれば随時補足します）

※追記：
wp-admin をイジるって対応がそもそもイケてない気がします。
その辺あまり気にしない人は、このまま読み進めてみてください。

## やりたいこと
Wordpress よ、メールアドレスなしでもユーザー追加させてくれ。

## 対象バージョン
Wordpress 5.1.1

## 結論から
以下のファイルを修正する。

[wp-admin/includes/user.php]

```php
if ( empty( $user->user_email ) ) {
  // ↓をコメントアウト
  $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an email address.' ), array( 'form-field' => 'email' ) );
}
```

[wp-admin/user-new.php]
メールアドレス部分のタグから form-required を削除。「必須」の表示が気になる人は required も削除。

```html
<!-- ↓からform-required を削除 -->
<tr class="form-field form-required">

<!-- ↓をまるごと削除 -->
<span class="description"><?php _e( '(required)' ); ?></span>
```

## 経緯
開発用のユーザーとシステム管理のユーザーを同じメールアドレスで登録しようとしたらエラーになる。
Wordpress では同じメールアドレスで複数ユーザーを登録できない。

ならば同じメールアドレスでも登録できるようにすればいいじゃない。
ということでソースを弄ることにする。

ユーザー登録周りは user.php で処理している。
メールアドレスの存在チェックは email_exists() でしてる。

```php
function email_exists( $email ) {
	$user = get_user_by( 'email', $email );
	if ( $user ) {
		return $user->ID;
	}
	return false;
}
```

最初は email_exists を弄るか、こいつの呼び出し元を変更しようと思ったけど、影響大きそうだからやめた。
ユーザー情報が複数とれたときの挙動の考慮とかしたくないし、email_exists の戻りのユーザーIDを一意にできない。
呼び出し元も各所に散らばってる。

ググると「Allow Multiple Accounts」ってプラグインで解決できるとのことだったけど、プラグインが見つからない。
プラグインの新規追加で検索したら普通出てくるんじゃないの？とか思いながら、出ないものはしょーがないので、自力でどうにかする。

そもそもメールアドレスを登録したいわけではないので、メールアドレスを非必須にする方針に変更。
意図的にメールアドレスを登録するなら、存在チェックもちゃんとやる。（つまり現状維持）

サーバ側（user.php）は POST されたメールアドレスがブランクだったらそもそもテーブル参照すらせずにエラーにしてるから、そこをコメントアウトするだけ。
クライアント側（user-new.php）は form-required で必須チェックが効いてるから、それを外すだけ。

これで無事、メールアドレスなしで複数ユーザー登録できました。
![qiita_01.jpg](https://qiita-image-store.s3.amazonaws.com/0/365593/3d623800-4a89-2eb9-b4cc-3243603cf1f3.jpeg)

メールアドレスなしユーザーでのログインも問題なし。（ログインしただけだからその先は知らない）

## おまけ
user.php は wp-includes/user.php と wp-admin/includes/user.php があるので注意。
最初 wp-includes/user.php しかないと思ってて、修正しても全然反映されないとか思ってハマった。
【Laravel】Request/Responseオブジェクトの利用

#コントーラ編集#
 - useで`Request`/`Response`追加。
 - アクションを定義時にも引数に`Request`/`Response`を入れる。
 - この引数に入れた変数がオブジェクトになるので、アクションとして使用していく感じ。


#サンプルコード#
テストページの表示。
クライアント側からのリクエスト情報を表示。
こちらからのレスポンスを表示。

```php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Response;

class HelloControllerRR extends Controller
{
	public function index(Request $request, Response $response) {
		$html= <<<EOF

<html>
<head>
<meta charset="UTF-8">
<title>Request/Response</title>
<style>body{font-size:16pt;} h1{font-size:100px; color:#eee;}</style>
</head>
<body>
<h1>Request/Response</h1>
<p>これはRequest/Responseオブジェクトを利用したアクションです。</p>
<hr>
<h3>Request</h3>
<pre>{$request}</pre>
<ul>
<li>url()メソッド：{$request->url()}</li>
<li>fullUrl()メソッド：{$request->fullUrl()}</li>
<li>path()メソッド：{$request->path()}</li>
</ul>
<hr>
<h3>Response</h3>
<pre>{$response}</pre>
</body>
</html>
EOF;

	$response->setContent($html);
	return $response;
	}
}
?>
```

#使用メソッド#
###Request###
 - `$request->url()`：アクセスしたURLを返す。
 - `$request->fullUrl()`：アクセスしたアドレスを完全な形で返す。クエリー文字(?abc=xyzなど)を含む。
 - `$request->path()`：ドメイン下のパス部分だけ返す。

###Response###
 - `this->status()`：クライアント返答時のステータスコードを返す。正常なら200。
 - `this->content()`：コンテンツの取得。
 - `this->setContent(値)`：引数の値にコンテンツを変更する。

#参考書籍#
[PHPフレームワークLaravel入門]
(https://www.amazon.co.jp/dp/B07CLLW4MX/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
Chapter2-2 Pp.51-55
Git Commit後にコメントを変更

[直前のもの]
git commit --amend

[直前のものではない場合]
1.
`git rebase -i HEAD~n`
を入力
~~・-iはCase Insensitiveの略~~
<font color="red">***・-iはInteractiveの略***</font>
・nは取得するコメントの数。２個前のコメントを修正したい場合はnを２に変更して入力。

2.
`Git rebase -i HEAD~3`
と入力した場合、


```
pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

# Rebase 9fdb3bd..f7fde4a onto 9fdb3bd
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out 
```


と出力されるので、以下のように変えたいコメントの行のPickをRewordに変更する。

```
pick e499d89 Delete CNAME
reword 0c39034 Better README
reword f7fde4a Change the commit message but push the same commit.
```

変更を保存して閉じるとコメントを修正する画面になるので修正して保存する。
Ruby on RailsでStripeのPlanの情報を取得する

# 前提

`stripe` の `gem` を使う。

```
gem 'stripe'
```

# 方法

`Stripe::Plan.all` でPlanの一覧を取得できる。

```
Stripe::Plan.all
=> #<Stripe::ListObject:0x3fefc6771f14> JSON: {
  "object": "list",
  "data": [
    {"id":"plan_Epxxxxxxxxxxxx","object":"plan","active":true,"aggregate_usage":null,"amount":480,"billing_scheme":"per_unit","created":1554439001,"currency":"jpy","interval":"month","interval_count":1,"livemode":false,"metadata":{},"nickname":"product_name","product":"prod_Epxxxxxxxxxxxx","tiers":null,"tiers_mode":null,"transform_usage":null,"trial_period_days":60,"usage_type":"licensed"}
  ],
  "has_more": false,
  "url": "/v1/plans"
}
```

classはArrayとなっている。

```
Stripe::Plan.all.data.class
=> Array
```
存在しない属性名を使ってdynamoにupdateをかけたい時

DynaoDBのMap属性をもつアイテムに対して更新をかけたいが、その際に存在していなキー名を追加して更新したい場合の覚書。



```javascript
let obj = {
        [departmentCode]:{
            [userId]:role
        }
    }

let putParams = {
        TableName: tenantTable,
        Key: { tenantId : tenantId },
        UpdateExpression: 'set #u = :r',
        ExpressionAttributeNames: {
            '#u' : 'users',
        },
        ExpressionAttributeValues: {
          ':r' : obj
        }
      };

let putData = await docClient.update(putParams).promise();

```

簡単にいうと、存在しない属性名を使って更新をかけることはできない。
（ValidationException: The document path provided in the update expression is invalid for update
）
なので、確実に存在している属性名までをExpressionAttributeNamesにかき、その値としてオブジェクトを渡す。
オブジェクトはあくまで値をして渡されるだけなので、そのままの形で登録される。結果的にMap型として保存される。
php-master-changes 2019-04-04

今日は JIT の修正、ドキュメントの typo 修正と不使用変数の削除があった！

# 2019-04-04
## dstogov: Avoid useless code generation for RECV opcodes
- https://github.com/php/php-src/commit/fc28e9a0b3b8752898a4538721a58e366836630f
- ext/opcache/jit で、RECV オペコード（関数用のコード冒頭で引数をスタックから取り出して型チェックする奴）での不要なコード生成をしないよう修正

## dstogov: Fixed crash
- https://github.com/php/php-src/commit/34d5c1b16fc0499548806b97e3d4c49a2756406a
- ext/opcache/jit で、最適化レベル 1 以下の場合でクラッシュする問題があったのを修正

## dstogov: jump optimization
- https://github.com/php/php-src/commit/a146e6eea7aeb395cfac9e706d81107a97009ed1
- ext/opcache/jit で、new 用の命令 ZNED_NEW のコードを最適化
- 関数分離してたのをインラインに開いて zend_jit_cond_jmp() 使うようにして is_terminated 付けるようにしてる

## dstogov: Avoid code generation for BB with single VM instruction
- https://github.com/php/php-src/commit/21f249cfa4c78466f54223092d4f2b316450e802
- ext/opcache/jit で、最適化レベル 1 以下の場合オペコード 1 つの basic block についてはコード生成をしないよう修正

## cmb69: Fix typos
- https://github.com/php/php-src/commit/54bed8d2ea7c885118ea73e197fc3ff8eaf24cca
- [7.3~]
- NEWS の typo を修正

## dstogov: unused variable
- https://github.com/php/php-src/commit/575c3576a719e7e7bebbd480b7aad7c8a61aa637
- [7.4~]
- 使っていない変数の削除
中間テーブルつくってみた

中間テーブル教えてもらったからメモ。

###環境
Laravel
mysql

###テーブル
・profilesテーブル
１：１のデータ

・businesstypesテーブル
１：ｎのデータ

###モデル
・profileモデル

・businesstypesモデル


###経緯
・profilesテーブルにフォーム情報送信
・今までは１：１のリレーションで動いていた
・フォーム情報の追加作業する
・追加情報の持っている値が文字列ではなく、配列だった
・１：ｎのリレーションが必要
・中間テーブルつくる

###必要な知識
| 関係 | 親 | 子 | 備考 |
|:--|:--|:--|:--|
| 1:1 | hasOne | belongsTo |  |
| 1:N | hasMany | belongsTo |  |
| N:N | belongsToMany | belongsToMany | 中間テーブル必要 |

##やったこと
１．businesstype_profileテーブル作成
２．profileモデルに追記
３．profileコントローラに追記

##１．businesstype_profileテーブル作成

```php
Schema::create('businesstype_profile', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('profile_id')->unsigned()->index('profile_id')->comment('プロフィールID');
            $table->integer('businesstype_id')->unsigned()->index('businesstype_id')->comment('業種ID');
            $table->timestamps();
        });
```
※これが中間テーブルになる
カラム
businesstype_profile_id
profile_id
bisinesstype_id
created_at
updated_at


##２．profileモデルに追記

```php:
class Profile extends Model
{
    public function businesstype_profile()
    {
        return $this->belongsToMany('App\Models\Businesstype', 'businesstype_profile', 
'profile_id', 'businesstype_id')->orderBy('sort')->withTimestamps();
    }
}
```
・第1引数では最終的な接続先モデルを指定する
・第2引数では中間テーブル名を指定する
・第3引数では接続元モデルIDを示す中間テーブル内のカラムを指定する
・第4引数では接続先モデルIDを示す中間テーブル内のカラムを指定する

##３．profileコントローラに追記

```php:
$profile->businesstype_profile()->sync([1, 2]);
```
更新したプロフィールに、businesstype_profileテーブルのID1とID2を関連付け

ID1 → businesstype_idに1が入る

ID2 → businesstype_idに2が入る

ここに変数入れれば欲しい値渡せる

###おまけ
sync()じゃなくて、attach()でもいける。

```php
$profile->businesstype_profile()->attach(4);
 ```
attach（４）はbusinesstype_profile関数の第4引数（relatedPivotKey）をみてる
pipenv(pyenv)で新しいpythonがinstallされないとき


## 1.環境
- ubuntu 18.04 (docker)
- pyenv 1.2.10-2-g3176c8b7 (2019/4/5時点最新)

## 2.エラー

```shell-session
root@b19a1760d4e6:~# pipenv install --python 3.6.8
Warning: Python 3.6.8 was not found on your system…
Would you like us to install CPython 3.6.8 with pyenv? [Y/n]: Y
Installing CPython 3.6.8 with pyenv (this may take a few minutes)…
✘ Failed...
Something went wrong…
Downloading Python-3.6.8.tar.xz...
-> https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz

Warning: The Python you just installed is not available on your PATH, apparently.
```

pipenvの下で動いてるpyenvでも同じ感じになった。

```shell-session
root@b19a1760d4e6:~# pyenv install 3.6.8
Downloading Python-3.6.8.tar.xz...
-> https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz
root@b19a1760d4e6:~#
```

Downloading以降が何もなく、エラーも出ない。

## 3.原因
findしてもPython-3.6.8.tar.xzが見つからないのでおかしいと思ったら，`wget`(と`curl`も)が入っていなかった．
pyenvはwgetがないと静かに死ぬのか...

wget入れたらインストールできた．

```shell
root@b19a1760d4e6:~# apt install wget
```

docker環境だと結構ハマりそう。

しかもpipenvから実行したときだとエラーメッセージがインストールは完了したけどパスの問題みたいにみえるのでややこしい。

## 4.備考
issueあげてみるか，と思ったら既にあった．
[pyenv install fails silently when downloader not found](https://github.com/pyenv/pyenv/issues/1156)
一年前＆まだオープン
Mac(10.4 Mojave)で gem install scrypt に失敗(ld: symbol(s) not found for architecture i386)

Macを10.4(Mojave)にアップデートし、Xcode Command Line Tools(macOS 10.14) for Xcode 10.2をインストールしたあと、`gem install scrypt`の実行に失敗しました。

```bash
$ gem install scrypt -v 2.0.2
Building native extensions.  This could take a while...
ERROR:  Error installing scrypt:
	ERROR: Failed to build gem native extension.
...
gcc -bundle -o x86_64-darwin/libscrypt_ext.bundle x86_64-darwin/crypto_scrypt-sse.o x86_64-darwin/memlimit.o x86_64-darwin/scrypt_calibrate.o x86_64-darwin/scrypt_ext.o x86_64-darwin/scryptenc_cpuperf.o x86_64-darwin/sha256.o -fexceptions -arch x86_64 -arch i386
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
ld: warning: ignoring file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libSystem.tbd, missing required architecture i386 in file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libSystem.tbd
Undefined symbols for architecture i386:
...
```

文字通り10.4(Mojave)向けのCommand Line Toolsから`-arch i386`をサポートしなくなったことが原因らしい。
https://developer.apple.com/download/more/ から Xcode Command Line Tools(macOS 10.13) for Xcode 10.1 をインストールしたら、`gem install scrypt`できるようにしました。
(ただ根本的な解決にはなっていないので、要調査)
TypeScript のテストを Jest (ts-jest) でやってみる

公式では `babel` でバベってやるやり方がメインで紹介されていますが
(https://jestjs.io/docs/ja/getting-started#typescript-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)
ちょっと違うやり方でやります。

> TypeScript support in Babel is just transpilation, Jest will not type-check your tests as they are ran. If you want that, you can use ts-jest.

と言われてるように、バベると型検査されないので
型検査が必要な場合には `ts-jest` を使うのがいいですね。


## セットアップ

パッケージを入れます:

```console:console
npm install --save-dev typescript jest ts-jest @types/jest
```

Jest の設定は `package.json` にも書いてみます:

```json:package.json
{
  "jest": {
    "moduleFileExtensions": [
      "ts",
      "js"
    ],
    "transform": {
      "^.+\\.ts$": "ts-jest"
    },
    "globals": {
      "ts-jest": {
        "tsConfig": "tsconfig.json"
      }
    },
    "testMatch": [
      "**/tests/**/*.test.ts"
    ]
  }
}
```

`testMatch` がテスト対象ですね。
`${projectRoot}/tests/` 以下の
`*.test.ts` に書かれたテストスペックが実行対象になります。

`transform` は `ts-jest` で TypeScript をよしなに実行してもらうのに必要です。
`SyntaxError: Unexpected identifier` とか出た場合は変換できてないので指定が漏れてないかチェックします。

あとは `globals > ts-jest > tsConfig` に `tsconfig.json` を読むように指定します。これで tsconfig の構成でテストできるようになります。

---

👉 https://jestjs.io/docs/ja/configuration
Jest の config は
ほかに `jest.config.js` として `export` する書き方や、
JSONとして `jest.config.json` のようにして実行時にオプションで指定もできます。
その場合は `jest` 以下を記述するようにします。

## `import` のエイリアスを指定

`import` するときに相対パスだとちょっと長ったらしいので
`import some from "#/some/module";` とかで
ソースディレクトリからモジュールを読み込めるようにしておくと若干嬉しいです:

```json:tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./src/",
    "paths": {
      "#/*": ["*"]
    },   
  }
}
```

Jest の設定にも追記します:

```json:package.json
{
  "jest": {
    "moduleNameMapper": {
      "^#/(.+)": "<rootDir>/src/$1"
    }
  }
}
```

これで `#/some/module` は `${projectRoot}/src/some/module` にマップされます。

## テストを書く

テストの書き方自体はいつもの感じで書けます。
無駄に型指定しかするとこんな感じです:

```typescript:tests/greet.test.ts
import greet from "#/greet";

describe('greet', (): void => {
    test('should say hello to Tom.', (): void => {
        const response: string = greet('Tom');
        expect(response).toBe('Hello, Tom!');
    });
})
```

```typescript:src/greet.ts
export default (name: string): string => `Hello, ${name}!`;
```

テストを書けました。
テストの実行に追加で指定は必要ありません (他にオプションが必要なければ)。
`npm test` で実行できるようにしましょう。:

```json:package.json
{
  "scripts": {
    "test": "jest"
  }
}

```

```console:console
> npm test

PASS  tests/greet.test.ts
  greet
    ✓ should say hello to Tom. (3ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.829s, estimated 3s
Ran all test suites.
```

これで OK です。

あとは [https://jestjs.io/docs/ja/getting-started にあるドキュメント](https://jestjs.io/docs/ja/getting-started) に沿って、効率的にテストを書いていくとよいですね！
【Laravel】コントローラの作成と編集

#前提知識#
MVCアーキテクチャ
 - Model：データ処理。DBに関係。
 - View：テンプレートのレンダリング。
 - Controller：全体制御。**<-ここの話**

#コントローラ作成#
ターミナルにて下記コマンド。

```
php artisan make:controller HelloController
```

`app/Http/Controllers`フォルダ内に`HellorController.php`が作成される。
これは`App/Http/Controllers`という名前空間にクラスとして配置される。

#コントローラにアクションを追加・ルーティング#
`HellorController.php`を開いてみるとデフォルトでいろいろ書いてある。

 - `namespace~`：名前空間
 - `use~`：Illuminate/Httpパッケージ内のRequestを使える状態にしている。
 - `class~`：HelloControllerはControllerというクラスを継承。
 - 
この下にアクションを追加していく。
なお、ルートパラメーターとして`$id`と`$unknown`を渡す。

```php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HelloController extends Controller
{
	public function index($id='noname', $pass='unknown'){
		return <<< EOF

<html>
<head>
<title>Hello/Index</title>
<meta chraset="UTF-8">
<style>
body{font-size:16pt;}
h1{font-size:100px; color:#eee;}
</style>
</head>
<body>
<h1>Index</h1>
<p>これは、Helloコントーラのindexアクションです。</p>
<ul>
<li>ID: {$id}</li>
<li>PASS: {$pass}</li>
</ul>
</body>
</html>
EOF;

	}
}
?>
```

次にルートを編集。
`routes/web.php`にて

```php
Route::get('hello/{id?}/{pass?}', 'HelloController@index');
```
これでOK。

#コントローラに複数のアクションを持たせる場合#
###（１）コントローラを記述###
`app/Http/Controllers/HelloController.php`を編集。
まず名前空間とRequestを設定(namespace~/use~)。
変数と関数の定義(global~/function~)。
そしてからクラス定義。
クラスの中にアクションを二つ以上持たせることで、コントーラに複数のアクションを持たせる。

```php
<?php
// 名前空間とRequestの使用可能を設定。
namespace App\Http\Controllers;
use Illuminate\Http\Request;

// コントーラクラス作成時に必要な関数を自作
global $head, $head, $style, $body, $end;
$head = '<html><head>';
$style = <<<EOF
<style>
body{font-size:16pt;}
h1{font-size:100px; color:#eee;}
</style>
EOF;
$body = '</head><body>';
$end = '</body></html>';

function tag($tag, $txt){
	return "<{$tag}>".$txt."</{$tag}>";
}

// コントーラクラスの作成
class HelloController extends Controller
{
	// 第一アクション
	public function index(){
		global $head, $head, $style, $body, $end;

		$html=$head.tag('title', 'Hello/Index')
		.$style
		.$body.tag('h1', 'Index').tag('p', 'this is Index page').'<a href="/hello/other">go to Other page</a>'
		.$end;

		return $html;
	}

	// 第二アクション
	public function other(){
		global $head, $head, $style, $body, $end;

		$html=$head.tag('title', 'Hello/Other')
		.$style
		.$body.tag('h1', 'other').tag('p', 'this is Other page')
		.$end;

		return $html;
	}
}
?>
```
###（２）ルート情報を編集###
`routes/web.php`を編集。
`Route:get`の第二引数でコントーラとアクション名を指定。

```php
Route::get('hello', 'HelloController@index');
Route::get('hello/other', 'HelloController@other');
```
これでコントローラに複数のアクションを持たせることができた。

#シングルアクションコントーラ#
namespace,useは省略。
クラスにつきアクションを一つのみ持つ。
アクション定義部に`__invoke()`を足す。

```php
class HelloControllerSingle extends Controller
{
	public function __invoke(){
	return <<<EOF

<html>
<head>
<meta charset="UTF-8">
<title>Hello/Single</title>
<style>body{font-size:16pt;} h1{font-size:100px; color:#eee;}</style>
</head>
<body>
<h1>Single Action</h1>
<p>これはシングルアクションコントーラのアクションです。</p>
</body>
</html>
EOF;
	}
}
```

#参考書籍#
[PHPフレームワークLaravel入門]
(https://www.amazon.co.jp/dp/B07CLLW4MX/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
Chapter2-2 Pp.39-51
Capistrano3-pipenv を書いた

# 一言で

ruby アプリケーションに対する、 `capistrano/bundler` 相当の python 版、 `capistrano3/pipenv` を書いた。

# 詳細

```ruby:Gemfile
group :development do
  gem 'capistrano3-pipenv', require: false
end
```

して、

```ruby:Capfile
require 'capistrano3/pipenv'
# pyenv を利用する場合
require 'capistrano3/pyenv'
```

すると、 `pyenv exec pipenv install --deploy` がデプロイの中で呼ばれるようになる。

設定項目と、そのデフォルト値は以下

```ruby:config/deploy.rb
# capistrano3/pipenv

set :pipenv_roles, :all
set :pipenv_servers, -> { release_roles(fetch(:pipenv_roles)) }
set :pipenv_flags, []
set :pipenv_env_variables, {}
set :pipenv_clean_options, '--all'

# capistrano3/pyenv
set :pyenv_path, -> {
  pyenv_path = fetch(:pyenv_custom_path)
  pyenv_path ||
    if fetch(:pyenv_type, :user) == :system
      '/usr/local/pyenv'
    else
      '$HOME/.pyenv'
    end
}
set :pyenv_roles, fetch(:pyenv_roles, :all)
set :pyenv_python_dir, -> { "#{fetch(:pyenv_path)}/versions/#{fetch(:pyenv_python)}" }
set :pyenv_map_bins, %w{pipenv}
```
Google App EngineのHTTPレスポンスヘッダにContent-Typeを書き込む順序について

`net/http` の ResponseWriter へのレスポンスヘッダへの書き込みは、以下のようにWriteしたあとに変更しても影響はないとされている。

> Changing the header map after a call to WriteHeader (or Write) has no effect unless the modified headers are trailers.
https://golang.org/src/net/http/server.go#L99

またGoogle App Engineのドキュメントには、BodyからContent-Typeを推定すると記載されている。
> Content-Type
> If you do not explicitly set this header, the http.ResponseWriter class detects the content type from the start of the response body, and sets the Content-Type header accordingly.
> このヘッダーを明示的に設定しない場合は、http.ResponseWriter クラスがレスポンス本文の先頭からコンテンツ タイプを検出し、それに応じて Content-Type ヘッダーが設定されます。


しかし上記の仕様とは異なる結果となることがあり、
実行環境、Content-Typeを設定するタイミングHTTPメソッドによってResponseとして返ってくるContent-Typeが変わる。

ローカルで実行したときの4つの結果はすべて想定通りである。

想定外の挙動は以下の2つ。

1. GAE(appdngine.Main)とGAE(http.ListenAndServe)どちらもGETのときはContent-Typeがapplication/jsonにならない。
2. GAE(appdngine.Main) | Writeの後 | POST の場合に、Content-Typeがapplication/jsonになっている。

| 実行環境 | Content-Typeを設定するタイミング | HTTPメソッド |Responseとして返ってくるContent-Type|
|-----------|------------|------------|------------|
| ローカル | Writeの前 | GET |application/json|
| ローカル | Writeの前 | POST |application/json|
| ローカル | Writeの後 | GET |text/plain; charset=utf-8|
| ローカル | Writeの後 | POST |text/plain; charset=utf-8|
| GAE(appdngine.Main) | Writeの前 | GET |text/html; charset=UTF-8|
| GAE(appdngine.Main) | Writeの前 | POST |application/json|
| GAE(appdngine.Main) | Writeの後 | GET |text/html; charset=UTF-8|
| GAE(appdngine.Main) | Writeの後 | POST |application/json|
| GAE(http.ListenAndServe) | Writeの前 | GET |text/html; charset=UTF-8|
| GAE(http.ListenAndServe) | Writeの前 | POST |application/json|
| GAE(http.ListenAndServe) | Writeの後 | GET |text/html; charset=UTF-8|
| GAE(http.ListenAndServe) | Writeの後 | POST |text/plain; charset=utf-8|

まだコードは読めていないが予想としては、UTF-8とutf-8と大文字、小文字のパターンが存在している。Go標準は小文字なので、大文字のときはGAEが書き換えている可能性がある。
つまりGAEでGETのときはresponseを書き換えられている。GAE(http.ListenAndServe) | Writeの後 | POST のときだけは、Go標準の挙動としてtext/plain; charset=utf-8が返っている。

検証コード

```go
package main

import (
	"net/http"

	"google.golang.org/appengine"
)

// 正しい実装
func handler1(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(`{"test": "hello"}`))
}
// 正しくない実装
func handler2(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(`{"test": "hello"}`))
	w.Header().Set("Content-Type", "application/json")
}

func main() {
	http.HandleFunc("/1", handler1)
	http.HandleFunc("/2", handler2)

	// ローカル
	// http.ListenAndServe(":8080", nil)
	// GAE(appdngine.Main)
	// appengine.Main()
	// GAE(http.ListenAndServe)
	// http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil) 
}
```


まだ実装の調査できてないけどいったんメモです。
初心者がProgate中級編でつまづいたところ

#はじめに

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンに参加している、tomokiyo_hiromuです。
プログラミングの勉強を始めて約10時間が経過しました。
今回は、Progate中級編を終えてつまづいたところを発信しようと思います。

#クラスでないものには「.」を付けない

ここに関しては、ガイドが教えてくれたおかげで苦労しませんでした。
ですが、実際に自分一人で作業するときにはきっとミスします。

stylesheet.cssでは、
index.htmlのタグでクラス指定していないものに「.」を付けてはいけません。

#終了タグを間違えない

タグ名を入力し、tabキーを押すと自動で終了タグを補完してくれます。
これは便利な機能ですが、終了タグの位置を間違えるとエラーが出てしまいます。
私がよくミスをしたのは
要素を挟んでいるのに、一行目に終了タグを配置していたこと。
役立つ機能だからこそ、有効に使って効率化したいところです。

#ペースを上げすぎない
これは初級編の時と変わりませんが、だからこそ大切なことだと実感しています。
一人でスラスラコードを書ける人は別として、私のような初心者は下手にペースを上げてはいけません。
まずは小さなミスがゼロになるくらい慎重に打ち、効率化を求めるのはそのあとでも遅くありません。

#まとめ
中級編まで終えて、未経験の頃よりもはるかに上達しました。
これからはサポートに頼らず、一人でアウトプットの練習をしていくつもりです。
プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。
最後まで読んでいただき、ありがとうございました。
Alexa Blueprintsで「じゃんけん」スキルをつくってみた 

#■Blueprintsは真のノンプログラミングスキル作成ツールっぽい
2019年3月、ノンプログラミングでAlexaのスキルが作成できる「Blueprints」がリリースされました。**今まで**は、ノンプログラミングではあるが、プログラミング関連に造詣がないと実はスキルは作れないツールがほとんどでした。何言っちゃってんのって感じだが、確かに**コードは書かなくてよいけど実は環境設定が必要**だったりする。。。。ってことが言いたいのです。
でも、この**「Blueprints」は違います**。これを使うと、**本当にプログラミングを知らない人でも、本当にスキルを作成できるっぽい**です。

ということで、そんな事も簡単にできちゃうんだ感を出すために「じゃんけん」スキルを作ってみたので紹介します。Blueprintの操作自体は説明しません、スキルのロジックだけ説明します。

~~そんな程度の事ならQiitaではなく、ほかでやってくれ的な向きもあるかとは思うが、固い事いわずに暖かい目で見てやってほしい。~~



##■まずは動作動画から
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/Alexa?src=hash&amp;ref_src=twsrc%5Etfw">#Alexa</a> の <a href="https://twitter.com/hashtag/Blueprints?src=hash&amp;ref_src=twsrc%5Etfw">#Blueprints</a> で、じゃんけんスキルを作ってみた。ルーレットテンプレート使用。 <a href="https://t.co/qK2xGzBUYi">pic.twitter.com/qK2xGzBUYi</a></p>&mdash; Google Homer (@google_homer_) <a href="https://twitter.com/google_homer_/status/1111897723513364480?ref_src=twsrc%5Etfw">March 30, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##■説明は面倒なのでスクショだけ上げます　(話し違う?)
先攻の手の発話に呼応する3つのスキル(グー/チョキ/パー)でできています。
テンプレートの「ルーレット」を使って、後攻の手としてグー/チョキ/パーのいずれかを返しています。
![Screenshot_20190405-115218.png](https://qiita-image-store.s3.amazonaws.com/0/234533/f5046515-c92b-107f-fd50-7a4aa2f0b7eb.png)

![グー.png](https://qiita-image-store.s3.amazonaws.com/0/234533/5d8d17a9-db3e-9aed-2799-f0a83b350069.png)
![チョキ.png](https://qiita-image-store.s3.amazonaws.com/0/234533/5a61eb04-c4d8-39f3-a754-53a3e3521eba.png)
![パー.png](https://qiita-image-store.s3.amazonaws.com/0/234533/ceaaf45e-7458-598f-4608-40dc55b3d6d9.png)
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "#{table_name}" does not exist

## 事象
こんなエラーが出てきた

```
     ActiveRecord::StatementInvalid:
       PG::UndefinedTable: ERROR:  relation "#{table_name}" does not exist
       LINE 8:                WHERE a.attrelid = '"#{table_name}"'::...
                                                 ^
       :               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                            pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
                            c.collname, col_description(a.attrelid, a.attnum) AS comment
                       FROM pg_attribute a
                       LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
                       LEFT JOIN pg_type t ON a.atttypid = t.oid
                       LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
                      WHERE a.attrelid = '"#{table_name}"'::regclass
                        AND a.attnum > 0 AND NOT a.attisdropped
                      ORDER BY a.attnum
```

## 解決方法

migrationファイルが消えているので作り直す
バッチファイルでログローテート

システム運用で忘れちゃいけないのがログのローテーション。
Windowsにはlinuxみたいにlogrotateが実装されていないので、バッチファイルで実現します。

```logrotate.bat
@echo off
cd /d %~dp0

:: ローテしたいファイル（バッチを置いた場所に応じて、絶対パスまたは相対パスを渡す）
set LogFile=%1
:: 超えたらローテさせるByte数（例：1048576 ＝ 1MB）
set LimitByte=%2

call :getTimeStamp
call :checkFileSize "%LogFile%"

if %FileSize% gtr %LimitByte% (
	rem ローテーション
	move "%LogFile%" "%LogFile%_%TimeStamp%"
)

exit /b

:: ファイルサイズチェック
:checkFileSize
	setlocal
	endlocal & set FileSize=%~z1
exit /b

:: タイムスタンプの取得
:getTimeStamp
    setlocal

    set YYYY=%DATE:~0,-6%
    set MM=%DATE:~5,-3%
    set DD=%DATE:~-2%
    set /a H=%TIME:~0,-9%
    set M=%TIME:~3,-6%
    set S=%TIME:~6,-3%
    if %H% lss 10 (
        set H=0%H%
    )
    endlocal & set TimeStamp=%YYYY%%MM%%DD%-%H%%M%%S%
exit /b
```

第二引数のバイト数にゼロを渡せば問答無用でローテーションします。
実行してみる。

```
>type nul > 0Byte.txt
>fsutil file createnew 1MByte.txt 1048576
>fsutil file createnew 5MByte.txt 5242880

>dir
2019/04/05  12:10    <DIR>          .
2019/04/05  12:10    <DIR>          ..
2019/04/05  12:05                 0 0Byte.txt
2019/04/05  12:07         1,048,576 1MByte.txt
2019/04/05  12:07         5,242,880 5MByte.txt
2019/04/05  12:02               739 logrotate.bat

>logrotate.bat 0Byte.txt 1024
>logrotate.bat 1MByte.txt 0
        1 個のファイルを移動しました。
>logrotate.bat 5MByte.txt 5242881
>logrotate.bat 5MByte.txt 5242879
        1 個のファイルを移動しました。

>dir
2019/04/05  12:17    <DIR>          .
2019/04/05  12:17    <DIR>          ..
2019/04/05  12:05                 0 0Byte.txt
2019/04/05  12:07         1,048,576 1MByte.txt_20190405-121649
2019/04/05  12:07         5,242,880 5MByte.txt_20190405-121743
2019/04/05  12:16               782 logrotate.bat
```

タスクスケジューラに組み込んだりして使ってください。