2017年11月19日 星期日

用 Ruby 實作 Elixir 的 cond statement

## Elixir:

```
defmodule Validator do
  def validate_age(age) do
    if age < 18 do
      "Under 18"
    else
      if age < 21 do
        "Under 21"
      else
        "Adult"
      end
    end
  end
end
```

變成

```
defmodule Validator do
  def validate_age(age) do
    cond do
      age < 18 -> "Under 18"
      age < 21 -> "Under 21"
      true -> "Adult"
    end
  end
end
```

## Ruby

Implement 1

```ruby
class Elixir

  def cond(&block)
    assertions = block.call()
    return assertions.compact[0]
  end

  def cassert(assertion, block)
    block.call() if assertion == true
  end

end



RSpec.describe Elixir do
  let(:elixir) { described_class.new }

  describe "cond" do
    specify do
      result = elixir.cond do
        [
          elixir.cassert(false, -> { return 1 }),
          elixir.cassert(true, -> { return 2 }),
          elixir.cassert(true, -> { return 3 })
        ]
      end

      expect(result).to eq(2)
    end
  end


  describe "cassert" do
    specify do
      result = elixir.cassert(true, -> { return 1 })

      expect(result).to eq(1)
    end

    specify do
      result = elixir.cassert(false, -> { return 1 })

      expect(result).to eq(nil)
    end
  end
end

```



Implement 2

```ruby

class Elixir
  def cond(*assertions)
    return assertions.compact.first
  end

  def cassert(assertion, block)
    return block.call() if assertion == true
  end
end



RSpec.describe Elixir do
  let(:elixir) { described_class.new }

  describe "cond" do
    specify do
      result = elixir.cond(
        elixir.cassert(false, -> { return 1 }),
        elixir.cassert(true, -> { return 2 }),
        elixir.cassert(true, -> { return 3 })
      )

      expect(result).to eq(2)
    end
  end

  describe "cassert" do
    specify do
      result = elixir.cassert(true, -> { 1 })

      expect(result).to eq(1)
    end

    specify do
      result = elixir.cassert(false, -> { 1 })

      expect(result).to eq(nil)
    end
  end
end

```


Implement 3

```ruby

class Elixir
  def cond(*assertions)
    return assertions.compact.first
  end

  def if(assertion)
    yield if block_given? && assertion == true
  end
end

RSpec.describe Elixir do
  let(:elixir) { described_class.new }

  describe "cond" do
    specify do
      result = elixir.cond(
        elixir.if(false) { 1 },
        elixir.if(true) { 2 },
        elixir.if(true) { 3 }
      )

      expect(result).to eq(2)
    end
  end

  describe "if" do
    specify do
      result = elixir.if(true) { 1 }

      expect(result).to eq(1)
    end

    specify do
      result = elixir.if(true)

      expect(result).to eq(nil)
    end

    specify do
      result = elixir.if(false) { 1 }

      expect(result).to eq(nil)
    end
  end
end
```




2017年11月18日 星期六

Capistrano forward agent


Capistrano forward agent 可以讓我們不用把 server 上的key 加到 github 也能拉 private repo


今天遇到 permission deny 的問題,結果是因為 mac 重開機就清空了 ssh agents ,導致沒有 key 可以 forward ,要永久加到 ssh agent 裡面,要執行

```
ssh-add -K ~/.ssh/id_rsa
```

之後再 deploy 就行了

https://chodounsky.net/2015/07/27/forward-ssh-keys-for-capistrano-deploys/

設定 domain

A record: 把這個 domain 綁到特定 IP
CNAME: 別名,例如 hello.waynechu.com,hello 就是



https://www.oyag.com/9501/websys


Nginx


/etc/nginx/site-availables/myconfig

```
server {
  listen 80;
  server_name www.example.com;
  location / {
    proxy_pass 127.0.0.1:8000;
  }
}
```

cd /etc/nginx/site-enabled

sudo ln -s /etc/nginx/site-availables/myconfig

https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-server-blocks-virtual-hosts-on-ubuntu-16-04

2017年11月17日 星期五

加速 git clone

最近網速慢到快死,尤其是 git clone,竟然不到 10kb/s 所以 google 了一下加速的方法


https://codeyarns.com/2016/01/12/slow-speed-on-git-clone/

在 Linode 跑 lending bot

Ubuntu 16.04 LTS

先參考裝機筆記 https://everyday1percent.blogspot.hk/2017/10/blog-post.html 把基本的機器安全設定設好


把機器加到github https://help.github.com/articles/connecting-to-github-with-ssh/

安裝 docker https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-using-the-repository

安裝 docker compose https://docs.docker.com/compose/install/

```
sudo docker login
```

server
```
mkdir projects
cd projects
git clone xxxxx
cd xxxxx
sudo docker-compose up -d
```

成功的log
```
Creating lendingbot_nginx_1 ...
Creating lendingbot_nginx_1 ... done
Creating lendingbot_poloniex_1 ...
Creating lendingbot_bitfinex_1 ...
Creating lendingbot_poloniex_1
Creating lendingbot_poloniex_1 ... done
```



測試一下是不是可以連線,進 http://poloniex.yourdomain

通常要等一陣子,但如果有出現 nginx 就是成功了

## 加上 HTTP auth

先進VPS機器裡面生成密碼檔案

bash -c “echo -n ‘USERNAME:’ >> /path/to/htpasswd/subdomain.doamin”
bash -c “openssl passwd -apr1 >> /path/to/htpasswd/subdomain.doamin”

建立好之後,修改 docker-compose.yaml

在 services nginx volumes 下加入
- /path/to/htpasswd:/etc/nginx/htpasswd

重啟 docker 就會有了

可以自動放貸的機器人 poloniexlendingbot 的筆記

可以自動放貸的機器人,支援 Bitfinex 和 Poloniex,而且有 docker compose 可以一鍵跑完還有 Web UI 介面,潮。

https://github.com/BitBotFactory/poloniexlendingbot


## 重要的參數:

- gapbottom
- gaptop
- gapMode

gapbottom 跟 gaptop

gapbottom 就是指要「跳過」多少 loan offers,這裡的「跳過」是指數量

例如下圖:現在共有 194 顆 BTC 想要用 0.017 的 rate 借出,那如果我 gapbottom 設 200 就是指我想要用比前 200 顆 BTC 想要借 rate 還要更好的 rate 借出,在此例就是會用 0.018 以上的 rate 借出。

gaptop 就是我最多借到多少 rate,像以下圖為例如果 gaptop 超過 4509 (超多人掛在 0.02 rate) 那基本上就是不可能借出了

那為什麼要有 gaptop 呢?這就跟 spreadlend 有關。

spreadlend 就是指在 gapbottom 和 gaptop 之間你要拆成幾個 loan offers 去借,假設是 10 好了,那麼就會幫你在這個區間平均 create 10 個 offer。

例如我有 10 BTC,spreadlend 10,那就會幫我建立 10 個出借 1 BTC 且 rate 在 gaptop 到 gapbottom 之間的 loan offers,至於 rate 是多少則是參考其他 offers 來算出來的。



那什麼是 gapMode? gapMode 就是指「算 gapbottom 和 gaptop」的「算法」,目前有三種 gapMode

* Raw

這是最簡單的一種,假設我選 `gapMode = Raw` 然後 gapbottom 設 10,那就是如果我借 ETH 就跳過 10 ETH,如果我借 BTC 就跳過 10 BTC

* RawBTC

這跟 Raw 很像,但唯一不同的點是他都是以 BTC 為單位,以上面選 `gapMode = RawBTC` 然後 gapbottom 設 10 的例子來說好了,如果我借 BTC 就跳過 10 BTC,但如果我借 ETH 他就會跳過「等值 10 BTC 的 ETH」,假設 1 BTC = 9 ETH,那就會跳過 90 ETH

* Relative

相較於 RawBTC 是以 BTC 為基礎,Relative 則是已你有的錢為基礎,假設我有 20 BTC 100 ETH,那選 `gapMode = Relative ` 然後 gapbottom 設 10 的例子來看的話就是我要跳過

- 出借 BTC 時,跳過 10% * 20 BTC = 2 BTC
- 出借 ETH 時,跳過 10% * 100 ETH = 10 ETH



## 次重要的參數

* mindailyrate: 最低接受多少 rate
* spreadlend: 拆幾單
* xdays: 借款週期,設 0 就是 2 days
* minloansize: 最低的 loan offer amount,因為程式會一直拆 loan offers,有可能會拆到很碎,所以需要設這個阻止程式一直往下拆


## Bonus

* 另外這個 bot 還支援各種通知,例如 slack, telegram, email, irc.... etc,只要在設定檔加些東西就行了,很簡單 http://poloniexlendingbot.readthedocs.io/en/latest/configuration.html#notifications

* Web UI 介面,潮




2017年11月16日 星期四

Ruby keyword arguments


TL;DR:


```ruby
  def log_operator(operator: nil, **options)
    self.operator = operator
  end
```

可以:

log_operator(operator: user, greeting: "hello")

因為

**options

會變成

{
  greeting: "hello"
}

https://www.justinweiss.com/articles/fun-with-keyword-arguments/